fix bug causing dashboard add menu to flicker

This commit is contained in:
Nate Kelley 2025-07-26 10:03:28 -06:00
parent 2ba9044d13
commit f3944a6dea
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
3 changed files with 59 additions and 74 deletions

View File

@ -15,18 +15,25 @@ import {
import { dashboardsGetDashboard } from './requests';
import { metricsQueryKeys } from '@/api/query_keys/metric';
export const useEnsureDashboardConfig = (prefetchData = true) => {
export const useEnsureDashboardConfig = (params?: { prefetchData?: boolean }) => {
const { prefetchData = true } = params || {};
const queryClient = useQueryClient();
const prefetchDashboard = useGetDashboardAndInitializeMetrics(prefetchData);
const prefetchDashboard = useGetDashboardAndInitializeMetrics({
prefetchData
});
const { openErrorMessage } = useBusterNotifications();
const getLatestDashboardVersion = useGetLatestDashboardVersionMemoized();
const method = useMemoizedFn(async (dashboardId: string) => {
const method = useMemoizedFn(async (dashboardId: string, initializeMetrics = true) => {
const latestVersion = getLatestDashboardVersion(dashboardId);
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId, latestVersion);
let dashboardResponse = queryClient.getQueryData(options.queryKey);
if (!dashboardResponse) {
const res = await prefetchDashboard(dashboardId, latestVersion || undefined).catch((e) => {
const res = await prefetchDashboard(
dashboardId,
latestVersion || undefined,
initializeMetrics
).catch((e) => {
openErrorMessage('Failed to save metrics to dashboard. Dashboard not found');
return null;
});
@ -46,7 +53,8 @@ export const useEnsureDashboardConfig = (prefetchData = true) => {
return method;
};
export const useGetDashboardAndInitializeMetrics = (prefetchData = true) => {
export const useGetDashboardAndInitializeMetrics = (params?: { prefetchData?: boolean }) => {
const { prefetchData = true } = params || {};
const queryClient = useQueryClient();
const setOriginalDashboard = useOriginalDashboardStore((x) => x.setOriginalDashboard);
const onSetLatestDashboardVersion = useDashboardQueryStore((x) => x.onSetLatestDashboardVersion);
@ -72,32 +80,40 @@ export const useGetDashboardAndInitializeMetrics = (prefetchData = true) => {
}
});
return useMemoizedFn(async (id: string, version_number: number | null | undefined) => {
const { password } = getAssetPassword?.(id) || {};
return useMemoizedFn(
async (
id: string,
version_number: number | null | undefined,
shouldInitializeMetrics = true
) => {
const { password } = getAssetPassword?.(id) || {};
return dashboardsGetDashboard({
id: id || '',
password,
version_number: version_number || undefined
}).then((data) => {
initializeMetrics(data.metrics);
const latestVersion = last(data.versions)?.version_number || 1;
const isLatestVersion = data.dashboard.version_number === latestVersion;
return dashboardsGetDashboard({
id: id || '',
password,
version_number: version_number || undefined
}).then((data) => {
if (shouldInitializeMetrics) initializeMetrics(data.metrics);
const latestVersion = last(data.versions)?.version_number || 1;
const isLatestVersion = data.dashboard.version_number === latestVersion;
if (isLatestVersion) {
setOriginalDashboard(data.dashboard);
}
if (isLatestVersion) {
setOriginalDashboard(data.dashboard);
}
if (data.dashboard.version_number) {
queryClient.setQueryData(
dashboardQueryKeys.dashboardGetDashboard(data.dashboard.id, data.dashboard.version_number)
.queryKey,
data
);
onSetLatestDashboardVersion(data.dashboard.id, latestVersion);
}
if (data.dashboard.version_number) {
queryClient.setQueryData(
dashboardQueryKeys.dashboardGetDashboard(
data.dashboard.id,
data.dashboard.version_number
).queryKey,
data
);
onSetLatestDashboardVersion(data.dashboard.id, latestVersion);
}
return data;
});
});
return data;
});
}
);
};

View File

@ -86,7 +86,7 @@ export const useGetDashboard = <TData = BusterDashboardResponse>(
export const usePrefetchGetDashboardClient = () => {
const queryClient = useQueryClient();
const queryFn = useGetDashboardAndInitializeMetrics(false);
const queryFn = useGetDashboardAndInitializeMetrics({ prefetchData: false });
return useMemoizedFn((id: string, versionNumber: number) => {
const getDashboardQueryKey = dashboardQueryKeys.dashboardGetDashboard(id, versionNumber);
const isStale = isQueryStale(getDashboardQueryKey, queryClient);
@ -447,7 +447,7 @@ export const useUpdateDashboardShare = () => {
export const useAddAndRemoveMetricsFromDashboard = () => {
const queryClient = useQueryClient();
const { openErrorMessage, openConfirmModal } = useBusterNotifications();
const ensureDashboardConfig = useEnsureDashboardConfig(false);
const ensureDashboardConfig = useEnsureDashboardConfig({ prefetchData: false });
const setOriginalDashboard = useOriginalDashboardStore((x) => x.setOriginalDashboard);
const setLatestDashboardVersion = useDashboardQueryStore((x) => x.onSetLatestDashboardVersion);
@ -560,7 +560,7 @@ export const useAddAndRemoveMetricsFromDashboard = () => {
export const useAddMetricsToDashboard = () => {
const queryClient = useQueryClient();
const { openErrorMessage, openConfirmModal } = useBusterNotifications();
const ensureDashboardConfig = useEnsureDashboardConfig(false);
const ensureDashboardConfig = useEnsureDashboardConfig({ prefetchData: false });
const setOriginalDashboard = useOriginalDashboardStore((x) => x.setOriginalDashboard);
const getLatestMetricVersion = useGetLatestMetricVersionMemoized();
const setLatestDashboardVersion = useDashboardQueryStore((x) => x.onSetLatestDashboardVersion);
@ -653,7 +653,7 @@ export const useAddMetricsToDashboard = () => {
export const useRemoveMetricsFromDashboard = () => {
const { openConfirmModal, openErrorMessage } = useBusterNotifications();
const queryClient = useQueryClient();
const ensureDashboardConfig = useEnsureDashboardConfig(false);
const ensureDashboardConfig = useEnsureDashboardConfig({ prefetchData: false });
const setOriginalDashboard = useOriginalDashboardStore((x) => x.setOriginalDashboard);
const getLatestMetricVersion = useGetLatestMetricVersionMemoized();
const setLatestDashboardVersion = useDashboardQueryStore((x) => x.onSetLatestDashboardVersion);
@ -683,7 +683,7 @@ export const useRemoveMetricsFromDashboard = () => {
}
}
const dashboardResponse = await ensureDashboardConfig(dashboardId);
const dashboardResponse = await ensureDashboardConfig(dashboardId, false);
if (dashboardResponse) {
const versionedOptions = dashboardQueryKeys.dashboardGetDashboard(
@ -715,13 +715,7 @@ export const useRemoveMetricsFromDashboard = () => {
).queryKey,
data
);
queryClient.setQueryData(
dashboardQueryKeys.dashboardGetDashboard(
data.dashboard.id,
data.dashboard.version_number
).queryKey,
data
);
setOriginalDashboard(data.dashboard);
return data;
@ -745,16 +739,6 @@ export const useRemoveMetricsFromDashboard = () => {
return useMutation({
mutationFn: removeMetricFromDashboard,
onMutate: (variables) => {
variables.metricIds.forEach((id) => {
queryClient.setQueryData(metricsQueryKeys.metricsGetMetric(id, null).queryKey, (old) => {
if (!old) return old;
return create(old, (draft) => {
draft.dashboards = old?.dashboards?.filter((d) => d.id !== variables.dashboardId) || [];
});
});
});
},
onSuccess: (data, variables) => {
if (data) {
setLatestDashboardVersion(data.dashboard.id, data.dashboard.version_number);
@ -762,7 +746,8 @@ export const useRemoveMetricsFromDashboard = () => {
variables.metricIds.forEach((id) => {
queryClient.invalidateQueries({
queryKey: metricsQueryKeys.metricsGetMetric(id, null).queryKey
queryKey: metricsQueryKeys.metricsGetMetric(id, null).queryKey,
refetchType: 'all'
});
});
}

View File

@ -5,7 +5,6 @@ import {
} from '@/api/buster_rest/dashboards';
import { Button } from '@/components/ui/buttons';
import { AppTooltip } from '@/components/ui/tooltip';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { useMemoizedFn } from '@/hooks';
import { ASSET_ICONS } from '../config/assetIcons';
import { SaveToDashboardDropdown } from '../dropdowns/SaveToDashboardDropdown';
@ -14,37 +13,22 @@ export const SaveMetricToDashboardButton: React.FC<{
metricIds: string[];
disabled?: boolean;
selectedDashboards: string[];
}> = React.memo(({ metricIds, disabled = false, selectedDashboards: selectedDashboardsProp }) => {
}> = React.memo(({ metricIds, disabled = false, selectedDashboards }) => {
const { mutateAsync: saveMetricsToDashboard } = useAddMetricsToDashboard();
const { mutateAsync: removeMetricsFromDashboard } = useRemoveMetricsFromDashboard();
const { openConfirmModal } = useBusterNotifications();
const [selectedDashboards, setSelectedDashboards] =
useState<Parameters<typeof SaveToDashboardDropdown>[0]['selectedDashboards']>(
selectedDashboardsProp
);
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
setSelectedDashboards((prev) => [...prev, ...dashboardIds]);
await Promise.all(
dashboardIds.map((dashboardId) => saveMetricsToDashboard({ metricIds, dashboardId }))
);
});
const onRemoveFromDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
const method = async () => {
setSelectedDashboards((prev) => prev.filter((x) => !dashboardIds.includes(x)));
await Promise.all(
dashboardIds.map((dashboardId) =>
removeMetricsFromDashboard({ useConfirmModal: false, metricIds, dashboardId })
)
);
};
return await openConfirmModal({
title: 'Remove from dashboard',
content: 'Are you sure you want to remove this from the dashboard?',
onOk: method
});
await Promise.all(
dashboardIds.map((dashboardId) =>
removeMetricsFromDashboard({ useConfirmModal: false, metricIds, dashboardId })
)
);
});
return (