5
5
*
6
6
* Copyright Oxide Computer Company
7
7
*/
8
+ import { createColumnHelper } from '@tanstack/react-table'
9
+ import { useCallback } from 'react'
8
10
import { Link , Outlet , type LoaderFunctionArgs } from 'react-router-dom'
9
11
10
12
import {
@@ -21,10 +23,11 @@ import { DiskStatusBadge } from '~/components/StatusBadge'
21
23
import { getProjectSelector , useProjectSelector , useToast } from '~/hooks'
22
24
import { confirmDelete } from '~/stores/confirm-delete'
23
25
import { DateCell } from '~/table/cells/DateCell'
26
+ import { defaultCell } from '~/table/cells/DefaultCell'
24
27
import { InstanceLinkCell } from '~/table/cells/InstanceLinkCell'
25
28
import { SizeCell } from '~/table/cells/SizeCell'
26
- import type { MenuAction } from '~/table/columns/action-col'
27
- import { useQueryTable } from '~/table/QueryTable '
29
+ import { useColsWithActions , type MenuAction } from '~/table/columns/action-col'
30
+ import { useQueryTable2 } from '~/table/QueryTable2 '
28
31
import { buttonStyle } from '~/ui/lib/Button'
29
32
import { EmptyMessage } from '~/ui/lib/EmptyMessage'
30
33
import { PageHeader , PageTitle } from '~/ui/lib/PageHeader'
@@ -68,10 +71,31 @@ DisksPage.loader = async ({ params }: LoaderFunctionArgs) => {
68
71
return null
69
72
}
70
73
74
+ const colHelper = createColumnHelper < Disk > ( )
75
+
76
+ const staticCols = [
77
+ colHelper . accessor ( 'name' , { cell : defaultCell } ) ,
78
+ // sneaky: rather than looking at particular states, just look at
79
+ // whether it has an instance field
80
+ colHelper . accessor ( ( disk ) => ( 'instance' in disk . state ? disk . state . instance : null ) , {
81
+ header : 'Attached to' ,
82
+ cell : ( props ) => < InstanceLinkCell value = { props . getValue ( ) } /> ,
83
+ } ) ,
84
+ colHelper . accessor ( 'size' , { cell : ( props ) => < SizeCell value = { props . getValue ( ) } /> } ) ,
85
+ colHelper . accessor ( 'state.state' , {
86
+ header : 'Status' ,
87
+ cell : ( props ) => < DiskStatusBadge status = { props . getValue ( ) } /> ,
88
+ } ) ,
89
+ colHelper . accessor ( 'timeCreated' , {
90
+ header : 'Created' ,
91
+ cell : ( props ) => < DateCell value = { props . getValue ( ) } /> ,
92
+ } ) ,
93
+ ]
94
+
71
95
export function DisksPage ( ) {
72
96
const queryClient = useApiQueryClient ( )
73
- const projectSelector = useProjectSelector ( )
74
- const { Table, Column } = useQueryTable ( 'diskList' , { query : projectSelector } )
97
+ const { project } = useProjectSelector ( )
98
+ const { Table } = useQueryTable2 ( 'diskList' , { query : { project } } )
75
99
const addToast = useToast ( )
76
100
77
101
const deleteDisk = useApiMutation ( 'diskDelete' , {
@@ -94,72 +118,59 @@ export function DisksPage() {
94
118
} ,
95
119
} )
96
120
97
- const makeActions = ( disk : Disk ) : MenuAction [ ] => [
98
- {
99
- label : 'Snapshot' ,
100
- onActivate ( ) {
101
- addToast ( { title : `Creating snapshot of disk '${ disk . name } '` } )
102
- createSnapshot . mutate ( {
103
- query : projectSelector ,
104
- body : {
105
- name : genName ( disk . name ) ,
106
- disk : disk . name ,
107
- description : '' ,
108
- } ,
109
- } )
121
+ const makeActions = useCallback (
122
+ ( disk : Disk ) : MenuAction [ ] => [
123
+ {
124
+ label : 'Snapshot' ,
125
+ onActivate ( ) {
126
+ addToast ( { title : `Creating snapshot of disk '${ disk . name } '` } )
127
+ createSnapshot . mutate ( {
128
+ query : { project } ,
129
+ body : {
130
+ name : genName ( disk . name ) ,
131
+ disk : disk . name ,
132
+ description : '' ,
133
+ } ,
134
+ } )
135
+ } ,
136
+ disabled : ! diskCan . snapshot ( disk ) && (
137
+ < >
138
+ Only disks in state { fancifyStates ( diskCan . snapshot . states ) } can be snapshotted
139
+ </ >
140
+ ) ,
110
141
} ,
111
- disabled : ! diskCan . snapshot ( disk ) && (
112
- < > Only disks in state { fancifyStates ( diskCan . snapshot . states ) } can be snapshotted </ >
113
- ) ,
114
- } ,
115
- {
116
- label : 'Delete' ,
117
- onActivate : confirmDelete ( {
118
- doDelete : ( ) =>
119
- deleteDisk . mutateAsync ( { path : { disk : disk . name } , query : projectSelector } ) ,
120
- label : disk . name ,
121
- } ) ,
122
- disabled :
123
- ! diskCan . delete ( disk ) &&
124
- ( disk . state . state === 'attached' ? (
125
- 'Disk must be detached before it can be deleted'
126
- ) : (
127
- < > Only disks in state { fancifyStates ( diskCan . delete . states ) } can be deleted </ >
128
- ) ) ,
129
- } ,
130
- ]
142
+ {
143
+ label : 'Delete' ,
144
+ onActivate : confirmDelete ( {
145
+ doDelete : ( ) =>
146
+ deleteDisk . mutateAsync ( { path : { disk : disk . name } , query : { project } } ) ,
147
+ label : disk . name ,
148
+ } ) ,
149
+ disabled :
150
+ ! diskCan . delete ( disk ) &&
151
+ ( disk . state . state === 'attached' ? (
152
+ 'Disk must be detached before it can be deleted'
153
+ ) : (
154
+ < > Only disks in state { fancifyStates ( diskCan . delete . states ) } can be deleted </ >
155
+ ) ) ,
156
+ } ,
157
+ ] ,
158
+ [ addToast , createSnapshot , deleteDisk , project ]
159
+ )
160
+
161
+ const columns = useColsWithActions ( staticCols , makeActions )
131
162
132
163
return (
133
164
< >
134
165
< PageHeader >
135
166
< PageTitle icon = { < Storage24Icon /> } > Disks</ PageTitle >
136
167
</ PageHeader >
137
168
< TableActions >
138
- < Link to = { pb . disksNew ( projectSelector ) } className = { buttonStyle ( { size : 'sm' } ) } >
169
+ < Link to = { pb . disksNew ( { project } ) } className = { buttonStyle ( { size : 'sm' } ) } >
139
170
New Disk
140
171
</ Link >
141
172
</ TableActions >
142
- < Table emptyState = { < EmptyState /> } makeActions = { makeActions } >
143
- < Column accessor = "name" />
144
- { /* TODO: show info about the instance it's attached to */ }
145
- < Column
146
- id = "attached-to"
147
- header = "Attached To"
148
- accessor = { ( disk ) =>
149
- // sneaky: rather than looking at particular states, just look at
150
- // whether it has an instance field
151
- 'instance' in disk . state ? disk . state . instance : null
152
- }
153
- cell = { InstanceLinkCell }
154
- />
155
- < Column header = "Size" accessor = "size" cell = { SizeCell } />
156
- < Column
157
- id = "status"
158
- accessor = { ( row ) => row . state . state }
159
- cell = { ( { value } ) => < DiskStatusBadge status = { value } /> }
160
- />
161
- < Column header = "Created" accessor = "timeCreated" cell = { DateCell } />
162
- </ Table >
173
+ < Table emptyState = { < EmptyState /> } columns = { columns } />
163
174
< Outlet />
164
175
</ >
165
176
)
0 commit comments