Summary
Add a global search palette to the WebUI: a search icon in the header plus Cmd/Ctrl+K opens an Astryx CommandPalette that finds pages/menus, in-page tabs, setting items, and actions by keyword and takes the user there.
Why
Users cannot find where a feature lives without walking the sidebar. The WebUI is a SPA whose routes are lazy chunks, so the palette cannot search rendered HTML of other pages — the index must come from source.
Design (decided)
- Index is generated at build time from source, never scraped from the DOM: route metadata (
handle.menuKey/labelKey), tab keys and setting items (TS AST), and the i18n keys reachable from each page component (esbuild-stripped value-import walk, keys present on >= 10 pages dropped). Output committed at react/src/__generated__/searchIndex.json with a verify.sh drift gate. The index stores i18n keys, resolved via t() at query time, so all 20 locales work without re-indexing.
- Hits: page, tab (
?tab=), setting item (?setting=<key> -> scroll + transient highlight), action (static registry: start session, create folder, start deployment, FastTrack, theme, UI language, notifications, sidebar, manual, user settings). Body-text matches surface as the page hit with a "found in: ..." line. Data entities (sessions/folders/users by name) are out of scope.
- Visibility reuses
useWebUIMenuItems() gating (roles, feature flags, blockList; inactiveList hidden). Current project only.
- Matching: current locale + English always; ASCII -> fuzzy (
fuse.js), non-ASCII -> substring; title > tab/setting > action > body; recents in the empty state.
- UI: Astryx
CommandPalette + useHotkeys; rows show icon, title, scope breadcrumb; admin groups prefixed "Administration".
Delivery
Stacked PRs (bottom-up): (1) extractor + generated index + drift gate, (2) search core, (3) palette UI, (4) arrival hooks, (5) action registry, (6) e2e.
JIRA Issue: FR-3558
Summary
Add a global search palette to the WebUI: a search icon in the header plus
Cmd/Ctrl+Kopens an AstryxCommandPalettethat finds pages/menus, in-page tabs, setting items, and actions by keyword and takes the user there.Why
Users cannot find where a feature lives without walking the sidebar. The WebUI is a SPA whose routes are lazy chunks, so the palette cannot search rendered HTML of other pages — the index must come from source.
Design (decided)
handle.menuKey/labelKey), tab keys and setting items (TS AST), and the i18n keys reachable from each page component (esbuild-stripped value-import walk, keys present on >= 10 pages dropped). Output committed atreact/src/__generated__/searchIndex.jsonwith averify.shdrift gate. The index stores i18n keys, resolved viat()at query time, so all 20 locales work without re-indexing.?tab=), setting item (?setting=<key>-> scroll + transient highlight), action (static registry: start session, create folder, start deployment, FastTrack, theme, UI language, notifications, sidebar, manual, user settings). Body-text matches surface as the page hit with a "found in: ..." line. Data entities (sessions/folders/users by name) are out of scope.useWebUIMenuItems()gating (roles, feature flags,blockList;inactiveListhidden). Current project only.fuse.js), non-ASCII -> substring; title > tab/setting > action > body; recents in the empty state.CommandPalette+useHotkeys; rows show icon, title, scope breadcrumb; admin groups prefixed "Administration".Delivery
Stacked PRs (bottom-up): (1) extractor + generated index + drift gate, (2) search core, (3) palette UI, (4) arrival hooks, (5) action registry, (6) e2e.
JIRA Issue: FR-3558