Files
AfiS-Aktensystem/web/app/(app)/admin/rollen/page.tsx
T
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

79 lines
2.8 KiB
TypeScript

import type { Metadata } from 'next'
import { db } from '@/lib/db'
import { requirePermission } from '@/lib/auth/current'
import { de } from '@/lib/i18n/de'
import { RoleRow } from './RoleRow'
import { ClearancePreview } from './ClearancePreview'
export const metadata: Metadata = { title: de.roleAdmin.heading }
export const dynamic = 'force-dynamic'
/**
* Reihenfolge der Abschnitte: erst die Ränge, dann die Zugehörigkeit, dann die
* Zugangsrollen - so, wie die Abteilung sie selbst aufzählt. Innerhalb eines
* Abschnitts entscheidet die Position der Rolle auf dem Discord-Server, oben
* die höchste. Damit steht die Hierarchie an einer Stelle, die ohnehin gepflegt
* wird, statt in einer zweiten Sortierung in dieser Anwendung.
*/
const ORDER = ['RANK', 'MEMBERSHIP', 'CLEARANCE', 'UNSORTED'] as const
export default async function RoleAdminPage() {
// Ohne roles.manage gibt es 404, nicht 403.
await requirePermission('roles.manage')
const [mappings, levels] = await Promise.all([
db.roleMapping.findMany({ orderBy: [{ sortOrder: 'desc' }, { label: 'asc' }] }),
db.clearanceLevelConfig.findMany({ orderBy: { level: 'asc' } }),
])
return (
<section>
<h2 className="font-condensed">{de.roleAdmin.heading}</h2>
<p className="mt-2 max-w-(--container-measure) text-text-dim">{de.roleAdmin.intro}</p>
{mappings.length === 0 ? (
<p className="mt-8 text-text-dim">{de.roleAdmin.empty}</p>
) : (
<>
<ClearancePreview
levels={levels}
mappings={mappings.map((m) => ({
label: m.label,
clearanceLevel: m.clearanceLevel,
}))}
/>
{ORDER.map((category) => {
const rows = mappings.filter((m) => m.category === category)
if (rows.length === 0) return null
return (
<section key={category} className="mt-10">
<h2 className="font-condensed text-text-dim">
{de.roleAdmin.categories[category]}
</h2>
<div className="mt-2 border-t border-line">
{rows.map((role) => (
<RoleRow
key={role.discordRoleId}
role={{
discordRoleId: role.discordRoleId,
label: role.label,
clearanceLevel: role.clearanceLevel,
grantsMembership: role.grantsMembership,
category: role.category,
permissions: role.permissions,
isPresent: role.isPresent,
}}
levels={levels.map((l) => ({ level: l.level, name: l.name }))}
/>
))}
</div>
</section>
)
})}
</>
)}
</section>
)
}