# 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
