Compare commits

..

2 Commits

Author SHA1 Message Date
librelad
7a5f4cdc33 Merge claude/1 2026-05-31 01:21:07 +01:00
librelad
c920ca2dc9 refactor(webui): align page-controller names with the -page convention
From the feng-shui audit naming findings:
- admin/overview/js/admin-overview.js -> overview-page.js (class AdminOverview ->
  OverviewPage, window globals + the 'admin-overview' task-refresh id ->
  overview-page, lazy-load path + typeof/new in config-manager.js).
- admin/system/js/admin-system.js -> system-page.js (class AdminSystem ->
  SystemPage; now sits beside its -page sub-views system-metric-page.js /
  system-storage-page.js).
- tasks/js/tasks-logs-modal.js -> tasks-log-modal.js (singular 'log' to match its
  sibling tasks-log-stream.js; single path ref in system-loader.js).

These were the only page controllers breaking the dominant <thing>-page.js /
<Thing>Page convention (ssh-page/peers-page/backup-page/updater-page/
system-metric-page/system-storage-page). Pure renames; node --check clean.

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-31 01:21:07 +01:00
8 changed files with 27 additions and 27 deletions

View File

@ -42,14 +42,14 @@ if (typeof window.ConfigManager === 'undefined') {
// Overview is the Admin landing — an ops/health board, not a config form.
if (category === 'overview') {
try { this.sidebar.populateSidebar(); } catch (e) {}
// charts.js is the chart-rendering helper admin-overview pulls in.
// charts.js is the chart-rendering helper overview-page pulls in.
await Promise.all([
lazyLoad('/components/admin/overview/js/admin-overview.js'),
lazyLoad('/components/admin/overview/js/overview-page.js'),
lazyLoad('/components/admin/system/js/charts.js')
]);
if (typeof AdminOverview !== 'undefined') {
window.adminOverview = new AdminOverview('config-section');
await window.adminOverview.init();
if (typeof OverviewPage !== 'undefined') {
window.overviewPage = new OverviewPage('config-section');
await window.overviewPage.init();
} else {
configSection.innerHTML = '<div class="error">Admin overview failed to load.</div>';
}
@ -101,13 +101,13 @@ if (typeof window.ConfigManager === 'undefined') {
try { this.sidebar.populateSidebar(); } catch (e) {}
await Promise.all([
lazyLoad('/components/admin/system/js/charts.js'),
lazyLoad('/components/admin/system/js/admin-system.js'),
lazyLoad('/components/admin/system/js/system-page.js'),
lazyLoad('/components/admin/system/js/system-metric-page.js'),
lazyLoad('/components/admin/system/js/system-storage-page.js')
]);
if (typeof AdminSystem !== 'undefined') {
window.adminSystem = new AdminSystem('config-section');
await window.adminSystem.init();
if (typeof SystemPage !== 'undefined') {
window.systemPage = new SystemPage('config-section');
await window.systemPage.init();
} else {
configSection.innerHTML = '<div class="error">System page failed to load.</div>';
}

View File

@ -33,10 +33,10 @@ LP.features.register({
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; AdminSystem additionally holds a live SSE sub + a 30s interval
// null them; SystemPage additionally holds a live SSE sub + a 30s interval
// we can stop cleanly.
try {
const as = window.adminSystem;
const as = window.systemPage;
if (as) {
if (typeof as._stopLive === 'function') as._stopLive();
if (as._timer) { clearInterval(as._timer); as._timer = null; }
@ -46,11 +46,11 @@ LP.features.register({
as._subview = null;
}
} catch (_) {}
// Drop AdminOverview's task-refresh registration so a finished verify/update
// 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('admin-overview'); } catch (_) {}
window.adminOverview = null;
window.adminSystem = null;
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.

View File

@ -2,7 +2,7 @@
// from the user Dashboard, which is app-centric): it summarises updates,
// backups, SSH/security and system health from data we already generate, and
// each card links to where you act on it. Renders into #config-section.
class AdminOverview {
class OverviewPage {
constructor(rootId = 'config-section') {
this.rootId = rootId;
this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null;
@ -57,7 +57,7 @@ class AdminOverview {
// and re-render so the badge reflects reality without a manual reload.
// Registered with the task-refresh coordinator (single source of truth).
window.taskRefresh?.register({
id: 'admin-overview',
id: 'overview-page',
match: (d) => ['verify', 'update', 'system_update'].includes(d.action)
|| /^libreportal (verify|update)\b/.test((d.task && d.task.command) || d.command || ''),
run: () => this.refreshVerify(),
@ -274,4 +274,4 @@ class AdminOverview {
}
}
window.AdminOverview = AdminOverview;
window.OverviewPage = OverviewPage;

View File

@ -122,7 +122,7 @@ class SystemMetricPage {
// Metric registry — keys map to label, unit, formatter, accent. Mirrors
// the same list the index view exposes; lives here so the metric page
// can mount cleanly without AdminSystem present (direct URL load).
// can mount cleanly without SystemPage present (direct URL load).
_metricDef(key) {
const fmt = window.SystemFmt || { bytes: (n) => `${n}`, rate: (n) => `${n}/s`, rgbVar: () => '0, 212, 255' };
const pct = (v) => `${(v ?? 0).toFixed(1)}%`;

View File

@ -1,6 +1,6 @@
// Admin → System — orchestrator + index view.
//
// One AdminSystem instance per page mount. Reads the URL path on init and
// One SystemPage instance per page mount. Reads the URL path on init and
// dispatches to one of four sub-views:
//
// /admin/system → index (gauges + trends + per-app table)
@ -12,14 +12,14 @@
// each own their own DOM + lifecycle inside #config-section. We mount one
// at a time; switching means tearing down the active renderer and starting
// a fresh one. The SPA re-runs handleAdmin() on every navigation, which
// re-runs ConfigManager.renderConfig('system') → AdminSystem.init, so the
// re-runs ConfigManager.renderConfig('system') → SystemPage.init, so the
// dispatch happens organically with the router.
//
// Live (1 Hz, via LiveSystem SSE) data flows directly to whichever sub-view
// is mounted. The index view ticks gauges in place; the metric page splices
// the live value into its chart's tail.
class AdminSystem {
class SystemPage {
constructor(rootId = 'config-section') {
this.rootId = rootId;
this.range = 60; // minutes of history to chart
@ -134,7 +134,7 @@ class AdminSystem {
return;
}
// Expand a metric → navigate to its detail page. The SPA picks up
// the new URL, ConfigManager re-renders, AdminSystem.init mounts
// the new URL, ConfigManager re-renders, SystemPage.init mounts
// the metric page.
const ex = e.target.closest('[data-sys-expand]');
if (ex) {
@ -440,7 +440,7 @@ class AdminSystem {
// Lightweight formatter helpers shared with sub-pages so they don't each
// reimplement bytes()/rate(). Attached as a global so a sub-page that mounts
// before AdminSystem still has them.
// before SystemPage still has them.
window.SystemFmt = window.SystemFmt || {
escape(s) { return String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])); },
bytes(n) {
@ -468,4 +468,4 @@ window.SystemFmt = window.SystemFmt || {
},
};
window.AdminSystem = AdminSystem;
window.SystemPage = SystemPage;

View File

@ -177,7 +177,7 @@ class SystemLoader {
'/components/tasks/js/tasks-row-expand.js',
'/components/tasks/js/tasks-actions.js',
'/components/tasks/js/tasks-modals.js',
'/components/tasks/js/tasks-logs-modal.js'
'/components/tasks/js/tasks-log-modal.js'
]
});

View File

@ -9,7 +9,7 @@
// feature's module top level, so the lazy getters always resolve.
//
// NOTE: page-owned controllers (appsManager, appTabbedManager, configManager,
// backupPage, adminSystem, …) are NOT services — they belong to their feature —
// backupPage, systemPage, …) are NOT services — they belong to their feature —
// so they are deliberately absent here. Slot names + globals were verified
// against the real code (the design doc's §4 list had several wrong names).
(function () {