From 72dba7a3a4c780def9810da7b356807a3db7473f Mon Sep 17 00:00:00 2001 From: root Date: Fri, 21 Aug 2026 11:07:01 +0200 Subject: [PATCH] Fix backup status dots disappearing after page load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /api/backups returned plain filename strings while pages/backups.html's server-rendered dots came from get_local_backups_with_status()/ get_vm_backups_with_status(). platform.js's DOMContentLoaded handler always calls refreshBackupsList() (backups.html has #backup-history-list, which triggers it unconditionally), which re-fetches /api/backups and rebuilds #local-backup-list/#vm-backup-list via renderBackupList() — a version with zero knowledge of status, wiping out the dots seconds after initial paint. Switch /api/backups to the *_with_status() variants and have renderBackupList() render the same status-dot markup as the Jinja template, so the dot is sourced from persisted backup metadata on every render path, not just the first one. --- platform/app.py | 2 +- platform/static/js/platform.js | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/platform/app.py b/platform/app.py index 6dd5964..b695ce1 100644 --- a/platform/app.py +++ b/platform/app.py @@ -377,7 +377,7 @@ def api_container_status(name): @app.route('/api/backups') @login_required def api_backups(): - return jsonify({'local': get_local_backups(), 'vm': get_vm_backups()}) + return jsonify({'local': get_local_backups_with_status(), 'vm': get_vm_backups_with_status()}) @app.route('/api/backups/log') diff --git a/platform/static/js/platform.js b/platform/static/js/platform.js index 05874ef..4b5b391 100644 --- a/platform/static/js/platform.js +++ b/platform/static/js/platform.js @@ -377,8 +377,8 @@ async function refreshBackupsList() { renderBackupList(d.vm, 'vm-backup-list', 'vm'); if (el('stat-local-bk')) el('stat-local-bk').textContent = d.local.length; if (el('stat-vm-bk')) el('stat-vm-bk').textContent = d.vm.length; - if (el('local-options')) el('local-options').innerHTML = d.local.length ? d.local.map((b) => ``).join('') : ''; - if (el('vm-options')) el('vm-options').innerHTML = d.vm.length ? d.vm.map((b) => ``).join('') : ''; + if (el('local-options')) el('local-options').innerHTML = d.local.length ? d.local.map((b) => ``).join('') : ''; + if (el('vm-options')) el('vm-options').innerHTML = d.vm.length ? d.vm.map((b) => ``).join('') : ''; } catch (_) {} } @@ -394,7 +394,13 @@ function renderBackupList(items, id, source) { return; } node.innerHTML = items.map((b) => { - const safe = jsStr(b); + const name = b.name; + const safe = jsStr(name); + const status = b.status || 'unknown'; + const titleParts = [status]; + if (b.apps && b.apps.length) titleParts.push(`apps: ${b.apps.join(', ')}`); + if (b.size_human) titleParts.push(b.size_human); + const title = escapeHtml(titleParts.join(' · ')); const uploadBtn = source === 'local' && typeof quickUploadR2 === 'function' ? `` : ''; @@ -402,9 +408,10 @@ function renderBackupList(items, id, source) { ? `` : ''; return ` -
+
- ${escapeHtml(b)} + + ${escapeHtml(name)}
${detailsBtn}