From d1a62ed56306a7990c28aa5a54a768b7356c6d11 Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Sun, 29 Jun 2025 09:08:05 -0700 Subject: [PATCH 1/3] Show size of attached disks in mini table --- app/components/form/fields/DisksTableField.tsx | 16 ++++++++++------ app/forms/instance-create.tsx | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/components/form/fields/DisksTableField.tsx b/app/components/form/fields/DisksTableField.tsx index b08bc1794..9cad9e275 100644 --- a/app/components/form/fields/DisksTableField.tsx +++ b/app/components/form/fields/DisksTableField.tsx @@ -8,7 +8,7 @@ import { useState } from 'react' import { useController, type Control } from 'react-hook-form' -import type { DiskCreate } from '@oxide/api' +import type { Disk, DiskCreate } from '@oxide/api' import { AttachDiskModalForm } from '~/forms/disk-attach' import { CreateDiskSideModalForm } from '~/forms/disk-create' @@ -22,7 +22,7 @@ import { Truncate } from '~/ui/lib/Truncate' export type DiskTableItem = | (DiskCreate & { type: 'create' }) - | { name: string; type: 'attach' } + | { name: string; type: 'attach'; size: number } /** * Designed less for reuse, more to encapsulate logic that would otherwise @@ -32,10 +32,12 @@ export function DisksTableField({ control, disabled, unavailableDiskNames, + allDisks, }: { control: Control disabled: boolean unavailableDiskNames: string[] + allDisks: Disk[] }) { const [showDiskCreate, setShowDiskCreate] = useState(false) const [showDiskAttach, setShowDiskAttach] = useState(false) @@ -61,8 +63,7 @@ export function DisksTableField({ }, { header: 'Size', - cell: (item) => - item.type === 'attach' ? : sizeCellInner(item.size), + cell: (item) => (item.size ? sizeCellInner(item.size) : ), }, ]} rowKey={(item) => item.name} @@ -99,8 +100,11 @@ export function DisksTableField({ {showDiskAttach && ( setShowDiskAttach(false)} - onSubmit={(values) => { - onChange([...items, { type: 'attach', ...values }]) + onSubmit={({ name }: { name: string }) => { + onChange([ + ...items, + { name, type: 'attach', size: allDisks.find((d) => d.name === name)?.size }, + ]) setShowDiskAttach(false) }} diskNamesToExclude={items.filter((i) => i.type === 'attach').map((i) => i.name)} diff --git a/app/forms/instance-create.tsx b/app/forms/instance-create.tsx index 5415e5de0..01f14a459 100644 --- a/app/forms/instance-create.tsx +++ b/app/forms/instance-create.tsx @@ -586,6 +586,7 @@ export default function CreateInstanceForm() { // Don't allow the user to create a new disk with a name that matches other disk names (either the boot disk, // the names of disks that will be created and attached to this instance, or disks that already exist). unavailableDiskNames={[bootDiskName, ...unavailableDiskNames]} + allDisks={allDisks} /> Authentication From 68a74b85d3073ba08018c6de993d8eec3045a5af Mon Sep 17 00:00:00 2001 From: Charlie Park Date: Mon, 30 Jun 2025 05:40:48 -0700 Subject: [PATCH 2/3] update test --- test/e2e/instance-create.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/instance-create.e2e.ts b/test/e2e/instance-create.e2e.ts index ad48dc4f4..33bba89cc 100644 --- a/test/e2e/instance-create.e2e.ts +++ b/test/e2e/instance-create.e2e.ts @@ -597,7 +597,7 @@ test('create instance with additional disks', async ({ page }) => { await selectOption(page, 'Disk name', 'disk-3') await page.getByRole('button', { name: 'Attach disk' }).click() - await expectRowVisible(disksTable, { Name: 'disk-3', Type: 'attach', Size: '—' }) + await expectRowVisible(disksTable, { Name: 'disk-3', Type: 'attach', Size: '6 GiB' }) // Create the instance await page.getByRole('button', { name: 'Create instance' }).click() From 34406e89deeb63ddd04314fb79adf46be6955a44 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Sun, 29 Jun 2025 11:49:13 -0500 Subject: [PATCH 3/3] get disk size more directly --- app/components/form/fields/DisksTableField.tsx | 14 ++++---------- app/forms/disk-attach.tsx | 10 ++++++++-- app/forms/instance-create.tsx | 1 - 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/app/components/form/fields/DisksTableField.tsx b/app/components/form/fields/DisksTableField.tsx index 9cad9e275..e5af57ff3 100644 --- a/app/components/form/fields/DisksTableField.tsx +++ b/app/components/form/fields/DisksTableField.tsx @@ -8,12 +8,11 @@ import { useState } from 'react' import { useController, type Control } from 'react-hook-form' -import type { Disk, DiskCreate } from '@oxide/api' +import type { DiskCreate } from '@oxide/api' import { AttachDiskModalForm } from '~/forms/disk-attach' import { CreateDiskSideModalForm } from '~/forms/disk-create' import type { InstanceCreateInput } from '~/forms/instance-create' -import { EmptyCell } from '~/table/cells/EmptyCell' import { sizeCellInner } from '~/table/columns/common' import { Badge } from '~/ui/lib/Badge' import { Button } from '~/ui/lib/Button' @@ -32,12 +31,10 @@ export function DisksTableField({ control, disabled, unavailableDiskNames, - allDisks, }: { control: Control disabled: boolean unavailableDiskNames: string[] - allDisks: Disk[] }) { const [showDiskCreate, setShowDiskCreate] = useState(false) const [showDiskAttach, setShowDiskAttach] = useState(false) @@ -63,7 +60,7 @@ export function DisksTableField({ }, { header: 'Size', - cell: (item) => (item.size ? sizeCellInner(item.size) : ), + cell: (item) => sizeCellInner(item.size), }, ]} rowKey={(item) => item.name} @@ -100,11 +97,8 @@ export function DisksTableField({ {showDiskAttach && ( setShowDiskAttach(false)} - onSubmit={({ name }: { name: string }) => { - onChange([ - ...items, - { name, type: 'attach', size: allDisks.find((d) => d.name === name)?.size }, - ]) + onSubmit={({ name, size }: { name: string; size: number }) => { + onChange([...items, { type: 'attach', name, size } satisfies DiskTableItem]) setShowDiskAttach(false) }} diskNamesToExclude={items.filter((i) => i.type === 'attach').map((i) => i.name)} diff --git a/app/forms/disk-attach.tsx b/app/forms/disk-attach.tsx index f3f07d841..b35f42735 100644 --- a/app/forms/disk-attach.tsx +++ b/app/forms/disk-attach.tsx @@ -20,7 +20,7 @@ const defaultValues = { name: '' } type AttachDiskProps = { /** If defined, this overrides the usual mutation */ - onSubmit: (diskAttach: { name: string }) => void + onSubmit: (diskAttach: { name: string; size: number }) => void onDismiss: () => void diskNamesToExclude?: string[] loading?: boolean @@ -64,7 +64,13 @@ export function AttachDiskModalForm({ submitError={submitError} loading={loading} title="Attach disk" - onSubmit={onSubmit} + onSubmit={({ name }) => { + // because the ComboboxField is required and does not allow arbitrary + // values (values not in the list of disks), we can only get here if the + // disk is defined and in the list + const disk = data!.items.find((d) => d.name === name)! + onSubmit({ name, size: disk.size }) + }} > Authentication