From 0a35a32afb6f216a16de3ddcb3d3dadf567664da Mon Sep 17 00:00:00 2001 From: Schalli Date: Mon, 5 Oct 2026 13:36:05 +0200 Subject: [PATCH] design(verwaltung): Einstellungen und Verwaltung aufgeraeumt Gemeinsame Navigation fuer Einstellungen und Verwaltung (Verwaltung in Benutzer und Zugang / Module / Anbindungen gegliedert), einheitlicher Seitenkopf und Abschnittskarten, Speichern in der Kartenfusszeile. Menuepunkt 'Administrator' heisst 'Verwaltung'; Seitentitel gleich den Navigationseintraegen. Kein 'Zurueck zum Dashboard' mehr. Tabellen ohne waagerechte Seitenscrollleiste; auf dem Handy Auswahlliste statt Liste. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../src/app/(portal)/admin/groups/page.tsx | 80 +- apps/web/src/app/(portal)/admin/layout.tsx | 47 +- apps/web/src/app/(portal)/admin/ldap/page.tsx | 1129 +++++++++-------- .../categories/categories-page.test.tsx | 7 +- .../admin/modules/categories/page.tsx | 187 ++- .../(portal)/admin/modules/grants/page.tsx | 67 +- .../src/app/(portal)/admin/modules/page.tsx | 189 +-- apps/web/src/app/(portal)/admin/smtp/page.tsx | 6 +- .../src/app/(portal)/admin/tenants/page.tsx | 65 +- .../web/src/app/(portal)/admin/users/page.tsx | 100 +- .../settings/dashboard/calendar/page.tsx | 6 +- .../app/(portal)/settings/dashboard/page.tsx | 6 +- .../settings/general/account/page.tsx | 6 +- .../settings/general/desktop/page.tsx | 6 +- apps/web/src/app/(portal)/settings/layout.tsx | 49 +- apps/web/src/app/(portal)/settings/page.tsx | 4 +- apps/web/src/app/globals.css | 182 +++ .../src/components/admin/admin-sidebar.tsx | 147 --- .../admin/welcome-mail-template-editor.tsx | 478 +++---- .../control-center/control-center-layout.tsx | 23 + .../control-center/control-center-nav.tsx | 278 ++++ .../components/control-center/page-header.tsx | 30 + .../control-center/settings-section.tsx | 47 + .../custom-modules/custom-module-manager.tsx | 79 +- .../settings/account-settings-form.tsx | 94 +- .../settings/calendar-settings-panel.tsx | 473 ++++--- .../settings/desktop-app-settings.tsx | 122 +- .../components/settings/settings-sidebar.tsx | 113 -- .../settings/smtp-settings-form.tsx | 481 +++---- .../settings/widget-settings-panel.tsx | 94 +- apps/web/src/messages/de.json | 80 +- apps/web/src/messages/en.json | 74 +- 32 files changed, 2579 insertions(+), 2170 deletions(-) delete mode 100644 apps/web/src/components/admin/admin-sidebar.tsx create mode 100644 apps/web/src/components/control-center/control-center-layout.tsx create mode 100644 apps/web/src/components/control-center/control-center-nav.tsx create mode 100644 apps/web/src/components/control-center/page-header.tsx create mode 100644 apps/web/src/components/control-center/settings-section.tsx delete mode 100644 apps/web/src/components/settings/settings-sidebar.tsx diff --git a/apps/web/src/app/(portal)/admin/groups/page.tsx b/apps/web/src/app/(portal)/admin/groups/page.tsx index 0845dbc..368c9b8 100644 --- a/apps/web/src/app/(portal)/admin/groups/page.tsx +++ b/apps/web/src/app/(portal)/admin/groups/page.tsx @@ -2,6 +2,8 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslations } from 'next-intl'; +import { PageHeader } from '@/components/control-center/page-header'; +import { SettingsSection } from '@/components/control-center/settings-section'; import { useAuthStore } from '@/lib/stores/auth-store'; import { GroupFormModal } from './components/GroupFormModal'; import { GroupMembersModal } from './components/GroupMembersModal'; @@ -30,6 +32,7 @@ export interface Group { export default function AdminGroupsPage() { const t = useTranslations('admin.groups'); const tCommon = useTranslations('common'); + const tCc = useTranslations('controlCenter'); const currentUser = useAuthStore((s) => s.user); const [groups, setGroups] = useState([]); @@ -122,20 +125,19 @@ export default function AdminGroupsPage() { } return ( -
-
-

{t('title')}

- -
+
+ + {t('create')} + + } + /> {error && ( -
+
{error}
)} @@ -143,35 +145,33 @@ export default function AdminGroupsPage() { {loading ? (

{tCommon('loading')}

) : groups.length === 0 ? ( -
-

{t('noGroups')}

-

{t('noGroupsBody')}

- -
+ +
+

{t('noGroups')}

+

{t('noGroupsBody')}

+ +
+
) : ( -
+ - + - - - - - @@ -179,10 +179,10 @@ export default function AdminGroupsPage() { {groups.map((group) => ( - - - - - +
+ {t('name')} + {t('ldapBinding')} + {t('defaultGroup')} + {t('memberCount')} + {t('actions')}
+ {group.internalName ?? group.name} + + {group.memberCount} -
+
{group.memberCount} +
@@ -252,7 +252,7 @@ export default function AdminGroupsPage() { ))}
-
+ )} {showFormModal && ( diff --git a/apps/web/src/app/(portal)/admin/layout.tsx b/apps/web/src/app/(portal)/admin/layout.tsx index b0657ce..4c460cb 100644 --- a/apps/web/src/app/(portal)/admin/layout.tsx +++ b/apps/web/src/app/(portal)/admin/layout.tsx @@ -1,42 +1,9 @@ -'use client'; +import { ControlCenterLayout } from '@/components/control-center/control-center-layout'; -import Link from 'next/link'; -import { useTranslations } from 'next-intl'; -import { AdminSidebar } from '@/components/admin/admin-sidebar'; - -export default function AdminLayout({ - children, -}: { - children: React.ReactNode; -}) { - const t = useTranslations('settings'); - - return ( -
- -
- - - {t('backToDashboard')} - - {children} -
-
- ); +/** + * Einstellungen und Verwaltung teilen sich einen Rahmen mit einer + * gemeinsamen Navigation (siehe ControlCenterLayout). + */ +export default function Layout({ children }: { children: React.ReactNode }) { + return {children}; } diff --git a/apps/web/src/app/(portal)/admin/ldap/page.tsx b/apps/web/src/app/(portal)/admin/ldap/page.tsx index a2cec94..0bf73ed 100644 --- a/apps/web/src/app/(portal)/admin/ldap/page.tsx +++ b/apps/web/src/app/(portal)/admin/ldap/page.tsx @@ -3,6 +3,8 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslations } from 'next-intl'; import { useAuthStore } from '@/lib/stores/auth-store'; +import { PageHeader } from '@/components/control-center/page-header'; +import { SettingsSection } from '@/components/control-center/settings-section'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; @@ -89,6 +91,7 @@ interface SyncResult { export default function AdminLdapPage() { const t = useTranslations('admin.ldap'); const tCommon = useTranslations('common'); + const tCc = useTranslations('controlCenter'); const currentUser = useAuthStore((s) => s.user); const [config, setConfig] = useState(null); @@ -545,19 +548,40 @@ export default function AdminLdapPage() { ); } + const inputClass = + 'flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm'; + const labelClass = 'mb-1 block text-sm font-medium text-foreground'; + const smallLabelClass = 'mb-1 block text-xs font-medium text-muted-foreground'; + return ( -
-

{t('title')}

+
+ {/* Section 1: Connection Settings */} -
-

- {t('connectionTitle')} -

-
-
-
-