Inline filtering results, select-all across pages, country flags, settings RBAC, and inline role changes

- Round detail: add skeleton loading for filtering stats, inline results table
  with expandable rows, pagination, override/reinstate, CSV export, and tooltip
  on AI summaries button (removes need for separate results page)
- Projects: add select-all-across-pages with Gmail-style banner, show country
  flags with tooltip instead of country codes (table + card views), add listAllIds
  backend endpoint
- Settings: allow PROGRAM_ADMIN access to settings page, restrict infrastructure
  tabs (AI, Email, Storage, Security, Webhooks) to SUPER_ADMIN only
- Members: add inline role change via dropdown submenu in user actions, enforce
  role hierarchy (only super admins can modify admin/super-admin roles) in both
  backend and UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-10 23:07:38 +01:00
parent 5cae78fe0c
commit 5c8d22ac11
9 changed files with 1257 additions and 197 deletions

View File

@@ -42,11 +42,16 @@ const TAB_ROLES: Record<TabKey, RoleValue[] | undefined> = {
}
const statusColors: Record<string, 'default' | 'success' | 'secondary' | 'destructive'> = {
NONE: 'secondary',
ACTIVE: 'success',
INVITED: 'secondary',
SUSPENDED: 'destructive',
}
const statusLabels: Record<string, string> = {
NONE: 'Not Invited',
}
const roleColors: Record<string, 'default' | 'outline' | 'secondary'> = {
JURY_MEMBER: 'default',
MENTOR: 'secondary',
@@ -92,6 +97,9 @@ export function MembersContent() {
const roles = TAB_ROLES[tab]
const { data: currentUser } = trpc.user.me.useQuery()
const currentUserRole = currentUser?.role as RoleValue | undefined
const { data, isLoading } = trpc.user.list.useQuery({
roles: roles,
search: search || undefined,
@@ -216,7 +224,7 @@ export function MembersContent() {
</TableCell>
<TableCell>
<Badge variant={statusColors[user.status] || 'secondary'}>
{user.status}
{statusLabels[user.status] || user.status}
</Badge>
</TableCell>
<TableCell>
@@ -233,6 +241,8 @@ export function MembersContent() {
userId={user.id}
userEmail={user.email}
userStatus={user.status}
userRole={user.role as RoleValue}
currentUserRole={currentUserRole}
/>
</TableCell>
</TableRow>
@@ -263,7 +273,7 @@ export function MembersContent() {
</div>
</div>
<Badge variant={statusColors[user.status] || 'secondary'}>
{user.status}
{statusLabels[user.status] || user.status}
</Badge>
</div>
</CardHeader>
@@ -305,6 +315,8 @@ export function MembersContent() {
userId={user.id}
userEmail={user.email}
userStatus={user.status}
userRole={user.role as RoleValue}
currentUserRole={currentUserRole}
/>
</CardContent>
</Card>