1- import { ExclamationCircleIcon } from "@heroicons/react/20/solid" ;
1+ import {
2+ ArrowPathRoundedSquareIcon ,
3+ ArrowRightIcon ,
4+ ExclamationCircleIcon ,
5+ } from "@heroicons/react/20/solid" ;
26import { BookOpenIcon } from "@heroicons/react/24/solid" ;
3- import { useNavigation } from "@remix-run/react" ;
7+ import { useLocation , useNavigation } from "@remix-run/react" ;
48import { LoaderFunctionArgs } from "@remix-run/server-runtime" ;
59import { formatDuration } from "@trigger.dev/core/v3/utils/durations" ;
610import { typedjson , useTypedLoaderData } from "remix-typedjson" ;
711import { ListPagination } from "~/components/ListPagination" ;
812import { AdminDebugTooltip } from "~/components/admin/debugTooltip" ;
913import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel" ;
1014import { PageBody , PageContainer } from "~/components/layout/AppLayout" ;
11- import { LinkButton } from "~/components/primitives/Buttons" ;
15+ import { Button , LinkButton } from "~/components/primitives/Buttons" ;
1216import { DateTime } from "~/components/primitives/DateTime" ;
17+ import { Dialog , DialogTrigger } from "~/components/primitives/Dialog" ;
1318import { NavBar , PageAccessories , PageTitle } from "~/components/primitives/PageHeader" ;
1419import { Paragraph } from "~/components/primitives/Paragraph" ;
20+ import { PopoverMenuItem } from "~/components/primitives/Popover" ;
1521import { Spinner } from "~/components/primitives/Spinner" ;
1622import {
1723 Table ,
1824 TableBlankRow ,
1925 TableBody ,
2026 TableCell ,
27+ TableCellMenu ,
2128 TableHeader ,
2229 TableHeaderCell ,
2330 TableRow ,
@@ -29,12 +36,17 @@ import {
2936 BatchStatusCombo ,
3037 descriptionForBatchStatus ,
3138} from "~/components/runs/v3/BatchStatus" ;
39+ import { CheckBatchCompletionDialog } from "~/components/runs/v3/CheckBatchCompletionDialog" ;
3240import { LiveTimer } from "~/components/runs/v3/LiveTimer" ;
3341import { useOrganization } from "~/hooks/useOrganizations" ;
3442import { useProject } from "~/hooks/useProject" ;
3543import { redirectWithErrorMessage } from "~/models/message.server" ;
3644import { findProjectBySlug } from "~/models/project.server" ;
37- import { BatchList , BatchListPresenter } from "~/presenters/v3/BatchListPresenter.server" ;
45+ import {
46+ BatchList ,
47+ BatchListItem ,
48+ BatchListPresenter ,
49+ } from "~/presenters/v3/BatchListPresenter.server" ;
3850import { requireUserId } from "~/services/session.server" ;
3951import { docsPath , ProjectParamSchema , v3BatchRunsPath } from "~/utils/pathBuilder" ;
4052
@@ -150,19 +162,22 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
150162 < TableHeaderCell > Duration</ TableHeaderCell >
151163 < TableHeaderCell > Created</ TableHeaderCell >
152164 < TableHeaderCell > Finished</ TableHeaderCell >
165+ < TableHeaderCell >
166+ < span className = "sr-only" > Go to batch</ span >
167+ </ TableHeaderCell >
153168 </ TableRow >
154169 </ TableHeader >
155170 < TableBody >
156171 { batches . length === 0 && ! hasFilters ? (
157- < TableBlankRow colSpan = { 7 } >
172+ < TableBlankRow colSpan = { 8 } >
158173 { ! isLoading && (
159174 < div className = "flex items-center justify-center" >
160175 < Paragraph className = "w-auto" > No batches</ Paragraph >
161176 </ div >
162177 ) }
163178 </ TableBlankRow >
164179 ) : batches . length === 0 ? (
165- < TableBlankRow colSpan = { 7 } >
180+ < TableBlankRow colSpan = { 8 } >
166181 < div className = "flex items-center justify-center" >
167182 < Paragraph className = "w-auto" > No batches match these filters</ Paragraph >
168183 </ div >
@@ -215,13 +230,14 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
215230 < TableCell to = { path } >
216231 { batch . finishedAt ? < DateTime date = { batch . finishedAt } /> : "–" }
217232 </ TableCell >
233+ < BatchActionsCell batch = { batch } path = { path } />
218234 </ TableRow >
219235 ) ;
220236 } )
221237 ) }
222238 { isLoading && (
223239 < TableBlankRow
224- colSpan = { 7 }
240+ colSpan = { 8 }
225241 className = "absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-charcoal-900/90"
226242 >
227243 < Spinner /> < span className = "text-text-dimmed" > Loading…</ span >
@@ -231,3 +247,48 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
231247 </ Table >
232248 ) ;
233249}
250+
251+ function BatchActionsCell ( { batch, path } : { batch : BatchListItem ; path : string } ) {
252+ const location = useLocation ( ) ;
253+
254+ if ( batch . hasFinished ) return < TableCell to = { path } > { "" } </ TableCell > ;
255+
256+ return (
257+ < TableCellMenu
258+ isSticky
259+ popoverContent = {
260+ < >
261+ < PopoverMenuItem
262+ to = { path }
263+ icon = { ArrowRightIcon }
264+ leadingIconClassName = "text-blue-500"
265+ title = "View batch"
266+ />
267+ { ! batch . hasFinished && (
268+ < Dialog >
269+ < DialogTrigger
270+ asChild
271+ className = "size-6 rounded-sm p-1 text-text-dimmed transition hover:bg-charcoal-700 hover:text-text-bright"
272+ >
273+ < Button
274+ variant = "small-menu-item"
275+ LeadingIcon = { ArrowPathRoundedSquareIcon }
276+ leadingIconClassName = "text-success"
277+ fullWidth
278+ textAlignLeft
279+ className = "w-full px-1.5 py-[0.9rem]"
280+ >
281+ Try and resume
282+ </ Button >
283+ </ DialogTrigger >
284+ < CheckBatchCompletionDialog
285+ batchId = { batch . id }
286+ redirectPath = { `${ location . pathname } ${ location . search } ` }
287+ />
288+ </ Dialog >
289+ ) }
290+ </ >
291+ }
292+ />
293+ ) ;
294+ }
0 commit comments