feat: build admin search data for cmd-k on admin pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-02 23:34:52 +02:00
parent cf36f81ef1
commit 111bcc302d

View File

@@ -19,6 +19,8 @@ import { Box, Settings, FileText, ChevronRight, Square, Pause, Star, X } from 'l
import { useRouteCatalog } from '../api/queries/catalog';
import { useAgents } from '../api/queries/agents';
import { useSearchExecutions, useAttributeKeys } from '../api/queries/executions';
import { useUsers, useGroups, useRoles } from '../api/queries/admin/rbac';
import type { UserDetail, GroupDetail, RoleDetail } from '../api/queries/admin/rbac';
import { useAuthStore } from '../auth/auth-store';
import { useState, useMemo, useCallback, useEffect, useRef, createElement } from 'react';
import type { ReactNode } from 'react';
@@ -95,6 +97,52 @@ function buildSearchData(
return results;
}
function buildAdminSearchData(
users: UserDetail[] | undefined,
groups: GroupDetail[] | undefined,
roles: RoleDetail[] | undefined,
): SearchResult[] {
const results: SearchResult[] = [];
if (users) {
for (const u of users) {
results.push({
id: `user:${u.userId}`,
category: 'user',
title: u.displayName || u.userId,
meta: u.userId,
path: '/admin/rbac',
});
}
}
if (groups) {
for (const g of groups) {
results.push({
id: `group:${g.id}`,
category: 'group',
title: g.name,
meta: g.parentGroupId ? `parent: ${g.parentGroupId}` : 'top-level group',
path: '/admin/rbac',
});
}
}
if (roles) {
for (const r of roles) {
results.push({
id: `role:${r.id}`,
category: 'role',
title: r.name,
meta: r.scope,
path: '/admin/rbac',
});
}
}
return results;
}
function healthToSearchColor(health: string): string {
switch (health) {
case 'live': return 'success';
@@ -226,6 +274,12 @@ function LayoutContent() {
const { data: catalog } = useRouteCatalog(timeRange.start.toISOString(), timeRange.end.toISOString());
const { data: agents } = useAgents();
const { data: attributeKeys } = useAttributeKeys();
// --- Admin search data (only fetched on admin pages) ----------------
const { data: adminUsers } = useUsers();
const { data: adminGroups } = useGroups();
const { data: adminRoles } = useRoles();
const { username, logout } = useAuthStore();
const { open: paletteOpen, setOpen: setPaletteOpen } = useCommandPalette();
const { scope, setTab } = useScope();
@@ -365,7 +419,14 @@ function LayoutContent() {
catalogRef.current = catalogData;
}
const searchData: SearchResult[] = useMemo(() => {
const adminSearchData: SearchResult[] = useMemo(
() => buildAdminSearchData(adminUsers, adminGroups, adminRoles),
[adminUsers, adminGroups, adminRoles],
);
const operationalSearchData: SearchResult[] = useMemo(() => {
if (isAdminPage) return [];
const exchangeItems: SearchResult[] = (exchangeResults?.data || []).map((e: any) => ({
id: e.executionId,
category: 'exchange' as const,
@@ -399,7 +460,9 @@ function LayoutContent() {
}
return [...catalogRef.current, ...exchangeItems, ...attributeItems];
}, [catalogRef.current, exchangeResults, debouncedQuery]);
}, [isAdminPage, catalogRef.current, exchangeResults, debouncedQuery]);
const searchData = isAdminPage ? adminSearchData : operationalSearchData;
// --- Breadcrumb ---------------------------------------------------
const breadcrumb = useMemo(() => {