feat: Verwaltungsmenü zu 3 Sammelseiten umgebaut - Benutzer & Rollen, Automatisierung, Backup
Backend Image / build-and-push (push) Successful in 2m17s
Frontend Image / build-and-push (push) Successful in 2m18s

Menü unter "Verwaltung" wie gewünscht neu strukturiert:

- "Benutzer & Rollen" (/settings/users-roles): Benutzerverwaltung und
  Rollen & Rechte als zwei Reiter auf einer Seite (vorher zwei
  getrennte Menüpunkte).
- "Automatisierung" (/settings/automation): Webhooks, Wiederkehrende
  Aufgaben, Etikettenvorlagen und Social Media Links als Reiter
  gebündelt - dazu (eigene Ergänzung, da sonst zwei fast gleich
  benannte Menüpunkte "Automatisierung"/"Automatisierungen"
  nebeneinander gestanden hätten) auch die bestehenden
  Automatisierungsregeln als fünfter Reiter "Regeln".
- "Backup" (/settings/backup): neuer voller Daten-Export/Import
  (Commit zuvor) plus der bisherige CSV-Import, beides auf einer Seite.

Aktiver Reiter wird als ?tab=... in der URL gehalten statt nur im
Client-State, damit z.B. "Speichern" im Etiketten-Designer wieder auf
den richtigen Reiter zurückführt.

Technisch: bestehende Seiteninhalte in Reiter-Komponenten extrahiert
(PageHeader entfernt, Rest unverändert übernommen), Dialog-Unterkomponenten
in die neuen Ordner verschoben (git mv, Historie bleibt erhalten). Die
Etiketten-Editor-Routen (/settings/label-templates/new, /[id]) bleiben
unverändert bestehen, nur der Rücksprung nach dem Speichern zeigt jetzt
auf den neuen Reiter. settings/layout.tsx's Berechtigungsliste um
label-templates:read, site-settings:read, backup:export/import ergänzt -
schließt nebenbei eine bestehende Lücke (eine Rolle mit ausschließlich
diesen Rechten wurde vorher faelschlich von der ganzen
Verwaltungssektion ausgesperrt.

Neuer Reiter-Baustein src/components/tab-switcher.tsx (generisch, nach
Vorbild von ActiveHistoryTabs). sidebar.tsx's NavItem.permission
unterstützt jetzt auch ein Array (irgendeine der Berechtigungen reicht),
fuer die neuen gebündelten Menüpunkte.

Lokal verifiziert: typecheck/lint/test/build fehlerfrei, Build zeigt
alle neuen Routen korrekt, Live-Test im Browser (ohne Login) zeigt
sauberen Redirect zu /login ohne Konsolenfehler.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Sonnet 5 committed 2026-09-03 10:37:22 +02:00
1 parent 2f223b6941
commit d998f611e2
24 files changed
+371 -148

No files matched your search

+35 -33
View File
@@ -6,10 +6,10 @@ import {
BarChart3,
CalendarDays,
Crown,
Database,
Droplet,
FileClock,
FlaskConical,
Globe,
Hexagon,
History,
LayoutDashboard,
@@ -18,16 +18,11 @@ import {
type LucideIcon,
MapPin,
Package,
Repeat,
Scissors,
Search,
Shield,
ShoppingBag,
Tag,
Upload,
Users,
Warehouse,
Webhook,
Wrench,
Zap,
} from "lucide-react";
@@ -38,7 +33,10 @@ interface NavItem {
label: string;
href: string;
icon: LucideIcon;
permission?: string;
// Any one of these grants visibility - used for hub pages that fold
// together several previously-separate settings pages, each gated by its
// own permission.
permission?: string | string[];
}
interface NavGroup {
@@ -90,35 +88,31 @@ const NAV_GROUPS: NavGroup[] = [
const ADMIN_GROUP: NavGroup = {
label: "Verwaltung",
items: [
{ label: "Benutzer", href: "/settings/users", icon: Users, permission: "users:read" },
{ label: "Rollen & Rechte", href: "/settings/roles", icon: Shield, permission: "roles:read" },
{ label: "Audit-Log", href: "/settings/audit-log", icon: History, permission: "audit:read" },
{ label: "Webhooks", href: "/settings/webhooks", icon: Webhook, permission: "webhooks:read" },
{
label: "Automatisierungen",
href: "/settings/automation-rules",
label: "Benutzer & Rollen",
href: "/settings/users-roles",
icon: Users,
permission: ["users:read", "roles:read"],
},
{
label: "Automatisierung",
href: "/settings/automation",
icon: Zap,
permission: "automation:read",
permission: [
"webhooks:read",
"automation:read",
"task-templates:read",
"label-templates:read",
"site-settings:read",
],
},
{
label: "Wiederkehrende Aufgaben",
href: "/settings/task-templates",
icon: Repeat,
permission: "task-templates:read",
},
{
label: "Etikettenvorlagen",
href: "/settings/label-templates",
icon: Tag,
permission: "label-templates:read",
},
{ label: "Import", href: "/settings/import", icon: Upload, permission: "import:execute" },
{
label: "Website",
href: "/settings/website",
icon: Globe,
permission: "site-settings:read",
label: "Backup",
href: "/settings/backup",
icon: Database,
permission: ["backup:export", "backup:import", "import:execute"],
},
{ label: "Audit-Log", href: "/settings/audit-log", icon: History, permission: "audit:read" },
],
};
@@ -147,10 +141,18 @@ function SidebarLink({ item, pathname }: { item: NavItem; pathname: string }) {
);
}
function hasNavPermission(user: AuthUser, permission: NavItem["permission"]): boolean {
if (!permission) {
return true;
}
const required = Array.isArray(permission) ? permission : [permission];
return required.some((key) => user.permissions.includes(key));
}
export function Sidebar({ user }: { user: AuthUser }) {
const pathname = usePathname();
const visibleAdminItems = ADMIN_GROUP.items.filter(
(item) => !item.permission || user.permissions.includes(item.permission),
const visibleAdminItems = ADMIN_GROUP.items.filter((item) =>
hasNavPermission(user, item.permission),
);
const groups =
visibleAdminItems.length > 0