2026-03-18 23:10:58 +01:00
import { useState , useMemo } from 'react'
import { Avatar } from '../../../design-system/primitives/Avatar/Avatar'
import { Badge } from '../../../design-system/primitives/Badge/Badge'
import { Button } from '../../../design-system/primitives/Button/Button'
import { Input } from '../../../design-system/primitives/Input/Input'
import { MonoText } from '../../../design-system/primitives/MonoText/MonoText'
import { SectionHeader } from '../../../design-system/primitives/SectionHeader/SectionHeader'
import { Tag } from '../../../design-system/primitives/Tag/Tag'
import { InlineEdit } from '../../../design-system/primitives/InlineEdit/InlineEdit'
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
import { RadioGroup , RadioItem } from '../../../design-system/primitives/Radio/Radio'
import { InfoCallout } from '../../../design-system/primitives/InfoCallout/InfoCallout'
2026-03-18 23:10:58 +01:00
import { MultiSelect } from '../../../design-system/composites/MultiSelect/MultiSelect'
import { ConfirmDialog } from '../../../design-system/composites/ConfirmDialog/ConfirmDialog'
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
import { AlertDialog } from '../../../design-system/composites/AlertDialog/AlertDialog'
import { useToast } from '../../../design-system/composites/Toast/Toast'
2026-03-18 23:10:58 +01:00
import { MOCK_USERS , MOCK_GROUPS , MOCK_ROLES , getEffectiveRoles , type MockUser } from './rbacMocks'
import styles from './UserManagement.module.css'
export function UsersTab() {
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
const { toast } = useToast ( )
2026-03-18 23:10:58 +01:00
const [ users , setUsers ] = useState ( MOCK_USERS )
const [ search , setSearch ] = useState ( '' )
const [ selectedId , setSelectedId ] = useState < string | null > ( null )
const [ creating , setCreating ] = useState ( false )
const [ deleteTarget , setDeleteTarget ] = useState < MockUser | null > ( null )
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
const [ removeGroupTarget , setRemoveGroupTarget ] = useState < string | null > ( null )
2026-03-18 23:10:58 +01:00
// Create form state
const [ newUsername , setNewUsername ] = useState ( '' )
const [ newDisplay , setNewDisplay ] = useState ( '' )
const [ newEmail , setNewEmail ] = useState ( '' )
const [ newPassword , setNewPassword ] = useState ( '' )
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
const [ newProvider , setNewProvider ] = useState < 'local' | 'oidc' > ( 'local' )
const [ resettingPassword , setResettingPassword ] = useState ( false )
const [ newPw , setNewPw ] = useState ( '' )
2026-03-18 23:10:58 +01:00
const filtered = useMemo ( ( ) = > {
if ( ! search ) return users
const q = search . toLowerCase ( )
return users . filter ( ( u ) = >
u . displayName . toLowerCase ( ) . includes ( q ) ||
u . email . toLowerCase ( ) . includes ( q ) ||
u . username . toLowerCase ( ) . includes ( q )
)
} , [ users , search ] )
const selected = users . find ( ( u ) = > u . id === selectedId ) ? ? null
function handleCreate() {
if ( ! newUsername . trim ( ) ) return
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
if ( newProvider === 'local' && ! newPassword . trim ( ) ) return
2026-03-18 23:10:58 +01:00
const newUser : MockUser = {
id : ` usr- ${ Date . now ( ) } ` ,
username : newUsername.trim ( ) ,
displayName : newDisplay.trim ( ) || newUsername . trim ( ) ,
email : newEmail.trim ( ) ,
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
provider : newProvider ,
2026-03-18 23:10:58 +01:00
createdAt : new Date ( ) . toISOString ( ) ,
directRoles : [ ] ,
directGroups : [ ] ,
}
setUsers ( ( prev ) = > [ . . . prev , newUser ] )
setCreating ( false )
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
setNewUsername ( '' ) ; setNewDisplay ( '' ) ; setNewEmail ( '' ) ; setNewPassword ( '' ) ; setNewProvider ( 'local' )
2026-03-18 23:10:58 +01:00
setSelectedId ( newUser . id )
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
setResettingPassword ( false )
toast ( { title : 'User created' , description : newUser.displayName , variant : 'success' } )
2026-03-18 23:10:58 +01:00
}
function handleDelete() {
if ( ! deleteTarget ) return
setUsers ( ( prev ) = > prev . filter ( ( u ) = > u . id !== deleteTarget . id ) )
if ( selectedId === deleteTarget . id ) setSelectedId ( null )
setDeleteTarget ( null )
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
toast ( { title : 'User deleted' , description : deleteTarget.username , variant : 'warning' } )
2026-03-18 23:10:58 +01:00
}
function updateUser ( id : string , patch : Partial < MockUser > ) {
setUsers ( ( prev ) = > prev . map ( ( u ) = > u . id === id ? { . . . u , . . . patch } : u ) )
}
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
const duplicateUsername = newUsername . trim ( ) !== '' && users . some ( ( u ) = > u . username . toLowerCase ( ) === newUsername . trim ( ) . toLowerCase ( ) )
2026-03-18 23:10:58 +01:00
const effectiveRoles = selected ? getEffectiveRoles ( selected ) : [ ]
const availableGroups = MOCK_GROUPS . filter ( ( g ) = > ! selected ? . directGroups . includes ( g . id ) )
. map ( ( g ) = > ( { value : g.id , label : g.name } ) )
const availableRoles = MOCK_ROLES . filter ( ( r ) = > ! selected ? . directRoles . includes ( r . name ) )
. map ( ( r ) = > ( { value : r.name , label : r.name } ) )
function getUserGroupPath ( user : MockUser ) : string {
if ( user . directGroups . length === 0 ) return 'no groups'
const group = MOCK_GROUPS . find ( ( g ) = > g . id === user . directGroups [ 0 ] )
if ( ! group ) return 'no groups'
const parent = group . parentId ? MOCK_GROUPS . find ( ( g ) = > g . id === group . parentId ) : null
return parent ? ` ${ parent . name } > ${ group . name } ` : group . name
}
return (
< >
< div className = { styles . splitPane } >
< div className = { styles . listPane } >
< div className = { styles . listHeader } >
< Input
placeholder = "Search users..."
value = { search }
onChange = { ( e ) = > setSearch ( e . target . value ) }
onClear = { ( ) = > setSearch ( '' ) }
className = { styles . listHeaderSearch }
/ >
< Button size = "sm" variant = "secondary" onClick = { ( ) = > setCreating ( true ) } >
+ Add user
< / Button >
< / div >
{ creating && (
< div className = { styles . createForm } >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< RadioGroup name = "provider" value = { newProvider } onChange = { ( v ) = > setNewProvider ( v as 'local' | 'oidc' ) } orientation = "horizontal" >
< RadioItem value = "local" label = "Local" / >
< RadioItem value = "oidc" label = "OIDC" / >
< / RadioGroup >
2026-03-18 23:10:58 +01:00
< div className = { styles . createFormRow } >
< Input placeholder = "Username *" value = { newUsername } onChange = { ( e ) = > setNewUsername ( e . target . value ) } / >
< Input placeholder = "Display name" value = { newDisplay } onChange = { ( e ) = > setNewDisplay ( e . target . value ) } / >
< / div >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
{ duplicateUsername && < span style = { { color : 'var(--error)' , fontSize : 11 } } > Username already exists < / span > }
< Input placeholder = "Email" value = { newEmail } onChange = { ( e ) = > setNewEmail ( e . target . value ) } / >
{ newProvider === 'local' && (
< Input placeholder = "Password *" type = "password" value = { newPassword } onChange = { ( e ) = > setNewPassword ( e . target . value ) } / >
) }
{ newProvider === 'oidc' && (
< InfoCallout variant = "amber" >
OIDC users authenticate via the configured identity provider . Pre - register to assign roles / groups before their first login .
< / InfoCallout >
) }
2026-03-18 23:10:58 +01:00
< div className = { styles . createFormActions } >
< Button size = "sm" variant = "ghost" onClick = { ( ) = > setCreating ( false ) } > Cancel < / Button >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< Button
size = "sm"
variant = "primary"
onClick = { handleCreate }
disabled = { ! newUsername . trim ( ) || ( newProvider === 'local' && ! newPassword . trim ( ) ) || duplicateUsername }
>
Create
< / Button >
2026-03-18 23:10:58 +01:00
< / div >
< / div >
) }
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< div className = { styles . entityList } role = "listbox" aria-label = "Users" >
2026-03-18 23:10:58 +01:00
{ filtered . map ( ( user ) = > (
< div
key = { user . id }
className = { ` ${ styles . entityItem } ${ selectedId === user . id ? styles . entityItemSelected : '' } ` }
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
onClick = { ( ) = > { setSelectedId ( user . id ) ; setResettingPassword ( false ) } }
role = "option"
tabIndex = { 0 }
aria - selected = { selectedId === user . id }
onKeyDown = { ( e ) = > { if ( e . key === 'Enter' || e . key === ' ' ) { e . preventDefault ( ) ; setSelectedId ( user . id ) ; setResettingPassword ( false ) } } }
2026-03-18 23:10:58 +01:00
>
< Avatar name = { user . displayName } size = "sm" / >
< div className = { styles . entityInfo } >
< div className = { styles . entityName } >
{ user . displayName }
{ user . provider !== 'local' && (
< Badge label = { user . provider } color = "running" variant = "outlined" className = { styles . providerBadge } / >
) }
< / div >
< div className = { styles . entityMeta } >
{ user . email } & middot ; { getUserGroupPath ( user ) }
< / div >
< div className = { styles . entityTags } >
{ user . directRoles . map ( ( r ) = > < Badge key = { r } label = { r } color = "warning" / > ) }
{ user . directGroups . map ( ( gId ) = > {
const g = MOCK_GROUPS . find ( ( gr ) = > gr . id === gId )
return g ? < Badge key = { gId } label = { g . name } color = "success" / > : null
} ) }
< / div >
< / div >
< / div >
) ) }
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
{ filtered . length === 0 && (
< div className = { styles . emptySearch } > No users match your search < / div >
) }
2026-03-18 23:10:58 +01:00
< / div >
< / div >
< div className = { styles . detailPane } >
{ selected ? (
< >
< div className = { styles . detailHeader } >
< Avatar name = { selected . displayName } size = "lg" / >
< div className = { styles . detailHeaderInfo } >
< div className = { styles . detailName } >
< InlineEdit
value = { selected . displayName }
onSave = { ( v ) = > updateUser ( selected . id , { displayName : v } ) }
/ >
< / div >
< div className = { styles . detailEmail } > { selected . email } < / div >
< / div >
< Button
size = "sm"
variant = "danger"
onClick = { ( ) = > setDeleteTarget ( selected ) }
disabled = { selected . username === 'hendrik' }
>
Delete
< / Button >
< / div >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< SectionHeader > Status < / SectionHeader >
< div className = { styles . sectionTags } >
< Tag label = "Active" color = "success" / >
< / div >
2026-03-18 23:10:58 +01:00
< div className = { styles . metaGrid } >
< span className = { styles . metaLabel } > ID < / span >
< MonoText size = "xs" > { selected . id } < / MonoText >
< span className = { styles . metaLabel } > Created < / span >
< span className = { styles . metaValue } > { new Date ( selected . createdAt ) . toLocaleDateString ( ) } < / span >
< span className = { styles . metaLabel } > Provider < / span >
< span className = { styles . metaValue } > { selected . provider } < / span >
< / div >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< SectionHeader > Security < / SectionHeader >
< div className = { styles . securitySection } >
{ selected . provider === 'local' ? (
< >
< div className = { styles . securityRow } >
< span className = { styles . metaLabel } > Password < / span >
< span className = { styles . passwordDots } > • • • • • • • • < / span >
{ ! resettingPassword && (
< Button size = "sm" variant = "ghost" onClick = { ( ) = > { setResettingPassword ( true ) ; setNewPw ( '' ) } } >
Reset password
< / Button >
) }
< / div >
{ resettingPassword && (
< div className = { styles . resetForm } >
< Input
placeholder = "New password"
type = "password"
value = { newPw }
onChange = { ( e ) = > setNewPw ( e . target . value ) }
className = { styles . resetInput }
/ >
< Button size = "sm" variant = "ghost" onClick = { ( ) = > setResettingPassword ( false ) } > Cancel < / Button >
< Button
size = "sm"
variant = "primary"
onClick = { ( ) = > { setResettingPassword ( false ) ; toast ( { title : 'Password updated' , description : selected.username , variant : 'success' } ) } }
disabled = { ! newPw . trim ( ) }
>
Set
< / Button >
< / div >
) }
< / >
) : (
< >
< div className = { styles . securityRow } >
< span className = { styles . metaLabel } > Authentication < / span >
< span className = { styles . metaValue } > OIDC ( { selected . provider } ) < / span >
< / div >
< InfoCallout variant = "amber" >
Password managed by the identity provider .
< / InfoCallout >
< / >
) }
< / div >
2026-03-18 23:10:58 +01:00
< SectionHeader > Group membership ( direct only ) < / SectionHeader >
< div className = { styles . sectionTags } >
{ selected . directGroups . map ( ( gId ) = > {
const g = MOCK_GROUPS . find ( ( gr ) = > gr . id === gId )
return g ? (
< Tag
key = { gId }
label = { g . name }
color = "success"
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
onRemove = { ( ) = > {
const group = MOCK_GROUPS . find ( ( gr ) = > gr . id === gId )
if ( group && group . directRoles . length > 0 ) {
setRemoveGroupTarget ( gId )
} else {
updateUser ( selected . id , { directGroups : selected.directGroups.filter ( ( id ) = > id !== gId ) } )
toast ( { title : 'Group removed' , variant : 'success' } )
}
} }
2026-03-18 23:10:58 +01:00
/ >
) : null
} ) }
{ selected . directGroups . length === 0 && (
< span className = { styles . inheritedNote } > ( no groups ) < / span >
) }
< MultiSelect
options = { availableGroups }
value = { [ ] }
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
onChange = { ( ids ) = > {
updateUser ( selected . id , { directGroups : [ . . . selected . directGroups , . . . ids ] } )
toast ( { title : ` ${ ids . length } group(s) added ` , variant : 'success' } )
} }
placeholder = "+ Add"
2026-03-18 23:10:58 +01:00
/ >
< / div >
< SectionHeader > Effective roles ( direct + inherited ) < / SectionHeader >
< div className = { styles . sectionTags } >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
{ effectiveRoles . map ( ( { role , source } ) = >
source === 'direct' ? (
< Tag
key = { role }
label = { role }
color = "warning"
onRemove = { ( ) = > {
updateUser ( selected . id , { directRoles : selected.directRoles.filter ( ( r ) = > r !== role ) } )
toast ( { title : 'Role removed' , description : role , variant : 'success' } )
} }
/ >
) : (
< Badge
key = { role }
label = { ` ${ role } ↑ ${ source } ` }
color = "warning"
variant = "dashed"
className = { styles . inherited }
/ >
)
) }
2026-03-18 23:10:58 +01:00
{ effectiveRoles . length === 0 && (
< span className = { styles . inheritedNote } > ( no roles ) < / span >
) }
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< MultiSelect
options = { availableRoles }
value = { [ ] }
onChange = { ( roles ) = > {
updateUser ( selected . id , { directRoles : [ . . . selected . directRoles , . . . roles ] } )
toast ( { title : ` ${ roles . length } role(s) added ` , variant : 'success' } )
} }
placeholder = "+ Add"
/ >
2026-03-18 23:10:58 +01:00
< / div >
{ effectiveRoles . some ( ( r ) = > r . source !== 'direct' ) && (
< span className = { styles . inheritedNote } >
Roles with ↑ are inherited through group membership
< / span >
) }
< / >
) : (
< div className = { styles . emptyDetail } > Select a user to view details < / div >
) }
< / div >
< / div >
< ConfirmDialog
open = { deleteTarget !== null }
onClose = { ( ) = > setDeleteTarget ( null ) }
onConfirm = { handleDelete }
message = { ` Delete user " ${ deleteTarget ? . username } "? This cannot be undone. ` }
confirmText = { deleteTarget ? . username ? ? '' }
/ >
refactor: admin section UX/UI redesign
- Fix critical --bg-base token bug (dark mode broken), replace with --bg-surface
- Replace hand-rolled admin nav with Tabs composite (proper ARIA)
- Migrate AuditLog from custom table to DataTable with sorting, row accents, card wrapper
- Remove duplicate h2 page titles (breadcrumb + tab already identify the page)
- Rework user creation with provider-aware form (Local/OIDC RadioGroup)
- Add Security section with password reset for local users, OIDC info for external
- Add toast notifications to all RBAC mutations (create/delete/add/remove)
- Add confirmation dialogs for cascading removals (group/role)
- Add keyboard accessibility to entity lists (role/tabIndex/aria-selected)
- Add empty search states, duplicate name validation
- Replace lock emoji with Badge, fix radii/shadow/padding consistency
- Badge dashed variant keeps background color
- Inherited roles shown with dashed outline + reduced opacity
- Inline MultiSelect (+Add) for groups, roles, members, child groups
- Center OIDC form, replace inline styles with CSS modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:44:19 +01:00
< AlertDialog
open = { removeGroupTarget !== null }
onClose = { ( ) = > setRemoveGroupTarget ( null ) }
onConfirm = { ( ) = > {
if ( removeGroupTarget && selected ) {
updateUser ( selected . id , { directGroups : selected.directGroups.filter ( ( id ) = > id !== removeGroupTarget ) } )
toast ( { title : 'Group removed' , variant : 'success' } )
}
setRemoveGroupTarget ( null )
} }
title = "Remove group membership"
description = { ` Removing this group will also revoke inherited roles: ${ MOCK_GROUPS . find ( ( g ) = > g . id === removeGroupTarget ) ? . directRoles . join ( ', ' ) ? ? '' } . Continue? ` }
confirmLabel = "Remove"
variant = "warning"
/ >
2026-03-18 23:10:58 +01:00
< / >
)
}