1
- import { ExclamationCircleIcon } from "@heroicons/react/20/solid" ;
1
+ import { ArrowPathRoundedSquareIcon , ArrowRightIcon , CheckIcon , ExclamationCircleIcon } from "@heroicons/react/20/solid" ;
2
2
import { BookOpenIcon } from "@heroicons/react/24/solid" ;
3
- import { useNavigation } from "@remix-run/react" ;
3
+ import { useLocation , useNavigation } from "@remix-run/react" ;
4
4
import { LoaderFunctionArgs } from "@remix-run/server-runtime" ;
5
5
import { formatDuration } from "@trigger.dev/core/v3/utils/durations" ;
6
6
import { typedjson , useTypedLoaderData } from "remix-typedjson" ;
7
7
import { ListPagination } from "~/components/ListPagination" ;
8
8
import { AdminDebugTooltip } from "~/components/admin/debugTooltip" ;
9
9
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel" ;
10
10
import { PageBody , PageContainer } from "~/components/layout/AppLayout" ;
11
- import { LinkButton } from "~/components/primitives/Buttons" ;
11
+ import { Button , LinkButton } from "~/components/primitives/Buttons" ;
12
12
import { DateTime } from "~/components/primitives/DateTime" ;
13
+ import { Dialog , DialogTrigger } from "~/components/primitives/Dialog" ;
13
14
import { NavBar , PageAccessories , PageTitle } from "~/components/primitives/PageHeader" ;
14
15
import { Paragraph } from "~/components/primitives/Paragraph" ;
16
+ import { PopoverMenuItem } from "~/components/primitives/Popover" ;
15
17
import { Spinner } from "~/components/primitives/Spinner" ;
16
18
import {
17
19
Table ,
18
20
TableBlankRow ,
19
21
TableBody ,
20
22
TableCell ,
23
+ TableCellMenu ,
21
24
TableHeader ,
22
25
TableHeaderCell ,
23
26
TableRow ,
@@ -29,12 +32,17 @@ import {
29
32
BatchStatusCombo ,
30
33
descriptionForBatchStatus ,
31
34
} from "~/components/runs/v3/BatchStatus" ;
35
+ import { CheckBatchCompletionDialog } from "~/components/runs/v3/CheckBatchCompletionDialog" ;
32
36
import { LiveTimer } from "~/components/runs/v3/LiveTimer" ;
33
37
import { useOrganization } from "~/hooks/useOrganizations" ;
34
38
import { useProject } from "~/hooks/useProject" ;
35
39
import { redirectWithErrorMessage } from "~/models/message.server" ;
36
40
import { 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" ;
38
46
import { requireUserId } from "~/services/session.server" ;
39
47
import { docsPath , ProjectParamSchema , v3BatchRunsPath } from "~/utils/pathBuilder" ;
40
48
@@ -150,19 +158,22 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
150
158
< TableHeaderCell > Duration</ TableHeaderCell >
151
159
< TableHeaderCell > Created</ TableHeaderCell >
152
160
< TableHeaderCell > Finished</ TableHeaderCell >
161
+ < TableHeaderCell >
162
+ < span className = "sr-only" > Go to batch</ span >
163
+ </ TableHeaderCell >
153
164
</ TableRow >
154
165
</ TableHeader >
155
166
< TableBody >
156
167
{ batches . length === 0 && ! hasFilters ? (
157
- < TableBlankRow colSpan = { 7 } >
168
+ < TableBlankRow colSpan = { 8 } >
158
169
{ ! isLoading && (
159
170
< div className = "flex items-center justify-center" >
160
171
< Paragraph className = "w-auto" > No batches</ Paragraph >
161
172
</ div >
162
173
) }
163
174
</ TableBlankRow >
164
175
) : batches . length === 0 ? (
165
- < TableBlankRow colSpan = { 7 } >
176
+ < TableBlankRow colSpan = { 8 } >
166
177
< div className = "flex items-center justify-center" >
167
178
< Paragraph className = "w-auto" > No batches match these filters</ Paragraph >
168
179
</ div >
@@ -215,13 +226,14 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
215
226
< TableCell to = { path } >
216
227
{ batch . finishedAt ? < DateTime date = { batch . finishedAt } /> : "–" }
217
228
</ TableCell >
229
+ < BatchActionsCell batch = { batch } path = { path } />
218
230
</ TableRow >
219
231
) ;
220
232
} )
221
233
) }
222
234
{ isLoading && (
223
235
< TableBlankRow
224
- colSpan = { 7 }
236
+ colSpan = { 8 }
225
237
className = "absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-charcoal-900/90"
226
238
>
227
239
< Spinner /> < span className = "text-text-dimmed" > Loading…</ span >
@@ -231,3 +243,50 @@ function BatchesTable({ batches, hasFilters, filters }: BatchList) {
231
243
</ Table >
232
244
) ;
233
245
}
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