prefetcher for version history panel

This commit is contained in:
Nate Kelley 2025-04-16 10:46:20 -06:00
parent 441ec1df40
commit 73768eebc9
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
3 changed files with 145 additions and 35 deletions

View File

@ -118,6 +118,30 @@ export const useGetMetric = <TData = IBusterMetric>(
});
};
export const prefetchGetMetricClient = async (
{ id, versionNumber }: { id: string; versionNumber: number | undefined },
queryClient: QueryClient
) => {
const options = metricsQueryKeys.metricsGetMetric(id, versionNumber);
const existingData = queryClient.getQueryData(options.queryKey);
if (!existingData) {
await queryClient.prefetchQuery({
...options,
queryFn: async () => {
const result = await getMetric({ id, version_number: versionNumber });
return upgradeMetricToIMetric(result, null);
}
});
}
};
export const usePrefetchGetMetricClient = () => {
const queryClient = useQueryClient();
return useMemoizedFn(({ id, versionNumber }: { id: string; versionNumber: number | undefined }) =>
prefetchGetMetricClient({ id, versionNumber }, queryClient)
);
};
export const useGetMetricsList = (
params: Omit<Parameters<typeof listMetrics>[0], 'page_token' | 'page_size'>
) => {
@ -206,6 +230,13 @@ export const prefetchGetMetricDataClient = async (
}
};
export const usePrefetchGetMetricDataClient = () => {
const queryClient = useQueryClient();
return useMemoizedFn(({ id, versionNumber }: { id: string; versionNumber: number | undefined }) =>
prefetchGetMetricDataClient({ id, version_number: versionNumber }, queryClient)
);
};
/**
* This is a mutation that saves a metric to the server.
* It will simply use the params passed in and not do any special logic.

View File

@ -8,17 +8,24 @@ import { cn } from '@/lib/classMerge';
import { timeFromNow, timeout } from '@/lib';
import { AppPageLayout } from '@/components/ui/layouts';
import { useListVersionHistories } from './useListVersionHistories';
import { useMount } from '@/hooks';
import { useMemoizedFn, useMount } from '@/hooks';
import { AppTooltip } from '@/components/ui/tooltip';
import Link from 'next/link';
import { useGetFileLink } from '@/context/Assets/useGetFileLink';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react';
export const VersionHistoryPanel = React.memo(
({ assetId, type }: { assetId: string; type: 'metric' | 'dashboard' }) => {
const chatId = useChatLayoutContextSelector((x) => x.chatId);
const { listItems, currentVersionNumber, selectedQueryVersion, onClickRestoreVersion } =
useListVersionHistories({
const {
listItems,
onPrefetchAsset,
currentVersionNumber,
selectedQueryVersion,
onClickRestoreVersion
} = useListVersionHistories({
assetId,
type
});
@ -51,6 +58,7 @@ export const VersionHistoryPanel = React.memo(
<ListItem
key={item.version_number}
{...item}
onPrefetchAsset={onPrefetchAsset}
selected={item.version_number === selectedQueryVersion}
showRestoreButton={item.version_number !== currentVersionNumber}
onClickRestoreVersion={onClickRestoreVersion}
@ -78,18 +86,37 @@ const ListItem = React.memo(
selected,
showRestoreButton,
link,
onClickRestoreVersion
onClickRestoreVersion,
onPrefetchAsset
}: {
version_number: number;
updated_at: string;
selected: boolean;
showRestoreButton: boolean;
onClickRestoreVersion: (versionNumber: number) => void;
onPrefetchAsset: (versionNumber: number, link: string) => Promise<void>;
link: string;
}) => {
const routePrefetchTimeoutRef = useRef<NodeJS.Timeout>();
const onHoverLink = useMemoizedFn(() => {
// Prefetch route after 50ms
routePrefetchTimeoutRef.current = setTimeout(() => {
onPrefetchAsset(version_number, link);
}, 125);
});
const onHoverEnd = useCallback(() => {
if (routePrefetchTimeoutRef.current) {
clearTimeout(routePrefetchTimeoutRef.current);
}
}, []);
return (
<Link prefetch={false} href={link}>
<div
onMouseEnter={onHoverLink}
onMouseLeave={onHoverEnd}
className={cn(
'group hover:bg-item-hover flex cursor-pointer items-center justify-between space-x-2 rounded px-2.5 py-1.5',
selected && 'bg-item-select hover:bg-item-select selected-version'

View File

@ -1,7 +1,11 @@
'use client';
import { useGetDashboard, useUpdateDashboard } from '@/api/buster_rest/dashboards';
import { useGetMetric, useSaveMetric } from '@/api/buster_rest/metrics';
import {
useGetMetric,
usePrefetchGetMetricDataClient,
useSaveMetric
} from '@/api/buster_rest/metrics';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useMemoizedFn } from '@/hooks';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
@ -9,6 +13,8 @@ import { useCloseVersionHistory } from '@/layouts/ChatLayout/FileContainer/FileC
import { BusterRoutes, createBusterRoute } from '@/routes';
import last from 'lodash/last';
import { useMemo } from 'react';
import { usePrefetchGetMetricClient } from '@/api/buster_rest/metrics';
import { useRouter } from 'next/navigation';
export const useListVersionHistories = ({
assetId,
@ -17,24 +23,27 @@ export const useListVersionHistories = ({
assetId: string;
type: 'metric' | 'dashboard';
}) => {
const router = useRouter();
const { onCloseVersionHistory } = useCloseVersionHistory();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const {
dashboardVersions,
versions: dashboardVersions,
selectedQueryVersion: dashboardSelectedQueryVersion,
currentVersionNumber: dashboardCurrentVersionNumber,
onRestoreVersion: onRestoreDashboardVersion,
isSavingDashboard
isSaving: isSavingDashboard,
onPrefetchAsset: onPrefetchDashboardAsset
} = useListDashboardVersions({
assetId,
type
});
const {
metricVersions,
versions: metricVersions,
selectedQueryVersion: metricSelectedQueryVersion,
currentVersionNumber: metricCurrentVersionNumber,
onRestoreVersion: onRestoreMetricVersion,
isSavingMetric
isSaving: isSavingMetric,
onPrefetchAsset: onPrefetchMetricAsset
} = useListMetricVersions({
assetId,
type
@ -82,13 +91,24 @@ export const useListVersionHistories = ({
}
);
const onPrefetchAsset = useMemoizedFn(async (versionNumber: number, link: string) => {
router.prefetch(link);
if (type === 'metric') {
await onPrefetchMetricAsset(versionNumber);
} else {
await onPrefetchDashboardAsset(versionNumber);
}
});
return useMemo(() => {
return {
listItems,
currentVersionNumber,
selectedQueryVersion,
onClickRestoreVersion,
isRestoringVersion: isSavingDashboard || isSavingMetric
isRestoringVersion: isSavingDashboard || isSavingMetric,
onPrefetchAsset
};
}, [
listItems,
@ -96,19 +116,34 @@ export const useListVersionHistories = ({
selectedQueryVersion,
onClickRestoreVersion,
isSavingDashboard,
isSavingMetric
isSavingMetric,
onPrefetchAsset
]);
};
type UseListVersionReturn = {
versions:
| {
version_number: number;
updated_at: string;
}[]
| undefined;
selectedQueryVersion: number | undefined;
onRestoreVersion: (versionNumber: number) => Promise<unknown>;
currentVersionNumber: number | undefined;
isSaving: boolean;
onPrefetchAsset: (versionNumber: number) => Promise<void>;
};
const useListDashboardVersions = ({
assetId,
type
}: {
assetId: string;
type: 'metric' | 'dashboard';
}) => {
}): UseListVersionReturn => {
const dashboardVersionNumber = useChatLayoutContextSelector((x) => x.dashboardVersionNumber);
const { mutateAsync: updateDashboard, isPending: isSavingDashboard } = useUpdateDashboard({
const { mutateAsync: updateDashboard, isPending: isSaving } = useUpdateDashboard({
saveToServer: true,
updateVersion: true
});
@ -125,13 +160,13 @@ const useListDashboardVersions = ({
}
);
const dashboardVersions = dashboardData?.versions;
const versions = dashboardData?.versions;
const currentVersionNumber = dashboardData?.version_number;
const selectedQueryVersion = useMemo(() => {
if (dashboardVersionNumber) return dashboardVersionNumber;
return last(dashboardVersions)?.version_number;
}, [dashboardVersions, dashboardVersionNumber]);
return last(versions)?.version_number;
}, [versions, dashboardVersionNumber]);
const onRestoreVersion = useMemoizedFn(async (versionNumber: number) => {
await updateDashboard({
@ -140,20 +175,26 @@ const useListDashboardVersions = ({
});
});
const onPrefetchAsset = useMemoizedFn(async (versionNumber: number) => {
//
});
return useMemo(() => {
return {
dashboardVersions,
versions,
selectedQueryVersion,
onRestoreVersion,
currentVersionNumber,
isSavingDashboard
isSaving,
onPrefetchAsset
};
}, [
dashboardVersions,
versions,
currentVersionNumber,
onRestoreVersion,
selectedQueryVersion,
isSavingDashboard
isSaving,
onPrefetchAsset
]);
};
@ -163,10 +204,12 @@ const useListMetricVersions = ({
}: {
assetId: string;
type: 'metric' | 'dashboard';
}) => {
const { mutateAsync: updateMetric, isPending: isSavingMetric } = useSaveMetric({
}): UseListVersionReturn => {
const { mutateAsync: updateMetric, isPending: isSaving } = useSaveMetric({
updateOnSave: true
});
const prefetchGetMetric = usePrefetchGetMetricClient();
const prefetchGetMetricData = usePrefetchGetMetricDataClient();
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
@ -181,9 +224,14 @@ const useListMetricVersions = ({
})
}
);
const metricVersions = metric?.versions;
const versions = metric?.versions;
const currentVersionNumber = metricVersionNumber || metric?.version_number;
const selectedQueryVersion = useMemo(() => {
if (metricVersionNumber) return metricVersionNumber;
return last(versions)?.version_number;
}, [versions, metricVersionNumber]);
const onRestoreVersion = useMemoizedFn(async (versionNumber: number) => {
await updateMetric({
id: assetId,
@ -191,24 +239,28 @@ const useListMetricVersions = ({
});
});
const selectedQueryVersion = useMemo(() => {
if (metricVersionNumber) return metricVersionNumber;
return last(metricVersions)?.version_number;
}, [metricVersions, metricVersionNumber]);
const onPrefetchAsset = useMemoizedFn(async (versionNumber: number) => {
await Promise.all([
prefetchGetMetric({ id: assetId, versionNumber }),
prefetchGetMetricData({ id: assetId, versionNumber })
]);
});
return useMemo(() => {
return {
metricVersions,
versions,
selectedQueryVersion,
onRestoreVersion,
currentVersionNumber,
isSavingMetric
isSaving,
onPrefetchAsset
};
}, [
metricVersions,
versions,
currentVersionNumber,
onRestoreVersion,
selectedQueryVersion,
currentVersionNumber,
isSavingMetric
isSaving,
onPrefetchAsset
]);
};