From 9d08d9243501c1150441a83625539a5e71bbb8a0 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Thu, 3 Sep 2026 00:01:39 +0800 Subject: [PATCH] fix(webui): align native sidebar controls --- webui/src/App.tsx | 154 +++------------------------- webui/src/components/Sidebar.tsx | 12 ++- webui/src/tests/app-layout.test.tsx | 35 +++---- 3 files changed, 35 insertions(+), 166 deletions(-) diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 8fc89e055..cb4d556ce 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -8,7 +8,7 @@ import { useState, type ReactNode, } from "react"; -import { Eye, EyeOff, Moon, PanelLeft, ShieldCheck, Sun, X } from "lucide-react"; +import { Eye, EyeOff, Moon, ShieldCheck, Sun, X } from "lucide-react"; import { useTranslation } from "react-i18next"; import { channelUiPresentation } from "@/channel-plugins/registry"; import { Sidebar } from "@/components/Sidebar"; @@ -475,39 +475,12 @@ function isBootstrapAuthRequired(error: unknown): boolean { } function HostChrome({ - onToggleSidebar, - onSidebarPreviewEnter, - onSidebarPreviewLeave, - sidebarOpen = true, rightAction, }: { - onToggleSidebar?: () => void; - onSidebarPreviewEnter?: () => void; - onSidebarPreviewLeave?: () => void; - sidebarOpen?: boolean; rightAction?: ReactNode; }) { - const { t } = useTranslation(); - return (
- {onToggleSidebar ? ( - - ) : null} {rightAction ? (
{rightAction} @@ -1055,7 +1028,6 @@ function Shell({ useState(initialRouteRef.current.settingsSection); const [hostSidebarOpen, setHostSidebarOpen] = useState(readSidebarOpen); - const [hostSidebarPreviewOpen, setHostSidebarPreviewOpen] = useState(false); const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); const [sessionSearchOpen, setSessionSearchOpen] = useState(false); const mobileWorkbench = useMediaQuery("(max-width: 767px)"); @@ -1112,7 +1084,6 @@ function Shell({ const activeChatIdRef = useRef(null); const pendingCreatedSessionKeyRef = useRef(null); const temporarySessionsRef = useRef>({}); - const hostSidebarPreviewCloseTimerRef = useRef(null); const effectiveRuntimeSurface = settingsSnapshot?.surface ?? settingsSnapshot?.runtime_surface ?? runtimeSurface; const showHostChrome = effectiveRuntimeSurface === "native"; @@ -1453,74 +1424,13 @@ function Shell({ }); }, [client, loading, sessions]); - const clearHostSidebarPreviewCloseTimer = useCallback(() => { - if (hostSidebarPreviewCloseTimerRef.current === null) return; - window.clearTimeout(hostSidebarPreviewCloseTimerRef.current); - hostSidebarPreviewCloseTimerRef.current = null; + const closeHostSidebar = useCallback(() => { + setHostSidebarOpen(false); }, []); - const closeHostSidebarPreview = useCallback(() => { - clearHostSidebarPreviewCloseTimer(); - setHostSidebarPreviewOpen(false); - }, [clearHostSidebarPreviewCloseTimer]); - - const openHostSidebarPreview = useCallback(() => { - if (!showHostChrome || !showMainSidebar || hostSidebarOpen) return; - clearHostSidebarPreviewCloseTimer(); - setHostSidebarPreviewOpen(true); - }, [ - clearHostSidebarPreviewCloseTimer, - hostSidebarOpen, - showHostChrome, - showMainSidebar, - ]); - - const scheduleHostSidebarPreviewClose = useCallback(() => { - clearHostSidebarPreviewCloseTimer(); - if (!showHostChrome || !showMainSidebar || hostSidebarOpen) { - setHostSidebarPreviewOpen(false); - return; - } - hostSidebarPreviewCloseTimerRef.current = window.setTimeout(() => { - setHostSidebarPreviewOpen(false); - hostSidebarPreviewCloseTimerRef.current = null; - }, 160); - }, [ - clearHostSidebarPreviewCloseTimer, - hostSidebarOpen, - showHostChrome, - showMainSidebar, - ]); - - useEffect(() => { - return () => clearHostSidebarPreviewCloseTimer(); - }, [clearHostSidebarPreviewCloseTimer]); - - useEffect(() => { - if (!showHostChrome || !showMainSidebar || hostSidebarOpen) { - closeHostSidebarPreview(); - } - }, [ - closeHostSidebarPreview, - hostSidebarOpen, - showHostChrome, - showMainSidebar, - ]); - - const closeHostSidebar = useCallback(() => { - closeHostSidebarPreview(); - setHostSidebarOpen(false); - }, [closeHostSidebarPreview]); - const openHostSidebar = useCallback(() => { - closeHostSidebarPreview(); setHostSidebarOpen(true); - }, [closeHostSidebarPreview]); - - const toggleHostSidebar = useCallback(() => { - closeHostSidebarPreview(); - setHostSidebarOpen((v) => !v); - }, [closeHostSidebarPreview]); + }, []); const closeMobileSidebar = useCallback(() => { setMobileSidebarOpen(false); @@ -1531,12 +1441,11 @@ function Shell({ typeof window !== "undefined" && window.matchMedia("(min-width: 1024px)").matches; if (isNativeHost) { - closeHostSidebarPreview(); setHostSidebarOpen((v) => !v); } else { setMobileSidebarOpen((v) => !v); } - }, [closeHostSidebarPreview]); + }, []); const applyWorkspaceScope = useCallback( (scope: WorkspaceScopePayload) => { @@ -2574,13 +2483,7 @@ function Shell({ archivedCount: sidebarArchivedTabKeys.length, defaultWorkspacePath: workspaces?.default_scope.project_path ?? null, }; - const hostSidebarCollapsed = showHostChrome && !hostSidebarOpen; - const showHostSidebarPreview = - showMainSidebar && hostSidebarCollapsed && hostSidebarPreviewOpen; - const hostSidebarFlowWidth = showHostChrome - ? (hostSidebarOpen ? SIDEBAR_WIDTH : 0) - : (hostSidebarOpen ? SIDEBAR_WIDTH : SIDEBAR_RAIL_WIDTH); - const renderHostSidebarFlowContent = !showHostChrome || hostSidebarOpen; + const hostSidebarFlowWidth = hostSidebarOpen ? SIDEBAR_WIDTH : SIDEBAR_RAIL_WIDTH; useEffect(() => { document.documentElement.classList.toggle("native-host", showHostChrome); @@ -2599,10 +2502,6 @@ function Shell({ > {showHostChrome ? ( - {renderHostSidebarFlowContent ? ( -
- -
- ) : null} - - ) : null} - - {showHostSidebarPreview ? ( -