From 91cf788221477f6a39746b55f1e10fe9b43889f6 Mon Sep 17 00:00:00 2001 From: enzo Date: Sun, 22 Mar 2026 02:55:39 +0100 Subject: [PATCH] refactor: sidebar nav items modules dynamiques selon is_enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les items CORE (dashboard, proxmox, updates, settings, modules) sont toujours affichés. Les modules optionnels (terminal, files, services, logs) n'apparaissent dans la sidebar que si leur module est activé en base de données — conformément à l'instruction.md. Co-Authored-By: Claude Sonnet 4.6 --- frontend/js/app.js | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/frontend/js/app.js b/frontend/js/app.js index 905c9cb..dc6be99 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -319,20 +319,48 @@ document.addEventListener('alpine:init', () => { }) // ── Composant: sidebar ────────────────────────────────────────────────── + // Items CORE : toujours visibles. + // Items modules : visibles seulement si le module est activé en DB. + const _coreNavItems = [ + { id: 'dashboard', iconClass: 'lnid-dashboard-square-1', iconColor: '#6c8ef4', labelKey: 'nav.dashboard', href: '/dashboard.html' }, + { id: 'proxmox', iconClass: 'lnid-server-1', iconColor: '#22c55e', labelKey: 'nav.proxmox', href: '/proxmox.html' }, + { id: 'updates', iconClass: 'lnid-arrow-upward', iconColor: '#f59e0b', labelKey: 'nav.updates', href: '/updates.html' }, + { id: 'settings', iconClass: 'lnid-gear-1', iconColor: '#94a3b8', labelKey: 'nav.settings', href: '/settings.html' }, + { id: 'modules', iconClass: 'lnid-puzzle', iconColor: '#f472b6', labelKey: 'nav.modules', href: '/modules.html' }, + ] + // Définition des items de navigation pour les modules optionnels. + // Un module dont l'id n'est pas ici n'aura pas d'entrée dans la sidebar. + const _moduleNavDef = { + terminal: { iconClass: 'lnid-terminal', iconColor: '#a78bfa', labelKey: 'nav.terminal', href: '/terminal.html' }, + files: { iconClass: 'lnid-folder-1', iconColor: '#84cc16', labelKey: 'nav.files', href: '/files.html' }, + services: { iconClass: 'lnid-gear-2', iconColor: '#fb923c', labelKey: 'nav.services', href: '/services.html' }, + logs: { iconClass: 'lnid-scroll-angular-1', iconColor: '#38bdf8', labelKey: 'nav.logs', href: '/logs.html' }, + } + Alpine.data('sidebar', () => ({ get collapsed() { return Alpine.store('ui').sidebarCollapsed }, get currentPage() { return Alpine.store('ui').currentPage }, - navItems: [ - { id: 'dashboard', iconClass: 'lnid-dashboard-square-1', iconColor: '#6c8ef4', labelKey: 'nav.dashboard', href: '/dashboard.html' }, - { id: 'proxmox', iconClass: 'lnid-server-1', iconColor: '#22c55e', labelKey: 'nav.proxmox', href: '/proxmox.html' }, - { id: 'updates', iconClass: 'lnid-arrow-upward', iconColor: '#f59e0b', labelKey: 'nav.updates', href: '/updates.html' }, - { id: 'terminal', iconClass: 'lnid-terminal', iconColor: '#a78bfa', labelKey: 'nav.terminal', href: '/terminal.html' }, - { id: 'services', iconClass: 'lnid-gear-2', iconColor: '#fb923c', labelKey: 'nav.services', href: '/services.html' }, - { id: 'logs', iconClass: 'lnid-scroll-angular-1', iconColor: '#38bdf8', labelKey: 'nav.logs', href: '/logs.html' }, - { id: 'settings', iconClass: 'lnid-gear-1', iconColor: '#94a3b8', labelKey: 'nav.settings', href: '/settings.html' }, - { id: 'modules', iconClass: 'lnid-puzzle', iconColor: '#f472b6', labelKey: 'nav.modules', href: '/modules.html' }, - ], + // Commence avec les items CORE ; init() ajoute les modules activés + navItems: [..._coreNavItems], + + async init() { + try { + const res = await apiFetch('/api/modules') + if (!res.ok) return + const modules = await res.json() || [] + const moduleItems = modules + .filter(m => m.is_enabled && !m.is_core && _moduleNavDef[m.id]) + .map(m => ({ id: m.id, ..._moduleNavDef[m.id] })) + // Insérer les modules entre Updates et Settings + const insertAt = this.navItems.findIndex(i => i.id === 'settings') + this.navItems = [ + ...this.navItems.slice(0, insertAt), + ...moduleItems, + ...this.navItems.slice(insertAt), + ] + } catch(e) {} + }, iconStyle(item) { return this.isActive(item.id) ? '' : `color: ${item.iconColor}`