Show which apps are in each backup + optional per-app manual backup
Prompted by today's testing: running backup-k8s-apps.sh --apps X repeatedly
for isolated per-app verification left a bunch of single-app archives in
the list, all named identically (myapps-k8s-backup-TIMESTAMP.tar.gz) with
no visible indication of which app(s) each one actually contains — the
data was already there (the .meta.json sidecar's `apps` field, used for
the status-dot rolling average) but only surfaced in a hover tooltip.
Cleaned up today's test archives (local + VM + R2) and ran one fresh full
backup so the list reflects real state.
Two things added, backup/restore logic itself untouched per explicit
instruction:
1. A small visible badge next to each backup's name — "All apps" for a
full bundle, or the specific list (e.g. "odoo, n8n") for a partial one
— in both the Jinja-rendered list and platform.js's refresh path.
2. An optional app-picker on the "Run Backup Now" manual trigger, same
checkbox-grid pattern already used on the Restore page's app selector.
All checked (default) = exactly today's existing behavior, no --apps
flag, everything bundled into one archive. Unchecking some = a
deliberate one-off partial backup (--apps a,b) for e.g. backing up just
odoo before a risky change without waiting on the other 4. The nightly
cron and "backup all together" behavior are completely unaffected —
this only touches the manual/UI-triggered path.
Verified: manual full backup still produces one bundled archive (249M, 5
apps); the apps-badge renders correctly ("All apps") on the live standby;
the --apps arg-construction logic unit-tested directly (partial selection
-> ['--apps', 'a,b'], all-selected -> [] i.e. default bundle).
This commit is contained in:
@@ -410,11 +410,15 @@ function renderBackupList(items, id, source) {
|
||||
const detailsBtn = typeof showBackupDetails === 'function'
|
||||
? `<button class="btn btn-ghost btn-sm" style="color:var(--text3);" onclick="showBackupDetails('${source}','${safe}',this)" title="Quick details"><i class="fas fa-circle-info"></i></button>`
|
||||
: '';
|
||||
const appsLabel = (b.apps && b.apps.length)
|
||||
? `<span class="badge" style="background:rgba(59,130,246,0.12);color:var(--accent2);font-size:10px;white-space:nowrap;">${b.apps.length >= 5 ? 'All apps' : escapeHtml(b.apps.join(', '))}</span>`
|
||||
: '';
|
||||
return `
|
||||
<div class="backup-item" id="bk-item-${source}-${name.replace(/[^a-z0-9]/gi, '_')}">
|
||||
<div class="backup-item-main">
|
||||
<span class="status-dot status-dot-${status}" title="${title}"></span>
|
||||
<span class="backup-name">${escapeHtml(name)}</span>
|
||||
${appsLabel}
|
||||
</div>
|
||||
<div class="backup-actions">
|
||||
${detailsBtn}
|
||||
@@ -489,7 +493,14 @@ async function runManualBackup() {
|
||||
if (wrapper) wrapper.style.display = '';
|
||||
if (logEl) logEl.innerHTML = '';
|
||||
try {
|
||||
const r = await fetch('/api/backups/run', { method: 'POST' });
|
||||
const selectedApps = Array.from(
|
||||
document.querySelectorAll('#backup-apps-checkbox-group input[type="checkbox"]:checked')
|
||||
).map((cb) => cb.value);
|
||||
const r = await fetch('/api/backups/run', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ apps: selectedApps }),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (!d.success) throw new Error(d.message || 'Failed');
|
||||
manualBackupJobId = d.job_id;
|
||||
|
||||
Reference in New Issue
Block a user