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

3.6 KiB

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. SwapsearchData = 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