// components/backup/index.js — Backup Center as a self-contained feature module. // // FIRST page migrated to the feature-module contract (docs/architecture/webui-architecture.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). // Controllers, organised by sub-system (tabs). core/ first: schema + base // class + the shared data/cron, then each tab's prototype-augment clusters. scripts: [ '/components/backup/core/js/backup-schema.js', '/components/backup/core/js/backup-page.js', // base: class + constructor + init/switchTab/render '/components/backup/core/js/backup-fetch-client.js', '/components/backup/core/js/backup-cron-schedule.js', '/components/backup/dashboard/js/backup-dashboard.js', '/components/backup/snapshots/js/backup-snapshots.js', '/components/backup/snapshots/js/backup-snapshot-actions.js', '/components/backup/locations/js/backup-locations.js', '/components/backup/locations/js/backup-location-fields.js', '/components/backup/locations/js/backup-location-modal.js', '/components/backup/locations/js/backup-ssh-key.js', '/components/backup/configuration/js/backup-configuration.js', '/components/backup/configuration/js/backup-retention-presets.js', '/components/backup/configuration/js/backup-engine-details.js', '/core/backup-card/js/backup-app-card.js', ], async mount(ctx) { await ctx.loadScripts(this.scripts); const html = await ctx.loadFragment('/components/backup/core/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) { // Release the page's document listeners + task-refresh registration so a // navigation away doesn't leave stale BackupPage listeners firing on the // live DOM — the backup sidebar "content stacks on revisit" bug. dispose() // aborts the click/input/change listeners and drops the coordinator reg. try { window.backupPage && window.backupPage.dispose(); } catch (_) {} try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {} window.backupPage = null; }, });