From e026fc7009cfe37cbee9d08a13323a830a522379 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Sat, 24 Aug 2024 22:07:16 -0400 Subject: [PATCH] fix: side panel resizing crashes --- client/src/components/SidePanel/SidePanel.tsx | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/client/src/components/SidePanel/SidePanel.tsx b/client/src/components/SidePanel/SidePanel.tsx index 0aebcfffc9..ef3f868d6a 100644 --- a/client/src/components/SidePanel/SidePanel.tsx +++ b/client/src/components/SidePanel/SidePanel.tsx @@ -30,6 +30,24 @@ interface SidePanelProps { const defaultMinSize = 20; const defaultInterface = getConfigDefaults().interface; +const normalizeLayout = (layout: number[]) => { + const sum = layout.reduce((acc, size) => acc + size, 0); + if (Math.abs(sum - 100) < 0.01) { + return layout.map((size) => Number(size.toFixed(2))); + } + + const factor = 100 / sum; + const normalizedLayout = layout.map((size) => Number((size * factor).toFixed(2))); + + const adjustedSum = normalizedLayout.reduce( + (acc, size, index) => (index === layout.length - 1 ? acc : acc + size), + 0, + ); + normalizedLayout[normalizedLayout.length - 1] = Number((100 - adjustedSum).toFixed(2)); + + return normalizedLayout; +}; + const SidePanel = ({ defaultLayout = [97, 3], defaultCollapsed = false, @@ -66,11 +84,11 @@ const SidePanel = ({ const assistants = useMemo(() => endpointsConfig?.[endpoint ?? ''], [endpoint, endpointsConfig]); const userProvidesKey = useMemo( - () => !!endpointsConfig?.[endpoint ?? '']?.userProvide, + () => !!(endpointsConfig?.[endpoint ?? '']?.userProvide ?? false), [endpointsConfig, endpoint], ); const keyProvided = useMemo( - () => (userProvidesKey ? !!keyExpiry.expiresAt : true), + () => (userProvidesKey ? !!(keyExpiry.expiresAt ?? '') : true), [keyExpiry.expiresAt, userProvidesKey], ); @@ -91,10 +109,26 @@ const SidePanel = ({ interfaceConfig, }); + const calculateLayout = useCallback(() => { + if (!artifacts) { + const navSize = defaultLayout.length === 2 ? defaultLayout[1] : defaultLayout[2]; + return [100 - navSize, navSize]; + } else { + const navSize = Math.max(minSize, navCollapsedSize); + const remainingSpace = 100 - navSize; + const newMainSize = Math.floor(remainingSpace / 2); + const artifactsSize = remainingSpace - newMainSize; + return [newMainSize, artifactsSize, navSize]; + } + }, [artifacts, defaultLayout, minSize, navCollapsedSize]); + + const currentLayout = useMemo(() => normalizeLayout(calculateLayout()), [calculateLayout]); + // eslint-disable-next-line react-hooks/exhaustive-deps const throttledSaveLayout = useCallback( throttle((sizes: number[]) => { - localStorage.setItem('react-resizable-panels:layout', JSON.stringify(sizes)); + const normalizedSizes = normalizeLayout(sizes); + localStorage.setItem('react-resizable-panels:layout', JSON.stringify(normalizedSizes)); }, 350), [], ); @@ -142,16 +176,26 @@ const SidePanel = ({ throttledSaveLayout(sizes)} + onLayout={(sizes) => throttledSaveLayout(sizes)} className="transition-width relative h-full w-full flex-1 overflow-auto bg-white dark:bg-gray-800" > - + {children} {artifacts != null && ( <> - + {artifacts} @@ -190,7 +234,7 @@ const SidePanel = ({ aria-label={localize('com_ui_controls')} role="region" collapsedSize={collapsedSize} - defaultSize={defaultLayout[1]} + defaultSize={currentLayout[currentLayout.length - 1]} collapsible={true} minSize={minSize} maxSize={40}