diff --git a/i18n/default_de.json b/i18n/default_de.json index dd67c2b..afd178a 100644 --- a/i18n/default_de.json +++ b/i18n/default_de.json @@ -157,6 +157,8 @@ "Permission key already exists": "Berechtigungs-Schlüssel existiert bereits", "Assigned permissions": "Zugewiesene Berechtigungen", "Select permissions": "Berechtigungen auswählen", + "No permissions available": "Keine Berechtigungen verfügbar", + "No active permissions are configured yet.": "Es sind noch keine aktiven Berechtigungen konfiguriert.", "Permission denied": "Keine Berechtigung", "No active tenant assigned": "Kein aktiver Mandant zugewiesen", "Please select at least one tenant": "Bitte mindestens einen Mandanten auswählen", @@ -524,9 +526,12 @@ "No departments": "Keine Abteilungen", "No departments available for this tenant": "Für diesen Mandanten sind keine Abteilungen verfügbar", "Assign tenants first to select departments": "Bitte zuerst Mandanten zuweisen, um Abteilungen auszuwählen", + "No tenants available": "Keine Mandanten verfügbar", + "No tenant is available in your current scope.": "Im aktuellen Geltungsbereich sind keine Mandanten verfügbar.", "Department options refresh after save": "Abteilungsoptionen werden nach dem Speichern aktualisiert", "Role": "Rolle", "Roles": "Rollen", + "No roles available": "Keine Rollen verfügbar", "Create role": "Rolle anlegen", "Edit role": "Rolle bearbeiten", "Role created": "Rolle erstellt", @@ -571,6 +576,7 @@ "Support": "Support", "Support email": "Support-E-Mail", "Support phone": "Support-Telefon", + "No contact details available": "Keine Kontaktdaten vorhanden", "VAT ID": "USt-ID", "Tax number": "Steuernummer", "Billing email": "Rechnungs-E-Mail", @@ -579,6 +585,7 @@ "Accounting info": "Buchhaltungsinfo", "Communication": "Kommunikation", "Legal": "Rechtliches", + "No legal links configured": "Keine rechtlichen Links konfiguriert", "Privacy URL": "Datenschutz-URL", "Imprint URL": "Impressum-URL", "Region": "Region", @@ -715,6 +722,8 @@ "More filters": "Weitere Filter", "Email unverified": "E-Mail nicht verifiziert", "Password resets": "Passwort-Resets", + "No password reset requests": "Keine Passwort-Reset-Anfragen", + "No reset has been requested for this account yet.": "Für dieses Konto wurde noch kein Reset angefordert.", "Requested at": "Angefordert am", "Expires at": "Gültig bis", "Used at": "Verwendet am", @@ -723,6 +732,8 @@ "Expired": "Abgelaufen", "Expired by admin": "Durch Admin abgelaufen", "Login tokens": "Login-Tokens", + "No login tokens": "Keine Login-Tokens", + "This user is currently not signed in via remember-me.": "Dieser Benutzer ist aktuell nicht per Angemeldet-bleiben eingeloggt.", "Expire all login tokens": "Alle Login-Tokens ablaufen", "Expire all login tokens?": "Alle Login-Tokens ablaufen?", "%d active login tokens": "%d aktive Login-Tokens", @@ -747,6 +758,8 @@ "IDs": "IDs", "Pages": "Seiten", "Permission": "Berechtigung", + "No effective permissions": "Keine effektiven Berechtigungen", + "Assign at least one role to show effective permissions.": "Weisen Sie mindestens eine Rolle zu, um effektive Berechtigungen anzuzeigen.", "Please verify your email first": "Bitte bestätige zuerst deine E-Mail", "Toggle search details": "Suchdetails umschalten", "Toggle sidebar": "Sidebar umschalten", @@ -923,6 +936,8 @@ "Revoked": "Widerrufen", "Prefix": "Präfix", "No API tokens": "Keine API-Tokens", + "Create a token to enable API access for this user.": "Erstellen Sie ein Token, um den API-Zugriff für diesen Benutzer zu aktivieren.", + "No API token has been created for this user yet.": "Für diesen Benutzer wurde noch kein API-Token erstellt.", "New API token (copy now — shown only once):": "Neues API-Token (jetzt kopieren — wird nur einmal angezeigt):", "API token created. Copy it now — it will not be shown again.": "API-Token erstellt. Jetzt kopieren — es wird nicht erneut angezeigt.", "Could not create API token: %s": "API-Token konnte nicht erstellt werden: %s", diff --git a/i18n/default_en.json b/i18n/default_en.json index de67329..ee1d714 100644 --- a/i18n/default_en.json +++ b/i18n/default_en.json @@ -157,6 +157,8 @@ "Permission key already exists": "Permission key already exists", "Assigned permissions": "Assigned permissions", "Select permissions": "Select permissions", + "No permissions available": "No permissions available", + "No active permissions are configured yet.": "No active permissions are configured yet.", "Permission denied": "Permission denied", "No active tenant assigned": "No active tenant assigned", "Please select at least one tenant": "Please select at least one tenant", @@ -524,9 +526,12 @@ "No departments": "No departments", "No departments available for this tenant": "No departments available for this tenant", "Assign tenants first to select departments": "Assign tenants first to select departments", + "No tenants available": "No tenants available", + "No tenant is available in your current scope.": "No tenant is available in your current scope.", "Department options refresh after save": "Department options refresh after save", "Role": "Role", "Roles": "Roles", + "No roles available": "No roles available", "Create role": "Create role", "Edit role": "Edit role", "Role created": "Role created", @@ -571,6 +576,7 @@ "Support": "Support", "Support email": "Support email", "Support phone": "Support phone", + "No contact details available": "No contact details available", "VAT ID": "VAT ID", "Tax number": "Tax number", "Billing email": "Billing email", @@ -579,6 +585,7 @@ "Accounting info": "Accounting info", "Communication": "Communication", "Legal": "Legal", + "No legal links configured": "No legal links configured", "Privacy URL": "Privacy URL", "Imprint URL": "Imprint URL", "Region": "Region", @@ -715,6 +722,8 @@ "More filters": "More filters", "Email unverified": "Email unverified", "Password resets": "Password resets", + "No password reset requests": "No password reset requests", + "No reset has been requested for this account yet.": "No reset has been requested for this account yet.", "Requested at": "Requested at", "Expires at": "Expires at", "Used at": "Used at", @@ -723,6 +732,8 @@ "Expired": "Expired", "Expired by admin": "Expired by admin", "Login tokens": "Login tokens", + "No login tokens": "No login tokens", + "This user is currently not signed in via remember-me.": "This user is currently not signed in via remember-me.", "Expire all login tokens": "Expire all login tokens", "Expire all login tokens?": "Expire all login tokens?", "%d active login tokens": "%d active login tokens", @@ -747,6 +758,8 @@ "IDs": "IDs", "Pages": "Pages", "Permission": "Permission", + "No effective permissions": "No effective permissions", + "Assign at least one role to show effective permissions.": "Assign at least one role to show effective permissions.", "Please verify your email first": "Please verify your email first", "Toggle search details": "Toggle search details", "Toggle sidebar": "Toggle sidebar", @@ -923,6 +936,8 @@ "Revoked": "Revoked", "Prefix": "Prefix", "No API tokens": "No API tokens", + "Create a token to enable API access for this user.": "Create a token to enable API access for this user.", + "No API token has been created for this user yet.": "No API token has been created for this user yet.", "New API token (copy now — shown only once):": "New API token (copy now — shown only once):", "API token created. Copy it now — it will not be shown again.": "API token created. Copy it now — it will not be shown again.", "Could not create API token: %s": "Could not create API token: %s", diff --git a/pages/admin/departments/_form.phtml b/pages/admin/departments/_form.phtml index db80354..406b6a2 100644 --- a/pages/admin/departments/_form.phtml +++ b/pages/admin/departments/_form.phtml @@ -71,6 +71,15 @@ $disabledAttr = $isReadOnly ? 'disabled' : ''; + + t('No tenants available'), + 'hint' => t('Please select at least one tenant'), + 'size' => 'compact', + ]; + require templatePath('partials/app-empty-state.phtml'); + ?> diff --git a/pages/admin/departments/create(default).phtml b/pages/admin/departments/create(default).phtml index 6561fe9..7c63006 100644 --- a/pages/admin/departments/create(default).phtml +++ b/pages/admin/departments/create(default).phtml @@ -9,6 +9,7 @@
t('Home'), 'path' => 'admin'], ['label' => t('Departments'), 'path' => 'admin/departments'], @@ -26,6 +27,7 @@ 'value' => 'create', 'class' => 'secondary outline', 'label' => t('Create'), + 'disabled' => !$hasTenantOptions, ], [ 'form' => 'department-form', @@ -33,6 +35,7 @@ 'value' => 'create_close', 'class' => 'primary', 'label' => t('Create & close'), + 'disabled' => !$hasTenantOptions, ], ], ]; diff --git a/pages/admin/departments/edit(default).phtml b/pages/admin/departments/edit(default).phtml index d69eba7..8bbbe7c 100644 --- a/pages/admin/departments/edit(default).phtml +++ b/pages/admin/departments/edit(default).phtml @@ -19,6 +19,7 @@ $isReadOnly = !$canUpdateDepartment;
t('Home'), 'path' => 'admin'], ['label' => t('Departments'), 'path' => 'admin/departments'], @@ -36,6 +37,7 @@ $isReadOnly = !$canUpdateDepartment; 'value' => 'save', 'class' => 'secondary outline', 'label' => t('Save'), + 'disabled' => !$hasTenantOptions, ], [ 'form' => 'department-form', @@ -43,6 +45,7 @@ $isReadOnly = !$canUpdateDepartment; 'value' => 'save_close', 'class' => 'primary', 'label' => t('Save & close'), + 'disabled' => !$hasTenantOptions, ], ] : [], ]; diff --git a/pages/admin/roles/_form.phtml b/pages/admin/roles/_form.phtml index cefdbb6..ea39a6e 100644 --- a/pages/admin/roles/_form.phtml +++ b/pages/admin/roles/_form.phtml @@ -24,15 +24,15 @@ $dangerZoneActionLabel = (string) ($dangerZoneActionLabel ?? t('Delete')); $detailsOpenAttr = $detailsOpenAll ? 'open' : ''; $readonlyAttr = $isReadOnly ? 'readonly' : ''; $disabledAttr = $isReadOnly ? 'disabled' : ''; +$permissions = is_array($permissions ?? null) ? $permissions : []; +$selectedPermissionIds = is_array($selectedPermissionIds ?? null) ? $selectedPermissionIds : []; ?>
- - - + @@ -54,11 +54,20 @@ $disabledAttr = $isReadOnly ? 'disabled' : '';
- -
- -
- +
+ + + + t('No permissions available'), + 'hint' => t('No active permissions are configured yet.'), + 'size' => 'compact', + ]; + require templatePath('partials/app-empty-state.phtml'); + ?> + +
-

+ t('Save tenant first to manage custom fields'), + 'size' => 'compact', + ]; + if (!$isReadOnly) { + $emptyState['action'] = [ + 'label' => t('Create'), + 'form' => $formId, + ]; + } + require templatePath('partials/app-empty-state.phtml'); + ?>
diff --git a/pages/admin/tenants/edit(default).phtml b/pages/admin/tenants/edit(default).phtml index eac1e58..44bccd3 100644 --- a/pages/admin/tenants/edit(default).phtml +++ b/pages/admin/tenants/edit(default).phtml @@ -229,7 +229,15 @@ $hasFavicon = $avatarUuid !== '' && $tenantFaviconService->hasFavicon($avatarUui
-

-

+ t('No contact details available'), + 'size' => 'small', + 'align' => 'left', + 'icon' => false, + ]; + require templatePath('partials/app-empty-state.phtml'); + ?>
@@ -258,7 +266,15 @@ $hasFavicon = $avatarUuid !== '' && $tenantFaviconService->hasFavicon($avatarUui
-

-

+ t('No legal links configured'), + 'size' => 'small', + 'align' => 'left', + 'icon' => false, + ]; + require templatePath('partials/app-empty-state.phtml'); + ?>
diff --git a/pages/admin/users/_form.phtml b/pages/admin/users/_form.phtml index 9812709..56f5a03 100644 --- a/pages/admin/users/_form.phtml +++ b/pages/admin/users/_form.phtml @@ -315,7 +315,8 @@ foreach ($tenants as $tenant) { t('No entries found'), + 'message' => t('No password reset requests'), + 'hint' => t('No reset has been requested for this account yet.'), 'size' => 'compact', ]; require templatePath('partials/app-empty-state.phtml'); @@ -380,7 +381,8 @@ foreach ($tenants as $tenant) { t('No entries found'), + 'message' => t('No login tokens'), + 'hint' => t('This user is currently not signed in via remember-me.'), 'size' => 'compact', ]; require templatePath('partials/app-empty-state.phtml'); @@ -543,10 +545,13 @@ foreach ($tenants as $tenant) {
- + t('No API tokens'), + 'hint' => $canManageApiTokens + ? t('Create a token to enable API access for this user.') + : t('No API token has been created for this user yet.'), 'size' => 'compact', ]; require templatePath('partials/app-empty-state.phtml'); @@ -563,35 +568,46 @@ foreach ($tenants as $tenant) {

- - - 0): ?> - - - - - - - - + +

@@ -655,7 +671,18 @@ foreach ($tenants as $tenant) {

- + + t('No roles available'), + 'hint' => t('No active roles are configured yet.'), + 'size' => 'compact', + ]; + require templatePath('partials/app-empty-state.phtml'); + ?> + + +
@@ -667,7 +694,8 @@ foreach ($tenants as $tenant) { t('No entries found'), + 'message' => t('No effective permissions'), + 'hint' => t('Assign at least one role to show effective permissions.'), 'size' => 'compact', ]; require templatePath('partials/app-empty-state.phtml'); diff --git a/pages/admin/users/edit($id).php b/pages/admin/users/edit($id).php index 70921b1..bfa37d3 100644 --- a/pages/admin/users/edit($id).php +++ b/pages/admin/users/edit($id).php @@ -175,7 +175,7 @@ if ($canViewSecurityArtifacts) { $apiTokens = $apiTokenService->listForUser($userId); } $canManageApiTokens = $canManageApiTokens && $canViewSecurityArtifacts; -$showApiTokens = $canViewSecurityArtifacts && (!empty($apiTokens) || $canManageApiTokens); +$showApiTokens = $canViewSecurityArtifacts; if ($request->isMethod('POST') && !Session::checkCsrfToken()) { Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired'); diff --git a/templates/partials/app-main-aside.phtml b/templates/partials/app-main-aside.phtml index 56d7edb..8ef2424 100644 --- a/templates/partials/app-main-aside.phtml +++ b/templates/partials/app-main-aside.phtml @@ -35,6 +35,7 @@ $adminNavGroups = [ [ 'key' => 'admin-organization', 'label' => t('Organization'), + 'icon' => 'bi-building', 'visible' => $hasOrganization, 'items' => [ [ @@ -63,6 +64,7 @@ $adminNavGroups = [ [ 'key' => 'admin-roles-permissions', 'label' => t('Roles & permissions'), + 'icon' => 'bi-shield-lock', 'visible' => $hasUsersSection, 'items' => [ [ @@ -84,6 +86,7 @@ $adminNavGroups = [ [ 'key' => 'admin-automation', 'label' => t('Automation & integrations'), + 'icon' => 'bi-plug', 'visible' => $hasAutomationSection, 'items' => [ [ @@ -112,6 +115,7 @@ $adminNavGroups = [ [ 'key' => 'admin-monitoring', 'label' => t('Monitoring'), + 'icon' => 'bi-graph-up', 'visible' => $hasMonitoringSection, 'items' => [ [ @@ -126,6 +130,7 @@ $adminNavGroups = [ [ 'key' => 'admin-logs', 'label' => t('Logs'), + 'icon' => 'bi-journal-text', 'visible' => $hasLogsSection, 'items' => [ [ @@ -168,6 +173,7 @@ $adminNavGroups = [ [ 'key' => 'admin-system', 'label' => t('System'), + 'icon' => 'bi-sliders', 'visible' => $hasSystemSection, 'items' => [ [ @@ -214,6 +220,7 @@ $renderAdminNavGroup = static function (array $group, string $tenantQueryParam):
  • open> +
      diff --git a/web/css/layout/app-sidebar.css b/web/css/layout/app-sidebar.css index 56273cf..f8d137c 100644 --- a/web/css/layout/app-sidebar.css +++ b/web/css/layout/app-sidebar.css @@ -8,7 +8,7 @@ --app-sidebar-tenant-size: 14px; --app-sidebar-titlebar-height: 30px; --app-sidebar-border-width: 2px; - --app-sidebar-summary-max-width: 157px; + --app-sidebar-summary-max-width: 142px; --app-sidebar-section-gap: 2rem; --app-sidebar-section-space: 5px; --app-sidebar-hover-bg: transparent; @@ -36,6 +36,17 @@ display: block; } + .app-sidebar-group.app-sidebar-admin-group details summary i { + font-size: 10px; + position: relative; + top: -4px; + margin-right: 3px; + } + + aside.app-sidebar li:has(> .app-empty-state) { + padding-inline: 19px; + } + .app-sidebar .app-sidebar-panel[hidden] { display: none !important; }