feat: fetch server capabilities and hide infra tabs when disabled
Adds a useServerCapabilities hook that fetches /api/v1/health once per session (staleTime: Infinity) and extracts the infrastructureEndpoints flag. buildAdminTreeNodes now accepts an opts parameter so ClickHouse and Database tabs are hidden when the server reports infra endpoints as disabled. LayoutShell wires the hook result into the admin tree memo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
29
ui/src/api/queries/capabilities.ts
Normal file
29
ui/src/api/queries/capabilities.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { config } from '../../config';
|
||||||
|
|
||||||
|
interface HealthResponse {
|
||||||
|
status: string;
|
||||||
|
components?: {
|
||||||
|
serverCapabilities?: {
|
||||||
|
details?: {
|
||||||
|
infrastructureEndpoints?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useServerCapabilities() {
|
||||||
|
return useQuery<{ infrastructureEndpoints: boolean }>({
|
||||||
|
queryKey: ['server-capabilities'],
|
||||||
|
queryFn: async () => {
|
||||||
|
const res = await fetch(config.apiBaseUrl + '/health');
|
||||||
|
if (!res.ok) return { infrastructureEndpoints: true };
|
||||||
|
const data: HealthResponse = await res.json();
|
||||||
|
return {
|
||||||
|
infrastructureEndpoints:
|
||||||
|
data.components?.serverCapabilities?.details?.infrastructureEndpoints ?? true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
staleTime: Infinity,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ import {
|
|||||||
readCollapsed,
|
readCollapsed,
|
||||||
writeCollapsed,
|
writeCollapsed,
|
||||||
} from './sidebar-utils';
|
} from './sidebar-utils';
|
||||||
|
import { useServerCapabilities } from '../api/queries/capabilities';
|
||||||
import type { SidebarApp } from './sidebar-utils';
|
import type { SidebarApp } from './sidebar-utils';
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
@@ -290,6 +291,9 @@ function LayoutContent() {
|
|||||||
const globalFilters = useGlobalFilters();
|
const globalFilters = useGlobalFilters();
|
||||||
const { timeRange, autoRefresh, refreshTimeRange } = globalFilters;
|
const { timeRange, autoRefresh, refreshTimeRange } = globalFilters;
|
||||||
|
|
||||||
|
// --- Server capabilities ------------------------------------------
|
||||||
|
const { data: capabilities } = useServerCapabilities();
|
||||||
|
|
||||||
// --- Role checks ----------------------------------------------------
|
// --- Role checks ----------------------------------------------------
|
||||||
const isAdmin = useIsAdmin();
|
const isAdmin = useIsAdmin();
|
||||||
|
|
||||||
@@ -432,8 +436,8 @@ function LayoutContent() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const adminTreeNodes: SidebarTreeNode[] = useMemo(
|
const adminTreeNodes: SidebarTreeNode[] = useMemo(
|
||||||
() => buildAdminTreeNodes(),
|
() => buildAdminTreeNodes({ infrastructureEndpoints: capabilities?.infrastructureEndpoints }),
|
||||||
[],
|
[capabilities?.infrastructureEndpoints],
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Starred items ------------------------------------------------
|
// --- Starred items ------------------------------------------------
|
||||||
|
|||||||
@@ -99,13 +99,15 @@ export function buildAppTreeNodes(
|
|||||||
/**
|
/**
|
||||||
* Admin tree — static nodes, alphabetically sorted.
|
* Admin tree — static nodes, alphabetically sorted.
|
||||||
*/
|
*/
|
||||||
export function buildAdminTreeNodes(): SidebarTreeNode[] {
|
export function buildAdminTreeNodes(opts?: { infrastructureEndpoints?: boolean }): SidebarTreeNode[] {
|
||||||
return [
|
const showInfra = opts?.infrastructureEndpoints !== false;
|
||||||
|
const nodes: SidebarTreeNode[] = [
|
||||||
{ id: 'admin:audit', label: 'Audit Log', path: '/admin/audit' },
|
{ id: 'admin:audit', label: 'Audit Log', path: '/admin/audit' },
|
||||||
{ id: 'admin:clickhouse', label: 'ClickHouse', path: '/admin/clickhouse' },
|
...(showInfra ? [{ id: 'admin:clickhouse', label: 'ClickHouse', path: '/admin/clickhouse' }] : []),
|
||||||
{ id: 'admin:database', label: 'Database', path: '/admin/database' },
|
...(showInfra ? [{ id: 'admin:database', label: 'Database', path: '/admin/database' }] : []),
|
||||||
{ id: 'admin:environments', label: 'Environments', path: '/admin/environments' },
|
{ id: 'admin:environments', label: 'Environments', path: '/admin/environments' },
|
||||||
{ id: 'admin:oidc', label: 'OIDC', path: '/admin/oidc' },
|
{ id: 'admin:oidc', label: 'OIDC', path: '/admin/oidc' },
|
||||||
{ id: 'admin:rbac', label: 'Users & Roles', path: '/admin/rbac' },
|
{ id: 'admin:rbac', label: 'Users & Roles', path: '/admin/rbac' },
|
||||||
];
|
];
|
||||||
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user