// components/admin/index.js — the whole Admin area as one feature module. // // Admin owns every /admin* sub-route: /admin & /admin/dashboard (overview // board), /admin/config/ (config-form pages), /admin/system[/] // (system ops boards), /admin/tools/ssh-access, /admin/tools/peers. The router // re-runs mount() on each distinct /admin* path; mount() just parses the // category and hands it to window.configManager.renderConfig(), which owns the // overview/ssh/peers/system/config-form dispatch and lazy-loads the per-category // sub-controllers. configManager is a system-loader singleton — call // renderConfig(), never `new`. (The legacy /config, /ssh, /peers redirect // handlers stay as-is; they just bounce into /admin/* which this feature serves.) LP.features.register({ id: 'admin', routes: ['/admin', '/admin*'], async mount(ctx) { window.configCategory = ctx.services.router.adminCategoryFromPath(window.location.pathname); const html = await ctx.loadFragment('/components/admin/config/html/config-content.html'); ctx.setContent(html, 'Admin'); if (window.configManager) { if (typeof window.configManager.renderConfig === 'function') { await window.configManager.renderConfig(window.configCategory || 'overview'); } } else { // Preserve the legacy failure rather than rendering blank. _mountFeature // catches this and falls back to handleAdmin (same showError end-state). throw new Error('ConfigManager not initialized by SystemLoader'); } }, async unmount(ctx) { // Release only this view's leaks; never destroy the configManager singleton. // The sub-controllers renderConfig() spawns are re-created on each visit, so // null them; SystemPage additionally holds a live SSE sub + a 30s interval // we can stop cleanly. try { const as = window.systemPage; if (as) { if (typeof as._stopLive === 'function') as._stopLive(); if (as._timer) { clearInterval(as._timer); as._timer = null; } if (as._subview && typeof as._subview.dispose === 'function') { try { as._subview.dispose(); } catch (_) {} } as._subview = null; } } catch (_) {} // Drop OverviewPage's task-refresh registration so a finished verify/update // task doesn't repaint a torn-down board. try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('overview-page'); } catch (_) {} window.overviewPage = null; window.systemPage = null; window.sshPage = null; window.peersPage = null; // configManager (+ its inner managers) intentionally left intact. }, });