@@ -18,6 +18,7 @@ import {
18
18
usePrefetchedApiQuery ,
19
19
type ExternalIp ,
20
20
type InstanceNetworkInterface ,
21
+ type InstanceState ,
21
22
} from '@oxide/api'
22
23
import { IpGlobal24Icon , Networking24Icon } from '@oxide/design-system/icons/react'
23
24
@@ -110,7 +111,15 @@ NetworkingTab.loader = async ({ params }: LoaderFunctionArgs) => {
110
111
return null
111
112
}
112
113
113
- const colHelper = createColumnHelper < InstanceNetworkInterface > ( )
114
+ // Bit of a hack: by putting the instance state in the row data, we can avoid
115
+ // remaking the row actions callback whenever the instance state changes, which
116
+ // causes the whole table to get re-rendered, which jarringly closes any open
117
+ // row actions menus
118
+ type NicRow = InstanceNetworkInterface & {
119
+ instanceState : InstanceState
120
+ }
121
+
122
+ const colHelper = createColumnHelper < NicRow > ( )
114
123
const staticCols = [
115
124
colHelper . accessor ( 'name' , {
116
125
header : 'name' ,
@@ -211,56 +220,58 @@ export function NetworkingTab() {
211
220
path : { instance : instanceName } ,
212
221
query : { project } ,
213
222
} )
214
- const canUpdateNic = instanceCan . updateNic ( instance )
215
223
216
224
const makeActions = useCallback (
217
- ( nic : InstanceNetworkInterface ) : MenuAction [ ] => [
218
- {
219
- label : 'Make primary' ,
220
- onActivate ( ) {
221
- editNic ( {
222
- path : { interface : nic . name } ,
223
- query : instanceSelector ,
224
- body : { ...nic , primary : true } ,
225
- } )
226
- } ,
227
- disabled : nic . primary
228
- ? 'This network interface is already set as primary'
229
- : ! canUpdateNic && (
230
- < >
231
- The instance must be { updateNicStates } to change its primary network
232
- interface
233
- </ >
234
- ) ,
235
- } ,
236
- {
237
- label : 'Edit' ,
238
- onActivate ( ) {
239
- setEditing ( nic )
240
- } ,
241
- disabled : ! canUpdateNic && (
242
- < >
243
- The instance must be { updateNicStates } before editing a network interface's
244
- settings
245
- </ >
246
- ) ,
247
- } ,
248
- {
249
- label : 'Delete' ,
250
- onActivate : confirmDelete ( {
251
- doDelete : ( ) =>
252
- deleteNic ( {
225
+ ( nic : NicRow ) : MenuAction [ ] => {
226
+ const canUpdateNic = instanceCan . updateNic ( { runState : nic . instanceState } )
227
+ return [
228
+ {
229
+ label : 'Make primary' ,
230
+ onActivate ( ) {
231
+ editNic ( {
253
232
path : { interface : nic . name } ,
254
233
query : instanceSelector ,
255
- } ) ,
256
- label : nic . name ,
257
- } ) ,
258
- disabled : ! canUpdateNic && (
259
- < > The instance must be { updateNicStates } to delete a network interface</ >
260
- ) ,
261
- } ,
262
- ] ,
263
- [ canUpdateNic , deleteNic , editNic , instanceSelector ]
234
+ body : { ...nic , primary : true } ,
235
+ } )
236
+ } ,
237
+ disabled : nic . primary
238
+ ? 'This network interface is already set as primary'
239
+ : ! canUpdateNic && (
240
+ < >
241
+ The instance must be { updateNicStates } to change its primary network
242
+ interface
243
+ </ >
244
+ ) ,
245
+ } ,
246
+ {
247
+ label : 'Edit' ,
248
+ onActivate ( ) {
249
+ setEditing ( nic )
250
+ } ,
251
+ disabled : ! canUpdateNic && (
252
+ < >
253
+ The instance must be { updateNicStates } before editing a network
254
+ interface's settings
255
+ </ >
256
+ ) ,
257
+ } ,
258
+ {
259
+ label : 'Delete' ,
260
+ onActivate : confirmDelete ( {
261
+ doDelete : ( ) =>
262
+ deleteNic ( {
263
+ path : { interface : nic . name } ,
264
+ query : instanceSelector ,
265
+ } ) ,
266
+ label : nic . name ,
267
+ } ) ,
268
+ disabled : ! canUpdateNic && (
269
+ < > The instance must be { updateNicStates } to delete a network interface</ >
270
+ ) ,
271
+ } ,
272
+ ]
273
+ } ,
274
+ [ deleteNic , editNic , instanceSelector ]
264
275
)
265
276
266
277
const columns = useColsWithActions ( staticCols , makeActions )
@@ -269,9 +280,14 @@ export function NetworkingTab() {
269
280
query : { ...instanceSelector , limit : 1000 } ,
270
281
} ) . data . items
271
282
283
+ const nicRows = useMemo (
284
+ ( ) => nics . map ( ( nic ) => ( { ...nic , instanceState : instance . runState } ) ) ,
285
+ [ nics , instance ]
286
+ )
287
+
272
288
const tableInstance = useReactTable ( {
273
289
columns,
274
- data : nics || [ ] ,
290
+ data : nicRows ,
275
291
getCoreRowModel : getCoreRowModel ( ) ,
276
292
} )
277
293
@@ -423,7 +439,7 @@ export function NetworkingTab() {
423
439
< TableTitle id = "nics-label" > Network interfaces</ TableTitle >
424
440
< CreateButton
425
441
onClick = { ( ) => setCreateModalOpen ( true ) }
426
- disabled = { ! canUpdateNic }
442
+ disabled = { ! instanceCan . updateNic ( instance ) }
427
443
disabledReason = {
428
444
< >
429
445
A network interface cannot be created or edited unless the instance is{ ' ' }
0 commit comments