feat(backup): auto-refresh the backup page when a backup/restore finishes
The page has no live feed, so a completed backup/restore wasn't reflected until a manual Refresh or re-navigation. Subscribe to the TaskEventBus 'taskCompleted' event and repaint on backup/restore completions. Debounced to coalesce the burst when several per-app tasks finish together; only the mounted instance reacts and a stale listener removes itself. The Refresh button stays as a manual pull. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
7a302d1af0
commit
d448d34f67
@ -98,6 +98,8 @@ class BackupPage {
|
|||||||
this.engines = []; // [{id,name,supported_types}, ...] — fetched once
|
this.engines = []; // [{id,name,supported_types}, ...] — fetched once
|
||||||
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._onTaskCompleted = this._onTaskCompleted.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
@ -111,6 +113,29 @@ class BackupPage {
|
|||||||
this.updatePrimaryAction();
|
this.updatePrimaryAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Backups/restores complete asynchronously and the page has no live feed,
|
||||||
|
so repaint when one finishes (snapshot lists, last-backup times, sizes).
|
||||||
|
The Refresh button stays as a manual pull. Debounced because picking
|
||||||
|
several apps queues a task each, which finish in a burst. Only the
|
||||||
|
mounted instance reacts; a stale listener removes itself. */
|
||||||
|
_onTaskCompleted(e) {
|
||||||
|
if (window.backupPage !== this || !document.getElementById('backup-page')) {
|
||||||
|
window.removeEventListener('taskCompleted', this._onTaskCompleted);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const d = e?.detail || {};
|
||||||
|
const cmd = d.task?.command || '';
|
||||||
|
const relevant = d.action === 'backup' || d.action === 'restore'
|
||||||
|
|| /^libreportal\s+(backup|restore)\b/.test(cmd);
|
||||||
|
if (!relevant) return;
|
||||||
|
clearTimeout(this._taskRefreshTimer);
|
||||||
|
this._taskRefreshTimer = setTimeout(() => {
|
||||||
|
if (window.backupPage === this && document.getElementById('backup-page')) {
|
||||||
|
this.refreshAll().then(() => this.render());
|
||||||
|
}
|
||||||
|
}, 600);
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the active tab slug from window.location, supporting both
|
/* Read the active tab slug from window.location, supporting both
|
||||||
/backup?=dashboard (the legacy libreportal ?= form used on /config)
|
/backup?=dashboard (the legacy libreportal ?= form used on /config)
|
||||||
and /backup?backup=dashboard (standard query string) so links from
|
and /backup?backup=dashboard (standard query string) so links from
|
||||||
@ -146,6 +171,8 @@ class BackupPage {
|
|||||||
if (this.eventBound) return;
|
if (this.eventBound) return;
|
||||||
this.eventBound = true;
|
this.eventBound = true;
|
||||||
|
|
||||||
|
window.addEventListener('taskCompleted', this._onTaskCompleted);
|
||||||
|
|
||||||
// Browser back/forward is handled by the SPA's popstate listener —
|
// Browser back/forward is handled by the SPA's popstate listener —
|
||||||
// pushTabToUrl includes a `route` field in state so the SPA's
|
// pushTabToUrl includes a `route` field in state so the SPA's
|
||||||
// handler picks it up and re-runs handleBackup, which re-parses
|
// handler picks it up and re-runs handleBackup, which re-parses
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user