feat(PROJ-69): Admin-Dashboard Tab-Gruppierung (2-Ebenen-Navigation)
17 flache Tabs unter /admin durch Gruppen-Leiste (Übersicht, Benutzer & Zugriff, Compliance, Mail-Eingang, System) ersetzt. Rollenbasierte Sichtbarkeit pro Tab unverändert, nur Navigation strukturiert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
8bd02facf5
commit
3b2a8388c1
+102
-24
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { useLDAPConfig } from "@/hooks/useLDAPConfig";
|
||||
import { useTenantLDAPConfig } from "@/hooks/useTenantLDAPConfig";
|
||||
@@ -135,6 +135,84 @@ export default function AdminPage() {
|
||||
loadServices();
|
||||
}, [user, loadUsers, loadAudit, loadServices]);
|
||||
|
||||
const tabGroups = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: "overview",
|
||||
label: "Übersicht",
|
||||
tabs: [
|
||||
{ value: "dashboard", label: "Dashboard", visible: true },
|
||||
{ value: "services", label: "Dienste", visible: isSuperAdmin },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "users",
|
||||
label: "Benutzer & Zugriff",
|
||||
tabs: [
|
||||
{ value: "users", label: "Benutzer", visible: true },
|
||||
{ value: "ldap", label: "LDAP (Global)", visible: isSuperAdmin, onClick: loadLDAP },
|
||||
{
|
||||
value: "tenant-ldap",
|
||||
label: "LDAP",
|
||||
visible: !isSuperAdmin && user?.role === "domain_admin",
|
||||
onClick: loadTenantLDAP,
|
||||
},
|
||||
{ value: "tenants", label: "Mandanten", visible: isSuperAdmin, onClick: tenantsState.loadTenants },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "compliance",
|
||||
label: "Compliance",
|
||||
tabs: [
|
||||
{ value: "audit", label: "Audit-Log", visible: true },
|
||||
{ value: "dsgvo", label: "DSGVO-Anfragen", visible: canViewDSGVO },
|
||||
{ value: "retention", label: "Retention", visible: isSuperAdmin },
|
||||
{ value: "archiving-rules", label: "Regeln", visible: isSuperAdmin },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "mail",
|
||||
label: "Mail-Eingang",
|
||||
tabs: [
|
||||
{ value: "import", label: "Import", visible: true },
|
||||
{ value: "imap-settings", label: "IMAP", visible: !isSuperAdmin },
|
||||
{ value: "routing-rules", label: "Routing-Regeln", visible: true },
|
||||
{ value: "smtp-out", label: "SMTP-Out", visible: isSuperAdmin },
|
||||
{ value: "quotas", label: "Quotas", visible: isSuperAdmin },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "system",
|
||||
label: "System",
|
||||
tabs: [
|
||||
{ value: "security", label: "Security", visible: isSuperAdmin },
|
||||
{ value: "cert", label: "Zertifikat", visible: isSuperAdmin, onClick: cert.loadCert },
|
||||
{ value: "modules", label: "Module", visible: isSuperAdmin },
|
||||
],
|
||||
},
|
||||
],
|
||||
[isSuperAdmin, canViewDSGVO, user?.role, loadLDAP, loadTenantLDAP, tenantsState.loadTenants, cert.loadCert]
|
||||
);
|
||||
|
||||
const visibleGroups = tabGroups
|
||||
.map((g) => ({ ...g, tabs: g.tabs.filter((t) => t.visible) }))
|
||||
.filter((g) => g.tabs.length > 0);
|
||||
|
||||
const [activeGroupId, setActiveGroupId] = useState(visibleGroups[0]?.id ?? "overview");
|
||||
const [activeTab, setActiveTab] = useState(visibleGroups[0]?.tabs[0]?.value ?? "dashboard");
|
||||
|
||||
const activeGroup = visibleGroups.find((g) => g.id === activeGroupId) ?? visibleGroups[0];
|
||||
|
||||
function handleGroupChange(groupId: string) {
|
||||
setActiveGroupId(groupId);
|
||||
const group = visibleGroups.find((g) => g.id === groupId);
|
||||
const firstTab = group?.tabs[0];
|
||||
if (firstTab) {
|
||||
setActiveTab(firstTab.value);
|
||||
firstTab.onClick?.();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Navbar username={user?.username ?? ""} role={user?.role ?? ""} />
|
||||
@@ -148,30 +226,30 @@ export default function AdminPage() {
|
||||
) : (<>
|
||||
<h1 className="mb-6 text-2xl font-bold">Administration</h1>
|
||||
|
||||
<Tabs defaultValue="dashboard">
|
||||
<div className="mb-4 flex flex-wrap gap-1 border-b pb-2">
|
||||
{visibleGroups.map((g) => (
|
||||
<button
|
||||
key={g.id}
|
||||
type="button"
|
||||
onClick={() => handleGroupChange(g.id)}
|
||||
className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
|
||||
g.id === activeGroup?.id
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{g.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||
<TabsList>
|
||||
<TabsTrigger value="dashboard">Dashboard</TabsTrigger>
|
||||
{isSuperAdmin && <TabsTrigger value="services">Dienste</TabsTrigger>}
|
||||
<TabsTrigger value="users">Benutzer</TabsTrigger>
|
||||
<TabsTrigger value="audit">Audit-Log</TabsTrigger>
|
||||
{canViewDSGVO && <TabsTrigger value="dsgvo">DSGVO-Anfragen</TabsTrigger>}
|
||||
<TabsTrigger value="import">Import</TabsTrigger>
|
||||
{isSuperAdmin && <TabsTrigger value="ldap" onClick={loadLDAP}>LDAP (Global)</TabsTrigger>}
|
||||
{!isSuperAdmin && user?.role === "domain_admin" && (
|
||||
<TabsTrigger value="tenant-ldap" onClick={loadTenantLDAP}>LDAP</TabsTrigger>
|
||||
)}
|
||||
{!isSuperAdmin && user?.role === "domain_admin" && (
|
||||
<TabsTrigger value="imap-settings">IMAP</TabsTrigger>
|
||||
)}
|
||||
{isSuperAdmin && <TabsTrigger value="security">Security</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="cert" onClick={cert.loadCert}>Zertifikat</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="tenants" onClick={tenantsState.loadTenants}>Mandanten</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="retention">Retention</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="archiving-rules">Regeln</TabsTrigger>}
|
||||
<TabsTrigger value="routing-rules">Routing-Regeln</TabsTrigger>
|
||||
{isSuperAdmin && <TabsTrigger value="quotas">Quotas</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="smtp-out">SMTP-Out</TabsTrigger>}
|
||||
{isSuperAdmin && <TabsTrigger value="modules">Module</TabsTrigger>}
|
||||
{activeGroup?.tabs.map((t) => (
|
||||
<TabsTrigger key={t.value} value={t.value} onClick={t.onClick}>
|
||||
{t.label}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="dashboard" className="mt-4 space-y-6">
|
||||
|
||||
Reference in New Issue
Block a user