move disabled to a global hook

This commit is contained in:
Nate Kelley 2025-04-19 22:48:41 -06:00
parent def7d2a341
commit 2bdccb6a7c
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
12 changed files with 141 additions and 64 deletions

View File

@ -20,14 +20,13 @@ import { useSignOut } from '@/components/features/auth/SignOutHandler';
export const SidebarUserFooter: React.FC<{}> = () => {
const user = useUserConfigContextSelector((x) => x.user);
const handleSignOut = useSignOut();
if (!user) return null;
const { name, email } = user;
if (!name || !email) return null;
const handleSignOut = useSignOut();
return (
<SidebarUserDropdown signOut={handleSignOut}>
<div className="flex w-full">

View File

@ -8,7 +8,7 @@ import { compareObjectsByKeys } from '@/lib/objects';
import { useMemo } from 'react';
import { create } from 'mutative';
export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string }) => {
export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string | undefined }) => {
const queryClient = useQueryClient();
const originalDashboard = useOriginalDashboardStore((x) => x.getOriginalDashboard(dashboardId));
@ -26,7 +26,7 @@ export const useIsDashboardChanged = ({ dashboardId }: { dashboardId: string })
const onResetDashboardToOriginal = useMemoizedFn(() => {
const options = dashboardQueryKeys.dashboardGetDashboard(
dashboardId,
dashboardId || '',
originalDashboard?.version_number || null
);
const currentDashboard = queryClient.getQueryData<BusterDashboardResponse>(options.queryKey);

View File

@ -8,7 +8,7 @@ type OriginalDashboardStore = {
originalDashboards: Record<string, BusterDashboard>;
bulkAddOriginalDashboards: (dashboards: Record<string, BusterDashboard>) => void;
setOriginalDashboard: (dashboard: BusterDashboard) => void;
getOriginalDashboard: (dashboardId: string) => BusterDashboard | undefined;
getOriginalDashboard: (dashboardId: string | undefined) => BusterDashboard | undefined;
removeOriginalDashboard: (dashboardId: string) => void;
};
@ -28,7 +28,8 @@ export const useOriginalDashboardStore = create<OriginalDashboardStore>((set, ge
[dashboard.id]: dashboard
}
})),
getOriginalDashboard: (dashboardId: string) => get().originalDashboards[dashboardId],
getOriginalDashboard: (dashboardId: string | undefined) =>
dashboardId ? get().originalDashboards[dashboardId] : undefined,
removeOriginalDashboard: (dashboardId: string) =>
set((state) => {
const { [dashboardId]: removed, ...rest } = state.originalDashboards;

View File

@ -1,13 +1,12 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { useOriginalMetricStore } from './useOriginalMetricStore';
import { useMemoizedFn } from '@/hooks';
import { metricsQueryKeys } from '@/api/query_keys/metric';
import { useGetMetric } from '@/api/buster_rest/metrics';
import { compareObjectsByKeys } from '@/lib/objects';
import { useMemo } from 'react';
import last from 'lodash/last';
export const useIsMetricChanged = ({ metricId }: { metricId: string }) => {
export const useIsMetricChanged = ({ metricId }: { metricId: string | undefined }) => {
const queryClient = useQueryClient();
const originalMetric = useOriginalMetricStore((x) => x.getOriginalMetric(metricId));
@ -31,7 +30,7 @@ export const useIsMetricChanged = ({ metricId }: { metricId: string }) => {
const onResetMetricToOriginal = useMemoizedFn(() => {
const options = metricsQueryKeys.metricsGetMetric(
metricId,
metricId || '',
originalMetric?.version_number || null
);
if (originalMetric) {

View File

@ -8,7 +8,7 @@ type OriginalMetricStore = {
originalMetrics: Record<string, IBusterMetric>;
bulkAddOriginalMetrics: (metrics: Record<string, IBusterMetric>) => void;
setOriginalMetric: (metric: IBusterMetric) => void;
getOriginalMetric: (metricId: string) => IBusterMetric | undefined;
getOriginalMetric: (metricId: string | undefined) => IBusterMetric | undefined;
removeOriginalMetric: (metricId: string) => void;
};
@ -28,7 +28,8 @@ export const useOriginalMetricStore = create<OriginalMetricStore>((set, get) =>
[metric.id]: metric
}
})),
getOriginalMetric: (metricId: string) => get().originalMetrics[metricId],
getOriginalMetric: (metricId: string | undefined) =>
metricId ? get().originalMetrics[metricId] : undefined,
removeOriginalMetric: (metricId: string) =>
set((state) => {
const { [metricId]: removed, ...rest } = state.originalMetrics;

View File

@ -1,17 +1,17 @@
import { useGetDashboard, useUpdateDashboard } from '@/api/buster_rest/dashboards';
import { SaveResetFilePopup } from '@/components/features/popups/SaveResetFilePopup';
import { useIsDashboardChanged } from '@/context/Dashboards';
import { useMemoizedFn } from '@/hooks';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
import React from 'react';
export const DashboardSavePopup: React.FC<{ dashboardId: string }> = React.memo(
export const DashboardSaveFilePopup: React.FC<{ dashboardId: string }> = React.memo(
({ dashboardId }) => {
const onResetToOriginal = useChatIndividualContextSelector((x) => x.onResetToOriginal);
const isFileChanged = useChatIndividualContextSelector((x) => x.isFileChanged);
const chatId = useChatLayoutContextSelector((x) => x.chatId);
const { data: dashboardResponse } = useGetDashboard({ id: dashboardId });
const { isDashboardChanged, onResetDashboardToOriginal } = useIsDashboardChanged({
dashboardId
});
const { mutateAsync: onSaveDashboard, isPending: isSaving } = useUpdateDashboard({
saveToServer: true,
updateOnSave: true,
@ -30,8 +30,8 @@ export const DashboardSavePopup: React.FC<{ dashboardId: string }> = React.memo(
return (
<SaveResetFilePopup
open={isDashboardChanged}
onReset={onResetDashboardToOriginal}
open={isFileChanged}
onReset={onResetToOriginal}
onSave={onSaveDashboardFileToServer}
isSaving={isSaving}
showHotsKeys={false}

View File

@ -8,7 +8,7 @@ import { useDashboardContentStore } from '@/context/Dashboards';
import { ScrollArea } from '@/components/ui/scroll-area';
import { StatusCard } from '@/components/ui/card/StatusCard';
import { useIsDashboardReadOnly } from '@/context/Dashboards/useIsDashboardReadOnly';
import { DashboardSavePopup } from './DashboardSavePopup';
import { DashboardSaveFilePopup } from './DashboardSaveFilePopup';
export const DashboardViewDashboardController: React.FC<{
dashboardId: string;
@ -64,7 +64,7 @@ export const DashboardViewDashboardController: React.FC<{
/>
{!isVersionHistoryMode && !isViewingOldVersion && (
<DashboardSavePopup dashboardId={dashboardId} />
<DashboardSaveFilePopup dashboardId={dashboardId} />
)}
</div>
</ScrollArea>

View File

@ -1,16 +1,17 @@
import { SaveResetFilePopup } from '@/components/features/popups/SaveResetFilePopup';
import { useIsMetricChanged } from '@/context/Metrics/useIsMetricChanged';
import { useUpdateMetricChart } from '@/context/Metrics/useUpdateMetricChart';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
import React from 'react';
export const MetricSaveFilePopup: React.FC<{ metricId: string }> = React.memo(({ metricId }) => {
const { isMetricChanged, onResetMetricToOriginal } = useIsMetricChanged({ metricId });
const onResetToOriginal = useChatIndividualContextSelector((x) => x.onResetToOriginal);
const isFileChanged = useChatIndividualContextSelector((x) => x.isFileChanged);
const { onSaveMetricToServer, isSaving } = useUpdateMetricChart({ metricId });
return (
<SaveResetFilePopup
open={isMetricChanged}
onReset={onResetMetricToOriginal}
open={isFileChanged}
onReset={onResetToOriginal}
onSave={onSaveMetricToServer}
isSaving={isSaving}
showHotsKeys={false}

View File

@ -3,8 +3,8 @@
import React, { useMemo } from 'react';
import { MetricViewChartContent } from './MetricViewChartContent';
import { MetricViewChartHeader } from './MetricViewChartHeader';
import { useGetMetric, useGetMetricData, useUpdateMetric } from '@/api/buster_rest/metrics';
import { useMemoizedFn, useMount } from '@/hooks';
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
import { useMemoizedFn } from '@/hooks';
import { inputHasText } from '@/lib/text';
import { MetricChartEvaluation } from './MetricChartEvaluation';
import { ChartType } from '@/api/asset_interfaces/metric/charts/enum';
@ -12,7 +12,6 @@ import { AnimatePresence, motion } from 'framer-motion';
import { cn } from '@/lib/classMerge';
import { useIsMetricReadOnly } from '@/context/Metrics/useIsMetricReadOnly';
import { MetricSaveFilePopup } from './MetricSaveFilePopup';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
import { useUpdateMetricChart } from '@/context/Metrics';
export const MetricViewChart: React.FC<{

View File

@ -2,6 +2,8 @@ import React, { useMemo } from 'react';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
import { useMemoizedFn } from '@/hooks';
import { useBusterNewChatContextSelector } from '@/context/Chats';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { timeout } from '@/lib';
type FlowType = 'followup-chat' | 'followup-metric' | 'followup-dashboard' | 'new';
@ -27,6 +29,9 @@ export const useChatInputFlow = ({
const onStartChatFromFile = useBusterNewChatContextSelector((state) => state.onStartChatFromFile);
const onStopChatContext = useBusterNewChatContextSelector((state) => state.onStopChat);
const currentMessageId = useChatIndividualContextSelector((x) => x.currentMessageId);
const isFileChanged = useChatIndividualContextSelector((x) => x.isFileChanged);
const onResetToOriginal = useChatIndividualContextSelector((x) => x.onResetToOriginal);
const { openConfirmModal } = useBusterNotifications();
const flow: FlowType = useMemo(() => {
if (hasChat) return 'followup-chat';
@ -43,6 +48,7 @@ export const useChatInputFlow = ({
return;
}
const method = async () => {
switch (flow) {
case 'followup-chat':
await onFollowUpChat({ prompt: inputValue, chatId });
@ -77,6 +83,30 @@ export const useChatInputFlow = ({
setTimeout(() => {
textAreaRef.current?.focus();
}, 50);
};
if (!isFileChanged) {
return method();
}
await openConfirmModal({
title: 'Unsaved changes',
content: 'Looks like you have unsaved changes. Do you want to save them before continuing?',
primaryButtonProps: {
text: 'Reset to original'
},
cancelButtonProps: {
text: 'Continue'
},
onOk: async () => {
onResetToOriginal();
return await method();
},
onCancel: async () => {
return await method();
}
});
});
const onStopChat = useMemoizedFn(() => {

View File

@ -7,15 +7,14 @@ import { useQueries } from '@tanstack/react-query';
import { queryKeys } from '@/api/query_keys';
import { IBusterChatMessage } from '@/api/asset_interfaces/chat';
import { useChatLayoutContextSelector } from '..';
import { useIsFileChanged } from './useIsFileChanged';
const useChatIndividualContext = ({
chatId,
selectedFile,
onSetSelectedFile
selectedFile
}: {
chatId?: string;
selectedFile: SelectedFile | null;
onSetSelectedFile: (file: SelectedFile) => void;
}) => {
const selectedFileId = selectedFile?.id;
const selectedFileType = selectedFile?.type;
@ -53,6 +52,11 @@ const useChatIndividualContext = ({
chatId
});
const { isFileChanged, onResetToOriginal } = useIsFileChanged({
selectedFileId,
selectedFileType
});
return React.useMemo(
() => ({
hasChat,
@ -63,7 +67,9 @@ const useChatIndividualContext = ({
selectedFileType,
chatMessageIds,
chatId,
isStreamingMessage
isStreamingMessage,
isFileChanged,
onResetToOriginal
}),
[
hasChat,
@ -74,7 +80,9 @@ const useChatIndividualContext = ({
chatTitle,
selectedFileType,
chatMessageIds,
chatId
chatId,
isFileChanged,
onResetToOriginal
]
);
};
@ -86,11 +94,9 @@ const IndividualChatContext = createContext<ReturnType<typeof useChatIndividualC
export const ChatContextProvider = React.memo(({ children }: PropsWithChildren<{}>) => {
const chatId = useChatLayoutContextSelector((x) => x.chatId);
const selectedFile = useChatLayoutContextSelector((x) => x.selectedFile);
const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile);
const useChatContextValue = useChatIndividualContext({
chatId,
selectedFile,
onSetSelectedFile
selectedFile
});
return (

View File

@ -0,0 +1,41 @@
import { useIsMetricChanged } from '@/context/Metrics';
import { SelectedFile } from '../interfaces';
import { useIsDashboardChanged } from '@/context/Dashboards';
import { useMemo } from 'react';
type UseIsFileChangeReturn = {
isFileChanged: boolean;
onResetToOriginal: () => void;
};
type UseIsFileChangeParams = {
selectedFileId: SelectedFile['id'] | undefined;
selectedFileType: SelectedFile['type'] | undefined;
};
export const useIsFileChanged = ({
selectedFileId,
selectedFileType
}: UseIsFileChangeParams): UseIsFileChangeReturn => {
const { isMetricChanged, onResetMetricToOriginal } = useIsMetricChanged({
metricId: selectedFileType === 'metric' ? selectedFileId : undefined
});
const { isDashboardChanged, onResetDashboardToOriginal } = useIsDashboardChanged({
dashboardId: selectedFileType === 'dashboard' ? selectedFileId : undefined
});
return useMemo(() => {
if (selectedFileType === 'metric')
return {
isFileChanged: isMetricChanged,
onResetToOriginal: onResetMetricToOriginal
};
if (selectedFileType === 'dashboard')
return {
isFileChanged: isDashboardChanged,
onResetToOriginal: onResetDashboardToOriginal
};
return { isFileChanged: false, onResetToOriginal: () => {} };
}, [isMetricChanged, isDashboardChanged, onResetMetricToOriginal, onResetDashboardToOriginal]);
};