'admin-organization', 'label' => t('Organization'), 'icon' => 'bi-building', 'visible' => $hasOrganization, 'items' => [ [ 'label' => t('Tenants'), 'path' => 'admin/tenants', 'active' => navActive('admin/tenants', true), 'visible' => $canViewTenants, 'withTenant' => false, ], [ 'label' => t('Departments'), 'path' => 'admin/departments', 'active' => navActive('admin/departments', true), 'visible' => $canViewDepartments, 'withTenant' => true, ], [ 'label' => t('Users'), 'path' => 'admin/users', 'active' => navActive('admin/users', true), 'visible' => $canViewUsers, 'withTenant' => true, ], ], ], [ 'key' => 'admin-roles-permissions', 'label' => t('Roles & permissions'), 'icon' => 'bi-shield-lock', 'visible' => $hasUsersSection, 'items' => [ [ 'label' => t('Roles'), 'path' => 'admin/roles', 'active' => navActive('admin/roles', true), 'visible' => $canViewRoles, 'withTenant' => false, ], [ 'label' => t('Permissions'), 'path' => 'admin/permissions', 'active' => navActive('admin/permissions', true), 'visible' => $canViewPermissions, 'withTenant' => false, ], ], ], [ 'key' => 'admin-automation', 'label' => t('Automation & integrations'), 'icon' => 'bi-plug', 'visible' => $hasAutomationSection, 'items' => [ [ 'label' => t('Imports'), 'path' => 'admin/imports', 'active' => navActive('admin/imports', true), 'visible' => $canViewImports, 'withTenant' => false, ], [ 'label' => t('Scheduled jobs'), 'path' => 'admin/scheduled-jobs', 'active' => navActive('admin/scheduled-jobs', true), 'visible' => $canViewJobs, 'withTenant' => false, ], ], ], [ 'key' => 'admin-monitoring', 'label' => t('Monitoring'), 'icon' => 'bi-graph-up', 'visible' => $hasMonitoringSection, 'items' => [ [ 'label' => t('Statistics'), 'path' => 'admin/stats', 'active' => navActive('admin/stats', true), 'visible' => $canViewStats, 'withTenant' => false, ], ], ], [ 'key' => 'admin-logs', 'label' => t('Logs'), 'icon' => 'bi-journal-text', 'visible' => $hasLogsSection, 'items' => [ [ 'label' => t('nav.logs.mail'), 'path' => 'admin/mail-log', 'active' => navActive('admin/mail-log', true), 'visible' => $canViewMailLog, 'withTenant' => false, ], ], ], [ 'key' => 'admin-system', 'label' => t('System'), 'icon' => 'bi-sliders', 'visible' => $hasSystemSection, 'items' => [ [ 'label' => t('Settings'), 'path' => 'admin/settings', 'active' => navActive('admin/settings', true), 'visible' => $canViewSettings, 'withTenant' => false, ], ], ], ]; // ── Append module-contributed admin nav groups (sidebar.admin_nav_item slot) ── // Module items are grouped by their 'group' key. Each unique group becomes a //
section appended after the core admin nav groups. if ($moduleNavItemSlots) { $moduleGroupsByKey = []; usort($moduleNavItemSlots, static fn ($a, $b) => ($a['order'] ?? 100) <=> ($b['order'] ?? 100)); foreach ($moduleNavItemSlots as $slot) { if (!is_array($slot)) { continue; } $groupKey = trim((string) ($slot['group'] ?? '')); $slotPath = trim((string) ($slot['path'] ?? '')); $slotLabel = trim((string) ($slot['label'] ?? '')); $slotPermission = trim((string) ($slot['permission'] ?? '')); if ($groupKey === '' || $slotPath === '' || $slotLabel === '') { continue; } $slotVisible = $slotPermission === '' || !empty($layoutAuth[$slotPermission]); if (!isset($moduleGroupsByKey[$groupKey])) { $moduleGroupsByKey[$groupKey] = []; } $moduleGroupsByKey[$groupKey][] = [ 'label' => t($slotLabel), 'path' => $slotPath, 'active' => navActive($slotPath, true), 'visible' => $slotVisible, 'withTenant' => false, ]; } // Known group metadata — modules declare their group key, we map to label + icon. $moduleGroupMeta = [ 'admin-automation' => ['label' => t('Automation & integrations'), 'icon' => 'bi-gear-wide-connected'], 'admin-logs' => ['label' => t('Audit & logs'), 'icon' => 'bi-journal-text'], ]; foreach ($moduleGroupsByKey as $groupKey => $items) { $hasVisible = false; foreach ($items as $item) { if (!empty($item['visible'])) { $hasVisible = true; break; } } // Also add mail log to the logs group if it exists as a core item if ($groupKey === 'admin-logs' && $canViewMailLog) { array_unshift($items, [ 'label' => t('nav.logs.mail'), 'path' => 'admin/mail-log', 'active' => navActive('admin/mail-log', true), 'visible' => $canViewMailLog, 'withTenant' => false, ]); $hasVisible = true; } $meta = $moduleGroupMeta[$groupKey] ?? ['label' => $groupKey, 'icon' => 'bi-list']; $adminNavGroups[] = [ 'key' => $groupKey, 'label' => $meta['label'], 'icon' => $meta['icon'], 'visible' => $hasVisible, 'items' => $items, ]; } // If modules contributed to admin-logs, remove the core-only logs group (which only had mail log) if (isset($moduleGroupsByKey['admin-logs'])) { $adminNavGroups = array_values(array_filter($adminNavGroups, static function ($g) { // Remove the original core logs group (it's been merged into the module-contributed one) return !(($g['key'] ?? '') === 'admin-logs' && count($g['items'] ?? []) === 1 && ($g['items'][0]['path'] ?? '') === 'admin/mail-log'); })); } } // Render helper for grouped admin aside navigation $renderAdminNavGroup = static function (array $group, string $tenantQueryParam): void { if (empty($group['visible'])) { return; } $groupKey = trim((string) ($group['key'] ?? '')); if ($groupKey === '') { return; } $items = $group['items'] ?? []; $items = array_values(array_filter($items, static fn ($item) => !empty($item['visible']))); if (!$items) { return; } $groupIsActive = false; foreach ($items as $item) { $activeState = $item['active'] ?? []; if (!empty($activeState['isActive'])) { $groupIsActive = true; break; } } ?>
  • open>
      '', 'aria' => '']; ?>
    • >