@checkstack/automation-frontend 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/package.json +16 -16
- package/src/pages/AutomationListPage.tsx +151 -140
- package/src/pages/RunsPage.tsx +117 -109
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# @checkstack/automation-frontend
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b218e3e: Migrate every list table to the shared `DataTable`, so columns can now be
|
|
8
|
+
sorted by clicking their headers (name, status, severity, timestamps, counts,
|
|
9
|
+
...) and tables that had no search gain a global search box. Tables render on
|
|
10
|
+
an opaque `bg-card` surface, fixing the previously transparent, hard-to-read
|
|
11
|
+
tables (e.g. Catalog Management). Existing per-page filters, bulk selection,
|
|
12
|
+
access gating, extension slots, provenance locks, row-click drawers, and
|
|
13
|
+
mobile card layouts are preserved. Incident/maintenance severity and status
|
|
14
|
+
sort by impact rank (most urgent first), not alphabetically. Server-paginated
|
|
15
|
+
tables keep server-side ordering and do not add a misleading page-local search.
|
|
16
|
+
|
|
17
|
+
Row action buttons are now standardized on the shared `RowActions`/`RowAction`
|
|
18
|
+
primitive, so every table's edit/delete/etc. look identical (a subtle ghost
|
|
19
|
+
icon button; destructive tinted red, confirmatory tinted green, never a loud
|
|
20
|
+
filled button). Redundant section headings that merely echoed the page title on
|
|
21
|
+
single-table pages (Incidents, Maintenances, SLO Objectives, Installed Plugins,
|
|
22
|
+
Satellite Nodes) were removed. The Infrastructure Settings tab rail gained an
|
|
23
|
+
accessible `Infrastructure settings` navigation label so its tab buttons stay
|
|
24
|
+
distinguishable from the new sortable column-header buttons in each tab's table.
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [b218e3e]
|
|
29
|
+
- Updated dependencies [b218e3e]
|
|
30
|
+
- @checkstack/auth-frontend@0.12.0
|
|
31
|
+
- @checkstack/gitops-frontend@0.7.0
|
|
32
|
+
- @checkstack/ui@1.25.0
|
|
33
|
+
- @checkstack/script-packages-frontend@0.4.9
|
|
34
|
+
- @checkstack/secrets-frontend@0.3.8
|
|
35
|
+
|
|
36
|
+
## 0.10.3
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Updated dependencies [c55d7c6]
|
|
41
|
+
- Updated dependencies [c55d7c6]
|
|
42
|
+
- @checkstack/ui@1.24.0
|
|
43
|
+
- @checkstack/common@0.21.0
|
|
44
|
+
- @checkstack/auth-frontend@0.11.3
|
|
45
|
+
- @checkstack/gitops-frontend@0.6.8
|
|
46
|
+
- @checkstack/script-packages-frontend@0.4.8
|
|
47
|
+
- @checkstack/secrets-frontend@0.3.7
|
|
48
|
+
- @checkstack/ai-common@0.6.5
|
|
49
|
+
- @checkstack/auth-common@0.12.2
|
|
50
|
+
- @checkstack/automation-common@0.9.2
|
|
51
|
+
- @checkstack/catalog-common@2.6.2
|
|
52
|
+
- @checkstack/frontend-api@0.13.2
|
|
53
|
+
- @checkstack/integration-common@0.9.7
|
|
54
|
+
- @checkstack/template-engine@0.4.10
|
|
55
|
+
- @checkstack/signal-frontend@0.3.4
|
|
56
|
+
|
|
3
57
|
## 0.10.2
|
|
4
58
|
|
|
5
59
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/automation-frontend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -16,20 +16,20 @@
|
|
|
16
16
|
"lint:code": "eslint . --max-warnings 0"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@checkstack/auth-common": "0.12.
|
|
20
|
-
"@checkstack/auth-frontend": "0.
|
|
21
|
-
"@checkstack/automation-common": "0.9.
|
|
22
|
-
"@checkstack/ai-common": "0.6.
|
|
23
|
-
"@checkstack/catalog-common": "2.6.
|
|
24
|
-
"@checkstack/common": "0.
|
|
25
|
-
"@checkstack/frontend-api": "0.13.
|
|
26
|
-
"@checkstack/gitops-frontend": "0.
|
|
27
|
-
"@checkstack/integration-common": "0.9.
|
|
28
|
-
"@checkstack/script-packages-frontend": "0.4.
|
|
29
|
-
"@checkstack/secrets-frontend": "0.3.
|
|
30
|
-
"@checkstack/signal-frontend": "0.3.
|
|
31
|
-
"@checkstack/template-engine": "0.4.
|
|
32
|
-
"@checkstack/ui": "1.
|
|
19
|
+
"@checkstack/auth-common": "0.12.2",
|
|
20
|
+
"@checkstack/auth-frontend": "0.12.0",
|
|
21
|
+
"@checkstack/automation-common": "0.9.2",
|
|
22
|
+
"@checkstack/ai-common": "0.6.5",
|
|
23
|
+
"@checkstack/catalog-common": "2.6.2",
|
|
24
|
+
"@checkstack/common": "0.21.0",
|
|
25
|
+
"@checkstack/frontend-api": "0.13.2",
|
|
26
|
+
"@checkstack/gitops-frontend": "0.7.0",
|
|
27
|
+
"@checkstack/integration-common": "0.9.7",
|
|
28
|
+
"@checkstack/script-packages-frontend": "0.4.9",
|
|
29
|
+
"@checkstack/secrets-frontend": "0.3.8",
|
|
30
|
+
"@checkstack/signal-frontend": "0.3.4",
|
|
31
|
+
"@checkstack/template-engine": "0.4.10",
|
|
32
|
+
"@checkstack/ui": "1.25.0",
|
|
33
33
|
"@dnd-kit/core": "^6.3.1",
|
|
34
34
|
"@dnd-kit/sortable": "^8.0.0",
|
|
35
35
|
"@dnd-kit/utilities": "^3.2.2",
|
|
@@ -43,6 +43,6 @@
|
|
|
43
43
|
"typescript": "^5.0.0",
|
|
44
44
|
"@types/react": "^19.0.0",
|
|
45
45
|
"@checkstack/tsconfig": "0.0.7",
|
|
46
|
-
"@checkstack/scripts": "0.7.
|
|
46
|
+
"@checkstack/scripts": "0.7.2"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Link, useNavigate } from "react-router-dom";
|
|
3
|
-
import { Workflow, Plus, FlaskConical, Trash2 } from "lucide-react";
|
|
3
|
+
import { Workflow, Plus, FlaskConical, Trash2, History } from "lucide-react";
|
|
4
4
|
import {
|
|
5
5
|
usePluginClient,
|
|
6
6
|
accessApiRef,
|
|
@@ -24,14 +24,10 @@ import {
|
|
|
24
24
|
Button,
|
|
25
25
|
Badge,
|
|
26
26
|
Toggle,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
TableBody,
|
|
32
|
-
TableCell,
|
|
33
|
-
ResponsiveTable,
|
|
34
|
-
MobileCardList,
|
|
27
|
+
DataTable,
|
|
28
|
+
type DataTableColumn,
|
|
29
|
+
RowActions,
|
|
30
|
+
RowAction,
|
|
35
31
|
LoadingSpinner,
|
|
36
32
|
QueryErrorState,
|
|
37
33
|
EmptyState,
|
|
@@ -186,56 +182,56 @@ const AutomationListContent: React.FC = () => {
|
|
|
186
182
|
// All sections expanded by default so nothing is hidden on first load.
|
|
187
183
|
const allGroupKeys = React.useMemo(() => groups.map((g) => g.key), [groups]);
|
|
188
184
|
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
>
|
|
205
|
-
{/* Status accent: enabled/disabled by position + hue, not toggle alone. */}
|
|
206
|
-
<span
|
|
207
|
-
className={cn(
|
|
208
|
-
"absolute inset-y-0 left-0 w-1",
|
|
209
|
-
automationAccent(automation.status),
|
|
210
|
-
)}
|
|
211
|
-
aria-hidden
|
|
212
|
-
/>
|
|
213
|
-
{canAccess(automation.id) ? (
|
|
214
|
-
<Toggle
|
|
215
|
-
checked={automation.status === "enabled"}
|
|
216
|
-
onCheckedChange={(enabled) =>
|
|
217
|
-
toggleMutation.mutate({
|
|
218
|
-
id: automation.id,
|
|
219
|
-
enabled,
|
|
220
|
-
})
|
|
221
|
-
}
|
|
222
|
-
aria-label={
|
|
223
|
-
automation.status === "enabled"
|
|
224
|
-
? "Disable automation"
|
|
225
|
-
: "Enable automation"
|
|
226
|
-
}
|
|
185
|
+
const columns: DataTableColumn<Automation>[] = [
|
|
186
|
+
{
|
|
187
|
+
id: "status",
|
|
188
|
+
header: "",
|
|
189
|
+
headClassName: "w-8",
|
|
190
|
+
cellClassName: "relative pl-4",
|
|
191
|
+
cell: (automation) => (
|
|
192
|
+
<>
|
|
193
|
+
{/* Status accent: enabled/disabled by position + hue, not toggle alone. */}
|
|
194
|
+
<span
|
|
195
|
+
className={cn(
|
|
196
|
+
"absolute inset-y-0 left-0 w-1",
|
|
197
|
+
automationAccent(automation.status),
|
|
198
|
+
)}
|
|
199
|
+
aria-hidden
|
|
227
200
|
/>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
201
|
+
<div onClick={(e) => e.stopPropagation()}>
|
|
202
|
+
{canAccess(automation.id) ? (
|
|
203
|
+
<Toggle
|
|
204
|
+
checked={automation.status === "enabled"}
|
|
205
|
+
onCheckedChange={(enabled) =>
|
|
206
|
+
toggleMutation.mutate({
|
|
207
|
+
id: automation.id,
|
|
208
|
+
enabled,
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
aria-label={
|
|
212
|
+
automation.status === "enabled"
|
|
213
|
+
? "Disable automation"
|
|
214
|
+
: "Enable automation"
|
|
215
|
+
}
|
|
216
|
+
/>
|
|
217
|
+
) : (
|
|
218
|
+
<Badge
|
|
219
|
+
variant={
|
|
220
|
+
automation.status === "enabled" ? "success" : "outline"
|
|
221
|
+
}
|
|
222
|
+
>
|
|
223
|
+
{automation.status}
|
|
224
|
+
</Badge>
|
|
225
|
+
)}
|
|
226
|
+
</div>
|
|
227
|
+
</>
|
|
228
|
+
),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: "name",
|
|
232
|
+
header: "Name",
|
|
233
|
+
sortValue: (automation) => automation.name,
|
|
234
|
+
cell: (automation) => (
|
|
239
235
|
<div className="flex flex-col gap-0.5">
|
|
240
236
|
<span className="font-semibold text-foreground">
|
|
241
237
|
{automation.name}
|
|
@@ -246,8 +242,12 @@ const AutomationListContent: React.FC = () => {
|
|
|
246
242
|
</span>
|
|
247
243
|
)}
|
|
248
244
|
</div>
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
),
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: "triggers",
|
|
249
|
+
header: "Triggers",
|
|
250
|
+
cell: (automation) => (
|
|
251
251
|
<div className="flex flex-wrap gap-1">
|
|
252
252
|
{automation.definition.triggers.slice(0, 3).map((trigger, index) => (
|
|
253
253
|
<Badge
|
|
@@ -267,45 +267,62 @@ const AutomationListContent: React.FC = () => {
|
|
|
267
267
|
</Badge>
|
|
268
268
|
)}
|
|
269
269
|
</div>
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
),
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: "mode",
|
|
274
|
+
header: "Mode",
|
|
275
|
+
sortValue: (automation) => automation.definition.mode,
|
|
276
|
+
cell: (automation) => (
|
|
272
277
|
<Badge variant="secondary" className="text-[10px]">
|
|
273
278
|
{automation.definition.mode}
|
|
274
279
|
</Badge>
|
|
275
|
-
|
|
276
|
-
|
|
280
|
+
),
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: "updated",
|
|
284
|
+
header: "Updated",
|
|
285
|
+
sortValue: (automation) => new Date(automation.updatedAt).getTime(),
|
|
286
|
+
cell: (automation) => (
|
|
277
287
|
<span className="text-xs text-muted-foreground">
|
|
278
288
|
{formatDistanceToNow(new Date(automation.updatedAt), {
|
|
279
289
|
addSuffix: true,
|
|
280
290
|
})}
|
|
281
291
|
</span>
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
292
|
+
),
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: "actions",
|
|
296
|
+
header: "Actions",
|
|
297
|
+
headClassName: "w-24 text-right",
|
|
298
|
+
cellClassName: "text-right",
|
|
299
|
+
cell: (automation) => (
|
|
300
|
+
<div onClick={(e) => e.stopPropagation()}>
|
|
301
|
+
<RowActions>
|
|
302
|
+
<RowAction
|
|
303
|
+
icon={History}
|
|
304
|
+
label="View runs"
|
|
305
|
+
onClick={() =>
|
|
306
|
+
navigate(
|
|
307
|
+
resolveRoute(automationRoutes.routes.runs, {
|
|
308
|
+
automationId: automation.id,
|
|
309
|
+
}),
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
/>
|
|
313
|
+
{canAccess(automation.id) && (
|
|
314
|
+
<RowAction
|
|
315
|
+
icon={Trash2}
|
|
316
|
+
label="Delete automation"
|
|
317
|
+
tone="destructive"
|
|
318
|
+
onClick={() => setDeleteId(automation.id)}
|
|
319
|
+
/>
|
|
320
|
+
)}
|
|
321
|
+
</RowActions>
|
|
305
322
|
</div>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
323
|
+
),
|
|
324
|
+
},
|
|
325
|
+
];
|
|
309
326
|
|
|
310
327
|
const renderMobileCard = (automation: Automation) => (
|
|
311
328
|
<div
|
|
@@ -391,30 +408,28 @@ const AutomationListContent: React.FC = () => {
|
|
|
391
408
|
addSuffix: true,
|
|
392
409
|
})}
|
|
393
410
|
</div>
|
|
394
|
-
<div
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
</Button>
|
|
417
|
-
)}
|
|
411
|
+
<div onClick={(e) => e.stopPropagation()} className="mt-3 pl-2">
|
|
412
|
+
<RowActions>
|
|
413
|
+
<RowAction
|
|
414
|
+
icon={History}
|
|
415
|
+
label="View runs"
|
|
416
|
+
onClick={() =>
|
|
417
|
+
navigate(
|
|
418
|
+
resolveRoute(automationRoutes.routes.runs, {
|
|
419
|
+
automationId: automation.id,
|
|
420
|
+
}),
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
/>
|
|
424
|
+
{canAccess(automation.id) && (
|
|
425
|
+
<RowAction
|
|
426
|
+
icon={Trash2}
|
|
427
|
+
label="Delete automation"
|
|
428
|
+
tone="destructive"
|
|
429
|
+
onClick={() => setDeleteId(automation.id)}
|
|
430
|
+
/>
|
|
431
|
+
)}
|
|
432
|
+
</RowActions>
|
|
418
433
|
</div>
|
|
419
434
|
</div>
|
|
420
435
|
);
|
|
@@ -516,32 +531,28 @@ const AutomationListContent: React.FC = () => {
|
|
|
516
531
|
</span>
|
|
517
532
|
</AccordionTrigger>
|
|
518
533
|
<AccordionContent className="px-0 pb-0">
|
|
519
|
-
<
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
{group.items.map((automation) =>
|
|
542
|
-
renderMobileCard(automation),
|
|
543
|
-
)}
|
|
544
|
-
</MobileCardList>
|
|
534
|
+
<DataTable
|
|
535
|
+
data={group.items}
|
|
536
|
+
columns={columns}
|
|
537
|
+
getRowId={(automation) => automation.id}
|
|
538
|
+
searchable={false}
|
|
539
|
+
// Nested inside the page's opaque Card, so the default
|
|
540
|
+
// bg-card surface would create a panel-in-panel; the
|
|
541
|
+
// enclosing Card already provides the opaque background.
|
|
542
|
+
surface={false}
|
|
543
|
+
onRowClick={(automation) =>
|
|
544
|
+
navigate(
|
|
545
|
+
resolveRoute(automationRoutes.routes.edit, {
|
|
546
|
+
automationId: automation.id,
|
|
547
|
+
}),
|
|
548
|
+
)
|
|
549
|
+
}
|
|
550
|
+
getRowProps={() => ({
|
|
551
|
+
className:
|
|
552
|
+
"relative transition-colors hover:bg-surface-inset",
|
|
553
|
+
})}
|
|
554
|
+
renderMobileCard={renderMobileCard}
|
|
555
|
+
/>
|
|
545
556
|
</AccordionContent>
|
|
546
557
|
</AccordionItem>
|
|
547
558
|
))}
|
package/src/pages/RunsPage.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Link, useParams } from "react-router-dom";
|
|
3
|
-
import { History, ChevronLeft } from "lucide-react";
|
|
2
|
+
import { Link, useParams, useNavigate } from "react-router-dom";
|
|
3
|
+
import { History, ChevronLeft, ArrowUpRight } from "lucide-react";
|
|
4
4
|
import {
|
|
5
5
|
usePluginClient,
|
|
6
6
|
accessApiRef,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
automationAccess,
|
|
13
13
|
automationRoutes,
|
|
14
14
|
} from "@checkstack/automation-common";
|
|
15
|
-
import type { RunStatus } from "@checkstack/automation-common";
|
|
15
|
+
import type { RunStatus, AutomationRun } from "@checkstack/automation-common";
|
|
16
16
|
import {
|
|
17
17
|
PageLayout,
|
|
18
18
|
Card,
|
|
@@ -20,17 +20,13 @@ import {
|
|
|
20
20
|
CardHeader,
|
|
21
21
|
CardTitle,
|
|
22
22
|
Button,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
TableBody,
|
|
28
|
-
TableCell,
|
|
23
|
+
DataTable,
|
|
24
|
+
type DataTableColumn,
|
|
25
|
+
RowActions,
|
|
26
|
+
RowAction,
|
|
29
27
|
LoadingSpinner,
|
|
30
28
|
QueryErrorState,
|
|
31
29
|
EmptyState,
|
|
32
|
-
ResponsiveTable,
|
|
33
|
-
MobileCardList,
|
|
34
30
|
} from "@checkstack/ui";
|
|
35
31
|
import { resolveRoute } from "@checkstack/common";
|
|
36
32
|
import { formatDistanceToNow } from "date-fns";
|
|
@@ -45,6 +41,7 @@ import { formatDuration } from "./run-duration";
|
|
|
45
41
|
*/
|
|
46
42
|
const RunsPageContent: React.FC = () => {
|
|
47
43
|
const { automationId } = useParams<{ automationId: string }>();
|
|
44
|
+
const navigate = useNavigate();
|
|
48
45
|
const client = usePluginClient(AutomationApi);
|
|
49
46
|
const accessApi = useApi(accessApiRef);
|
|
50
47
|
const { allowed, loading: accessLoading } = accessApi.useAccess(
|
|
@@ -73,6 +70,72 @@ const RunsPageContent: React.FC = () => {
|
|
|
73
70
|
|
|
74
71
|
const runs = runsQuery.data?.items ?? [];
|
|
75
72
|
|
|
73
|
+
const columns: DataTableColumn<AutomationRun>[] = [
|
|
74
|
+
{
|
|
75
|
+
id: "status",
|
|
76
|
+
header: "Status",
|
|
77
|
+
sortValue: (run) => run.status,
|
|
78
|
+
cell: (run) => <RunStatusPill status={run.status} />,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "trigger",
|
|
82
|
+
header: "Trigger",
|
|
83
|
+
sortValue: (run) => run.triggerEventId || "manual",
|
|
84
|
+
cell: (run) => (
|
|
85
|
+
<code className="font-mono text-xs">
|
|
86
|
+
{run.triggerEventId || "manual"}
|
|
87
|
+
</code>
|
|
88
|
+
),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "started",
|
|
92
|
+
header: "Started",
|
|
93
|
+
sortValue: (run) => new Date(run.startedAt).getTime(),
|
|
94
|
+
cell: (run) => (
|
|
95
|
+
<span className="text-xs text-muted-foreground">
|
|
96
|
+
{formatDistanceToNow(new Date(run.startedAt), { addSuffix: true })}
|
|
97
|
+
</span>
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: "duration",
|
|
102
|
+
header: "Duration",
|
|
103
|
+
sortValue: (run) =>
|
|
104
|
+
run.finishedAt
|
|
105
|
+
? new Date(run.finishedAt).getTime() -
|
|
106
|
+
new Date(run.startedAt).getTime()
|
|
107
|
+
: undefined,
|
|
108
|
+
cell: (run) => (
|
|
109
|
+
<span className="text-xs text-muted-foreground">
|
|
110
|
+
{formatDuration(run.startedAt, run.finishedAt)}
|
|
111
|
+
</span>
|
|
112
|
+
),
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "actions",
|
|
116
|
+
header: "",
|
|
117
|
+
headClassName: "w-24 text-right",
|
|
118
|
+
cellClassName: "text-right",
|
|
119
|
+
cell: (run) =>
|
|
120
|
+
automationId ? (
|
|
121
|
+
<RowActions>
|
|
122
|
+
<RowAction
|
|
123
|
+
icon={ArrowUpRight}
|
|
124
|
+
label="Open run details"
|
|
125
|
+
onClick={() =>
|
|
126
|
+
navigate(
|
|
127
|
+
resolveRoute(automationRoutes.routes.runDetail, {
|
|
128
|
+
automationId,
|
|
129
|
+
runId: run.id,
|
|
130
|
+
}),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
/>
|
|
134
|
+
</RowActions>
|
|
135
|
+
) : null,
|
|
136
|
+
},
|
|
137
|
+
];
|
|
138
|
+
|
|
76
139
|
return (
|
|
77
140
|
<PageLayout
|
|
78
141
|
title={
|
|
@@ -142,107 +205,52 @@ const RunsPageContent: React.FC = () => {
|
|
|
142
205
|
description="Manually trigger the automation from the edit page to generate a run."
|
|
143
206
|
/>
|
|
144
207
|
) : (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{formatDuration(run.startedAt, run.finishedAt)}
|
|
178
|
-
</span>
|
|
179
|
-
</TableCell>
|
|
180
|
-
<TableCell className="text-right">
|
|
181
|
-
{automationId && (
|
|
182
|
-
<Link
|
|
183
|
-
to={resolveRoute(
|
|
184
|
-
automationRoutes.routes.runDetail,
|
|
185
|
-
{
|
|
186
|
-
automationId,
|
|
187
|
-
runId: run.id,
|
|
188
|
-
},
|
|
189
|
-
)}
|
|
190
|
-
>
|
|
191
|
-
<Button variant="ghost" size="sm">
|
|
192
|
-
Open
|
|
193
|
-
</Button>
|
|
194
|
-
</Link>
|
|
195
|
-
)}
|
|
196
|
-
</TableCell>
|
|
197
|
-
</TableRow>
|
|
198
|
-
))}
|
|
199
|
-
</TableBody>
|
|
200
|
-
</Table>
|
|
201
|
-
</ResponsiveTable>
|
|
202
|
-
|
|
203
|
-
<MobileCardList className="p-4">
|
|
204
|
-
{runs.map((run) => (
|
|
205
|
-
<div
|
|
206
|
-
key={run.id}
|
|
207
|
-
className="rounded-md border bg-surface p-4"
|
|
208
|
-
>
|
|
209
|
-
<div className="flex items-start justify-between gap-2">
|
|
210
|
-
<RunStatusPill status={run.status} />
|
|
211
|
-
{automationId && (
|
|
212
|
-
<Link
|
|
213
|
-
to={resolveRoute(automationRoutes.routes.runDetail, {
|
|
214
|
-
automationId,
|
|
215
|
-
runId: run.id,
|
|
216
|
-
})}
|
|
217
|
-
>
|
|
218
|
-
<Button variant="ghost" size="sm">
|
|
219
|
-
Open
|
|
220
|
-
</Button>
|
|
221
|
-
</Link>
|
|
222
|
-
)}
|
|
208
|
+
<DataTable
|
|
209
|
+
data={runs}
|
|
210
|
+
columns={columns}
|
|
211
|
+
getRowId={(run) => run.id}
|
|
212
|
+
searchable={false}
|
|
213
|
+
renderMobileCard={(run) => (
|
|
214
|
+
<div className="rounded-md border bg-surface p-4">
|
|
215
|
+
<div className="flex items-start justify-between gap-2">
|
|
216
|
+
<RunStatusPill status={run.status} />
|
|
217
|
+
{automationId && (
|
|
218
|
+
<RowActions>
|
|
219
|
+
<RowAction
|
|
220
|
+
icon={ArrowUpRight}
|
|
221
|
+
label="Open run details"
|
|
222
|
+
onClick={() =>
|
|
223
|
+
navigate(
|
|
224
|
+
resolveRoute(automationRoutes.routes.runDetail, {
|
|
225
|
+
automationId,
|
|
226
|
+
runId: run.id,
|
|
227
|
+
}),
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
/>
|
|
231
|
+
</RowActions>
|
|
232
|
+
)}
|
|
233
|
+
</div>
|
|
234
|
+
<div className="mt-2 flex flex-col gap-1 text-xs text-muted-foreground">
|
|
235
|
+
<div className="flex items-center gap-1">
|
|
236
|
+
<span>Trigger:</span>
|
|
237
|
+
<code className="font-mono">
|
|
238
|
+
{run.triggerEventId || "manual"}
|
|
239
|
+
</code>
|
|
223
240
|
</div>
|
|
224
|
-
<div
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
Started{" "}
|
|
233
|
-
{formatDistanceToNow(new Date(run.startedAt), {
|
|
234
|
-
addSuffix: true,
|
|
235
|
-
})}
|
|
236
|
-
</div>
|
|
237
|
-
<div>
|
|
238
|
-
Duration:{" "}
|
|
239
|
-
{formatDuration(run.startedAt, run.finishedAt)}
|
|
240
|
-
</div>
|
|
241
|
+
<div>
|
|
242
|
+
Started{" "}
|
|
243
|
+
{formatDistanceToNow(new Date(run.startedAt), {
|
|
244
|
+
addSuffix: true,
|
|
245
|
+
})}
|
|
246
|
+
</div>
|
|
247
|
+
<div>
|
|
248
|
+
Duration: {formatDuration(run.startedAt, run.finishedAt)}
|
|
241
249
|
</div>
|
|
242
250
|
</div>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
253
|
+
/>
|
|
246
254
|
)}
|
|
247
255
|
</CardContent>
|
|
248
256
|
</Card>
|