ActionStatusBadge.tsx86 lines · main
1import type { PropsWithChildren } from 'react'
2import { Badge, StatusIcon, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
3
4import { ActionName, ActionStatus, type ActionRunStep } from '@/data/actions/action-runs-query'
5
6export interface ActionStatusBadgeProps {
7 name: ActionName
8 status: ActionStatus
9}
10
11const UNHEALTHY_STATUES: ActionStatus[] = ['DEAD', 'REMOVING']
12const WAITING_STATUSES: ActionStatus[] = ['CREATED', 'RESTARTING', 'RUNNING']
13
14export const STATUS_TO_LABEL: Record<ActionStatus, string> = {
15 CREATED: 'pending',
16 DEAD: 'failed',
17 EXITED: 'succeeded',
18 PAUSED: 'skipped',
19 REMOVING: 'failed',
20 RESTARTING: 'restarting',
21 RUNNING: 'running',
22}
23
24const NAME_TO_LABEL: Record<ActionName, string> = {
25 clone: 'Cloning repo',
26 pull: 'Pulling data',
27 health: 'Health check',
28 configure: 'Configurations',
29 migrate: 'Migrations',
30 seed: 'Data seeding',
31 deploy: 'Functions deployment',
32}
33
34export const ActionStatusBadgeCondensed = ({
35 children,
36 status,
37 details,
38}: PropsWithChildren<{
39 status: ActionStatus
40 details: Array<ActionRunStep>
41}>) => {
42 if (status === 'EXITED') {
43 return null
44 }
45
46 const isUnhealthy = UNHEALTHY_STATUES.includes(status)
47
48 return (
49 <Tooltip>
50 <TooltipTrigger asChild>
51 <Badge variant={isUnhealthy ? 'destructive' : 'default'} className="gap-1.5">
52 {isUnhealthy && <StatusIcon variant="destructive" hideBackground />}
53 {children}
54 </Badge>
55 </TooltipTrigger>
56 <TooltipContent>
57 Additional {STATUS_TO_LABEL[status]} steps:
58 <ul>
59 {details.map((step) => (
60 <li key={step.name} className="before:content-['-'] before:mr-0.5">
61 {NAME_TO_LABEL[step.name]}
62 </li>
63 ))}
64 </ul>
65 </TooltipContent>
66 </Tooltip>
67 )
68}
69
70export const ActionStatusBadge = ({ name, status }: ActionStatusBadgeProps) => {
71 if (status === 'EXITED') {
72 return null
73 }
74
75 const isUnhealthy = UNHEALTHY_STATUES.includes(status)
76 const isWaiting = WAITING_STATUSES.includes(status)
77
78 return (
79 <Badge variant={isUnhealthy ? 'destructive' : 'default'} className="gap-1.5">
80 {(isUnhealthy || isWaiting) && (
81 <StatusIcon variant={isUnhealthy ? 'destructive' : 'default'} hideBackground />
82 )}
83 {NAME_TO_LABEL[name]}: {STATUS_TO_LABEL[status]}
84 </Badge>
85 )
86}