mirror of https://github.com/buster-so/buster.git
debebounce sidebar
This commit is contained in:
parent
60d59ff313
commit
f8f6bc7a8c
|
@ -49,13 +49,15 @@ export function useDebounceFn<T extends noop>(fn: T, options?: DebounceOptions)
|
|||
flush: debounced.flush
|
||||
};
|
||||
}
|
||||
|
||||
export function useDebounce<T>(value: T, options: DebounceOptions = {}) {
|
||||
const { wait = 1000, maxWait } = options;
|
||||
const { wait = 1000, maxWait, leading = false, trailing = true } = options;
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const maxTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const lastUpdateTime = useRef<number>(Date.now());
|
||||
const valueRef = useRef<T>(value);
|
||||
const isFirstCallRef = useRef<boolean>(true);
|
||||
|
||||
// Keep latest value in ref
|
||||
useEffect(() => {
|
||||
|
@ -70,17 +72,29 @@ export function useDebounce<T>(value: T, options: DebounceOptions = {}) {
|
|||
if (maxTimeoutRef.current) {
|
||||
clearTimeout(maxTimeoutRef.current);
|
||||
}
|
||||
|
||||
isFirstCallRef.current = true;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
clearTimeouts();
|
||||
const now = Date.now();
|
||||
|
||||
// Set up the regular debounce timeout
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setDebouncedValue(valueRef.current);
|
||||
lastUpdateTime.current = Date.now();
|
||||
}, wait);
|
||||
// Handle leading edge
|
||||
if (leading && isFirstCallRef.current) {
|
||||
setDebouncedValue(value);
|
||||
lastUpdateTime.current = now;
|
||||
isFirstCallRef.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only set up trailing timeout if trailing is true
|
||||
if (trailing) {
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
setDebouncedValue(valueRef.current);
|
||||
lastUpdateTime.current = Date.now();
|
||||
}, wait);
|
||||
}
|
||||
|
||||
// Handle maxWait
|
||||
if (maxWait) {
|
||||
|
@ -96,8 +110,9 @@ export function useDebounce<T>(value: T, options: DebounceOptions = {}) {
|
|||
}, maxWaitTimeRemaining);
|
||||
}
|
||||
|
||||
isFirstCallRef.current = false;
|
||||
return () => clearTimeouts();
|
||||
}, [value, wait, maxWait, clearTimeouts]);
|
||||
}, [value, wait, maxWait, leading, trailing, clearTimeouts]);
|
||||
|
||||
return debouncedValue;
|
||||
}
|
||||
|
|
|
@ -44,13 +44,6 @@ export const useSelectedFile = ({
|
|||
return false;
|
||||
}, [selectedFile?.type, metricVersionNumber, dashboardVersionNumber]);
|
||||
|
||||
console.log(
|
||||
'isVersionHistoryMode',
|
||||
isVersionHistoryMode,
|
||||
metricVersionNumber,
|
||||
dashboardVersionNumber
|
||||
);
|
||||
|
||||
const [renderViewLayoutKey, setRenderViewLayoutKey] = useState<ChatLayoutView>(
|
||||
selectedLayout || 'chat'
|
||||
);
|
||||
|
|
|
@ -6,7 +6,8 @@ import { AppPageLayout, AppSplitter, AppSplitterRef } from '@/components/ui/layo
|
|||
import { useChatLayoutContextSelector } from '../ChatLayoutContext';
|
||||
import { createAutoSaveId } from '@/components/ui/layouts/AppSplitter/helper';
|
||||
import Cookies from 'js-cookie';
|
||||
import { useMemoizedFn, useUpdateLayoutEffect } from '@/hooks';
|
||||
import { useDebounce, useMemoizedFn, useUpdateLayoutEffect } from '@/hooks';
|
||||
import { FileContainerSecondary } from './FileContainerSecondary';
|
||||
|
||||
interface FileContainerProps {
|
||||
children: React.ReactNode;
|
||||
|
@ -18,15 +19,22 @@ const autoSaveId = 'file-container-splitter';
|
|||
|
||||
export const FileContainer: React.FC<FileContainerProps> = ({ children }) => {
|
||||
const appSplitterRef = useRef<AppSplitterRef>(null);
|
||||
|
||||
const selectedFile = useChatLayoutContextSelector((x) => x.selectedFile);
|
||||
const selectedFileViewSecondary = useChatLayoutContextSelector(
|
||||
(x) => x.selectedFileViewSecondary
|
||||
);
|
||||
const selectedFileViewRenderSecondary = useChatLayoutContextSelector(
|
||||
(x) => x.selectedFileViewRenderSecondary
|
||||
);
|
||||
|
||||
const isOpenSecondary = selectedFileViewRenderSecondary;
|
||||
|
||||
//we need to debounce the selectedFileViewSecondary to avoid flickering
|
||||
const debouncedSelectedFileViewSecondary = useDebounce(selectedFileViewSecondary, {
|
||||
wait: 350,
|
||||
leading: selectedFileViewRenderSecondary
|
||||
});
|
||||
|
||||
const secondaryLayoutDimensions: [string, string] = useMemo(() => {
|
||||
const cookieKey = createAutoSaveId(autoSaveId);
|
||||
const cookieValue = Cookies.get(cookieKey);
|
||||
|
@ -58,6 +66,15 @@ export const FileContainer: React.FC<FileContainerProps> = ({ children }) => {
|
|||
}
|
||||
});
|
||||
|
||||
const rightChildren = useMemo(() => {
|
||||
return (
|
||||
<FileContainerSecondary
|
||||
selectedFile={selectedFile}
|
||||
selectedFileViewSecondary={debouncedSelectedFileViewSecondary}
|
||||
/>
|
||||
);
|
||||
}, [debouncedSelectedFileViewSecondary, selectedFile?.id, selectedFile?.type]);
|
||||
|
||||
useUpdateLayoutEffect(() => {
|
||||
animateOpenSplitter(isOpenSecondary ? 'open' : 'closed');
|
||||
}, [isOpenSecondary]);
|
||||
|
@ -70,7 +87,7 @@ export const FileContainer: React.FC<FileContainerProps> = ({ children }) => {
|
|||
defaultLayout={defaultLayout}
|
||||
initialReady={false}
|
||||
leftChildren={children}
|
||||
rightChildren={<div>Right {selectedFileViewSecondary}</div>}
|
||||
rightChildren={rightChildren}
|
||||
allowResize={selectedFileViewRenderSecondary}
|
||||
preserveSide={'right'}
|
||||
rightPanelMinSize={250}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use client';
|
||||
|
||||
import { Button } from '@/components/ui/buttons';
|
||||
import { ArrowLeft, History } from '@/components/ui/icons';
|
||||
import React, { useMemo, useTransition } from 'react';
|
||||
|
@ -8,6 +10,7 @@ import { useGetDashboard } from '@/api/buster_rest/dashboards';
|
|||
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { timeout } from '@/lib';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
||||
export const FileContainerVersionHistory = React.memo(() => {
|
||||
return (
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
import type { FileType } from '@/api/asset_interfaces/chat';
|
||||
import type { FileContainerSecondaryProps } from './interfaces';
|
||||
import type {
|
||||
DashboardFileViewSecondary,
|
||||
MetricFileViewSecondary
|
||||
} from '../../ChatLayoutContext/useLayoutConfig/interfaces';
|
||||
import { SelectedFileSecondaryRecord } from './secondaryPanelsConfig';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const MetricSecondaryRecord: Record<
|
||||
MetricFileViewSecondary,
|
||||
React.FC<FileContainerSecondaryProps>
|
||||
> = {
|
||||
'chart-edit': () => null,
|
||||
'sql-edit': () => null,
|
||||
'version-history': () => null
|
||||
};
|
||||
export const FileContainerSecondary: React.FC<FileContainerSecondaryProps> = ({
|
||||
selectedFile,
|
||||
selectedFileViewSecondary
|
||||
}) => {
|
||||
const Component = useMemo(() => {
|
||||
if (!selectedFile || !selectedFileViewSecondary) return null;
|
||||
|
||||
const DashboardSecondaryRecord: Record<
|
||||
DashboardFileViewSecondary,
|
||||
React.FC<FileContainerSecondaryProps>
|
||||
> = {
|
||||
'version-history': () => null
|
||||
};
|
||||
const assosciatedType = SelectedFileSecondaryRecord[selectedFile?.type];
|
||||
|
||||
const SelectedFileSecondaryRecord: Record<
|
||||
FileType,
|
||||
Record<string, React.FC<FileContainerSecondaryProps>>
|
||||
> = {
|
||||
metric: MetricSecondaryRecord,
|
||||
dashboard: DashboardSecondaryRecord,
|
||||
reasoning: {}
|
||||
if (!assosciatedType) return null;
|
||||
|
||||
return assosciatedType[selectedFileViewSecondary];
|
||||
}, [selectedFileViewSecondary, selectedFile?.id, selectedFile?.type]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Component && (
|
||||
<Component
|
||||
selectedFile={selectedFile}
|
||||
selectedFileViewSecondary={selectedFileViewSecondary}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { FileViewSecondary } from '@/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig';
|
||||
import { SelectedFile } from '../../interfaces';
|
||||
|
||||
export type FileContainerSecondaryProps = {
|
||||
selectedFileId: string | undefined;
|
||||
selectedFileViewSecondary: FileViewSecondary | undefined;
|
||||
selectedFile: SelectedFile | null;
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ export const DashboardSecondaryRecord: Record<
|
|||
DashboardFileViewSecondary,
|
||||
React.FC<FileContainerSecondaryProps>
|
||||
> = {
|
||||
'version-history': ({ selectedFileId }) => (
|
||||
<VersionHistoryPanel assetId={selectedFileId || ''} type="dashboard" />
|
||||
'version-history': ({ selectedFile }) => (
|
||||
<VersionHistoryPanel assetId={selectedFile?.id || ''} type="dashboard" />
|
||||
)
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import { CircleSpinnerLoaderContainer } from '@/components/ui/loaders/CircleSpin
|
|||
|
||||
export const loading = () => {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<div className="flex h-full w-full items-center justify-center overflow-hidden">
|
||||
<CircleSpinnerLoaderContainer />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -26,9 +26,9 @@ export const MetricSecondaryRecord: Record<
|
|||
MetricFileViewSecondary,
|
||||
React.FC<FileContainerSecondaryProps>
|
||||
> = {
|
||||
'chart-edit': ({ selectedFileId }) => <MetricEditController metricId={selectedFileId || ''} />,
|
||||
'sql-edit': ({ selectedFileId }) => <MetricViewResults metricId={selectedFileId || ''} />,
|
||||
'version-history': ({ selectedFileId }) => (
|
||||
<VersionHistoryPanel assetId={selectedFileId || ''} type="metric" />
|
||||
'chart-edit': ({ selectedFile }) => <MetricEditController metricId={selectedFile?.id || ''} />,
|
||||
'sql-edit': ({ selectedFile }) => <MetricViewResults metricId={selectedFile?.id || ''} />,
|
||||
'version-history': ({ selectedFile }) => (
|
||||
<VersionHistoryPanel assetId={selectedFile?.id || ''} type="metric" />
|
||||
)
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue