Files
cameleer-server/docs/superpowers/specs/2026-04-02-context-aware-cmdk-design.md
hsiegeln 394fde30c7 docs: spec for context-aware cmd-k search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 23:21:53 +02:00

67 lines
3.6 KiB
Markdown

# Context-Aware Cmd-K Search
## Goal
Make the cmd-k command palette context-aware: when the user is on admin pages, search users, groups, and roles instead of operational data (applications, routes, exchanges, agents).
## Background
The `CommandPalette` component from `@cameleer/design-system` currently searches five categories: application, exchange, attribute, route, agent. All data is assembled in `LayoutShell.tsx` and passed as a flat `SearchResult[]` array. The `SearchCategory` type is a closed union in the DS.
The DS team is already updating `CommandPalette` to accept an open `SearchCategory` type (string instead of fixed union) and handle unknown categories gracefully (title-cased tab labels, default icons).
## Approach
Route-based data swap in `LayoutShell`. The component already tracks `isAdminPage` via `useLocation()`. When true, it provides admin search data instead of operational search data. No new providers, contexts, or abstractions.
## Design
### Search Data Swap (LayoutShell.tsx)
When `isAdminPage` is true:
1. **Skip operational data assembly** — do not build catalog/agent/attribute search items, do not fire the debounced `useSearchExecutions` query
2. **Fetch admin data** — call existing hooks: `useUsers()`, `useGroups()`, `useRoles()` from `api/queries/admin/rbac.ts`
3. **Build admin search items** — map each entity to a `SearchResult`:
- **Users**: `{ id: 'user:{userId}', category: 'user', title: displayName, meta: userId, path: '/admin/rbac' }`
- **Groups**: `{ id: 'group:{id}', category: 'group', title: name, meta: parentGroupId ?? 'top-level group', path: '/admin/rbac' }`
- **Roles**: `{ id: 'role:{id}', category: 'role', title: name, meta: scope, path: '/admin/rbac' }`
4. **Swap**`searchData = isAdminPage ? adminSearchData : operationalSearchData`
All three admin collections are small (dozens of items at most) — client-side filtering is sufficient. No server-side search endpoint needed.
### Navigation on Select
When the user selects an admin search result:
1. Navigate to `/admin/rbac` with location state: `{ tab: 'users' | 'groups' | 'roles', highlight: itemId }`
2. Tab mapping from category: `'user' → 'users'`, `'group' → 'groups'`, `'role' → 'roles'`
3. `RbacPage` reads location state, switches to the correct tab, and highlights the matching item
4. The `highlight` state is consumed once — after reading, clear it so back-navigation doesn't re-trigger
### Submit Handler (Enter without selection)
When the user presses Enter without explicitly selecting a result, navigate to the top (first visible) result — same behavior as selecting it. This matches standard command palette UX.
### Operational search behavior (unchanged)
When not on admin pages, search data assembly remains exactly as-is: catalog apps/routes, agents, exchanges (server-side), and attributes.
## Files Changed
| File | Change |
|------|--------|
| `ui/src/components/LayoutShell.tsx` | Import admin hooks, build admin search data, swap based on `isAdminPage`, update `handlePaletteSelect` for admin categories |
| `ui/src/pages/Admin/RbacPage.tsx` | Read location state `{ tab, highlight }`, switch tab and highlight item on mount |
## Dependencies
- `@cameleer/design-system` update: `SearchCategory` opened to `string`, unknown categories handled gracefully (DS team already working on this)
## Out of Scope
- Audit log search via cmd-k (has its own dedicated filter UI)
- App config search via cmd-k (already accessible via operational sidebar)
- Server-side admin search endpoint (not needed for small collections)
- Admin-specific submit behavior beyond navigating to top result