feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
import { useEffect , useState } from 'react' ;
2026-03-23 18:25:14 +01:00
import { Button , Input , Toggle , FormField , Card , Alert , SectionHeader , Tag , ConfirmDialog } from '@cameleer/design-system' ;
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
import { adminFetch } from '../../api/queries/admin/admin-api' ;
2026-03-23 18:25:14 +01:00
import styles from './OidcConfigPage.module.css' ;
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
interface OidcConfig {
enabled : boolean ;
issuerUri : string ;
clientId : string ;
clientSecret : string ;
rolesClaim : string ;
defaultRoles : string [ ] ;
autoSignup : boolean ;
displayNameClaim : string ;
}
export default function OidcConfigPage() {
const [ config , setConfig ] = useState < OidcConfig | null > ( null ) ;
const [ saving , setSaving ] = useState ( false ) ;
const [ error , setError ] = useState < string | null > ( null ) ;
const [ success , setSuccess ] = useState ( false ) ;
2026-03-23 18:25:14 +01:00
const [ newRole , setNewRole ] = useState ( '' ) ;
const [ deleteOpen , setDeleteOpen ] = useState ( false ) ;
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
useEffect ( ( ) = > {
adminFetch < OidcConfig > ( '/oidc' )
. then ( setConfig )
. catch ( ( ) = > setConfig ( { enabled : false , issuerUri : '' , clientId : '' , clientSecret : '' , rolesClaim : 'roles' , defaultRoles : [ 'VIEWER' ] , autoSignup : true , displayNameClaim : 'name' } ) ) ;
} , [ ] ) ;
const handleSave = async ( ) = > {
if ( ! config ) return ;
setSaving ( true ) ;
setError ( null ) ;
try {
await adminFetch ( '/oidc' , { method : 'PUT' , body : JSON.stringify ( config ) } ) ;
setSuccess ( true ) ;
setTimeout ( ( ) = > setSuccess ( false ) , 3000 ) ;
} catch ( e : any ) {
setError ( e . message ) ;
} finally {
setSaving ( false ) ;
}
} ;
const handleDelete = async ( ) = > {
try {
await adminFetch ( '/oidc' , { method : 'DELETE' } ) ;
setConfig ( { enabled : false , issuerUri : '' , clientId : '' , clientSecret : '' , rolesClaim : 'roles' , defaultRoles : [ 'VIEWER' ] , autoSignup : true , displayNameClaim : 'name' } ) ;
} catch ( e : any ) {
setError ( e . message ) ;
}
} ;
if ( ! config ) return null ;
return (
< div >
< h2 style = { { marginBottom : '1rem' } } > OIDC Configuration < / h2 >
< Card >
< div style = { { padding : '1.5rem' , display : 'grid' , gap : '1rem' } } >
< Toggle checked = { config . enabled } onChange = { ( e ) = > setConfig ( { . . . config , enabled : e.target.checked } ) } label = "Enable OIDC" / >
< FormField label = "Issuer URI" > < Input value = { config . issuerUri } onChange = { ( e ) = > setConfig ( { . . . config , issuerUri : e.target.value } ) } / > < / FormField >
< FormField label = "Client ID" > < Input value = { config . clientId } onChange = { ( e ) = > setConfig ( { . . . config , clientId : e.target.value } ) } / > < / FormField >
< FormField label = "Client Secret" > < Input type = "password" value = { config . clientSecret } onChange = { ( e ) = > setConfig ( { . . . config , clientSecret : e.target.value } ) } / > < / FormField >
< FormField label = "Roles Claim" > < Input value = { config . rolesClaim } onChange = { ( e ) = > setConfig ( { . . . config , rolesClaim : e.target.value } ) } / > < / FormField >
< FormField label = "Display Name Claim" > < Input value = { config . displayNameClaim } onChange = { ( e ) = > setConfig ( { . . . config , displayNameClaim : e.target.value } ) } / > < / FormField >
< Toggle checked = { config . autoSignup } onChange = { ( e ) = > setConfig ( { . . . config , autoSignup : e.target.checked } ) } label = "Auto Signup" / >
2026-03-23 18:25:14 +01:00
< div className = { styles . section } >
< h3 > Default Roles < / h3 >
< div className = { styles . tagRow } >
{ ( config . defaultRoles || [ ] ) . map ( role = > (
< Tag key = { role } label = { role } onRemove = { ( ) = > {
setConfig ( prev = > ( { . . . prev ! , defaultRoles : prev ! . defaultRoles . filter ( r = > r !== role ) } ) ) ;
} } / >
) ) }
< / div >
< div className = { styles . addRow } >
< Input placeholder = "Add role..." value = { newRole } onChange = { e = > setNewRole ( e . target . value ) } / >
< Button onClick = { ( ) = > {
if ( newRole . trim ( ) && ! config . defaultRoles ? . includes ( newRole . trim ( ) ) ) {
setConfig ( prev = > ( { . . . prev ! , defaultRoles : [ . . . ( prev ! . defaultRoles || [ ] ) , newRole . trim ( ) ] } ) ) ;
setNewRole ( '' ) ;
}
} } > Add < / Button >
< / div >
< / div >
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
< div style = { { display : 'flex' , gap : '0.75rem' } } >
< Button variant = "primary" onClick = { handleSave } disabled = { saving } > { saving ? 'Saving...' : 'Save' } < / Button >
2026-03-23 18:25:14 +01:00
< Button variant = "danger" onClick = { ( ) = > setDeleteOpen ( true ) } > Delete Configuration < / Button >
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
< / div >
{ error && < Alert variant = "error" > { error } < / Alert > }
{ success && < Alert variant = "success" > Configuration saved < / Alert > }
< / div >
< / Card >
2026-03-23 18:25:14 +01:00
< ConfirmDialog
open = { deleteOpen }
onClose = { ( ) = > setDeleteOpen ( false ) }
onConfirm = { handleDelete }
title = "Delete OIDC Configuration"
message = "Delete OIDC configuration? All OIDC users will lose access."
confirmText = "DELETE"
/ >
feat: migrate UI to @cameleer/design-system, add backend endpoints
Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)
Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg
CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:39 +01:00
< / div >
) ;
}