Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add switches tab to system inventory #2620

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/pages/system/inventory/InventoryPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function InventoryPage() {
<RouteTabs fullWidth>
<Tab to={pb.sledInventory()}>Sleds</Tab>
<Tab to={pb.diskInventory()}>Disks</Tab>
<Tab to={pb.switchInventory()}>Switches</Tab>
</RouteTabs>
</>
)
Expand Down
44 changes: 44 additions & 0 deletions app/pages/system/inventory/SwitchesTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import { createColumnHelper } from '@tanstack/react-table'

import { getListQFn, queryClient, type Switch } from '@oxide/api'
import { Servers24Icon } from '@oxide/design-system/icons/react'

import { useQueryTable } from '~/table/QueryTable'
import { EmptyMessage } from '~/ui/lib/EmptyMessage'

const EmptyState = () => (
<EmptyMessage
icon={<Servers24Icon />}
title="Something went wrong"
body="We expected some switches here, but none were found"
/>
)

const switchList = getListQFn('switchList', {})

export async function loader() {
await queryClient.prefetchQuery(switchList.optionsFn())
return null
}

const colHelper = createColumnHelper<Switch>()
const staticCols = [
colHelper.accessor('id', {}),
colHelper.accessor('baseboard.part', { header: 'part number' }),
colHelper.accessor('baseboard.serial', { header: 'serial number' }),
colHelper.accessor('baseboard.revision', { header: 'revision' }),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is useful here, it's probably useful on the other tabs. Worth asking someone.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have PART NUMBER / SERIAL NUMBER / REVISION columns on Sleds, but, in looking at it, there are a few columns available in the Sled type that we aren't using (usableHardwareThreads, usablePhysicalRam). I'll check in with rm in a second on what of those would be useful to add.
The PhysicalDisk type doesn't seem to have similar data to draw from.

]

Component.displayName = 'SwitchesTab'
export function Component() {
const emptyState = <EmptyState />
const { table } = useQueryTable({ query: switchList, columns: staticCols, emptyState })
return table
}
2 changes: 2 additions & 0 deletions app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import { InventoryPage } from './pages/system/inventory/InventoryPage'
import * as SledInstances from './pages/system/inventory/sled/SledInstancesTab'
import * as SledPage from './pages/system/inventory/sled/SledPage'
import * as SledsTab from './pages/system/inventory/SledsTab'
import * as SwitchesTab from './pages/system/inventory/SwitchesTab'
import * as IpPool from './pages/system/networking/IpPoolPage'
import * as IpPools from './pages/system/networking/IpPoolsPage'
import * as SiloImages from './pages/system/SiloImagesPage'
Expand Down Expand Up @@ -162,6 +163,7 @@ export const routes = createRoutesFromElements(
<Route index element={<Navigate to="sleds" replace />} loader={SledsTab.loader} />
<Route path="sleds" {...SledsTab} handle={{ crumb: 'Sleds' }} />
<Route path="disks" {...DisksTab} handle={{ crumb: 'Disks' }} />
<Route path="switches" {...SwitchesTab} handle={{ crumb: 'Switches' }} />
</Route>
<Route path="inventory" handle={{ crumb: 'Inventory' }}>
<Route path="sleds" handle={{ crumb: 'Sleds' }}>
Expand Down
10 changes: 10 additions & 0 deletions app/util/__snapshots__/path-builder.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ exports[`breadcrumbs 2`] = `
"path": "/settings/ssh-keys",
},
],
"switchInventory (/system/inventory/switches)": [
{
"label": "Inventory",
"path": "/system/inventory/sleds",
},
{
"label": "Switches",
"path": "/system/inventory/switches",
},
],
"systemUtilization (/system/utilization)": [
{
"label": "Utilization",
Expand Down
1 change: 1 addition & 0 deletions app/util/path-builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ test('path builder', () => {
"sshKeyEdit": "/settings/ssh-keys/ss/edit",
"sshKeys": "/settings/ssh-keys",
"sshKeysNew": "/settings/ssh-keys-new",
"switchInventory": "/system/inventory/switches",
"systemUtilization": "/system/utilization",
"vpc": "/projects/p/vpcs/v/firewall-rules",
"vpcEdit": "/projects/p/vpcs/v/edit",
Expand Down
1 change: 1 addition & 0 deletions app/util/path-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const pb = {

sledInventory: () => '/system/inventory/sleds',
diskInventory: () => '/system/inventory/disks',
switchInventory: () => '/system/inventory/switches',
sled: ({ sledId }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`,
sledInstances: ({ sledId }: PP.Sled) => `/system/inventory/sleds/${sledId}/instances`,

Expand Down
1 change: 1 addition & 0 deletions mock-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './silo'
export * from './sled'
export * from './snapshot'
export * from './sshKeys'
export * from './switch'
export * from './user'
export * from './user-group'
export * from './user'
Expand Down
1 change: 1 addition & 0 deletions mock-api/msw/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ const initDb = {
siloProvisioned: [...mock.siloProvisioned],
identityProviders: [...mock.identityProviders],
sleds: [...mock.sleds],
switches: [...mock.switches],
snapshots: [...mock.snapshots],
sshKeys: [...mock.sshKeys],
users: [...mock.users],
Expand Down
6 changes: 5 additions & 1 deletion mock-api/msw/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,11 @@ export const handlers = makeHandlers({
return paginated(query, db.users)
},

switchList: ({ query, cookies }) => {
requireFleetViewer(cookies)
return paginated(query, db.switches)
},

systemPolicyView({ cookies }) {
requireFleetViewer(cookies)

Expand Down Expand Up @@ -1587,7 +1592,6 @@ export const handlers = makeHandlers({
sledAdd: NotImplemented,
sledListUninitialized: NotImplemented,
sledSetProvisionPolicy: NotImplemented,
switchList: NotImplemented,
switchView: NotImplemented,
systemPolicyUpdate: NotImplemented,
systemQuotasList: NotImplemented,
Expand Down
25 changes: 25 additions & 0 deletions mock-api/switch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import type { Switch } from '@oxide/api'

import type { Json } from './json-type'
import { rack } from './rack'

export const switches: Json<Switch[]> = [
{
baseboard: {
part: '832-0431906',
serial: 'BDS02141689',
revision: 1,
},
id: 'ed66617e-4955-465e-b810-0d0dc55d4511',
rack_id: rack.id,
time_created: rack.time_created,
time_modified: rack.time_modified,
},
]
20 changes: 19 additions & 1 deletion test/e2e/inventory.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Copyright Oxide Computer Company
*/

import { physicalDisks, sleds } from '@oxide/api-mocks'
import { physicalDisks, sleds, switches } from '@oxide/api-mocks'

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

Expand Down Expand Up @@ -85,3 +85,21 @@ test('Disk inventory page', async ({ page }) => {
state: 'decommissioned',
})
})

test('Switch inventory page', async ({ page }) => {
await page.goto('/system/inventory/switches')

await expectVisible(page, ['role=heading[name*="Inventory"]'])

const switchesTab = page.getByRole('tab', { name: 'Switches' })
await expect(switchesTab).toBeVisible()
await expect(switchesTab).toHaveClass(/is-selected/)

const table = page.getByRole('table')
await expectRowVisible(table, {
id: switches[0].id,
'part number': '832-0431906',
'serial number': 'BDS02141689',
revision: '1',
})
})
Loading