diff --git a/web/src/api/buster_rest/dashboards/queryRequests.ts b/web/src/api/buster_rest/dashboards/queryRequests.ts index bb6c644a8..5919886e5 100644 --- a/web/src/api/buster_rest/dashboards/queryRequests.ts +++ b/web/src/api/buster_rest/dashboards/queryRequests.ts @@ -32,6 +32,7 @@ import { addMetricToDashboardConfig, removeMetricFromDashboardConfig } from './h import { addAndRemoveMetricsToDashboard } from './helpers/addAndRemoveMetricsToDashboard'; import { useParams, useSearchParams } from 'next/navigation'; import { RustApiError } from '../errors'; +import { useOriginalDashboardStore } from '@/context/Dashboards'; export const useGetDashboardsList = ( params: Omit[0], 'page_token' | 'page_size'> @@ -125,7 +126,8 @@ export const useUpdateDashboard = (params?: { updateVersion?: boolean; saveToServer?: boolean; }) => { - const { updateVersion = true, saveToServer = false } = params || {}; + const setOriginalDashboards = useOriginalDashboardStore((x) => x.setOriginalDashboard); + const { updateVersion = false, saveToServer = false } = params || {}; const queryClient = useQueryClient(); @@ -159,6 +161,7 @@ export const useUpdateDashboard = (params?: { dashboardQueryKeys.dashboardGetDashboard(variables.id).queryKey, data ); + setOriginalDashboards(data.dashboard); } } }); @@ -176,12 +179,13 @@ export const useUpdateDashboardConfig = (params?: { const queryClient = useQueryClient(); const method = useMemoizedFn( - async ( - newDashboard: Partial & { - id: string; - } - ) => { - const options = dashboardQueryKeys.dashboardGetDashboard(newDashboard.id); + async ({ + dashboardId, + ...newDashboard + }: Partial & { + dashboardId: string; + }) => { + const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId); const previousDashboard = queryClient.getQueryData(options.queryKey); const previousConfig = previousDashboard?.dashboard?.config; if (previousConfig) { @@ -189,7 +193,7 @@ export const useUpdateDashboardConfig = (params?: { Object.assign(draft, newDashboard); }); return mutateAsync({ - id: newDashboard.id, + id: dashboardId, config: newConfig }); } diff --git a/web/src/api/buster_rest/metrics/queryRequests.ts b/web/src/api/buster_rest/metrics/queryRequests.ts index 032b79996..357b71e91 100644 --- a/web/src/api/buster_rest/metrics/queryRequests.ts +++ b/web/src/api/buster_rest/metrics/queryRequests.ts @@ -390,7 +390,7 @@ export const useUpdateMetric = (params: { const { wait = 0, updateOnSave = false, - updateVersion = true, + updateVersion = false, saveToServer = false } = params || {}; const queryClient = useQueryClient(); @@ -408,8 +408,10 @@ export const useUpdateMetric = (params: { ); const combineAndSaveMetric = useMemoizedFn( - (newMetricPartial: Omit, 'status'> & { id: string }) => { - const metricId = newMetricPartial.id; + ({ + id: metricId, + ...newMetricPartial + }: Omit, 'status'> & { id: string }) => { const options = metricsQueryKeys.metricsGetMetric(metricId); const prevMetric = getOriginalMetric(metricId); const newMetric = create(prevMetric, (draft) => { diff --git a/web/src/components/ui/grid/BusterResizeColumns.tsx b/web/src/components/ui/grid/BusterResizeColumns.tsx index 17a4aa012..70ab4af65 100644 --- a/web/src/components/ui/grid/BusterResizeColumns.tsx +++ b/web/src/components/ui/grid/BusterResizeColumns.tsx @@ -133,7 +133,7 @@ export const BusterResizeColumns: React.FC = ({ useLayoutEffect(() => { setSizes(columnSpansToPercent(columnSizes)); - }, [items.length, columnSizes?.length]); + }, [items.length, columnSizes]); return ( diff --git a/web/src/components/ui/grid/BusterResizeableGrid.tsx b/web/src/components/ui/grid/BusterResizeableGrid.tsx index d7f751c48..3331b6d33 100644 --- a/web/src/components/ui/grid/BusterResizeableGrid.tsx +++ b/web/src/components/ui/grid/BusterResizeableGrid.tsx @@ -63,7 +63,6 @@ export const BusterResizeableGrid: React.FC<{ if (checkRowEquality(filteredRows, rows)) { return; } - onRowLayoutChange(filteredRows); setRows(filteredRows); }); diff --git a/web/src/context/Chats/useChatUpdate.ts b/web/src/context/Chats/useChatUpdate.ts index d2dba4b0d..826b708b1 100644 --- a/web/src/context/Chats/useChatUpdate.ts +++ b/web/src/context/Chats/useChatUpdate.ts @@ -8,8 +8,8 @@ export const useChatUpdate = () => { const queryClient = useQueryClient(); const onUpdateChat = useMemoizedFn( - async (newChatConfig: Partial & { id: string }) => { - const options = queryKeys.chatsGetChat(newChatConfig.id); + async ({ id: chatId, ...newChatConfig }: Partial & { id: string }) => { + const options = queryKeys.chatsGetChat(chatId); const queryKey = options.queryKey; const currentData = queryClient.getQueryData(queryKey); const iChat = create(currentData || ({} as IBusterChat), (draft) => { diff --git a/web/src/context/Dashboards/useIsDashboardChanged.tsx b/web/src/context/Dashboards/useIsDashboardChanged.tsx index f81441304..49a72027c 100644 --- a/web/src/context/Dashboards/useIsDashboardChanged.tsx +++ b/web/src/context/Dashboards/useIsDashboardChanged.tsx @@ -5,6 +5,8 @@ import { useGetDashboard } from '@/api/buster_rest/dashboards'; import { BusterDashboardResponse } from '@/api/asset_interfaces/dashboard'; import { dashboardQueryKeys } from '@/api/query_keys/dashboard'; import { compareObjectsByKeys } from '@/lib/objects'; +import { useMemo } from 'react'; +import { create } from 'mutative'; export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string }) => { const queryClient = useQueryClient(); @@ -26,17 +28,16 @@ export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string }) const options = dashboardQueryKeys.dashboardGetDashboard(dashboardId); const currentDashboard = queryClient.getQueryData(options.queryKey); if (originalDashboard && currentDashboard) { - queryClient.setQueryData(options.queryKey, { - ...currentDashboard, - dashboard: originalDashboard + const resetDashboard = create(currentDashboard, (draft) => { + Object.assign(draft, originalDashboard); }); + queryClient.setQueryData(options.queryKey, resetDashboard); } refetchCurrentDashboard(); }); - return { - onResetDashboardToOriginal, - isDashboardChanged: + const isDashboardChanged = useMemo(() => { + return ( !originalDashboard || !currentDashboard || !compareObjectsByKeys(originalDashboard, currentDashboard, [ @@ -45,5 +46,11 @@ export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string }) 'config', 'file' ]) + ); + }, [originalDashboard, currentDashboard]); + + return { + onResetDashboardToOriginal, + isDashboardChanged }; }; diff --git a/web/src/context/Metrics/useUpdateMetricChart.ts b/web/src/context/Metrics/useUpdateMetricChart.ts index 6230b365c..2f39a222f 100644 --- a/web/src/context/Metrics/useUpdateMetricChart.ts +++ b/web/src/context/Metrics/useUpdateMetricChart.ts @@ -10,7 +10,6 @@ import { useUpdateMetric } from '@/api/buster_rest/metrics'; import { useMemoizedFn } from '@/hooks'; import { useGetMetricMemoized } from './useGetMetricMemoized'; import { useParams } from 'next/navigation'; -import { useOriginalMetricStore } from './useOriginalMetricStore'; import { timeout } from '@/lib'; import { useState } from 'react'; diff --git a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx index cb8613bcd..5c65461a2 100644 --- a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx +++ b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx @@ -94,7 +94,7 @@ export const DashboardContentController: React.FC<{ const onRowLayoutChange = useMemoizedFn((rows: BusterResizeableGridRow[]) => { if (dashboard) { - onUpdateDashboardConfig({ rows: removeChildrenFromItems(rows), id: dashboard.id }); + onUpdateDashboardConfig({ rows: removeChildrenFromItems(rows), dashboardId: dashboard.id }); } }); @@ -108,7 +108,7 @@ export const DashboardContentController: React.FC<{ useEffect(() => { if (remapMetrics && dashboard?.id) { - debouncedForInitialRenderOnUpdateDashboardConfig({ rows, id: dashboard.id }); + debouncedForInitialRenderOnUpdateDashboardConfig({ rows, dashboardId: dashboard.id }); } }, [dashboard?.id, remapMetrics]); diff --git a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardEditTitle.tsx b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardEditTitle.tsx index 4e702dcf8..a1710cc32 100644 --- a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardEditTitle.tsx +++ b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardEditTitle.tsx @@ -25,11 +25,10 @@ export const DashboardEditTitles: React.FC<{ if (!readOnly) onUpdateDashboard({ name, id: dashboardId }); }); - const { run: onChangeDashboardDescription } = useDebounceFn( - useMemoizedFn((value: React.ChangeEvent) => { + const onChangeDashboardDescription = useMemoizedFn( + (value: React.ChangeEvent) => { if (!readOnly) onUpdateDashboard({ description: value.target.value, id: dashboardId }); - }), - { wait: 650 } + } ); return ( @@ -37,6 +36,7 @@ export const DashboardEditTitles: React.FC<{ = React.memo( + ({ dashboardId }) => { + const { data: dashboardResponse } = useGetDashboard({ id: dashboardId }); + const { isDashboardChanged, onResetDashboardToOriginal } = useIsDashboardChanged({ + dashboardId + }); + const { mutateAsync: onSaveDashboard, isPending: isSaving } = useUpdateDashboard({ + saveToServer: true + }); + + const onSaveDashboardToServer = useMemoizedFn(() => { + const dashboard = dashboardResponse?.dashboard; + onSaveDashboard({ + id: dashboardId, + name: dashboard?.name, + description: dashboard?.description, + config: dashboard?.config, + file: dashboard?.file + }); + }); + + return ( + + ); + } +); diff --git a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx index c9fb6e68d..2e597c421 100644 --- a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx +++ b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx @@ -8,6 +8,8 @@ import { useDashboardContentStore, useIsDashboardChanged } from '@/context/Dashb import { ScrollArea } from '@/components/ui/scroll-area'; import { StatusCard } from '@/components/ui/card/StatusCard'; import { useIsDashboardReadOnly } from '@/context/Dashboards/useIsDashboardReadOnly'; +import { useChatLayoutContextSelector } from '@/layouts/ChatLayout'; +import { DashboardSaveFilePopup } from './DashboardSaveFilePopup'; export const DashboardViewDashboardController: React.FC<{ dashboardId: string; @@ -22,10 +24,8 @@ export const DashboardViewDashboardController: React.FC<{ } = useGetDashboard({ id: dashboardId }); const { mutateAsync: onUpdateDashboardConfig } = useUpdateDashboardConfig(); + const isVersionHistoryMode = useChatLayoutContextSelector((x) => x.isVersionHistoryMode); const onOpenAddContentModal = useDashboardContentStore((x) => x.onOpenAddContentModal); - const { isDashboardChanged, onResetDashboardToOriginal } = useIsDashboardChanged({ - dashboardId - }); const metrics = dashboardResponse?.metrics; const dashboard = dashboardResponse?.dashboard; @@ -34,6 +34,10 @@ export const DashboardViewDashboardController: React.FC<{ readOnly: readOnlyProp }); + if (!isFetched) { + return <>; + } + if (isError) { return (
@@ -42,10 +46,6 @@ export const DashboardViewDashboardController: React.FC<{ ); } - if (!isFetched) { - return <>; - } - return (
@@ -64,6 +64,8 @@ export const DashboardViewDashboardController: React.FC<{ onOpenAddContentModal={onOpenAddContentModal} readOnly={isReadOnly} /> + + {!isVersionHistoryMode && }
); diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricSaveFilePopup.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricSaveFilePopup.tsx new file mode 100644 index 000000000..a90a7fbc6 --- /dev/null +++ b/web/src/controllers/MetricController/MetricViewChart/MetricSaveFilePopup.tsx @@ -0,0 +1,21 @@ +import { SaveResetFilePopup } from '@/components/features/popups/SaveResetFilePopup'; +import { useIsMetricChanged } from '@/context/Metrics/useIsMetricChanged'; +import { useUpdateMetricChart } from '@/context/Metrics/useUpdateMetricChart'; +import React from 'react'; + +export const MetricSaveFilePopup: React.FC<{ metricId: string }> = React.memo(({ metricId }) => { + const { isMetricChanged, onResetMetricToOriginal } = useIsMetricChanged({ metricId }); + const { onSaveMetricToServer, isSaving } = useUpdateMetricChart({ metricId }); + + return ( + + ); +}); + +MetricSaveFilePopup.displayName = 'MetricSaveFilePopup'; diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx index 4ea6a125c..3ac893cdc 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricViewChart.tsx @@ -14,6 +14,7 @@ import { SaveResetFilePopup } from '@/components/features/popups/SaveResetFilePo import { useIsMetricChanged } from '@/context/Metrics/useIsMetricChanged'; import { useUpdateMetricChart } from '@/context/Metrics'; import { useIsMetricReadOnly } from '@/context/Metrics/useIsMetricReadOnly'; +import { MetricSaveFilePopup } from './MetricSaveFilePopup'; export const MetricViewChart: React.FC<{ metricId: string; @@ -161,20 +162,3 @@ const AnimatePresenceWrapper: React.FC<{ ); }; - -const MetricSaveFilePopup: React.FC<{ metricId: string }> = React.memo(({ metricId }) => { - const { isMetricChanged, onResetMetricToOriginal } = useIsMetricChanged({ metricId }); - const { onSaveMetricToServer, isSaving } = useUpdateMetricChart({ metricId }); - - return ( - - ); -}); - -MetricSaveFilePopup.displayName = 'MetricSaveFilePopup'; diff --git a/web/src/controllers/MetricListContainer/MetricItemsSelectedPopup.tsx b/web/src/controllers/MetricListContainer/MetricItemsSelectedPopup.tsx index 5b8e27a91..bdd9a19b8 100644 --- a/web/src/controllers/MetricListContainer/MetricItemsSelectedPopup.tsx +++ b/web/src/controllers/MetricListContainer/MetricItemsSelectedPopup.tsx @@ -14,8 +14,7 @@ import { useBulkUpdateMetricVerificationStatus, useDeleteMetric, useRemoveMetricFromCollection, - useSaveMetricToCollections, - useUpdateMetric + useSaveMetricToCollections } from '@/api/buster_rest/metrics'; import { useThreeDotFavoritesOptions } from '@/components/features/dropdowns/useThreeDotFavoritesOptions'; @@ -123,7 +122,6 @@ const StatusButton: React.FC<{ const isAdmin = useUserConfigContextSelector((state) => state.isAdmin); const onVerify = useMemoizedFn(async (data: { id: string; status: VerificationStatus }[]) => { - console.log('onVerify', data); await updateStatus(data); onSelectChange([]); });