Final modularization layout (user-chosen): every page is a self-contained folder under components/<id>/ (controllers + CSS + its html fragment), and all shared/framework code folds into core/: core/kernel (feature-registry, lifecycle, services, spa) core/boot (auth, system-loader/orchestrator, setup, loaders) core/lib (data-loader, router, helpers, the task kernel, shared modules) core/ui (topbar, modal, notifications, … + topbar.html) core/css (all shared stylesheets) core/icons Top level is now just: components/, core/, themes/, index.html (+ runtime data/). Every path reference rewritten (index.html, scripts arrays, fetch()/ loadFragment()/loadScript() literals, system-loader + config-manager controller paths, kernel manifest URL, feature.json, backend FEATURES_DIR). The /api/features/list endpoint NAME is unchanged (it now scans components/). Deleted 3 dead files (app-content.html, apps-content.html, html-cache.js). Verified: 0 stale prefixes, 0 double-rewrites, all JS/JSON valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
43 lines
2.0 KiB
JavaScript
43 lines
2.0 KiB
JavaScript
// features/dashboard/index.js — the landing Dashboard as a feature module.
|
|
//
|
|
// dashboard.js exposes bare global functions (loadInstalledApps,
|
|
// loadDashboardData live in dashboard.js / data-loader.js, both eager core
|
|
// scripts) — there is no controller class to lazy-load, so scripts is empty.
|
|
// system-loader's 'dashboard' component already ran initializeData()/
|
|
// loadSystemInfo()/setupEventListeners() once at boot; mount() only does the
|
|
// per-navigation refresh (mirrors the old handleDashboard + the navigate()
|
|
// data-reload special-case, which has been removed from spa.js so the reload
|
|
// now fires exactly once here).
|
|
LP.features.register({
|
|
id: 'dashboard',
|
|
routes: ['/', '/dashboard'],
|
|
|
|
async mount(ctx) {
|
|
const html = await ctx.loadFragment('/components/dashboard/dashboard-content.html');
|
|
ctx.setContent(html, 'Dashboard');
|
|
|
|
// Render the installed-apps icon grid (handleDashboard's only post-render call).
|
|
if (typeof loadInstalledApps === 'function') loadInstalledApps();
|
|
|
|
// Repaint the stat cards / disk donut + (re)wire the 1 Hz live SSE. The
|
|
// 100 ms cushion lets the freshly-injected DOM settle (loadSystemInfo also
|
|
// guards on element presence). ctx.sub() cancels it if we navigate away
|
|
// before it fires.
|
|
const reloadTimer = setTimeout(() => {
|
|
if (typeof loadDashboardData === 'function') loadDashboardData();
|
|
}, 100);
|
|
ctx.sub(() => clearTimeout(reloadTimer));
|
|
},
|
|
|
|
async unmount() {
|
|
// Nothing this view owns is destroyable from here: the dashboard has no
|
|
// handler-newed controller and no system-loader singleton to tear down.
|
|
// The pending reload timer is cancelled via the ctx.sub() above (ctx.teardown).
|
|
// The 1 Hz LiveSystem SSE sub (attachDashboardLive) self-releases on its
|
|
// next sample once the dashboard DOM is gone, and the 1 s update countdown
|
|
// is a module-private interval with no exported stopper (pre-existing; it
|
|
// self-clears on the next dashboard mount). Both are noted for the Phase 5
|
|
// dashboard cleanup; neither is reachable here.
|
|
},
|
|
});
|