Merge claude/1
This commit is contained in:
commit
7a5f4cdc33
@ -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>';
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
@ -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)}%`;
|
||||
|
||||
@ -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 => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); },
|
||||
bytes(n) {
|
||||
@ -468,4 +468,4 @@ window.SystemFmt = window.SystemFmt || {
|
||||
},
|
||||
};
|
||||
|
||||
window.AdminSystem = AdminSystem;
|
||||
window.SystemPage = SystemPage;
|
||||
@ -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'
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@ -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 () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user