From 2c2ec21ae1f5332b63b4f5ad1cb409b179a5799a Mon Sep 17 00:00:00 2001 From: David Crespo Date: Tue, 12 Mar 2024 00:44:08 -0500 Subject: [PATCH] get wild with prefetches for *NameFromId cells --- app/api/hooks.ts | 5 ++++ app/pages/project/disks/DisksPage.tsx | 24 +++++++++++++-- app/pages/project/snapshots/SnapshotsPage.tsx | 29 +++++++++++++++++-- app/pages/system/networking/IpPoolPage.tsx | 9 ++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/app/api/hooks.ts b/app/api/hooks.ts index a44aba237c..88c82a2053 100644 --- a/app/api/hooks.ts +++ b/app/api/hooks.ts @@ -219,6 +219,11 @@ export const wrapQueryClient = (api: A, queryClient: QueryC queryClient.invalidateQueries({ queryKey: [method], ...filters }), setQueryData: (method: M, params: Params, data: Result) => queryClient.setQueryData([method, params], data), + setQueryDataErrorsAllowed: ( + method: M, + params: Params, + data: ErrorsAllowed, ApiError> + ) => queryClient.setQueryData([method, params, ERRORS_ALLOWED], data), fetchQuery: ( method: M, params: Params, diff --git a/app/pages/project/disks/DisksPage.tsx b/app/pages/project/disks/DisksPage.tsx index 0ac9448ef1..9fe75ed560 100644 --- a/app/pages/project/disks/DisksPage.tsx +++ b/app/pages/project/disks/DisksPage.tsx @@ -44,9 +44,27 @@ const EmptyState = () => ( ) DisksPage.loader = async ({ params }: LoaderFunctionArgs) => { - await apiQueryClient.prefetchQuery('diskList', { - query: { ...getProjectSelector(params), limit: 25 }, - }) + const { project } = getProjectSelector(params) + await Promise.all([ + apiQueryClient.prefetchQuery('diskList', { + query: { project, limit: 25 }, + }), + + // fetch instances and preload into RQ cache so fetches by ID in + // InstanceLinkCell can be mostly instant yet gracefully fall back to + // fetching individually if we don't fetch them all here + apiQueryClient + .fetchQuery('instanceList', { query: { project, limit: 200 } }) + .then((instances) => { + for (const instance of instances.items) { + apiQueryClient.setQueryData( + 'instanceView', + { path: { instance: instance.id } }, + instance + ) + } + }), + ]) return null } diff --git a/app/pages/project/snapshots/SnapshotsPage.tsx b/app/pages/project/snapshots/SnapshotsPage.tsx index 13fdf3aed6..4208dee58a 100644 --- a/app/pages/project/snapshots/SnapshotsPage.tsx +++ b/app/pages/project/snapshots/SnapshotsPage.tsx @@ -50,9 +50,32 @@ const EmptyState = () => ( ) SnapshotsPage.loader = async ({ params }: LoaderFunctionArgs) => { - await apiQueryClient.prefetchQuery('snapshotList', { - query: { ...getProjectSelector(params), limit: 25 }, - }) + const { project } = getProjectSelector(params) + await Promise.all([ + apiQueryClient.prefetchQuery('snapshotList', { + query: { project, limit: 25 }, + }), + + // Fetch disks and preload into RQ cache so fetches by ID in DiskNameFromId + // can be mostly instant yet gracefully fall back to fetching individually + // if we don't fetch them all here. This has to be the *ErrorsAllowed + // version of setQueryData because the disk fetchs are also the errors + // allowed version. If we use regular setQueryData, nothing blows up; the + // data is just never found in the cache. Note that the disks that error + // (delete disks) are not prefetched here because they are (obviously) not + // in the disk list response. + apiQueryClient + .fetchQuery('diskList', { query: { project, limit: 200 } }) + .then((disks) => { + for (const disk of disks.items) { + apiQueryClient.setQueryDataErrorsAllowed( + 'diskView', + { path: { disk: disk.id } }, + { type: 'success', data: disk } + ) + } + }), + ]) return null } diff --git a/app/pages/system/networking/IpPoolPage.tsx b/app/pages/system/networking/IpPoolPage.tsx index ddaaf89ab5..b64b777dcd 100644 --- a/app/pages/system/networking/IpPoolPage.tsx +++ b/app/pages/system/networking/IpPoolPage.tsx @@ -54,6 +54,15 @@ IpPoolPage.loader = async function ({ params }: LoaderFunctionArgs) { path: { pool }, query: { limit: 25 }, // match QueryTable }), + + // fetch silos and preload into RQ cache so fetches by ID in SiloNameFromId + // can be mostly instant yet gracefully fall back to fetching individually + // if we don't fetch them all here + apiQueryClient.fetchQuery('siloList', { query: { limit: 200 } }).then((silos) => { + for (const silo of silos.items) { + apiQueryClient.setQueryData('siloView', { path: { silo: silo.id } }, silo) + } + }), ]) return null }