mirror of https://github.com/buster-so/buster.git
make new saving to dashboard endpoints
This commit is contained in:
parent
abb54f4dbb
commit
6a30100f3f
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './addMetricToDashboard';
|
||||||
|
export * from './removeMetricFromDashboard';
|
|
@ -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]);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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;
|
||||||
|
};
|
|
@ -25,6 +25,7 @@ import {
|
||||||
useRemoveAssetFromCollection
|
useRemoveAssetFromCollection
|
||||||
} from '../collections/queryRequests';
|
} from '../collections/queryRequests';
|
||||||
import { collectionQueryKeys } from '@/api/query_keys/collection';
|
import { collectionQueryKeys } from '@/api/query_keys/collection';
|
||||||
|
import { addMetricToDashboardConfig, removeMetricFromDashboardConfig } from './helpers';
|
||||||
|
|
||||||
export const useGetDashboardsList = (
|
export const useGetDashboardsList = (
|
||||||
params: Omit<DashboardsListRequest, 'page_token' | 'page_size'>
|
params: Omit<DashboardsListRequest, 'page_token' | 'page_size'>
|
||||||
|
@ -43,33 +44,38 @@ export const useGetDashboardsList = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetDashboard = <TData = BusterDashboardResponse>(
|
const useGetDashboardAndInitializeMetrics = () => {
|
||||||
id: string | undefined,
|
|
||||||
select?: (data: BusterDashboardResponse) => TData
|
|
||||||
) => {
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
|
const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
|
||||||
const { password } = getAssetPassword(id!);
|
|
||||||
|
|
||||||
const initializeMetrics = useMemoizedFn((metrics: BusterDashboardResponse['metrics']) => {
|
return useMemoizedFn(async (id: string) => {
|
||||||
for (const metric of Object.values(metrics)) {
|
const { password } = getAssetPassword(id);
|
||||||
const prevMetric = queryClient.getQueryData(queryKeys.metricsGetMetric(metric.id).queryKey);
|
|
||||||
const upgradedMetric = upgradeMetricToIMetric(metric, prevMetric);
|
const initializeMetrics = useMemoizedFn((metrics: BusterDashboardResponse['metrics']) => {
|
||||||
queryClient.setQueryData(queryKeys.metricsGetMetric(metric.id).queryKey, upgradedMetric);
|
for (const metric of Object.values(metrics)) {
|
||||||
prefetchGetMetricDataClient({ id: metric.id }, queryClient);
|
const prevMetric = queryClient.getQueryData(queryKeys.metricsGetMetric(metric.id).queryKey);
|
||||||
}
|
const upgradedMetric = upgradeMetricToIMetric(metric, prevMetric);
|
||||||
});
|
queryClient.setQueryData(queryKeys.metricsGetMetric(metric.id).queryKey, upgradedMetric);
|
||||||
|
prefetchGetMetricDataClient({ id: metric.id }, queryClient);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const queryFn = useMemoizedFn(async () => {
|
|
||||||
return dashboardsGetDashboard({ id: id!, password }).then((data) => {
|
return dashboardsGetDashboard({ id: id!, password }).then((data) => {
|
||||||
initializeMetrics(data.metrics);
|
initializeMetrics(data.metrics);
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetDashboard = <TData = BusterDashboardResponse>(
|
||||||
|
id: string | undefined,
|
||||||
|
select?: (data: BusterDashboardResponse) => TData
|
||||||
|
) => {
|
||||||
|
const queryFn = useGetDashboardAndInitializeMetrics();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
...dashboardQueryKeys.dashboardGetDashboard(id!),
|
...dashboardQueryKeys.dashboardGetDashboard(id!),
|
||||||
queryFn: queryFn,
|
queryFn: () => queryFn(id!),
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
select
|
select
|
||||||
});
|
});
|
||||||
|
@ -318,46 +324,87 @@ export const useUpdateDashboardShare = () => {
|
||||||
|
|
||||||
export const useSaveMetricsToDashboard = () => {
|
export const useSaveMetricsToDashboard = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const prefetchDashboard = useGetDashboardAndInitializeMetrics();
|
||||||
|
const { openErrorMessage } = useBusterNotifications();
|
||||||
|
|
||||||
const saveMetricToDashboard = useMemoizedFn(
|
const saveMetricToDashboard = useMemoizedFn(
|
||||||
async ({ metricIds, dashboardId }: { metricIds: string[]; dashboardId: string }) => {
|
async ({ metricIds, dashboardId }: { metricIds: string[]; dashboardId: string }) => {
|
||||||
// await saveMetric({
|
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
|
||||||
// id: metricId,
|
let dashboardResponse = queryClient.getQueryData(options.queryKey);
|
||||||
// save_to_dashboard: dashboardIds
|
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({
|
return useMutation({
|
||||||
mutationFn: saveMetricToDashboard,
|
mutationFn: saveMetricToDashboard,
|
||||||
onSuccess: (data, variables) => {
|
onSuccess: (data, variables) => {
|
||||||
// queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
// queryKey: variables.dashboardIds.map(
|
queryKey: dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
|
||||||
// (id) => dashboardQueryKeys.dashboardGetDashboard(id).queryKey
|
});
|
||||||
// )
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRemoveMetricFromDashboard = () => {
|
export const useRemoveMetricsFromDashboard = () => {
|
||||||
const { openConfirmModal } = useBusterNotifications();
|
const { openConfirmModal, openErrorMessage } = useBusterNotifications();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const prefetchDashboard = useGetDashboardAndInitializeMetrics();
|
||||||
const removeMetricFromDashboard = useMemoizedFn(
|
const removeMetricFromDashboard = useMemoizedFn(
|
||||||
async ({
|
async ({
|
||||||
metricId,
|
metricIds,
|
||||||
dashboardId,
|
dashboardId,
|
||||||
useConfirmModal = true
|
useConfirmModal = true
|
||||||
}: {
|
}: {
|
||||||
metricId: string;
|
metricIds: string[];
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
useConfirmModal?: boolean;
|
useConfirmModal?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const method = async () => {
|
const method = async () => {
|
||||||
// await saveMetric({
|
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
|
||||||
// id: metricId,
|
let dashboardResponse = queryClient.getQueryData(options.queryKey);
|
||||||
// remove_from_dashboard: [dashboardId]
|
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();
|
if (!useConfirmModal) return await method();
|
||||||
|
@ -372,24 +419,25 @@ export const useRemoveMetricFromDashboard = () => {
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: removeMetricFromDashboard,
|
mutationFn: removeMetricFromDashboard,
|
||||||
onMutate: async (variables) => {
|
onMutate: async ({ metricIds, dashboardId }) => {
|
||||||
const currentDashboard = queryClient.getQueryData(
|
const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId);
|
||||||
dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
|
const currentDashboard = queryClient.getQueryData(options.queryKey);
|
||||||
);
|
|
||||||
if (currentDashboard) {
|
if (currentDashboard) {
|
||||||
queryClient.setQueryData(
|
const newConfig = removeMetricFromDashboardConfig(
|
||||||
dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey,
|
metricIds,
|
||||||
(currentDashboard) => {
|
currentDashboard.dashboard.config
|
||||||
if (currentDashboard?.dashboard.config.rows) {
|
|
||||||
currentDashboard.dashboard.config.rows.forEach((row) => {
|
|
||||||
row.items = row.items.filter((item) => item.id !== variables.metricId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
delete currentDashboard!.metrics[variables.metricId];
|
|
||||||
return currentDashboard;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
queryClient.setQueryData(options.queryKey, (currentDashboard) => {
|
||||||
|
return create(currentDashboard!, (draft) => {
|
||||||
|
draft.dashboard.config = newConfig;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onSuccess: (data, variables) => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: dashboardQueryKeys.dashboardGetDashboard(variables.dashboardId).queryKey
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -170,7 +170,7 @@ export const useDeleteMetric = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSaveMetricToCollection = () => {
|
export const useSaveMetricToCollections = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
|
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
|
||||||
const { mutateAsync: addAssetToCollection } = useAddAssetToCollection();
|
const { mutateAsync: addAssetToCollection } = useAddAssetToCollection();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { SaveToCollectionsDropdown } from '../dropdowns/SaveToCollectionsDropdow
|
||||||
import { CollectionButton } from './CollectionsButton';
|
import { CollectionButton } from './CollectionsButton';
|
||||||
import {
|
import {
|
||||||
useRemoveMetricFromCollection,
|
useRemoveMetricFromCollection,
|
||||||
useSaveMetricToCollection
|
useSaveMetricToCollections
|
||||||
} from '@/api/buster_rest/metrics';
|
} from '@/api/buster_rest/metrics';
|
||||||
|
|
||||||
export const SaveMetricToCollectionButton: React.FC<{
|
export const SaveMetricToCollectionButton: React.FC<{
|
||||||
|
@ -14,7 +14,7 @@ export const SaveMetricToCollectionButton: React.FC<{
|
||||||
useText?: boolean;
|
useText?: boolean;
|
||||||
}> = ({ metricIds, buttonType = 'ghost', useText = false }) => {
|
}> = ({ metricIds, buttonType = 'ghost', useText = false }) => {
|
||||||
const { openInfoMessage } = useBusterNotifications();
|
const { openInfoMessage } = useBusterNotifications();
|
||||||
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
|
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
|
||||||
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
||||||
|
|
||||||
const [selectedCollections, setSelectedCollections] = useState<
|
const [selectedCollections, setSelectedCollections] = useState<
|
||||||
|
|
|
@ -4,7 +4,10 @@ import { SaveToDashboardDropdown } from '../dropdowns/SaveToDashboardDropdown';
|
||||||
import type { BusterMetric } from '@/api/asset_interfaces';
|
import type { BusterMetric } from '@/api/asset_interfaces';
|
||||||
import { Button } from '@/components/ui/buttons';
|
import { Button } from '@/components/ui/buttons';
|
||||||
import { ASSET_ICONS } from '../config/assetIcons';
|
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'] = [];
|
const EMPTY_SELECTED_DASHBOARDS: BusterMetric['dashboards'] = [];
|
||||||
|
|
||||||
|
@ -14,22 +17,18 @@ export const SaveMetricToDashboardButton: React.FC<{
|
||||||
selectedDashboards?: BusterMetric['dashboards'];
|
selectedDashboards?: BusterMetric['dashboards'];
|
||||||
}> = React.memo(
|
}> = React.memo(
|
||||||
({ metricIds, disabled = false, selectedDashboards = EMPTY_SELECTED_DASHBOARDS }) => {
|
({ metricIds, disabled = false, selectedDashboards = EMPTY_SELECTED_DASHBOARDS }) => {
|
||||||
const { mutateAsync: saveMetricToDashboard } = useSaveMetricToDashboard();
|
const { mutateAsync: saveMetricsToDashboard } = useSaveMetricsToDashboard();
|
||||||
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
|
const { mutateAsync: removeMetricsFromDashboard } = useRemoveMetricsFromDashboard();
|
||||||
|
|
||||||
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
|
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
metricIds.map((metricId) => {
|
dashboardIds.map((dashboardId) => saveMetricsToDashboard({ metricIds, dashboardId }))
|
||||||
return saveMetricToDashboard({ metricId, dashboardIds });
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const onRemoveFromDashboard = useMemoizedFn(async (dashboardId: string) => {
|
const onRemoveFromDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
metricIds.map((metricId) => {
|
dashboardIds.map((dashboardId) => removeMetricsFromDashboard({ metricIds, dashboardId }))
|
||||||
return removeMetricFromDashboard({ metricId, dashboardId });
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const SaveToDashboardDropdown: React.FC<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
selectedDashboards: BusterMetric['dashboards'];
|
selectedDashboards: BusterMetric['dashboards'];
|
||||||
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
|
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
|
||||||
onRemoveFromDashboard: (dashboardId: string) => void;
|
onRemoveFromDashboard: (dashboardId: string[]) => Promise<void>;
|
||||||
}> = ({ children, onRemoveFromDashboard, onSaveToDashboard, selectedDashboards }) => {
|
}> = ({ children, onRemoveFromDashboard, onSaveToDashboard, selectedDashboards }) => {
|
||||||
const [showDropdown, setShowDropdown] = useState(false);
|
const [showDropdown, setShowDropdown] = useState(false);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export const useSaveToDashboardDropdownContent = ({
|
||||||
}: {
|
}: {
|
||||||
selectedDashboards: BusterMetric['dashboards'];
|
selectedDashboards: BusterMetric['dashboards'];
|
||||||
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
|
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
|
||||||
onRemoveFromDashboard: (dashboardId: string) => void;
|
onRemoveFromDashboard: (dashboardId: string[]) => Promise<void>;
|
||||||
}): Pick<
|
}): Pick<
|
||||||
DropdownProps,
|
DropdownProps,
|
||||||
'items' | 'footerContent' | 'menuHeader' | 'selectType' | 'emptyStateText'
|
'items' | 'footerContent' | 'menuHeader' | 'selectType' | 'emptyStateText'
|
||||||
|
@ -58,10 +58,9 @@ export const useSaveToDashboardDropdownContent = ({
|
||||||
const onClickItem = useMemoizedFn(async (dashboard: BusterDashboardListItem) => {
|
const onClickItem = useMemoizedFn(async (dashboard: BusterDashboardListItem) => {
|
||||||
const isSelected = selectedDashboards.some((d) => d.id === dashboard.id);
|
const isSelected = selectedDashboards.some((d) => d.id === dashboard.id);
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
onRemoveFromDashboard(dashboard.id);
|
await onRemoveFromDashboard([dashboard.id]);
|
||||||
} else {
|
} else {
|
||||||
const allDashboardsAndSelected = selectedDashboards.map((d) => d.id).concat(dashboard.id);
|
await onSaveToDashboard([dashboard.id]);
|
||||||
await onSaveToDashboard(allDashboardsAndSelected);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { ASSET_ICONS } from '@/components/features/config/assetIcons';
|
||||||
import {
|
import {
|
||||||
useDeleteMetric,
|
useDeleteMetric,
|
||||||
useRemoveMetricFromCollection,
|
useRemoveMetricFromCollection,
|
||||||
useSaveMetricToCollection
|
useSaveMetricToCollections
|
||||||
} from '@/api/buster_rest/metrics';
|
} from '@/api/buster_rest/metrics';
|
||||||
import {
|
import {
|
||||||
useAddUserFavorite,
|
useAddUserFavorite,
|
||||||
|
@ -63,7 +63,7 @@ const CollectionsButton: React.FC<{
|
||||||
onSelectChange: (selectedRowKeys: string[]) => void;
|
onSelectChange: (selectedRowKeys: string[]) => void;
|
||||||
}> = ({ selectedRowKeys, onSelectChange }) => {
|
}> = ({ selectedRowKeys, onSelectChange }) => {
|
||||||
const { openInfoMessage } = useBusterNotifications();
|
const { openInfoMessage } = useBusterNotifications();
|
||||||
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
|
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
|
||||||
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
||||||
|
|
||||||
const [selectedCollections, setSelectedCollections] = useState<
|
const [selectedCollections, setSelectedCollections] = useState<
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
|
||||||
import { Button } from '@/components/ui/buttons';
|
import { Button } from '@/components/ui/buttons';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import React, { useContext, useMemo } from 'react';
|
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<{
|
export const MetricTitle: React.FC<{
|
||||||
title: BusterMetric['title'];
|
title: BusterMetric['title'];
|
||||||
|
@ -105,7 +105,7 @@ const ThreeDotMenu: React.FC<{
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
metricId: string;
|
metricId: string;
|
||||||
}> = React.memo(({ dashboardId, metricId, className }) => {
|
}> = React.memo(({ dashboardId, metricId, className }) => {
|
||||||
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
|
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricsFromDashboard();
|
||||||
|
|
||||||
const dropdownItems: DropdownItems = useMemo(
|
const dropdownItems: DropdownItems = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
@ -117,7 +117,7 @@ const ThreeDotMenu: React.FC<{
|
||||||
try {
|
try {
|
||||||
await removeMetricFromDashboard({
|
await removeMetricFromDashboard({
|
||||||
dashboardId,
|
dashboardId,
|
||||||
metricId
|
metricIds: [metricId]
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//
|
//
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { Dots, Star, Trash, Xmark } from '@/components/ui/icons';
|
||||||
import {
|
import {
|
||||||
useDeleteMetric,
|
useDeleteMetric,
|
||||||
useRemoveMetricFromCollection,
|
useRemoveMetricFromCollection,
|
||||||
useSaveMetricToCollection,
|
useSaveMetricToCollections,
|
||||||
useUpdateMetric
|
useUpdateMetric
|
||||||
} from '@/api/buster_rest/metrics';
|
} from '@/api/buster_rest/metrics';
|
||||||
import {
|
import {
|
||||||
|
@ -68,7 +68,7 @@ const CollectionsButton: React.FC<{
|
||||||
onSelectChange: (selectedRowKeys: string[]) => void;
|
onSelectChange: (selectedRowKeys: string[]) => void;
|
||||||
}> = ({ selectedRowKeys, onSelectChange }) => {
|
}> = ({ selectedRowKeys, onSelectChange }) => {
|
||||||
const { openInfoMessage } = useBusterNotifications();
|
const { openInfoMessage } = useBusterNotifications();
|
||||||
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
|
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
|
||||||
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
||||||
|
|
||||||
const [selectedCollections, setSelectedCollections] = useState<
|
const [selectedCollections, setSelectedCollections] = useState<
|
||||||
|
|
|
@ -3,11 +3,13 @@ import {
|
||||||
useGetMetric,
|
useGetMetric,
|
||||||
useGetMetricData,
|
useGetMetricData,
|
||||||
useRemoveMetricFromCollection,
|
useRemoveMetricFromCollection,
|
||||||
useRemoveMetricFromDashboard,
|
useSaveMetricToCollections,
|
||||||
useSaveMetricToCollection,
|
|
||||||
useSaveMetricToDashboard,
|
|
||||||
useUpdateMetric
|
useUpdateMetric
|
||||||
} from '@/api/buster_rest/metrics';
|
} from '@/api/buster_rest/metrics';
|
||||||
|
import {
|
||||||
|
useSaveMetricsToDashboard,
|
||||||
|
useRemoveMetricsFromDashboard
|
||||||
|
} from '@/api/buster_rest/dashboards';
|
||||||
import { DropdownContent, DropdownItem, DropdownItems } from '@/components/ui/dropdown';
|
import { DropdownContent, DropdownItem, DropdownItems } from '@/components/ui/dropdown';
|
||||||
import {
|
import {
|
||||||
Trash,
|
Trash,
|
||||||
|
@ -123,16 +125,24 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }
|
||||||
ThreeDotMenuButton.displayName = 'ThreeDotMenuButton';
|
ThreeDotMenuButton.displayName = 'ThreeDotMenuButton';
|
||||||
|
|
||||||
const useDashboardSelectMenu = ({ metricId }: { metricId: string }) => {
|
const useDashboardSelectMenu = ({ metricId }: { metricId: string }) => {
|
||||||
const { mutateAsync: saveMetricToDashboard } = useSaveMetricToDashboard();
|
const { mutateAsync: saveMetricsToDashboard } = useSaveMetricsToDashboard();
|
||||||
const { mutateAsync: removeMetricFromDashboard } = useRemoveMetricFromDashboard();
|
const { mutateAsync: removeMetricsFromDashboard } = useRemoveMetricsFromDashboard();
|
||||||
const { data: dashboards } = useGetMetric({ id: metricId }, (x) => x.dashboards);
|
const { data: dashboards } = useGetMetric({ id: metricId }, (x) => x.dashboards);
|
||||||
|
|
||||||
const onSaveToDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
|
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) => {
|
const onRemoveFromDashboard = useMemoizedFn(async (dashboardIds: string[]) => {
|
||||||
await removeMetricFromDashboard({ metricId, dashboardId });
|
await Promise.all(
|
||||||
|
dashboardIds.map((dashboardId) =>
|
||||||
|
removeMetricsFromDashboard({ metricIds: [metricId], dashboardId })
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const { items, footerContent, selectType, menuHeader } = useSaveToDashboardDropdownContent({
|
const { items, footerContent, selectType, menuHeader } = useSaveToDashboardDropdownContent({
|
||||||
|
@ -193,7 +203,7 @@ const useVersionHistorySelectMenu = ({ metricId }: { metricId: string }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const useCollectionSelectMenu = ({ metricId }: { metricId: string }) => {
|
const useCollectionSelectMenu = ({ metricId }: { metricId: string }) => {
|
||||||
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollection();
|
const { mutateAsync: saveMetricToCollection } = useSaveMetricToCollections();
|
||||||
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
const { mutateAsync: removeMetricFromCollection } = useRemoveMetricFromCollection();
|
||||||
const { data: collections } = useGetMetric({ id: metricId }, (x) => x.collections);
|
const { data: collections } = useGetMetric({ id: metricId }, (x) => x.collections);
|
||||||
const { openInfoMessage } = useBusterNotifications();
|
const { openInfoMessage } = useBusterNotifications();
|
||||||
|
|
Loading…
Reference in New Issue