diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 6742857a..111cb661 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -111,7 +111,11 @@ function buildSearchData( id: `attr-key-${key}`, category: 'attribute', title: key, - meta: 'attribute key', + meta: 'attribute key — filter list', + // Path carries the facet in query-string form; handlePaletteSelect routes + // attribute results to the current scope, so the leading segment below is + // only used as a fallback when no scope is active. + path: `/exchanges?attr=${encodeURIComponent(key)}`, }); } } @@ -744,6 +748,32 @@ function LayoutContent() { setPaletteOpen(false); return; } + + if (result.category === 'attribute') { + // Three sources feed 'attribute' results: + // - buildSearchData → id `attr-key-` (key-only) + // - operationalSearchData per-exchange → id `-attr-`, title `key = "value"` + // - synthetic facet (Task 9) → id `facet-` where is already + // the URL `attr=` form (`key` or `key:value`) + let attrParam: string | null = null; + if (typeof result.id === 'string' && result.id.startsWith('attr-key-')) { + attrParam = result.id.substring('attr-key-'.length); + } else if (typeof result.id === 'string' && result.id.startsWith('facet-')) { + attrParam = result.id.substring('facet-'.length); + } else if (typeof result.title === 'string') { + const m = /^([a-zA-Z0-9._-]+)\s*=\s*"([^"]*)"/.exec(result.title); + if (m) attrParam = `${m[1]}:${m[2]}`; + } + if (attrParam) { + const base = ['/exchanges']; + if (scope.appId) base.push(scope.appId); + if (scope.routeId) base.push(scope.routeId); + navigate(`${base.join('/')}?attr=${encodeURIComponent(attrParam)}`); + } + setPaletteOpen(false); + return; + } + if (result.path) { if (ADMIN_CATEGORIES.has(result.category)) { const itemId = result.id.split(':').slice(1).join(':'); @@ -752,7 +782,7 @@ function LayoutContent() { }); } else { const state: Record = { sidebarReveal: result.path }; - if (result.category === 'exchange' || result.category === 'attribute') { + if (result.category === 'exchange') { const parts = result.path.split('/').filter(Boolean); if (parts.length === 4 && parts[0] === 'exchanges') { state.selectedExchange = { @@ -766,7 +796,7 @@ function LayoutContent() { } } setPaletteOpen(false); - }, [navigate, setPaletteOpen]); + }, [navigate, setPaletteOpen, scope.appId, scope.routeId]); const handlePaletteSubmit = useCallback((query: string) => { if (isAdminPage) {