diff --git a/containers/libreportal/frontend/features/admin/index.js b/containers/libreportal/frontend/features/admin/index.js new file mode 100644 index 0000000..21b76a3 --- /dev/null +++ b/containers/libreportal/frontend/features/admin/index.js @@ -0,0 +1,58 @@ +// features/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 = window.adminCategoryFromPath(window.location.pathname); + + const html = await ctx.loadFragment('/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() { + // 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; AdminSystem additionally holds a live SSE sub + a 30s interval + // we can stop cleanly. + try { + const as = window.adminSystem; + 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 AdminOverview's task-refresh registration so a finished verify/update + // task doesn't repaint a torn-down board. + try { window.taskRefresh && window.taskRefresh.unregister && window.taskRefresh.unregister('admin-overview'); } catch (_) {} + window.adminOverview = null; + window.adminSystem = null; + window.sshPage = null; + window.peersPage = null; + // configManager (+ its inner managers) intentionally left intact. + }, +}); diff --git a/containers/libreportal/frontend/index.html b/containers/libreportal/frontend/index.html index b172361..69eaf03 100755 --- a/containers/libreportal/frontend/index.html +++ b/containers/libreportal/frontend/index.html @@ -114,6 +114,7 @@ +