Merge claude/2

This commit is contained in:
librelad 2026-05-31 14:48:54 +01:00
commit 429ec419cf
2 changed files with 19 additions and 8 deletions

View File

@ -16,6 +16,7 @@ class BackupPage {
this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null; this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null;
this.eventBound = false; this.eventBound = false;
this._taskRefreshTimer = null; this._taskRefreshTimer = null;
this._ac = new AbortController(); // dispose() aborts this to remove the document listeners on unmount
} }
async init() { async init() {
@ -294,13 +295,13 @@ class BackupPage {
this.saveSection(saveBtn.dataset.backupSave); this.saveSection(saveBtn.dataset.backupSave);
return; return;
} }
}); }, { signal: this._ac.signal });
document.addEventListener('input', (e) => { document.addEventListener('input', (e) => {
if (e.target.id === 'backup-snapshot-filter' || e.target.id === 'backup-snapshot-repo') { if (e.target.id === 'backup-snapshot-filter' || e.target.id === 'backup-snapshot-repo') {
this.renderSnapshots(); this.renderSnapshots();
} }
}); }, { signal: this._ac.signal });
// Type select changes refresh the visible connection fields inline. // Type select changes refresh the visible connection fields inline.
// Retention preset changes are handled by applyRetentionPreset, which // Retention preset changes are handled by applyRetentionPreset, which
@ -323,7 +324,17 @@ class BackupPage {
if (presetSel) { if (presetSel) {
this.applyRetentionPreset(presetSel); this.applyRetentionPreset(presetSel);
} }
}); }, { signal: this._ac.signal });
}
/* Release everything this page attached to document/window so navigating
away (kernel unmount) can't leave stale listeners firing on the live DOM
the cause of the backup sidebar "content stacks on revisit" bug. Called by
the feature module's unmount(). */
dispose() {
try { this._ac && this._ac.abort(); } catch (_) {}
try { window.taskRefresh && window.taskRefresh.unregister('backups'); } catch (_) {}
if (this._taskRefreshTimer) { clearTimeout(this._taskRefreshTimer); this._taskRefreshTimer = null; }
} }

View File

@ -46,11 +46,11 @@ LP.features.register({
}, },
async unmount(ctx) { async unmount(ctx) {
// Best-effort teardown. BackupPage self-guards stale work via // Release the page's document listeners + task-refresh registration so a
// (window.backupPage === this), so nulling the global neutralises any // navigation away doesn't leave stale BackupPage listeners firing on the
// pending task-refresh repaint; we also drop its coordinator registration. // live DOM — the backup sidebar "content stacks on revisit" bug. dispose()
// A proper dispose() (removing the leaked document listeners) lands with // aborts the click/input/change listeners and drops the coordinator reg.
// the Phase 5 backup decomposition. try { window.backupPage && window.backupPage.dispose(); } catch (_) {}
try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {} try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {}
window.backupPage = null; window.backupPage = null;
}, },