55 *
66 * Copyright Oxide Computer Company
77 */
8+ import { type UseQueryOptions } from '@tanstack/react-query'
89import { createColumnHelper } from '@tanstack/react-table'
910import { filesize } from 'filesize'
1011import { useMemo , useRef } from 'react'
1112import { useNavigate , type LoaderFunctionArgs } from 'react-router-dom'
1213
13- import { apiQueryClient , usePrefetchedApiQuery , type Instance } from '@oxide/api'
14+ import {
15+ apiQueryClient ,
16+ getListQFn ,
17+ queryClient ,
18+ type ApiError ,
19+ type Instance ,
20+ type InstanceResultsPage ,
21+ } from '@oxide/api'
1422import { Instances24Icon } from '@oxide/design-system/icons/react'
1523
1624import { instanceTransitioning } from '~/api/util'
@@ -22,7 +30,7 @@ import { InstanceStateCell } from '~/table/cells/InstanceStateCell'
2230import { makeLinkCell } from '~/table/cells/LinkCell'
2331import { getActionsCol } from '~/table/columns/action-col'
2432import { Columns } from '~/table/columns/common'
25- import { PAGE_SIZE , useQueryTable } from '~/table/QueryTable '
33+ import { useQueryTable } from '~/table/QueryTable2 '
2634import { CreateLink } from '~/ui/lib/CreateButton'
2735import { EmptyMessage } from '~/ui/lib/EmptyMessage'
2836import { PageHeader , PageTitle } from '~/ui/lib/PageHeader'
@@ -46,11 +54,16 @@ const EmptyState = () => (
4654
4755const colHelper = createColumnHelper < Instance > ( )
4856
57+ const instanceList = (
58+ project : string ,
59+ // kinda gnarly, but we need refetchInterval in the component but not in the loader.
60+ // pick refetchInterval to avoid annoying type conflicts on the full object
61+ options ?: Pick < UseQueryOptions < InstanceResultsPage , ApiError > , 'refetchInterval' >
62+ ) => getListQFn ( 'instanceList' , { query : { project } } , options )
63+
4964InstancesPage . loader = async ( { params } : LoaderFunctionArgs ) => {
5065 const { project } = getProjectSelector ( params )
51- await apiQueryClient . prefetchQuery ( 'instanceList' , {
52- query : { project, limit : PAGE_SIZE } ,
53- } )
66+ await queryClient . prefetchQuery ( instanceList ( project ) . optionsFn ( ) )
5467 return null
5568}
5669
@@ -69,6 +82,46 @@ export function InstancesPage() {
6982 { onSuccess : refetchInstances , onDelete : refetchInstances }
7083 )
7184
85+ const columns = useMemo (
86+ ( ) => [
87+ colHelper . accessor ( 'name' , {
88+ cell : makeLinkCell ( ( instance ) => pb . instance ( { project, instance } ) ) ,
89+ } ) ,
90+ colHelper . accessor ( 'ncpus' , {
91+ header : 'CPU' ,
92+ cell : ( info ) => (
93+ < >
94+ { info . getValue ( ) } < span className = "ml-1 text-quaternary" > vCPU</ span >
95+ </ >
96+ ) ,
97+ } ) ,
98+ colHelper . accessor ( 'memory' , {
99+ header : 'Memory' ,
100+ cell : ( info ) => {
101+ const memory = filesize ( info . getValue ( ) , { output : 'object' , base : 2 } )
102+ return (
103+ < >
104+ { memory . value } < span className = "ml-1 text-quaternary" > { memory . unit } </ span >
105+ </ >
106+ )
107+ } ,
108+ } ) ,
109+ colHelper . accessor (
110+ ( i ) => ( { runState : i . runState , timeRunStateUpdated : i . timeRunStateUpdated } ) ,
111+ {
112+ header : 'state' ,
113+ cell : ( info ) => < InstanceStateCell value = { info . getValue ( ) } /> ,
114+ }
115+ ) ,
116+ colHelper . accessor ( 'timeCreated' , Columns . timeCreated ) ,
117+ getActionsCol ( ( instance : Instance ) => [
118+ ...makeButtonActions ( instance ) ,
119+ ...makeMenuActions ( instance ) ,
120+ ] ) ,
121+ ] ,
122+ [ project , makeButtonActions , makeMenuActions ]
123+ )
124+
72125 // this is a whole thing. sit down.
73126
74127 // We initialize this set as empty because we don't have the instances on hand
@@ -77,10 +130,8 @@ export function InstancesPage() {
77130 const transitioningInstances = useRef < Set < string > > ( new Set ( ) )
78131 const pollingStartTime = useRef < number > ( Date . now ( ) )
79132
80- const { data : instances , dataUpdatedAt } = usePrefetchedApiQuery (
81- 'instanceList' ,
82- { query : { project, limit : PAGE_SIZE } } ,
83- {
133+ const { table, query } = useQueryTable ( {
134+ query : instanceList ( project , {
84135 // The point of all this is to poll quickly for a certain amount of time
85136 // after some instance in the current page enters a transitional state
86137 // like starting or stopping. After that, it will keep polling, but more
@@ -122,8 +173,12 @@ export function InstancesPage() {
122173 ? POLL_INTERVAL_FAST
123174 : POLL_INTERVAL_SLOW
124175 } ,
125- }
126- )
176+ } ) ,
177+ columns,
178+ emptyState : < EmptyState /> ,
179+ } )
180+
181+ const { data : instances , dataUpdatedAt } = query
127182
128183 const navigate = useNavigate ( )
129184 useQuickActions (
@@ -143,54 +198,6 @@ export function InstancesPage() {
143198 )
144199 )
145200
146- const { Table } = useQueryTable (
147- 'instanceList' ,
148- { query : { project } } ,
149- { placeholderData : ( x ) => x }
150- )
151-
152- const columns = useMemo (
153- ( ) => [
154- colHelper . accessor ( 'name' , {
155- cell : makeLinkCell ( ( instance ) => pb . instance ( { project, instance } ) ) ,
156- } ) ,
157- colHelper . accessor ( 'ncpus' , {
158- header : 'CPU' ,
159- cell : ( info ) => (
160- < >
161- { info . getValue ( ) } < span className = "ml-1 text-quaternary" > vCPU</ span >
162- </ >
163- ) ,
164- } ) ,
165- colHelper . accessor ( 'memory' , {
166- header : 'Memory' ,
167- cell : ( info ) => {
168- const memory = filesize ( info . getValue ( ) , { output : 'object' , base : 2 } )
169- return (
170- < >
171- { memory . value } < span className = "ml-1 text-quaternary" > { memory . unit } </ span >
172- </ >
173- )
174- } ,
175- } ) ,
176- colHelper . accessor (
177- ( i ) => ( { runState : i . runState , timeRunStateUpdated : i . timeRunStateUpdated } ) ,
178- {
179- header : 'state' ,
180- cell : ( info ) => < InstanceStateCell value = { info . getValue ( ) } /> ,
181- }
182- ) ,
183- colHelper . accessor ( 'timeCreated' , Columns . timeCreated ) ,
184- getActionsCol ( ( instance : Instance ) => [
185- ...makeButtonActions ( instance ) ,
186- ...makeMenuActions ( instance ) ,
187- ] ) ,
188- ] ,
189- [ project , makeButtonActions , makeMenuActions ]
190- )
191-
192- if ( ! instances ) return null
193-
194201 return (
195202 < >
196203 < PageHeader >
@@ -213,7 +220,7 @@ export function InstancesPage() {
213220 </ div >
214221 < CreateLink to = { pb . instancesNew ( { project } ) } > New Instance</ CreateLink >
215222 </ TableActions >
216- < Table columns = { columns } emptyState = { < EmptyState /> } />
223+ { table }
217224 </ >
218225 )
219226}
0 commit comments