make new saving to dashboard endpoints

This commit is contained in:
Nate Kelley 2025-03-20 15:03:57 -06:00
parent abb54f4dbb
commit 6a30100f3f
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
12 changed files with 443 additions and 81 deletions

View File

@ -0,0 +1,2 @@
export * from './addMetricToDashboard';
export * from './removeMetricFromDashboard';

View File

@ -0,0 +1,266 @@
import { removeMetricFromDashboardConfig } from './removeMetricFromDashboard';
import type { BusterDashboard } from '@/api/asset_interfaces/dashboard';
describe('removeMetricFromDashboardConfig', () => {
const createEmptyConfig = (): BusterDashboard['config'] => ({
rows: []
});
const createConfigWithRows = (
rows: BusterDashboard['config']['rows']
): BusterDashboard['config'] => ({
rows
});
it('should return the same config if no metrics to remove are provided', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }],
columnSizes: [12],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig([], config);
expect(result.rows).toHaveLength(1);
expect(result.rows![0].items).toHaveLength(1);
});
it('should remove a single metric from a single row', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric1'], config);
expect(result.rows).toHaveLength(1);
expect(result.rows![0].items).toHaveLength(1);
expect(result.rows![0].items[0].id).toBe('metric2');
expect(result.rows![0].items.length).toBe(1);
expect(result.rows![0].columnSizes).toEqual([12]); // Single column takes full width
});
it('should remove multiple metrics from a single row', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }, { id: 'metric3' }, { id: 'metric4' }],
columnSizes: [3, 3, 3, 3],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric1', 'metric3'], config);
expect(result.rows).toHaveLength(1);
expect(result.rows![0].items).toHaveLength(2);
expect(result.rows![0].items.map((item) => item.id)).toEqual(['metric2', 'metric4']);
expect(result.rows![0].columnSizes).toEqual([6, 6]); // Two equal columns
});
it('should remove entire row when all metrics in the row are removed', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
},
{
id: 'row2',
items: [{ id: 'metric3' }],
columnSizes: [12],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric1', 'metric2'], config);
expect(result.rows).toHaveLength(1);
expect(result.rows![0].items).toHaveLength(1);
expect(result.rows![0].items.length).toBe(1);
expect(result.rows![0].columnSizes).toEqual([12]);
expect(result.rows![0].id).toBe('row2');
expect(result.rows![0].items[0].id).toBe('metric3');
});
it('should handle removing metrics from multiple rows', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
},
{
id: 'row2',
items: [{ id: 'metric3' }, { id: 'metric4' }],
columnSizes: [6, 6],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric1', 'metric4'], config);
expect(result.rows).toHaveLength(2);
expect(result.rows![0].items).toHaveLength(1);
expect(result.rows![1].items).toHaveLength(1);
expect(result.rows![0].items[0].id).toBe('metric2');
expect(result.rows![1].items[0].id).toBe('metric3');
expect(result.rows![0].columnSizes).toEqual([12]);
expect(result.rows![1].columnSizes).toEqual([12]);
});
it('should handle removing non-existent metrics', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['nonexistent1', 'nonexistent2'], config);
expect(result.rows).toHaveLength(1);
expect(result.rows![0].items).toHaveLength(2);
expect(result.rows![0].columnSizes).toEqual([6, 6]);
});
it('should handle empty config', () => {
const config = createEmptyConfig();
const result = removeMetricFromDashboardConfig(['metric1'], config);
expect(result.rows).toHaveLength(0);
});
it('should preserve row properties while updating items and columnSizes', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }, { id: 'metric3' }],
columnSizes: [4, 4, 4],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric2'], config);
expect(result.rows![0]).toMatchObject({
id: 'row1',
rowHeight: 320
});
expect(result.rows![0].items).toHaveLength(2);
expect(result.rows![0].columnSizes).toEqual([6, 6]);
});
it('should handle removing all metrics from config', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
},
{
id: 'row2',
items: [{ id: 'metric3' }],
columnSizes: [12],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric1', 'metric2', 'metric3'], config);
expect(result.rows).toHaveLength(0);
});
it('should correctly remove metrics from a large config with multiple rows', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }],
columnSizes: [6, 6],
rowHeight: 320
},
{
id: 'row2',
items: [{ id: 'metric3' }, { id: 'metric4' }, { id: 'metric5' }],
columnSizes: [4, 4, 4],
rowHeight: 320
},
{
id: 'row3',
items: [{ id: 'metric6' }],
columnSizes: [12],
rowHeight: 320
},
{
id: 'row4',
items: [{ id: 'metric7' }, { id: 'metric8' }, { id: 'metric9' }, { id: 'metric10' }],
columnSizes: [3, 3, 3, 3],
rowHeight: 320
},
{
id: 'row5',
items: [{ id: 'metric11' }, { id: 'metric12' }],
columnSizes: [6, 6],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(['metric2', 'metric4', 'metric11'], config);
expect(result.rows).toHaveLength(5);
// Check row 1
expect(result.rows![0].items).toHaveLength(1);
expect(result.rows![0].items[0].id).toBe('metric1');
expect(result.rows![0].columnSizes).toEqual([12]);
// Check row 2
expect(result.rows![1].items).toHaveLength(2);
expect(result.rows![1].items.map((item) => item.id)).toEqual(['metric3', 'metric5']);
expect(result.rows![1].columnSizes).toEqual([6, 6]);
// Check row 3 (unchanged)
expect(result.rows![2].items).toHaveLength(1);
expect(result.rows![2].items[0].id).toBe('metric6');
// Check row 4 (unchanged)
expect(result.rows![3].items).toHaveLength(4);
expect(result.rows![3].columnSizes).toEqual([3, 3, 3, 3]);
// Check row 5
expect(result.rows![4].items).toHaveLength(1);
expect(result.rows![4].items[0].id).toBe('metric12');
expect(result.rows![4].columnSizes).toEqual([12]);
});
it('should handle removing non-existent metrics while preserving existing structure', () => {
const config = createConfigWithRows([
{
id: 'row1',
items: [{ id: 'metric1' }, { id: 'metric2' }, { id: 'metric3' }],
columnSizes: [4, 4, 4],
rowHeight: 320
},
{
id: 'row2',
items: [{ id: 'metric4' }, { id: 'metric5' }],
columnSizes: [6, 6],
rowHeight: 320
}
]);
const result = removeMetricFromDashboardConfig(
['nonexistent1', 'nonexistent2', 'metric1'],
config
);
// Should only remove metric1 and ignore non-existent metrics
expect(result.rows).toHaveLength(2);
// Check first row
expect(result.rows![0].items).toHaveLength(2);
expect(result.rows![0].items.map((item) => item.id)).toEqual(['metric2', 'metric3']);
expect(result.rows![0].columnSizes).toEqual([6, 6]);
// Check second row (should be unchanged)
expect(result.rows![1].items).toHaveLength(2);
expect(result.rows![1].items.map((item) => item.id)).toEqual(['metric4', 'metric5']);
expect(result.rows![1].columnSizes).toEqual([6, 6]);
});
});

View File

@ -0,0 +1,38 @@
import type { BusterDashboard } from '@/api/asset_interfaces/dashboard';
import { NUMBER_OF_COLUMNS } from '@/components/ui/grid/helpers';
export const removeMetricFromDashboardConfig = (
metricIds: string[],
existingConfig: BusterDashboard['config']
) => {
// Create a new config object to avoid mutating the original
const newConfig = {
...existingConfig,
rows: [...(existingConfig.rows || [])]
};
// Filter out rows that contain metrics to be removed
newConfig.rows = newConfig.rows
.map((row) => {
// Remove the specified metrics from the row
const filteredItems = row.items.filter((item) => !metricIds.includes(item.id));
// If no items left in the row, return null to filter out later
if (filteredItems.length === 0) {
return null;
}
// Recalculate column sizes for remaining items
const columnSize = NUMBER_OF_COLUMNS / filteredItems.length;
const columnSizes = Array(filteredItems.length).fill(columnSize);
return {
...row,
items: filteredItems,
columnSizes
};
})
.filter((row): row is NonNullable<typeof row> => row !== null);
return newConfig;
};

View File

@ -25,6 +25,7 @@ import {
useRemoveAssetFromCollection
} from '../collections/queryRequests';
import { collectionQueryKeys } from '@/api/query_keys/collection';
import { addMetricToDashboardConfig, removeMetricFromDashboardConfig } from './helpers';
export const useGetDashboardsList = (
params: Omit<DashboardsListRequest, 'page_token' | 'page_size'>
@ -43,13 +44,12 @@ export const useGetDashboardsList = (
});
};
export const useGetDashboard = <TData = BusterDashboardResponse>(
id: string | undefined,
select?: (data: BusterDashboardResponse) => TData
) => {
const useGetDashboardAndInitializeMetrics = () => {
const queryClient = useQueryClient();
const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
const { password } = getAssetPassword(id!);
return useMemoizedFn(async (id: string) => {
const { password } = getAssetPassword(id);
const initializeMetrics = useMemoizedFn((metrics: BusterDashboardResponse['metrics']) => {
for (const metric of Object.values(metrics)) {
@ -60,16 +60,22 @@ export const useGetDashboard = <TData = BusterDashboardResponse>(
}
});
const queryFn = useMemoizedFn(async () => {
return dashboardsGetDashboard({ id: id!, password }).then((data) => {
initializeMetrics(data.metrics);
return data;
});
});
};
export const useGetDashboard = <TData = BusterDashboardResponse>(
id: string | undefined,
select?: (data: BusterDashboardResponse) => TData
) => {
const queryFn = useGetDashboardAndInitializeMetrics();
return useQuery({
...dashboardQueryKeys.dashboardGetDashboard(id!),
queryFn: queryFn,
queryFn: () => queryFn(id!),
enabled: !!id,
select
});
@ -318,46 +324,87 @@ export const useUpdateDashboardShare = () => {
export const useSaveMetricsToDashboard = () => {
const queryClient = useQueryClient();
const prefetchDashboard = useGetDashboardAndInitializeMetrics();
const { openErrorMessage } = useBusterNotifications();
const saveMetricToDashboard = useMemoizedFn(
async ({ metricIds, dashboardId }: { metricIds: string[]; dashboardId: string }) => {
// await saveMetric({
// id: metricId,
// save_to_dashboard: dashboardIds
// });
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
let dashboardResponse = queryClient.getQueryData(options.queryKey);
if (!dashboardResponse) {
const res = await prefetchDashboard(dashboardId).catch((e) => {
openErrorMessage('Failed to save metrics to dashboard. Dashboard not found');
return null;
});
if (res) {
queryClient.setQueryData(options.queryKey, res);
dashboardResponse = res;
}
}
if (dashboardResponse) {
const newConfig = addMetricToDashboardConfig(metricIds, dashboardResponse.dashboard.config);
return dashboardsUpdateDashboard({
id: dashboardId,
config: newConfig
});
}
openErrorMessage('Failed to save metrics to dashboard');
}
);
return useMutation({
mutationFn: saveMetricToDashboard,
onSuccess: (data, variables) => {
// queryClient.invalidateQueries({
// queryKey: variables.dashboardIds.map(
// (id) => dashboardQueryKeys.dashboardGetDashboard(id).queryKey
// )
// });
queryClient.invalidateQueries({
queryKey: dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
});
}
});
};
export const useRemoveMetricFromDashboard = () => {
const { openConfirmModal } = useBusterNotifications();
export const useRemoveMetricsFromDashboard = () => {
const { openConfirmModal, openErrorMessage } = useBusterNotifications();
const queryClient = useQueryClient();
const prefetchDashboard = useGetDashboardAndInitializeMetrics();
const removeMetricFromDashboard = useMemoizedFn(
async ({
metricId,
metricIds,
dashboardId,
useConfirmModal = true
}: {
metricId: string;
metricIds: string[];
dashboardId: string;
useConfirmModal?: boolean;
}) => {
const method = async () => {
// await saveMetric({
// id: metricId,
// remove_from_dashboard: [dashboardId]
// });
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
let dashboardResponse = queryClient.getQueryData(options.queryKey);
if (!dashboardResponse) {
const res = await prefetchDashboard(dashboardId).catch((e) => {
openErrorMessage('Failed to remove metrics from dashboard. Dashboard not found');
return null;
});
if (res) {
queryClient.setQueryData(options.queryKey, res);
dashboardResponse = res;
}
}
if (dashboardResponse) {
const newConfig = removeMetricFromDashboardConfig(
metricIds,
dashboardResponse.dashboard.config
);
await dashboardsUpdateDashboard({
id: dashboardId,
config: newConfig
});
return;
}
openErrorMessage('Failed to remove metrics from dashboard');
};
if (!useConfirmModal) return await method();
@ -372,24 +419,25 @@ export const useRemoveMetricFromDashboard = () => {
return useMutation({
mutationFn: removeMetricFromDashboard,
onMutate: async (variables) => {
const currentDashboard = queryClient.getQueryData(
dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
);
onMutate: async ({ metricIds, dashboardId }) => {
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
const currentDashboard = queryClient.getQueryData(options.queryKey);
if (currentDashboard) {
queryClient.setQueryData(
dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey,
(currentDashboard) => {
if (currentDashboard?.dashboard.config.rows) {
currentDashboard.dashboard.config.rows.forEach((row) => {
row.items = row.items.filter((item) => item.id !== variables.metricId);
const newConfig = removeMetricFromDashboardConfig(
metricIds,
currentDashboard.dashboard.config
);
queryClient.setQueryData(options.queryKey, (currentDashboard) => {
return create(currentDashboard!, (draft) => {
draft.dashboard.config = newConfig;
});
});
}
delete currentDashboard!.metrics[variables.metricId];
return currentDashboard;
}
);
}
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({
queryKey: dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
});
}
});
};

View File

@ -170,7 +170,7 @@ export const useDeleteMetric = () => {
});
};
export const useSaveMetricToCollection = () => {
export const useSaveMetricToCollections = () => {
const queryClient = useQueryClient();
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
const { mutateAsync: addAssetToCollection } = useAddAssetToCollection();

View File

@ -5,7 +5,7 @@ import { SaveToCollectionsDropdown } from '../dropdowns/SaveToCollectionsDropdow
import { CollectionButton } from './CollectionsButton';
import {
useRemoveMetricFromCollection,
useSaveMetricToCollection
useSaveMetricToCollections
} from '@/api/buster_rest/metrics';
export const SaveMetricToCollectionButton: React.FC<{
@ -14,7 +14,7 @@ export const SaveMetricToCollectionButton: React.FC<{
useText?: boolean;
}> = ({ metricIds, buttonType = 'ghost', useText = false }) => {
const { openInfoMessage } = useBusterNotifications();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
const [selectedCollections, setSelectedCollections] = useState<

View File

@ -4,7 +4,10 @@ import { SaveToDashboardDropdown } from '../dropdowns/SaveToDashboardDropdown';
import type { BusterMetric } from '@/api/asset_interfaces';
import { Button } from '@/components/ui/buttons';
import { ASSET_ICONS } from '../config/assetIcons';
import { useRemoveMetricFromDashboard, useSaveMetricToDashboard } from '@/api/buster_rest/metrics';
import {
useRemoveMetricsFromDashboard,
useSaveMetricsToDashboard
} from '@/api/buster_rest/dashboards';
const EMPTY_SELECTED_DASHBOARDS: BusterMetric['dashboards'] = [];
@ -14,22 +17,18 @@ export const SaveMetricToDashboardButton: React.FC<{
selectedDashboards?: BusterMetric['dashboards'];
}> = React.memo(
({ metricIds, disabled = false, selectedDashboards = EMPTY_SELECTED_DASHBOARDS }) => {
const { mutateAsync: saveMetricToDashboard } = useSaveMetricToDashboard();
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
const { mutateAsync: saveMetricsToDashboard } = useSaveMetricsToDashboard();
const { mutateAsync: removeMetricsFromDashboard } = useRemoveMetricsFromDashboard();
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
await Promise.all(
metricIds.map((metricId) => {
return saveMetricToDashboard({ metricId, dashboardIds });
})
dashboardIds.map((dashboardId) => saveMetricsToDashboard({ metricIds, dashboardId }))
);
});
const onRemoveFromDashboard = useMemoizedFn(async (dashboardId: string) => {
const onRemoveFromDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
await Promise.all(
metricIds.map((metricId) => {
return removeMetricFromDashboard({ metricId, dashboardId });
})
dashboardIds.map((dashboardId) => removeMetricsFromDashboard({ metricIds, dashboardId }))
);
});

View File

@ -13,7 +13,7 @@ export const SaveToDashboardDropdown: React.FC<{
children: React.ReactNode;
selectedDashboards: BusterMetric['dashboards'];
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
onRemoveFromDashboard: (dashboardId: string) => void;
onRemoveFromDashboard: (dashboardId: string[]) => Promise<void>;
}> = ({ children, onRemoveFromDashboard, onSaveToDashboard, selectedDashboards }) => {
const [showDropdown, setShowDropdown] = useState(false);
@ -46,7 +46,7 @@ export const useSaveToDashboardDropdownContent = ({
}: {
selectedDashboards: BusterMetric['dashboards'];
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
onRemoveFromDashboard: (dashboardId: string) => void;
onRemoveFromDashboard: (dashboardId: string[]) => Promise<void>;
}): Pick<
DropdownProps,
'items' | 'footerContent' | 'menuHeader' | 'selectType' | 'emptyStateText'
@ -58,10 +58,9 @@ export const useSaveToDashboardDropdownContent = ({
const onClickItem = useMemoizedFn(async (dashboard: BusterDashboardListItem) => {
const isSelected = selectedDashboards.some((d) => d.id === dashboard.id);
if (isSelected) {
onRemoveFromDashboard(dashboard.id);
await onRemoveFromDashboard([dashboard.id]);
} else {
const allDashboardsAndSelected = selectedDashboards.map((d) => d.id).concat(dashboard.id);
await onSaveToDashboard(allDashboardsAndSelected);
await onSaveToDashboard([dashboard.id]);
}
});

View File

@ -12,7 +12,7 @@ import { ASSET_ICONS } from '@/components/features/config/assetIcons';
import {
useDeleteMetric,
useRemoveMetricFromCollection,
useSaveMetricToCollection
useSaveMetricToCollections
} from '@/api/buster_rest/metrics';
import {
useAddUserFavorite,
@ -63,7 +63,7 @@ const CollectionsButton: React.FC<{
onSelectChange: (selectedRowKeys: string[]) => void;
}> = ({ selectedRowKeys, onSelectChange }) => {
const { openInfoMessage } = useBusterNotifications();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
const [selectedCollections, setSelectedCollections] = useState<

View File

@ -7,7 +7,7 @@ import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
import { Button } from '@/components/ui/buttons';
import Link from 'next/link';
import React, { useContext, useMemo } from 'react';
import { useRemoveMetricFromDashboard } from '@/api/buster_rest/metrics';
import { useRemoveMetricsFromDashboard } from '@/api/buster_rest/dashboards';
export const MetricTitle: React.FC<{
title: BusterMetric['title'];
@ -105,7 +105,7 @@ const ThreeDotMenu: React.FC<{
dashboardId: string;
metricId: string;
}> = React.memo(({ dashboardId, metricId, className }) => {
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricsFromDashboard();
const dropdownItems: DropdownItems = useMemo(
() => [
@ -117,7 +117,7 @@ const ThreeDotMenu: React.FC<{
try {
await removeMetricFromDashboard({
dashboardId,
metricId
metricIds: [metricId]
});
} catch (error) {
//

View File

@ -13,7 +13,7 @@ import { Dots, Star, Trash, Xmark } from '@/components/ui/icons';
import {
useDeleteMetric,
useRemoveMetricFromCollection,
useSaveMetricToCollection,
useSaveMetricToCollections,
useUpdateMetric
} from '@/api/buster_rest/metrics';
import {
@ -68,7 +68,7 @@ const CollectionsButton: React.FC<{
onSelectChange: (selectedRowKeys: string[]) => void;
}> = ({ selectedRowKeys, onSelectChange }) => {
const { openInfoMessage } = useBusterNotifications();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
const [selectedCollections, setSelectedCollections] = useState<

View File

@ -3,11 +3,13 @@ import {
useGetMetric,
useGetMetricData,
useRemoveMetricFromCollection,
useRemoveMetricFromDashboard,
useSaveMetricToCollection,
useSaveMetricToDashboard,
useSaveMetricToCollections,
useUpdateMetric
} from '@/api/buster_rest/metrics';
import {
useSaveMetricsToDashboard,
useRemoveMetricsFromDashboard
} from '@/api/buster_rest/dashboards';
import { DropdownContent, DropdownItem, DropdownItems } from '@/components/ui/dropdown';
import {
Trash,
@ -123,16 +125,24 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }
ThreeDotMenuButton.displayName = 'ThreeDotMenuButton';
const useDashboardSelectMenu = ({ metricId }: { metricId: string }) => {
const { mutateAsync: saveMetricToDashboard } = useSaveMetricToDashboard();
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
const { mutateAsync: saveMetricsToDashboard } = useSaveMetricsToDashboard();
const { mutateAsync: removeMetricsFromDashboard } = useRemoveMetricsFromDashboard();
const { data: dashboards } = useGetMetric({ id: metricId }, (x) => x.dashboards);
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
await saveMetricToDashboard({ metricId, dashboardIds });
await Promise.all(
dashboardIds.map((dashboardId) =>
saveMetricsToDashboard({ metricIds: [metricId], dashboardId })
)
);
});
const onRemoveFromDashboard = useMemoizedFn(async (dashboardId: string) => {
await removeMetricFromDashboard({ metricId, dashboardId });
const onRemoveFromDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
await Promise.all(
dashboardIds.map((dashboardId) =>
removeMetricsFromDashboard({ metricIds: [metricId], dashboardId })
)
);
});
const { items, footerContent, selectType, menuHeader } = useSaveToDashboardDropdownContent({
@ -193,7 +203,7 @@ const useVersionHistorySelectMenu = ({ metricId }: { metricId: string }) => {
};
const useCollectionSelectMenu = ({ metricId }: { metricId: string }) => {
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
const { data: collections } = useGetMetric({ id: metricId }, (x) => x.collections);
const { openInfoMessage } = useBusterNotifications();