1- import { ExclamationCircleIcon } from "@heroicons/react/20/solid" ;
1+ import { ArrowPathRoundedSquareIcon , ArrowRightIcon , CheckIcon , ExclamationCircleIcon } from "@heroicons/react/20/solid" ;
22import { BookOpenIcon } from "@heroicons/react/24/solid" ;
3- import { useNavigation } from "@remix-run/react" ;
3+ import { useLocation , useNavigation } from "@remix-run/react" ;
44import { LoaderFunctionArgs } from "@remix-run/server-runtime" ;
55import { formatDuration } from "@trigger.dev/core/v3/utils/durations" ;
66import { typedjson , useTypedLoaderData } from "remix-typedjson" ;
77import { ListPagination } from "~/components/ListPagination" ;
88import { AdminDebugTooltip } from "~/components/admin/debugTooltip" ;
99import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel" ;
1010import { PageBody , PageContainer } from "~/components/layout/AppLayout" ;
11- import { LinkButton } from "~/components/primitives/Buttons" ;
11+ import { Button , LinkButton } from "~/components/primitives/Buttons" ;
1212import { DateTime } from "~/components/primitives/DateTime" ;
13+ import { Dialog , DialogTrigger } from "~/components/primitives/Dialog" ;
1314import { NavBar , PageAccessories , PageTitle } from "~/components/primitives/PageHeader" ;
1415import { Paragraph } from "~/components/primitives/Paragraph" ;
16+ import { PopoverMenuItem } from "~/components/primitives/Popover" ;
1517import { Spinner } from "~/components/primitives/Spinner" ;
1618import {
1719 Table ,
1820 TableBlankRow ,
1921 TableBody ,
2022 TableCell ,
23+ TableCellMenu ,
2124 TableHeader ,
2225 TableHeaderCell ,
2326 TableRow ,
@@ -29,12 +32,17 @@ import {
2932 BatchStatusCombo ,
3033 descriptionForBatchStatus ,
3134} from "~/components/runs/v3/BatchStatus" ;
35+ import { CheckBatchCompletionDialog } from "~/components/runs/v3/CheckBatchCompletionDialog" ;
3236import { LiveTimer } from "~/components/runs/v3/LiveTimer" ;
3337import { useOrganization } from "~/hooks/useOrganizations" ;
3438import { useProject } from "~/hooks/useProject" ;
3539import { redirectWithErrorMessage } from "~/models/message.server" ;
3640import { findProjectBySlug } from "~/models/project.server" ;
37- import { BatchList , BatchListPresenter } from "~/presenters/v3/BatchListPresenter.server" ;
41+ import {
42+ BatchList ,
43+ BatchListItem ,
44+ BatchListPresenter ,
45+ } from "~/presenters/v3/BatchListPresenter.server" ;
3846import { requireUserId } from "~/services/session.server" ;
3947import { docsPath , ProjectParamSchema , v3BatchRunsPath } from "~/utils/pathBuilder" ;
4048
@@ -150,19 +158,22 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
150158 < TableHeaderCell > Duration</ TableHeaderCell >
151159 < TableHeaderCell > Created</ TableHeaderCell >
152160 < TableHeaderCell > Finished</ TableHeaderCell >
161+ < TableHeaderCell >
162+ < span className = "sr-only" > Go to batch</ span >
163+ </ TableHeaderCell >
153164 </ TableRow >
154165 </ TableHeader >
155166 < TableBody >
156167 { batches . length === 0 && ! hasFilters ? (
157- < TableBlankRow colSpan = { 7 } >
168+ < TableBlankRow colSpan = { 8 } >
158169 { ! isLoading && (
159170 < div className = "flex items-center justify-center" >
160171 < Paragraph className = "w-auto" > No batches</ Paragraph >
161172 </ div >
162173 ) }
163174 </ TableBlankRow >
164175 ) : batches . length === 0 ? (
165- < TableBlankRow colSpan = { 7 } >
176+ < TableBlankRow colSpan = { 8 } >
166177 < div className = "flex items-center justify-center" >
167178 < Paragraph className = "w-auto" > No batches match these filters</ Paragraph >
168179 </ div >
@@ -215,13 +226,14 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
215226 < TableCell to = { path } >
216227 { batch . finishedAt ? < DateTime date = { batch . finishedAt } /> : "–" }
217228 </ TableCell >
229+ < BatchActionsCell batch = { batch } path = { path } />
218230 </ TableRow >
219231 ) ;
220232 } )
221233 ) }
222234 { isLoading && (
223235 < TableBlankRow
224- colSpan = { 7 }
236+ colSpan = { 8 }
225237 className = "absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-charcoal-900/90"
226238 >
227239 < Spinner /> < span className = "text-text-dimmed" > Loading…</ span >
@@ -231,3 +243,50 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
231243 </ Table >
232244 ) ;
233245}
246+
247+ function BatchActionsCell ( { batch, path } : { batch : BatchListItem ; path : string } ) {
248+ const location = useLocation ( ) ;
249+
250+ const isPending = batch . status === "PENDING" ;
251+
252+ if ( ! isPending ) return < TableCell to = { path } > { "" } </ TableCell > ;
253+
254+ return (
255+ < TableCellMenu
256+ isSticky
257+ popoverContent = {
258+ < >
259+ < PopoverMenuItem
260+ to = { path }
261+ icon = { ArrowRightIcon }
262+ leadingIconClassName = "text-blue-500"
263+ title = "View batch"
264+ />
265+ { isPending && (
266+ < Dialog >
267+ < DialogTrigger
268+ asChild
269+ className = "size-6 rounded-sm p-1 text-text-dimmed transition hover:bg-charcoal-700 hover:text-text-bright"
270+ >
271+ < Button
272+ variant = "small-menu-item"
273+ LeadingIcon = { ArrowPathRoundedSquareIcon }
274+ leadingIconClassName = "text-success"
275+ fullWidth
276+ textAlignLeft
277+ className = "w-full px-1.5 py-[0.9rem]"
278+ >
279+ Try and resume
280+ </ Button >
281+ </ DialogTrigger >
282+ < CheckBatchCompletionDialog
283+ batchId = { batch . id }
284+ redirectPath = { `${ location . pathname } ${ location . search } ` }
285+ />
286+ </ Dialog >
287+ ) }
288+ </ >
289+ }
290+ />
291+ ) ;
292+ }
0 commit comments