-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathDisksTableField.tsx
More file actions
109 lines (101 loc) · 3.41 KB
/
DisksTableField.tsx
File metadata and controls
109 lines (101 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
* 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 { useState } from 'react'
import { useController, type Control } from 'react-hook-form'
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 { sizeCellInner } from '~/table/columns/common'
import { Badge } from '~/ui/lib/Badge'
import { Button } from '~/ui/lib/Button'
import { MiniTable } from '~/ui/lib/MiniTable'
import { Truncate } from '~/ui/lib/Truncate'
export type DiskTableItem =
| (DiskCreate & { type: 'create' })
| { name: string; type: 'attach'; size: number }
/**
* Designed less for reuse, more to encapsulate logic that would otherwise
* clutter the instance create form.
*/
export function DisksTableField({
control,
disabled,
unavailableDiskNames,
}: {
control: Control<InstanceCreateInput>
disabled: boolean
unavailableDiskNames: string[]
}) {
const [showDiskCreate, setShowDiskCreate] = useState(false)
const [showDiskAttach, setShowDiskAttach] = useState(false)
const {
field: { value: items, onChange },
} = useController({ control, name: 'otherDisks' })
return (
<>
<div className="flex max-w-lg flex-col items-end gap-3">
<MiniTable
ariaLabel="Disks"
items={items}
columns={[
{
header: 'Name',
cell: (item) => <Truncate text={item.name} maxLength={35} />,
},
{
header: 'Type',
cell: (item) => <Badge>{item.type}</Badge>,
},
{
header: 'Size',
cell: (item) => sizeCellInner(item.size),
},
]}
rowKey={(item) => item.name}
onRemoveItem={(item) => onChange(items.filter((i) => i.name !== item.name))}
removeLabel={(item) => `Remove disk ${item.name}`}
emptyState={{ title: 'No disks', body: 'Add a disk to see it here' }}
/>
<div className="space-x-3">
<Button size="sm" onClick={() => setShowDiskCreate(true)} disabled={disabled}>
Create new disk
</Button>
<Button
variant="secondary"
size="sm"
onClick={() => setShowDiskAttach(true)}
disabled={disabled}
>
Attach existing disk
</Button>
</div>
</div>
{showDiskCreate && (
<CreateDiskSideModalForm
onSubmit={(values) => {
onChange([...items, { type: 'create', ...values }])
setShowDiskCreate(false)
}}
unavailableDiskNames={unavailableDiskNames}
onDismiss={() => setShowDiskCreate(false)}
/>
)}
{showDiskAttach && (
<AttachDiskModalForm
onDismiss={() => setShowDiskAttach(false)}
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)}
/>
)}
</>
)
}