add additional routes to new handlers

This commit is contained in:
Nate Kelley 2025-02-12 23:11:44 -07:00
parent 0ee588a6c5
commit 4d4ab66e2c
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
25 changed files with 160 additions and 356 deletions

View File

@ -40,7 +40,7 @@ export interface BusterDashboard
deleted_at: string | null;
description: string | null;
id: string;
title: string;
name: string;
updated_at: string | null;
updated_by: string;
status: VerificationStatus;

View File

@ -38,7 +38,7 @@ export interface BusterUserFavorite {
id: string;
asset_type: ShareAssetType;
index?: number;
title: string;
name: string;
//collections - TODO: type this better
collection_name?: string;
collection_id?: string;

View File

@ -87,8 +87,8 @@ export type DashboardUpdate = BusterSocketRequestBase<
{
/** The unique identifier of the dashboard */
id: string;
/** New title for the dashboard */
title?: string;
/** New name for the dashboard */
name?: string;
/** New description for the dashboard */
description?: string | null;
/** Updated dashboard configuration */

View File

@ -31,7 +31,7 @@ export type UsersFavoritePost = BusterSocketRequestBase<
id: string;
asset_type: ShareAssetType;
index?: number;
title: string; //sooo... this is a bit of hack...
name: string;
}
>;

View File

@ -14,7 +14,10 @@ import { CircleSpinnerLoaderContainer } from '@/components/loaders';
import { BusterCollection } from '@/api/asset_interfaces';
import { useBusterSearchContextSelector } from '@/context/Search';
import isEmpty from 'lodash/isEmpty';
import { useBusterDashboardContextSelector } from '@/context/Dashboards';
import {
useBusterDashboardContextSelector,
useBusterDashboardIndividual
} from '@/context/Dashboards';
import { useBusterCollectionIndividualContextSelector } from '@/context/Collections';
import { SegmentedValue } from 'antd/es/segmented';
import { BusterSearchRequest } from '@/api/buster_socket/search';

View File

@ -32,7 +32,7 @@ export const FavoriteStar: React.FC<{
title: string;
className?: string;
iconStyle?: 'default' | 'tertiary';
}> = React.memo(({ title, id, type, className = '', iconStyle = 'default' }) => {
}> = React.memo(({ title: name, id, type, className = '', iconStyle = 'default' }) => {
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites);
const removeItemFromFavorite = useUserConfigContextSelector(
(state) => state.removeItemFromFavorite
@ -51,7 +51,7 @@ export const FavoriteStar: React.FC<{
return await addItemToFavorite({
asset_type: type,
id,
title
name
});
await removeItemFromFavorite({

View File

@ -38,13 +38,16 @@ export const StatusBadgeButton: React.FC<{
if ((!isAdmin && !userStatus.includes(newStatus)) || newStatus === status) {
return;
}
const ids = Array.isArray(id) ? id : [id];
const verifyFunction =
type === 'dashboard'
? (id: string) => onVerifiedDashboard({ dashboardId: id, status: newStatus })
: (id: string) => onVerifiedMetric({ metricId: id, status: newStatus });
const ids = Array.isArray(id) ? id : [id];
await Promise.all(ids.map(verifyFunction));
const allPromises = ids.map((id) => verifyFunction(id));
await Promise.all(allPromises);
setIsOpen(false);
onChangedStatus?.();
});

View File

@ -111,19 +111,20 @@ const createListItem = ({
let icon = asset_typeToIcon(item.asset_type, {
open: openedIds.includes(item.collection_id || '')
});
let name = item.title || item.collection_name;
let name = item.name || item.collection_name;
const assetType = item.asset_type;
if (item.title === ShareAssetType.METRIC) {
if (assetType === ShareAssetType.METRIC) {
link = createBusterRoute({
route: BusterRoutes.APP_METRIC_ID,
metricId: item.id
});
} else if (item.title === ShareAssetType.DASHBOARD) {
} else if (assetType === ShareAssetType.DASHBOARD) {
link = createBusterRoute({
route: BusterRoutes.APP_DASHBOARD_ID,
dashboardId: item.id
});
} else if (item.title === ShareAssetType.COLLECTION) {
} else if (assetType === ShareAssetType.COLLECTION) {
link = createBusterRoute({
route: BusterRoutes.APP_COLLECTIONS_ID,
collectionId: item.collection_id!

View File

@ -21,8 +21,8 @@ const DEFAULT_EMPTY_CONFIG: DashboardConfig = {};
export const DashboardContentController: React.FC<{
allowEdit?: boolean;
metrics: BusterDashboardResponse['metrics'];
dashboard: BusterDashboardResponse['dashboard'];
metrics: BusterDashboardResponse['metrics'] | undefined;
dashboard: BusterDashboardResponse['dashboard'] | undefined;
onUpdateDashboardConfig: ReturnType<typeof useBusterDashboards>['onUpdateDashboardConfig'];
openAddContentModal: () => void;
}> = React.memo(
@ -33,7 +33,7 @@ export const DashboardContentController: React.FC<{
metrics = DEFAULT_EMPTY_METRICS,
onUpdateDashboardConfig
}) => {
const dashboardConfig = dashboard.config || DEFAULT_EMPTY_CONFIG;
const dashboardConfig = dashboard?.config || DEFAULT_EMPTY_CONFIG;
const configRows = dashboardConfig?.rows || DEFAULT_EMPTY_ROWS;
const hasMetrics = !isEmpty(metrics);
const [draggingId, setDraggingId] = useState<string | null>(null);
@ -52,7 +52,7 @@ export const DashboardContentController: React.FC<{
}))
};
});
onUpdateDashboardConfig({ rows: formattedRows }, dashboard.id);
onUpdateDashboardConfig({ rows: formattedRows }, dashboard!.id);
});
const remapMetrics = useMemo(() => {
@ -77,7 +77,7 @@ export const DashboardContentController: React.FC<{
<DashboardMetricItem
key={item.id}
metricId={item.id}
dashboardId={dashboard.id}
dashboardId={dashboard!.id}
allowEdit={allowEdit}
numberOfMetrics={metrics.length}
/>
@ -97,14 +97,14 @@ export const DashboardContentController: React.FC<{
});
useEffect(() => {
if (remapMetrics && dashboard.id) {
if (remapMetrics && dashboard?.id) {
debouncedForInitialRenderOnUpdateDashboardConfig({ rows }, dashboard.id);
}
}, [dashboard.id, remapMetrics]);
}, [dashboard?.id, remapMetrics]);
return (
<div className="dashboard-content-controller">
{hasMetrics && !!dashboardRows.length ? (
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
<DashboardContentControllerProvider dashboard={dashboard}>
<BusterResizeableGrid
rows={dashboardRows}

View File

@ -11,8 +11,8 @@ export const DashboardEditTitles: React.FC<{
allowEdit?: boolean;
dashboardId: string;
}> = React.memo(({ onUpdateDashboard, allowEdit, title, description, dashboardId }) => {
const onChangeTitle = useMemoizedFn((title: string) => {
onUpdateDashboard({ title, id: dashboardId });
const onChangeTitle = useMemoizedFn((name: string) => {
onUpdateDashboard({ name, id: dashboardId });
});
const onChangeDescription = useMemoizedFn((description: string) => {

View File

@ -2,8 +2,8 @@ import { useUserConfigContextSelector } from '@/context/Users';
import { DashboardViewProps } from '../config';
import React from 'react';
import {
useBusterDashboardIndividual,
useBusterDashboardContextSelector
useBusterDashboardContextSelector,
useBusterDashboardIndividual
} from '@/context/Dashboards';
import { ShareRole } from '@/api/asset_interfaces';
import { useMemoizedFn } from 'ahooks';
@ -12,7 +12,7 @@ import { DashboardContentController } from './DashboardContentController';
export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({ dashboardId }) => {
const isAnonymousUser = useUserConfigContextSelector((state) => state.isAnonymousUser);
const { dashboardResponse: dashboardResponse } = useBusterDashboardIndividual({
const { dashboardResponse, metrics, dashboard } = useBusterDashboardIndividual({
dashboardId
});
const onUpdateDashboard = useBusterDashboardContextSelector((x) => x.onUpdateDashboard);
@ -21,8 +21,6 @@ export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({
);
const setOpenAddContentModal = useBusterDashboardContextSelector((x) => x.setOpenAddContentModal);
const metrics = dashboardResponse?.metrics;
const dashboard = dashboardResponse?.dashboard;
const allowEdit = dashboardResponse?.permission !== ShareRole.VIEWER && !isAnonymousUser;
const onOpenAddContentModal = useMemoizedFn(() => {
@ -35,7 +33,7 @@ export const DashboardViewDashboardController: React.FC<DashboardViewProps> = ({
onUpdateDashboard={onUpdateDashboard}
dashboardId={dashboardId}
allowEdit={allowEdit}
title={dashboardResponse?.dashboard?.title || ''}
title={dashboardResponse?.dashboard?.name || ''}
description={dashboardResponse?.dashboard?.description || ''}
/>

View File

@ -15,7 +15,7 @@ export const DashboardViewFileController: React.FC<DashboardViewProps> = React.m
const { openSuccessMessage } = useBusterNotifications();
const onUpdateDashboard = useBusterDashboardContextSelector((x) => x.onUpdateDashboard);
const { file: fileProp, file_name } = dashboard;
const { file: fileProp, file_name } = dashboard || {};
const [file, setFile] = React.useState(fileProp);
@ -40,9 +40,9 @@ export const DashboardViewFileController: React.FC<DashboardViewProps> = React.m
return (
<div className="relative h-full overflow-hidden p-3">
<CodeCard
code={file}
code={file || ''}
language="yaml"
fileName={file_name}
fileName={file_name || ''}
onChange={setFile}
onMetaEnter={onSaveFile}
/>

View File

@ -143,12 +143,10 @@ const useMetricParams = (fileId: string) => {
};
const useDashboardParams = (fileId: string) => {
const dashboardTitle = useBusterDashboardContextSelector(
(x) => x.dashboards[fileId]?.dashboard?.title
);
const dashboardVersionNumber = useBusterDashboardContextSelector(
(x) => x.dashboards[fileId]?.dashboard?.version_number
);
const getDashboardMemoized = useBusterDashboardContextSelector((x) => x.getDashboardMemoized);
const dashboard = getDashboardMemoized(fileId);
const dashboardTitle = dashboard?.dashboard?.name;
const dashboardVersionNumber = dashboard?.dashboard?.version_number;
return { dashboardTitle, dashboardVersionNumber };
};

View File

@ -1 +0,0 @@
export * from './useFileFallback';

View File

@ -1,141 +0,0 @@
import type { SelectedFile } from '@appLayouts/ChatLayout';
import { useBusterDashboardContextSelector } from '@/context/Dashboards';
import { useBusterMetricsIndividualContextSelector } from '@/context/Metrics';
import { useMemo } from 'react';
import type { IBusterChat, IBusterChatMessage } from '../../interfaces';
import { FileType } from '@/api/asset_interfaces';
export const useFileFallback = ({
defaultSelectedFile
}: {
//if metricId is provided (without a chatId), we can assume that the chat is a new chat starting from a metric
defaultSelectedFile?: SelectedFile;
}) => {
const fileId = defaultSelectedFile?.id || '';
const { metricTitle, metricVersionNumber } = useMetricParams(fileId);
const { dashboardTitle, dashboardVersionNumber } = useDashboardParams(fileId);
const fileType: FileType = useMemo(() => {
if (defaultSelectedFile?.type === 'metric') {
return 'metric';
} else {
return 'dashboard';
}
}, [defaultSelectedFile]);
const title = useMemo(() => {
if (fileType === 'metric') {
return metricTitle;
} else if (fileType === 'dashboard') {
return dashboardTitle;
}
}, [fileType, metricTitle, dashboardTitle]);
const versionNumber = useMemo(() => {
if (fileType === 'metric') {
return metricVersionNumber || 1;
} else if (fileType === 'dashboard') {
return dashboardVersionNumber || 1;
}
return 1;
}, [fileType, metricVersionNumber, dashboardVersionNumber]);
const memoizedFallbackToMetricChat = useMemo(() => {
return fallbackToFileChat({
id: fileId
});
}, [fileId]);
const memoizedFallbackToChatMessage = useMemo(() => {
return fallbackToFileChatMessage({
id: fileId,
title: title,
versionNumber: versionNumber,
type: fileType
});
}, [fileId, title, versionNumber, fileType]);
return { memoizedFallbackToMetricChat, memoizedFallbackToChatMessage };
};
const fallbackToFileChat = ({ id }: { id: string }): IBusterChat => {
return {
id,
messages: [fallbackMessageId(id)],
title: '',
is_favorited: false,
updated_at: '',
created_at: '',
created_by: '',
created_by_id: '',
created_by_name: '',
created_by_avatar: '',
isNewChat: false
};
};
const fallbackMessageId = (id: string) => {
return `init-message-${id}`;
};
const fallbackToFileChatMessage = ({
id,
title,
versionNumber,
type = 'metric'
}: {
id: string;
title: string | undefined;
versionNumber: number;
type: FileType;
}): IBusterChatMessage => {
return {
request_message: null,
reasoning: [],
response_messages: [
{
id: 'init',
type: 'text',
message: `I've pulled in your ${type}. How can I help? Is there anything you'd like to modify?`
},
{
id,
type: 'file',
file_type: type,
file_name: title || `New ${type}`,
version_number: versionNumber,
version_id: id,
filter_version_id: null,
metadata: [
{
status: 'completed',
message: `Retrieved ${type}`
}
]
}
],
created_at: '',
id: fallbackMessageId(id),
isCompletedStream: false
};
};
const useMetricParams = (fileId: string) => {
const metricTitle = useBusterMetricsIndividualContextSelector((x) => x.metrics[fileId]?.title);
const metricVersionNumber = useBusterMetricsIndividualContextSelector(
(x) => x.metrics[fileId]?.version_number
);
return { metricTitle, metricVersionNumber };
};
const useDashboardParams = (fileId: string) => {
const dashboardTitle = useBusterDashboardContextSelector(
(x) => x.dashboards[fileId]?.dashboard?.title
);
const dashboardVersionNumber = useBusterDashboardContextSelector(
(x) => x.dashboards[fileId]?.dashboard?.version_number
);
return { dashboardTitle, dashboardVersionNumber };
};

View File

@ -8,38 +8,45 @@ import {
import { BusterDashboardResponse } from '@/api/asset_interfaces';
import { useDashboardAssosciations } from './useDashboardAssosciations';
import { useDashboardCreate } from './useDashboardCreate';
import { useShareDashboard } from './useDashboardShare';
import { useDashboardSubscribe } from './useDashboardSubscribe';
import { useDashboardUpdateConfig } from './useDashboardUpdateConfig';
import { createQueryKey } from '@/hooks';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider';
export const useBusterDashboards = () => {
const [openAddContentModal, setOpenAddContentModal] = useState(false);
const queryClient = useQueryClient();
const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
const [dashboards, setDashboard] = useState<Record<string, BusterDashboardResponse>>({});
const getDashboard = useQuery({
queryKey: ['/dashboards/get:getDashboardState', { id: '1' }],
queryFn: () => {
return { id: '1' };
},
enabled: false
});
const dashboardSubscribe = useDashboardSubscribe({ setDashboard });
const getDashboardMemoized = useMemoizedFn((dashboardId: string) => {
const { password } = getAssetPassword(dashboardId);
const queryKey = createQueryKey(
{ route: '/dashboards/get:getDashboardState' },
{ route: '/dashboards/get', payload: { id: dashboardId, password } }
);
return queryClient.getQueryData<BusterDashboardResponse>(queryKey);
});
const dashboardUpdateConfig = useDashboardUpdateConfig({ dashboards, setDashboard });
const dashboardUpdateConfig = useDashboardUpdateConfig({ getDashboardMemoized });
const dashboardAssosciations = useDashboardAssosciations({ setDashboard });
const dashboardAssosciations = useDashboardAssosciations();
const dashboardCreate = useDashboardCreate({
onUpdateDashboard: dashboardUpdateConfig.onUpdateDashboard
});
const dashboardShare = useShareDashboard({
initializeDashboard: dashboardSubscribe.initializeDashboard
});
const getDashboardMemoized = useMemoizedFn((id: string) => dashboards[id]);
return {
...dashboardAssosciations,
...dashboardCreate,
...dashboardUpdateConfig,
...dashboardSubscribe,
...dashboardShare,
dashboards,
openAddContentModal,
getDashboardMemoized,
setOpenAddContentModal
@ -59,34 +66,3 @@ export const BusterDashboardIndividualProvider: React.FC<PropsWithChildren> = ({
export const useBusterDashboardContextSelector = <T,>(
selector: ContextSelector<ReturnType<typeof useBusterDashboards>, T>
) => useContextSelector(BusterDashboards, selector);
export const useBusterDashboardIndividual = ({
dashboardId
}: {
dashboardId: string | undefined;
}) => {
const dashboardResponse = useBusterDashboardContextSelector(
(state) => state.dashboards[dashboardId || '']
);
const subscribeToDashboard = useBusterDashboardContextSelector(
(state) => state.subscribeToDashboard
);
const unSubscribeToDashboard = useBusterDashboardContextSelector((x) => x.unSubscribeToDashboard);
useLayoutEffect(() => {
if (dashboardId) subscribeToDashboard({ dashboardId });
}, [dashboardId]);
useUnmount(() => {
if (dashboardId) unSubscribeToDashboard({ dashboardId });
});
const dashboard = dashboardResponse?.dashboard;
const metrics = dashboardResponse?.metrics;
return {
dashboard,
metrics,
dashboardResponse
};
};

View File

@ -72,7 +72,7 @@ export const generateMockDashboard = (numMetrics: number): DashboardMockResponse
const dashboard: BusterDashboard = {
id: '123',
title: 'Mock Dashboard',
name: 'Mock Dashboard',
file: `title: Mock Dashboard
description: A sample dashboard configuration
version: 1.0

View File

@ -8,7 +8,7 @@ export const defaultBusterDashboard: BusterDashboard = {
created_at: '',
deleted_at: '',
description: '',
title: '',
name: '',
updated_at: '',
created_by: '',
updated_by: '',

View File

@ -1 +1,2 @@
export * from './DashboardIndividualProvider';
export * from './useBusterDashboardIndividual';

View File

@ -1,19 +1,22 @@
import { BusterDashboardResponse } from '@/api/asset_interfaces';
import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider';
import { useBusterWebSocket } from '@/context/BusterWebSocket';
import { useMemoizedFn, useMount } from 'ahooks';
import React, { useEffect, useRef } from 'react';
import { useMemoizedFn } from 'ahooks';
import React, { useEffect } from 'react';
import { useBusterMetricsIndividualContextSelector } from '@/context/Metrics';
import { useSocketQueryEmitOn } from '@/hooks';
export const useDashboardIndividual = ({ dashboardId }: { dashboardId: string }) => {
export const useBusterDashboardIndividual = ({
dashboardId = ''
}: {
dashboardId: string | undefined;
}) => {
const onInitializeMetric = useBusterMetricsIndividualContextSelector(
(state) => state.onInitializeMetric
);
const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
const { password } = getAssetPassword(dashboardId);
const { data, refetch: refreshDashboard } = useSocketQueryEmitOn(
const { data: dashboardResponse, refetch: refreshDashboard } = useSocketQueryEmitOn(
{ route: '/dashboards/get', payload: { id: dashboardId, password } },
{ route: '/dashboards/get:getDashboardState' },
{ enabled: !!dashboardId }
@ -28,13 +31,18 @@ export const useDashboardIndividual = ({ dashboardId }: { dashboardId: string })
});
useEffect(() => {
if (data) {
initializeDashboard(data);
if (dashboardResponse) {
initializeDashboard(dashboardResponse);
}
}, [data]);
}, [dashboardResponse]);
const dashboard = dashboardResponse?.dashboard;
const metrics = dashboardResponse?.metrics || [];
return {
refreshDashboard,
initializeDashboard
dashboard,
metrics,
dashboardResponse,
refreshDashboard
};
};

View File

@ -2,14 +2,10 @@ import type { BusterDashboardResponse } from '@/api/asset_interfaces';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { useBusterWebSocket } from '@/context/BusterWebSocket';
import { useMemoizedFn } from 'ahooks';
import React from 'react';
import { useBusterDashboardListContextSelector } from '../DashboardListProvider/DashboardListProvider';
import { useSocketQueryMutation } from '@/hooks';
export const useDashboardAssosciations = ({
setDashboard
}: {
setDashboard: React.Dispatch<React.SetStateAction<Record<string, BusterDashboardResponse>>>;
}) => {
export const useDashboardAssosciations = () => {
const busterSocket = useBusterWebSocket();
const { openConfirmModal } = useBusterNotifications();
const removeItemFromDashboardsList = useBusterDashboardListContextSelector(
@ -66,18 +62,18 @@ export const useDashboardAssosciations = ({
const removeItemFromIndividualDashboard = useMemoizedFn(
({ dashboardId, metricId }: { dashboardId: string; metricId: string }) => {
setDashboard((prevDashboards) => {
const dashboardResponse: BusterDashboardResponse | undefined = prevDashboards[dashboardId];
if (!dashboardResponse) return prevDashboards;
const newMetrics = dashboardResponse.metrics.filter((t) => t.id !== metricId);
return {
...prevDashboards,
[dashboardId]: {
...prevDashboards[dashboardId],
metrics: newMetrics
}
};
});
// setDashboard((prevDashboards) => {
// const dashboardResponse: BusterDashboardResponse | undefined = prevDashboards[dashboardId];
// if (!dashboardResponse) return prevDashboards;
// const newMetrics = dashboardResponse.metrics.filter((t) => t.id !== metricId);
// return {
// ...prevDashboards,
// [dashboardId]: {
// ...prevDashboards[dashboardId],
// metrics: newMetrics
// }
// };
// });
}
);

View File

@ -1,43 +0,0 @@
import { BusterDashboardResponse } from '@/api/asset_interfaces';
import { DashboardUpdate } from '@/api/buster_socket/dashboards';
import { useBusterWebSocket } from '@/context/BusterWebSocket';
import { useMemoizedFn } from 'ahooks';
export const useShareDashboard = ({
initializeDashboard
}: {
initializeDashboard: (d: BusterDashboardResponse) => void;
}) => {
const busterSocket = useBusterWebSocket();
const onShareDashboard = useMemoizedFn(
async (
props: Pick<
DashboardUpdate['payload'],
| 'id'
| 'publicly_accessible'
| 'public_password'
| 'user_permissions'
| 'team_permissions'
| 'public_expiry_date'
| 'remove_users'
| 'remove_teams'
>
) => {
return busterSocket.emitAndOnce({
emitEvent: {
route: '/dashboards/update',
payload: props
},
responseEvent: {
route: '/dashboards/update:updateDashboard',
callback: initializeDashboard
}
});
}
);
return {
onShareDashboard
};
};

View File

@ -3,80 +3,77 @@ import type {
BusterDashboardResponse,
VerificationStatus
} from '@/api/asset_interfaces';
import { DashboardUpdate } from '@/api/buster_socket/dashboards';
import { useBusterWebSocket } from '@/context/BusterWebSocket';
import { useSocketQueryMutation } from '@/hooks';
import { useMemoizedFn } from 'ahooks';
import isEqual from 'lodash/isEqual';
import React from 'react';
import { create } from 'mutative';
export const useDashboardUpdateConfig = ({
dashboards,
setDashboard
getDashboardMemoized
}: {
dashboards: Record<string, BusterDashboardResponse>;
setDashboard: React.Dispatch<React.SetStateAction<Record<string, BusterDashboardResponse>>>;
getDashboardMemoized: (dashboardId: string) => BusterDashboardResponse | undefined;
}) => {
const busterSocket = useBusterWebSocket();
const _updateDashboardResponseToServer = useMemoizedFn(
(newDashboard: Partial<BusterDashboardResponse>, dashboardId: string) => {
const newDashboardState: BusterDashboardResponse = {
...dashboards[dashboardId],
...newDashboard
};
const oldDashboard = dashboards[dashboardId];
if (isEqual(oldDashboard, newDashboard)) {
return;
}
setDashboard((prevDashboards) => {
return {
...prevDashboards,
[dashboardId]: newDashboardState
};
});
busterSocket.emit({
route: '/dashboards/update',
payload: {
id: dashboardId,
description: newDashboardState.dashboard.description,
title: newDashboardState.dashboard.title,
config: newDashboardState.dashboard.config
const { mutateAsync: updateDashboard, isPending: isUpdatingDashboard } = useSocketQueryMutation(
{ route: '/dashboards/update' },
{ route: '/dashboards/update:updateDashboard' },
{
preSetQueryDataFunction: {
responseRoute: '/dashboards/get:getDashboardState',
callback: (data, variables) => {
const newObject: BusterDashboardResponse = create(data!, (draft) => {
Object.assign(draft.dashboard, variables, {
config: { ...draft.dashboard.config, ...variables.config }
});
});
return newObject;
}
});
}
}
);
const onUpdateDashboard = useMemoizedFn(
(newDashboard: Partial<BusterDashboard> & { id: string }) => {
const id = newDashboard.id;
const currentDashboard = dashboards[id] || {};
const newDashboardState = {
...currentDashboard,
dashboard: {
...currentDashboard.dashboard,
...newDashboard
}
};
const currentDashboard = getDashboardMemoized(newDashboard.id);
const newDashboardState: BusterDashboard = create(currentDashboard?.dashboard!, (draft) => {
Object.assign(draft, newDashboard);
});
return updateDashboard({
id: newDashboard.id,
name: newDashboardState.name,
description: newDashboardState.description,
config: newDashboardState.config
});
}
);
_updateDashboardResponseToServer(newDashboardState, id);
const onShareDashboard = useMemoizedFn(
async (
props: Pick<
DashboardUpdate['payload'],
| 'id'
| 'publicly_accessible'
| 'public_password'
| 'user_permissions'
| 'team_permissions'
| 'public_expiry_date'
| 'remove_users'
| 'remove_teams'
>
) => {
return updateDashboard(props);
}
);
const onUpdateDashboardConfig = useMemoizedFn(
(newDashboard: Partial<BusterDashboard['config']>, dashboardId: string) => {
const newDashboardState = {
...dashboards[dashboardId],
dashboard: {
...dashboards[dashboardId].dashboard,
config: {
...dashboards[dashboardId].dashboard.config,
...newDashboard
}
}
};
_updateDashboardResponseToServer(newDashboardState, dashboardId);
const currentDashboard = getDashboardMemoized(dashboardId);
const newDashboardState: BusterDashboard = create(currentDashboard?.dashboard!, (draft) => {
Object.assign(draft.config, newDashboard);
});
return onUpdateDashboard(newDashboardState);
}
);
@ -89,9 +86,15 @@ export const useDashboardUpdateConfig = ({
}
);
const refreshDashboard = useMemoizedFn((dashboardId: string) => {
busterSocket.emit({ route: '/dashboards/get', payload: { id: dashboardId } });
});
return {
onShareDashboard,
onUpdateDashboardConfig,
onUpdateDashboard,
onVerifiedDashboard
onVerifiedDashboard,
refreshDashboard
};
};

View File

@ -46,6 +46,8 @@ export const useUpdateMetricConfig = ({
_prepareMetricAndSaveToServer(newMetric, currentMetric);
}
});
return newMetric;
}
);

View File

@ -258,7 +258,7 @@ const Example = () => {
mutate({
id: 'some-asset-id',
asset_type: ShareAssetType.DASHBOARD,
title: 'some-title'
name: 'some-title'
});
return null;