feat: role-based UI access control
- 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:
@@ -1,5 +1,6 @@
|
||||
import { createBrowserRouter, Navigate, useParams } from 'react-router';
|
||||
import { ProtectedRoute } from './auth/ProtectedRoute';
|
||||
import { RequireAdmin } from './auth/RequireAdmin';
|
||||
import { LoginPage } from './auth/LoginPage';
|
||||
import { OidcCallback } from './auth/OidcCallback';
|
||||
import { LayoutShell } from './components/LayoutShell';
|
||||
@@ -76,6 +77,10 @@ export const router = createBrowserRouter([
|
||||
{ path: 'logs/:appId', element: <SuspenseWrapper><LogsPage /></SuspenseWrapper> },
|
||||
{ path: 'logs/:appId/:routeId', element: <SuspenseWrapper><LogsPage /></SuspenseWrapper> },
|
||||
|
||||
// Config tab (per-app, accessible to VIEWER+)
|
||||
{ path: 'config', element: <Navigate to="/exchanges" replace /> },
|
||||
{ path: 'config/:appId', element: <SuspenseWrapper><AppConfigPage /></SuspenseWrapper> },
|
||||
|
||||
// Legacy redirects — Sidebar uses hardcoded /apps/... and /agents/... paths
|
||||
{ path: 'apps', element: <Navigate to="/exchanges" replace /> },
|
||||
{ path: 'apps/:appId', element: <LegacyAppRedirect /> },
|
||||
@@ -84,19 +89,21 @@ export const router = createBrowserRouter([
|
||||
{ path: 'agents/:appId', element: <LegacyAgentRedirect /> },
|
||||
{ path: 'agents/:appId/:instanceId', element: <LegacyAgentRedirect /> },
|
||||
|
||||
// Admin (unchanged)
|
||||
// Admin (ADMIN role required)
|
||||
{
|
||||
path: 'admin',
|
||||
element: <SuspenseWrapper><AdminLayout /></SuspenseWrapper>,
|
||||
children: [
|
||||
{ index: true, element: <Navigate to="/admin/rbac" replace /> },
|
||||
{ path: 'rbac', element: <SuspenseWrapper><RbacPage /></SuspenseWrapper> },
|
||||
{ path: 'audit', element: <SuspenseWrapper><AuditLogPage /></SuspenseWrapper> },
|
||||
{ path: 'oidc', element: <SuspenseWrapper><OidcConfigPage /></SuspenseWrapper> },
|
||||
{ path: 'appconfig', element: <SuspenseWrapper><AppConfigPage /></SuspenseWrapper> },
|
||||
{ path: 'database', element: <SuspenseWrapper><DatabaseAdminPage /></SuspenseWrapper> },
|
||||
{ path: 'clickhouse', element: <SuspenseWrapper><ClickHouseAdminPage /></SuspenseWrapper> },
|
||||
],
|
||||
element: <RequireAdmin />,
|
||||
children: [{
|
||||
path: 'admin',
|
||||
element: <SuspenseWrapper><AdminLayout /></SuspenseWrapper>,
|
||||
children: [
|
||||
{ index: true, element: <Navigate to="/admin/rbac" replace /> },
|
||||
{ path: 'rbac', element: <SuspenseWrapper><RbacPage /></SuspenseWrapper> },
|
||||
{ path: 'audit', element: <SuspenseWrapper><AuditLogPage /></SuspenseWrapper> },
|
||||
{ path: 'oidc', element: <SuspenseWrapper><OidcConfigPage /></SuspenseWrapper> },
|
||||
{ path: 'database', element: <SuspenseWrapper><DatabaseAdminPage /></SuspenseWrapper> },
|
||||
{ path: 'clickhouse', element: <SuspenseWrapper><ClickHouseAdminPage /></SuspenseWrapper> },
|
||||
],
|
||||
}],
|
||||
},
|
||||
{ path: 'api-docs', element: <SuspenseWrapper><SwaggerPage /></SuspenseWrapper> },
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user