|
5 | 5 | * |
6 | 6 | * Copyright Oxide Computer Company |
7 | 7 | */ |
8 | | -import type { DiskState, InstanceState, SnapshotState } from '@oxide/api' |
| 8 | +import cn from 'classnames' |
9 | 9 |
|
10 | | -import { Badge, type BadgeColor, type BadgeProps } from '~/ui/lib/Badge' |
| 10 | +import { |
| 11 | + diskTransitioning, |
| 12 | + instanceTransitioning, |
| 13 | + type DiskState, |
| 14 | + type InstanceState, |
| 15 | + type SnapshotState, |
| 16 | +} from '@oxide/api' |
11 | 17 |
|
12 | | -const INSTANCE_COLORS: Record<InstanceState, Pick<BadgeProps, 'color' | 'variant'>> = { |
13 | | - creating: { color: 'purple', variant: 'solid' }, |
14 | | - starting: { color: 'blue', variant: 'solid' }, |
15 | | - running: { color: 'default' }, |
16 | | - rebooting: { color: 'notice' }, |
17 | | - stopping: { color: 'notice' }, |
18 | | - stopped: { color: 'neutral', variant: 'solid' }, |
19 | | - repairing: { color: 'notice', variant: 'solid' }, |
20 | | - migrating: { color: 'notice', variant: 'solid' }, |
21 | | - failed: { color: 'destructive', variant: 'solid' }, |
22 | | - destroyed: { color: 'neutral', variant: 'solid' }, |
| 18 | +import { Badge, type BadgeColor } from '~/ui/lib/Badge' |
| 19 | +import { Spinner } from '~/ui/lib/Spinner' |
| 20 | + |
| 21 | +const INSTANCE_COLORS: Record<InstanceState, BadgeColor> = { |
| 22 | + running: 'default', |
| 23 | + stopped: 'neutral', |
| 24 | + failed: 'destructive', |
| 25 | + destroyed: 'destructive', |
| 26 | + creating: 'default', |
| 27 | + starting: 'blue', |
| 28 | + rebooting: 'blue', |
| 29 | + migrating: 'purple', |
| 30 | + repairing: 'notice', |
| 31 | + stopping: 'neutral', |
23 | 32 | } |
24 | 33 |
|
| 34 | +const badgeClasses = 'children:flex children:items-center children:gap-1' |
| 35 | + |
25 | 36 | export const InstanceStateBadge = (props: { state: InstanceState; className?: string }) => ( |
26 | | - <Badge {...INSTANCE_COLORS[props.state]} className={props.className}> |
| 37 | + <Badge color={INSTANCE_COLORS[props.state]} className={cn(props.className, badgeClasses)}> |
| 38 | + {instanceTransitioning(props.state) && ( |
| 39 | + <Spinner size="sm" variant={INSTANCE_COLORS[props.state]} /> |
| 40 | + )} |
27 | 41 | {props.state} |
28 | 42 | </Badge> |
29 | 43 | ) |
30 | 44 |
|
31 | 45 | type DiskStateStr = DiskState['state'] |
32 | 46 |
|
33 | | -const DISK_COLORS: Record<DiskStateStr, Pick<BadgeProps, 'color' | 'variant'>> = { |
34 | | - attached: { color: 'default' }, |
35 | | - attaching: { color: 'blue', variant: 'solid' }, |
36 | | - creating: { color: 'purple', variant: 'solid' }, |
37 | | - detaching: { color: 'notice', variant: 'solid' }, |
38 | | - detached: { color: 'neutral', variant: 'solid' }, |
39 | | - destroyed: { color: 'destructive', variant: 'solid' }, // should we ever see this? |
40 | | - faulted: { color: 'destructive', variant: 'solid' }, |
41 | | - maintenance: { color: 'notice', variant: 'solid' }, |
42 | | - import_ready: { color: 'blue', variant: 'solid' }, |
43 | | - importing_from_url: { color: 'purple', variant: 'solid' }, |
44 | | - importing_from_bulk_writes: { color: 'purple', variant: 'solid' }, |
45 | | - finalizing: { color: 'blue', variant: 'solid' }, |
| 47 | +const DISK_COLORS: Record<DiskStateStr, BadgeColor> = { |
| 48 | + attached: 'default', |
| 49 | + attaching: 'blue', |
| 50 | + creating: 'default', |
| 51 | + detaching: 'blue', |
| 52 | + detached: 'neutral', |
| 53 | + destroyed: 'destructive', // should we ever see this? |
| 54 | + faulted: 'destructive', |
| 55 | + maintenance: 'notice', |
| 56 | + import_ready: 'blue', |
| 57 | + importing_from_url: 'purple', |
| 58 | + importing_from_bulk_writes: 'purple', |
| 59 | + finalizing: 'blue', |
46 | 60 | } |
47 | 61 |
|
48 | 62 | export const DiskStateBadge = (props: { state: DiskStateStr; className?: string }) => ( |
49 | | - <Badge {...DISK_COLORS[props.state]} className={props.className}> |
50 | | - {props.state} |
| 63 | + <Badge color={DISK_COLORS[props.state]} className={cn(props.className, badgeClasses)}> |
| 64 | + {diskTransitioning(props.state) && ( |
| 65 | + <Spinner size="sm" variant={DISK_COLORS[props.state]} /> |
| 66 | + )} |
| 67 | + {props.state.replace(/_/g, ' ')} |
51 | 68 | </Badge> |
52 | 69 | ) |
53 | 70 |
|
54 | 71 | const SNAPSHOT_COLORS: Record<SnapshotState, BadgeColor> = { |
55 | | - creating: 'notice', |
| 72 | + creating: 'default', |
56 | 73 | destroyed: 'neutral', |
57 | 74 | faulted: 'destructive', |
58 | 75 | ready: 'default', |
59 | 76 | } |
60 | 77 |
|
61 | 78 | export const SnapshotStateBadge = (props: { state: SnapshotState; className?: string }) => ( |
62 | | - <Badge color={SNAPSHOT_COLORS[props.state]} className={props.className}> |
| 79 | + <Badge color={SNAPSHOT_COLORS[props.state]} className={cn(props.className, badgeClasses)}> |
| 80 | + {props.state === 'creating' && ( |
| 81 | + <Spinner size="sm" variant={SNAPSHOT_COLORS[props.state]} /> |
| 82 | + )} |
63 | 83 | {props.state} |
64 | 84 | </Badge> |
65 | 85 | ) |
0 commit comments