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:
root
2026-08-21 15:15:13 +02:00
parent 5802b200a7
commit 9b631f527c
3 changed files with 84 additions and 5 deletions

View File

@@ -252,7 +252,52 @@
<div class="card-title"><i class="fas fa-shield-halved"></i> Manual Backup</div>
</div>
<div style="padding:4px 0 12px;">
<p style="color:var(--text2);font-size:13px;margin-bottom:14px;">Manually trigger a backup of all containers</p>
<p style="color:var(--text2);font-size:13px;margin-bottom:10px;">
All apps are backed up together into one archive by default. Uncheck any app to leave it out —
useful for a quick one-off backup of a single app before a risky change, without waiting on the rest.
</p>
<div class="app-picker-grid" id="backup-apps-checkbox-group" style="margin-bottom:14px;">
<label class="app-picker-card">
<input type="checkbox" value="frappe" checked>
<div class="app-picker-body">
<span class="app-picker-icon">🧾</span>
<div><div class="app-picker-name">Frappe / ERPNext</div></div>
<span class="app-picker-check"><i class="fas fa-check"></i></span>
</div>
</label>
<label class="app-picker-card">
<input type="checkbox" value="odoo" checked>
<div class="app-picker-body">
<span class="app-picker-icon">🟣</span>
<div><div class="app-picker-name">Odoo</div></div>
<span class="app-picker-check"><i class="fas fa-check"></i></span>
</div>
</label>
<label class="app-picker-card">
<input type="checkbox" value="nextcloud" checked>
<div class="app-picker-body">
<span class="app-picker-icon">☁️</span>
<div><div class="app-picker-name">Nextcloud</div></div>
<span class="app-picker-check"><i class="fas fa-check"></i></span>
</div>
</label>
<label class="app-picker-card">
<input type="checkbox" value="mautic" checked>
<div class="app-picker-body">
<span class="app-picker-icon">📣</span>
<div><div class="app-picker-name">Mautic</div></div>
<span class="app-picker-check"><i class="fas fa-check"></i></span>
</div>
</label>
<label class="app-picker-card">
<input type="checkbox" value="n8n" checked>
<div class="app-picker-body">
<span class="app-picker-icon">🔁</span>
<div><div class="app-picker-name">n8n</div></div>
<span class="app-picker-check"><i class="fas fa-check"></i></span>
</div>
</label>
</div>
<button class="btn btn-primary" onclick="runManualBackup()" id="manual-backup-btn">
<i class="fas fa-play"></i> Run Backup Now
</button>
@@ -288,6 +333,11 @@
<div class="backup-item-main">
<span class="status-dot status-dot-{{ b.status }}" title="{{ b.status }}{% if b.apps %} · apps: {{ b.apps|join(', ') }}{% endif %}{% if b.size_human %} · {{ b.size_human }}{% endif %}"></span>
<span class="backup-name">{{ b.name }}</span>
{% if b.apps %}
<span class="badge" style="background:rgba(59,130,246,0.12);color:var(--accent2);font-size:10px;white-space:nowrap;">
{% if b.apps|length >= 5 %}All apps{% else %}{{ b.apps|join(', ') }}{% endif %}
</span>
{% endif %}
</div>
<div class="backup-actions">
<button class="btn btn-ghost btn-sm" style="color:var(--text3);" onclick="showBackupDetails('local','{{ b.name }}',this)" title="Quick details"><i class="fas fa-circle-info"></i></button>
@@ -313,6 +363,11 @@
<div class="backup-item-main">
<span class="status-dot status-dot-{{ b.status }}" title="{{ b.status }}{% if b.apps %} · apps: {{ b.apps|join(', ') }}{% endif %}{% if b.size_human %} · {{ b.size_human }}{% endif %}"></span>
<span class="backup-name">{{ b.name }}</span>
{% if b.apps %}
<span class="badge" style="background:rgba(59,130,246,0.12);color:var(--accent2);font-size:10px;white-space:nowrap;">
{% if b.apps|length >= 5 %}All apps{% else %}{{ b.apps|join(', ') }}{% endif %}
</span>
{% endif %}
</div>
<div class="backup-actions">
<button class="btn btn-ghost btn-sm" style="color:var(--text3);" onclick="showBackupDetails('vm','{{ b.name }}',this)" title="Quick details"><i class="fas fa-circle-info"></i></button>