ActionStatusBadge.tsx86 lines · main
| 1 | import type { PropsWithChildren } from 'react' |
| 2 | import { Badge, StatusIcon, Tooltip, TooltipContent, TooltipTrigger } from 'ui' |
| 3 | |
| 4 | import { ActionName, ActionStatus, type ActionRunStep } from '@/data/actions/action-runs-query' |
| 5 | |
| 6 | export interface ActionStatusBadgeProps { |
| 7 | name: ActionName |
| 8 | status: ActionStatus |
| 9 | } |
| 10 | |
| 11 | const UNHEALTHY_STATUES: ActionStatus[] = ['DEAD', 'REMOVING'] |
| 12 | const WAITING_STATUSES: ActionStatus[] = ['CREATED', 'RESTARTING', 'RUNNING'] |
| 13 | |
| 14 | export 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 | |
| 24 | const 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 | |
| 34 | export 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 | |
| 70 | export 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 | } |