From eb7cd9ba621e85bd01587691878a87caf1db0c2a Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 9 Apr 2026 07:13:04 +0200 Subject: [PATCH] fix: keep sidebar selection when switching tabs Normalize the sidebar selectedPath so the app highlight persists across tab switches (Dashboard, Runtime, Deployments). Also make sidebar clicks tab-aware: clicking an app navigates to the current tab's path instead of always going to /exchanges/. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/src/components/LayoutShell.tsx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 423fee78..ec3c3c68 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -443,7 +443,14 @@ function LayoutContent() { if (sidebarRevealPath.startsWith('/admin') && !adminOpen) setAdminOpen(true); }, [sidebarRevealPath]); // eslint-disable-line react-hooks/exhaustive-deps - const effectiveSelectedPath = sidebarRevealPath ?? location.pathname; + // Normalize path so sidebar highlights the app regardless of which tab is active. + // Sidebar nodes use /exchanges/{slug} paths, so map /dashboard/{slug}, /apps/{slug}, etc. + const effectiveSelectedPath = useMemo(() => { + const raw = sidebarRevealPath ?? location.pathname; + const match = raw.match(/^\/(exchanges|dashboard|apps|runtime)\/([^/]+)(\/.*)?$/); + if (match) return `/exchanges/${match[2]}${match[3] ?? ''}`; + return raw; + }, [sidebarRevealPath, location.pathname]); // --- About Me dialog ----------------------------------------------- const [aboutMeOpen, setAboutMeOpen] = useState(false); @@ -629,6 +636,17 @@ function LayoutContent() { return; } + const exchangeMatch = path.match(/^\/exchanges\/([^/]+)(?:\/(.+))?$/); + if (exchangeMatch) { + const [, sAppId, sRouteId] = exchangeMatch; + if (scope.tab === 'apps') { + navigate(`/apps/${sAppId}`, { state }); + } else { + navigate(sRouteId ? `/${scope.tab}/${sAppId}/${sRouteId}` : `/${scope.tab}/${sAppId}`, { state }); + } + return; + } + const agentMatch = path.match(/^\/agents\/([^/]+)(?:\/(.+))?$/); if (agentMatch) { const [, sAppId, sInstanceId] = agentMatch;