Skip to content

Commit 016ad1b

Browse files
authored
Add columns on SledsTab for sled Policy and State (#2337)
* Add columns on SledsTab for Policy and State * set enum for policy colors * don't be so DRY with the component * refactoring a few UI bits; adding extra examples to mock api * enhance tests
1 parent 2d1a22a commit 016ad1b

File tree

5 files changed

+146
-33
lines changed

5 files changed

+146
-33
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ module.exports = {
4545
'@typescript-eslint/no-empty-interface': 'off',
4646
'@typescript-eslint/ban-ts-comment': 'off',
4747
'@typescript-eslint/no-non-null-assertion': 'off',
48+
'@typescript-eslint/no-duplicate-type-constituents': 'off',
4849
'@typescript-eslint/no-unused-vars': [
4950
'error',
5051
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },

app/pages/system/inventory/DisksTab.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,28 @@
77
*/
88
import { createColumnHelper } from '@tanstack/react-table'
99

10-
import { apiQueryClient, type PhysicalDisk } from '@oxide/api'
10+
import {
11+
apiQueryClient,
12+
type PhysicalDisk,
13+
type PhysicalDiskPolicy,
14+
type PhysicalDiskState,
15+
} from '@oxide/api'
1116
import { Servers24Icon } from '@oxide/design-system/icons/react'
1217

1318
import { PAGE_SIZE, useQueryTable } from '~/table/QueryTable'
14-
import { Badge } from '~/ui/lib/Badge'
19+
import { Badge, type BadgeColor } from '~/ui/lib/Badge'
1520
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
1621

22+
const POLICY_KIND_BADGE_COLORS: Record<PhysicalDiskPolicy['kind'], BadgeColor> = {
23+
in_service: 'default',
24+
expunged: 'neutral',
25+
}
26+
27+
const STATE_BADGE_COLORS: Record<PhysicalDiskState, BadgeColor> = {
28+
active: 'default',
29+
decommissioned: 'neutral',
30+
}
31+
1732
const EmptyState = () => (
1833
<EmptyMessage
1934
icon={<Servers24Icon />}
@@ -36,19 +51,18 @@ const staticCols = [
3651
}),
3752
colHelper.accessor('model', { header: 'model number' }),
3853
colHelper.accessor('serial', { header: 'serial number' }),
39-
colHelper.accessor('policy', {
40-
cell: (info) => {
41-
const policy = info.getValue().kind
42-
const color = policy === 'in_service' ? 'default' : 'neutral'
43-
return <Badge color={color}>{policy.replace(/_/g, ' ')}</Badge>
44-
},
54+
colHelper.accessor('policy.kind', {
55+
header: 'policy',
56+
cell: (info) => (
57+
<Badge color={POLICY_KIND_BADGE_COLORS[info.getValue()]}>
58+
{info.getValue().replace(/_/g, ' ')}
59+
</Badge>
60+
),
4561
}),
4662
colHelper.accessor('state', {
47-
cell: (info) => {
48-
const state = info.getValue()
49-
const color = state === 'active' ? 'default' : 'neutral'
50-
return <Badge color={color}>{state}</Badge>
51-
},
63+
cell: (info) => (
64+
<Badge color={STATE_BADGE_COLORS[info.getValue()]}>{info.getValue()}</Badge>
65+
),
5266
}),
5367
]
5468

app/pages/system/inventory/SledsTab.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,25 @@
77
*/
88
import { createColumnHelper } from '@tanstack/react-table'
99

10-
import { apiQueryClient, type Sled } from '@oxide/api'
10+
import { apiQueryClient, type Sled, type SledPolicy, type SledState } from '@oxide/api'
1111
import { Servers24Icon } from '@oxide/design-system/icons/react'
1212

1313
import { makeLinkCell } from '~/table/cells/LinkCell'
1414
import { PAGE_SIZE, useQueryTable } from '~/table/QueryTable'
15+
import { Badge, type BadgeColor } from '~/ui/lib/Badge'
1516
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
1617
import { pb } from '~/util/path-builder'
1718

19+
const POLICY_KIND_BADGE_COLORS: Record<SledPolicy['kind'], BadgeColor> = {
20+
in_service: 'default',
21+
expunged: 'neutral',
22+
}
23+
24+
const STATE_BADGE_COLORS: Record<SledState, BadgeColor> = {
25+
active: 'default',
26+
decommissioned: 'neutral',
27+
}
28+
1829
const EmptyState = () => {
1930
return (
2031
<EmptyMessage
@@ -41,6 +52,19 @@ const staticCols = [
4152
colHelper.accessor('baseboard.part', { header: 'part number' }),
4253
colHelper.accessor('baseboard.serial', { header: 'serial number' }),
4354
colHelper.accessor('baseboard.revision', { header: 'revision' }),
55+
colHelper.accessor('policy.kind', {
56+
header: 'policy',
57+
cell: (info) => (
58+
<Badge color={POLICY_KIND_BADGE_COLORS[info.getValue()]}>
59+
{info.getValue().replace(/_/g, ' ')}
60+
</Badge>
61+
),
62+
}),
63+
colHelper.accessor('state', {
64+
cell: (info) => (
65+
<Badge color={STATE_BADGE_COLORS[info.getValue()]}>{info.getValue()}</Badge>
66+
),
67+
}),
4468
]
4569

4670
export function SledsTab() {

mock-api/sled.ts

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,75 @@ import type { Sled } from '@oxide/api'
99

1010
import type { Json } from './json-type'
1111

12-
export const sled: Json<Sled> = {
13-
id: 'c2519937-44a4-493b-9b38-5c337c597d08',
14-
time_created: new Date(2021, 0, 1).toISOString(),
15-
time_modified: new Date(2021, 0, 2).toISOString(),
16-
rack_id: '6fbafcc7-1626-4785-be65-e212f8ad66d0',
17-
policy: {
18-
kind: 'in_service',
19-
provision_policy: 'provisionable',
12+
export const sleds: Json<Sled[]> = [
13+
{
14+
id: 'c2519937-44a4-493b-9b38-5c337c597d08',
15+
time_created: new Date(2023, 0, 1).toISOString(),
16+
time_modified: new Date(2023, 0, 2).toISOString(),
17+
rack_id: '6fbafcc7-1626-4785-be65-e212f8ad66d0',
18+
policy: {
19+
kind: 'in_service',
20+
provision_policy: 'provisionable',
21+
},
22+
state: 'active',
23+
baseboard: {
24+
part: '913-0000108',
25+
serial: 'BRM02222869',
26+
revision: 0,
27+
},
28+
usable_hardware_threads: 128,
29+
usable_physical_ram: 1_099_511_627_776,
2030
},
21-
state: 'active',
22-
baseboard: {
23-
part: '913-0000008',
24-
serial: 'BRM02222867',
25-
revision: 0,
31+
{
32+
id: '1ec7df9d-a6de-423c-8bf8-01557e8e5aea',
33+
time_created: new Date(2024, 0, 1).toISOString(),
34+
time_modified: new Date(2024, 0, 2).toISOString(),
35+
rack_id: '759a1c80-4bff-4d0b-97ce-b482ca936724',
36+
policy: {
37+
kind: 'in_service',
38+
provision_policy: 'provisionable',
39+
},
40+
state: 'active',
41+
baseboard: {
42+
part: '913-0001008',
43+
serial: 'BRM02222870',
44+
revision: 0,
45+
},
46+
usable_hardware_threads: 128,
47+
usable_physical_ram: 1_099_511_627_776,
2648
},
27-
usable_hardware_threads: 128,
28-
usable_physical_ram: 1_099_511_627_776,
29-
}
30-
31-
export const sleds: Json<Sled[]> = [sled]
49+
{
50+
id: 'fca81647-868a-4aa5-b8c3-84364d4b4dc9',
51+
time_created: new Date(2022, 0, 1).toISOString(),
52+
time_modified: new Date(2022, 0, 2).toISOString(),
53+
rack_id: 'ebe9a4c0-248b-491c-9448-04ddb10ef648',
54+
policy: {
55+
kind: 'expunged',
56+
},
57+
state: 'active',
58+
baseboard: {
59+
part: '913-0000018',
60+
serial: 'BRM02222868',
61+
revision: 0,
62+
},
63+
usable_hardware_threads: 128,
64+
usable_physical_ram: 1_099_511_627_776,
65+
},
66+
{
67+
id: 'a4ed0c62-cb3a-48bc-a7a8-ee544a8a8869',
68+
time_created: new Date(2021, 0, 1).toISOString(),
69+
time_modified: new Date(2021, 0, 2).toISOString(),
70+
rack_id: '64f712fe-4320-407d-835a-d63b0455d89c',
71+
policy: {
72+
kind: 'expunged',
73+
},
74+
state: 'decommissioned',
75+
baseboard: {
76+
part: '913-0000008',
77+
serial: 'BRM02222867',
78+
revision: 0,
79+
},
80+
usable_hardware_threads: 128,
81+
usable_physical_ram: 1_099_511_627_776,
82+
},
83+
]

test/e2e/inventory.e2e.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*
66
* Copyright Oxide Computer Company
77
*/
8-
import { physicalDisks } from '@oxide/api-mocks'
8+
9+
import { physicalDisks, sleds } from '@oxide/api-mocks'
910

1011
import { expect, expectRowVisible, expectVisible, test } from './utils'
1112

@@ -19,6 +20,25 @@ test('Sled inventory page', async ({ page }) => {
1920
await expect(sledsTab).toHaveClass(/is-selected/)
2021

2122
const sledsTable = page.getByRole('table')
23+
await expectRowVisible(sledsTable, {
24+
id: sleds[1].id,
25+
'serial number': sleds[1].baseboard.serial,
26+
policy: 'in service',
27+
state: 'active',
28+
})
29+
await expectRowVisible(sledsTable, {
30+
id: sleds[2].id,
31+
'serial number': sleds[2].baseboard.serial,
32+
policy: 'expunged',
33+
state: 'active',
34+
})
35+
await expectRowVisible(sledsTable, {
36+
id: sleds[3].id,
37+
'serial number': sleds[3].baseboard.serial,
38+
policy: 'expunged',
39+
state: 'decommissioned',
40+
})
41+
2242
// Visit the sled detail page of the first sled
2343
await sledsTable.getByRole('link').first().click()
2444

@@ -54,11 +74,13 @@ test('Disk inventory page', async ({ page }) => {
5474
})
5575
await expectRowVisible(table, {
5676
id: physicalDisks[4].id,
77+
'Form factor': 'M.2',
5778
policy: 'expunged',
5879
state: 'active',
5980
})
6081
await expectRowVisible(table, {
6182
id: physicalDisks[5].id,
83+
'Form factor': 'M.2',
6284
policy: 'expunged',
6385
state: 'decommissioned',
6486
})

0 commit comments

Comments
 (0)