feat: role-based UI access control
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / docker (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / deploy-feature (push) Has been cancelled
CI / build (push) Has been cancelled

- Hide Admin sidebar section for non-ADMIN users
- Add RequireAdmin route guard — /admin/* redirects to / for non-admin
- Move App Config from admin section to main Config tab (per-app,
  visible when app selected). VIEWER sees read-only, OPERATOR+ can edit
- Hide diagram node toolbar for VIEWER (onNodeAction conditional)
- Add useIsAdmin/useCanControl helpers to centralize role checks
- Remove App Config from admin sidebar tree

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-06 15:51:15 +02:00
parent e54f308607
commit b1655b366e
10 changed files with 84 additions and 50 deletions

View File

@@ -7,7 +7,7 @@ import { useRouteCatalog } from '../../api/queries/catalog';
import { useAgents } from '../../api/queries/agents';
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
import type { TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
import { useAuthStore } from '../../auth/auth-store';
import { useCanControl } from '../../auth/auth-store';
import { useTracingStore } from '../../stores/tracing-store';
import type { NodeAction, NodeConfig } from '../../components/ProcessDiagram/types';
import { TapConfigModal } from '../../components/TapConfigModal';
@@ -154,8 +154,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
// Route state + capabilities for topology-only control bar
const { data: agents } = useAgents(undefined, appId);
const roles = useAuthStore((s) => s.roles);
const canControl = roles.some(r => r === 'OPERATOR' || r === 'ADMIN');
const canControl = useCanControl();
const { hasRouteControl, hasReplay } = useMemo(() => {
if (!agents) return { hasRouteControl: false, hasReplay: false };
const agentList = agents as any[];
@@ -332,7 +331,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
executionDetail={detail}
knownRouteIds={knownRouteIds}
endpointRouteMap={endpointRouteMap}
onNodeAction={handleNodeAction}
onNodeAction={canControl ? handleNodeAction : undefined}
nodeConfigs={nodeConfigs}
/>
{tapModal}
@@ -359,7 +358,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
diagramLayout={diagramQuery.data}
knownRouteIds={knownRouteIds}
endpointRouteMap={endpointRouteMap}
onNodeAction={handleNodeAction}
onNodeAction={canControl ? handleNodeAction : undefined}
nodeConfigs={nodeConfigs}
/>
{tapModal}