From 4168a6d45b8a9d2884628d57f0e8673b77d16490 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:41:42 +0200 Subject: [PATCH] fix: sidebar selection highlight and scoped command palette search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes: - Pass sidebarReveal state on sidebar navigation so the design system can highlight the selected entry (it compares internal /apps/... paths against this state value, not the browser URL) - Command palette search now includes scope.appId and scope.routeId so results are filtered to the current sidebar selection Note: sidebar highlighting works on the exchanges tab. The design system's selectedPath logic only checks pathname.startsWith("/exchanges/") for sidebarReveal — a DS update is needed to support /dashboard/ and /runtime/ tabs too. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/src/components/LayoutShell.tsx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 7a5c7aa6..999ff86f 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -98,11 +98,17 @@ function LayoutContent() { const { open: paletteOpen, setOpen: setPaletteOpen } = useCommandPalette(); const { scope, setTab } = useScope(); - // Exchange full-text search via command palette + // Exchange full-text search via command palette (scoped to current sidebar selection) const [paletteQuery, setPaletteQuery] = useState(''); const debouncedQuery = useDebouncedValue(paletteQuery, 300); const { data: exchangeResults } = useSearchExecutions( - { text: debouncedQuery || undefined, offset: 0, limit: 10 }, + { + text: debouncedQuery || undefined, + application: scope.appId || undefined, + routeId: scope.routeId || undefined, + offset: 0, + limit: 10, + }, false, ); @@ -243,13 +249,17 @@ function LayoutContent() { navigate(`${baseParts.join('/')}?text=${encodeURIComponent(query)}`); }, [navigate, scope.appId, scope.routeId]); - // Translate Sidebar's internal paths to our URL structure + // Translate Sidebar's internal paths to our URL structure. + // Pass `sidebarReveal` state so the Sidebar can highlight the selected entry + // (it compares its internal /apps/... paths against this state value). const handleSidebarNavigate = useCallback((path: string) => { + const state = { sidebarReveal: path }; + // /apps/:appId and /apps/:appId/:routeId → current tab const appMatch = path.match(/^\/apps\/([^/]+)(?:\/(.+))?$/); if (appMatch) { const [, sAppId, sRouteId] = appMatch; - navigate(sRouteId ? `/${scope.tab}/${sAppId}/${sRouteId}` : `/${scope.tab}/${sAppId}`); + navigate(sRouteId ? `/${scope.tab}/${sAppId}/${sRouteId}` : `/${scope.tab}/${sAppId}`, { state }); return; } @@ -257,11 +267,11 @@ function LayoutContent() { const agentMatch = path.match(/^\/agents\/([^/]+)(?:\/(.+))?$/); if (agentMatch) { const [, sAppId, sInstanceId] = agentMatch; - navigate(sInstanceId ? `/runtime/${sAppId}/${sInstanceId}` : `/runtime/${sAppId}`); + navigate(sInstanceId ? `/runtime/${sAppId}/${sInstanceId}` : `/runtime/${sAppId}`, { state }); return; } - navigate(path); + navigate(path, { state }); }, [navigate, scope.tab]); return (