feat(sidebar): render module-contributed admin nav items via sidebar.admin_nav_item slot
The sidebar template now reads sidebar.admin_nav_item UI slots from modules and merges them into the matching admin nav group (by group key). Module permissions are resolved via layoutAuth which already includes module UI abilities from ModuleRegistry::getModuleUiAbilities(). This restores audit nav items (API audit, System audit, Import logs, User lifecycle logs) in the Logs group when the audit module is active. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,39 @@ $adminNavGroups = [
|
||||
],
|
||||
];
|
||||
|
||||
// ── Merge module-contributed sidebar nav items into admin groups ──
|
||||
if ($moduleNavItemSlots) {
|
||||
// Index groups by key for fast lookup
|
||||
$groupIndex = [];
|
||||
foreach ($adminNavGroups as $idx => $group) {
|
||||
$groupIndex[$group['key'] ?? ''] = $idx;
|
||||
}
|
||||
// Sort module items by order, then append to matching group
|
||||
usort($moduleNavItemSlots, static fn ($a, $b) => ($a['order'] ?? 100) <=> ($b['order'] ?? 100));
|
||||
foreach ($moduleNavItemSlots as $slot) {
|
||||
if (!is_array($slot)) { continue; }
|
||||
$targetGroup = trim((string) ($slot['group'] ?? ''));
|
||||
$slotPath = trim((string) ($slot['path'] ?? ''));
|
||||
$slotLabel = trim((string) ($slot['label'] ?? ''));
|
||||
$slotPermission = trim((string) ($slot['permission'] ?? ''));
|
||||
if ($targetGroup === '' || $slotPath === '' || $slotLabel === '') { continue; }
|
||||
// Check permission via layoutAuth (module permissions are merged into layout capabilities)
|
||||
$slotVisible = $slotPermission === '' || !empty($layoutAuth[$slotPermission]);
|
||||
if (!isset($groupIndex[$targetGroup])) { continue; }
|
||||
$gIdx = $groupIndex[$targetGroup];
|
||||
$adminNavGroups[$gIdx]['items'][] = [
|
||||
'label' => t($slotLabel),
|
||||
'path' => $slotPath,
|
||||
'active' => navActive($slotPath, true),
|
||||
'visible' => $slotVisible,
|
||||
'withTenant' => false,
|
||||
];
|
||||
if ($slotVisible) {
|
||||
$adminNavGroups[$gIdx]['visible'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render helper for grouped admin aside navigation
|
||||
$renderAdminNavGroup = static function (array $group, string $tenantQueryParam): void {
|
||||
if (empty($group['visible'])) {
|
||||
@@ -233,6 +266,7 @@ $csrfToken = (string) ($layoutNav['csrfToken'] ?? '');
|
||||
$moduleSlots = is_array($layoutNav['moduleSlots'] ?? null) ? $layoutNav['moduleSlots'] : [];
|
||||
$modulePanelSlots = is_array($moduleSlots['aside.tab_panel'] ?? null) ? $moduleSlots['aside.tab_panel'] : [];
|
||||
$moduleSearchSlots = is_array($moduleSlots['search.resource_item'] ?? null) ? $moduleSlots['search.resource_item'] : [];
|
||||
$moduleNavItemSlots = is_array($moduleSlots['sidebar.admin_nav_item'] ?? null) ? $moduleSlots['sidebar.admin_nav_item'] : [];
|
||||
?>
|
||||
<aside class="app-sidebar" id="app-sidebar" data-app-component="sidebar-toggle">
|
||||
<?php if ($currentTenant): ?>
|
||||
|
||||
Reference in New Issue
Block a user