mirror of https://github.com/buster-so/buster.git
move disabled to a global hook
This commit is contained in:
parent
def7d2a341
commit
2bdccb6a7c
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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<{
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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]);
|
||||
};
|
Loading…
Reference in New Issue