De-clutter each component into sub-system folders (apps: core/ port-manager/
services/ tools/ routing/; admin: config/ overview/ system/ ssh/ peers/) with
the standard js/ css/ html/ icons/ layout inside; single-page components
(backup/dashboard/tasks/updater) get js/ css/ html/. Single-feature icon sets
moved into their sub-system (vpn -> apps/core/icons, config/cpu/os ->
admin/{config,system}/icons); shared app + category icons stay in core/icons.
feature.json + index.js stay at each component root (the scanned descriptor +
entry). Every controller/CSS/fragment/icon path reference rewritten; verified
no stale refs, all JS valid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
43 lines
1.8 KiB
JavaScript
43 lines
1.8 KiB
JavaScript
// features/backup/index.js — Backup Center as a self-contained feature module.
|
|
//
|
|
// FIRST page migrated to the feature-module contract (docs/frontend-modularization.md).
|
|
// The kernel drives mount()/unmount() for the /backup route instead of
|
|
// spa.js's handleBackup(). The heavy controller (backup-page.js, ~129KB) is
|
|
// still lazy-loaded on first mount, so cold-load cost is unchanged.
|
|
//
|
|
// Snap-out demo: deleting this folder removes the backup route's module
|
|
// registration; the manifest entry then falls back to the legacy handler
|
|
// (and, once handleBackup is retired, to the kernel's not-found route). The
|
|
// full decomposition of backup-page.js into per-tab modules is Phase 5.
|
|
LP.features.register({
|
|
id: 'backup',
|
|
routes: ['/backup', '/backup*'],
|
|
// Controllers the feature needs; lazy-loaded on first mount (idempotent).
|
|
scripts: [
|
|
'/components/backup/js/backup-schema.js',
|
|
'/components/backup/js/backup-page.js',
|
|
'/core/lib/backup-app-card.js',
|
|
],
|
|
|
|
async mount(ctx) {
|
|
await ctx.loadScripts(this.scripts);
|
|
const html = await ctx.loadFragment('/components/backup/html/backup-content.html');
|
|
ctx.setContent(html, 'Backups');
|
|
if (typeof BackupPage === 'undefined') {
|
|
throw new Error('BackupPage controller failed to load');
|
|
}
|
|
window.backupPage = new BackupPage();
|
|
await window.backupPage.init();
|
|
},
|
|
|
|
async unmount(ctx) {
|
|
// Best-effort teardown. BackupPage self-guards stale work via
|
|
// (window.backupPage === this), so nulling the global neutralises any
|
|
// pending task-refresh repaint; we also drop its coordinator registration.
|
|
// A proper dispose() (removing the leaked document listeners) lands with
|
|
// the Phase 5 backup decomposition.
|
|
try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {}
|
|
window.backupPage = null;
|
|
},
|
|
});
|