ui(backup): merge System config into the Backup status grid
The dashboard had two parallel sections — 'Per-app status' (every app's latest backup) and a standalone 'System config' card below it. Folded them into one grid: a single 'Backup status' card with the System config tile rendered FIRST, then every app tile. Why first: a bare-metal restore needs the system config (CFG_* + backup-location credentials) — without it the backups exist but the keys to reach them don't. Putting it at eye-level above the app tiles makes the dependency visible. System tile reuses the .backup-app-tile shape: server-stack icon, 'System config' as the name, status dot + 'Last backed up X ago' / 'No backup yet'. Plus two compact inline action buttons (Back up / Restore) on the right that wire into the same data-action handlers the old standalone card used — no behaviour change, just the visual container. grid-column: 1 / -1 on the system tile makes it span the row so the two action buttons fit alongside the meta text without crushing the app-tile grid template. Section header: 'Per-app status' → 'Backup status' + hint 'System config and every installed app's latest backup. System config always first — a bare-metal restore needs it.' Dashboard subtitle updated to match. Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
parent
6fb595e481
commit
102fc38da0
@ -83,9 +83,15 @@
|
||||
<div class="backup-cards-row">
|
||||
<div class="backup-card">
|
||||
<div class="backup-card-header">
|
||||
<h2>Per-app status</h2>
|
||||
<span class="backup-card-hint">Latest backup per app on this host</span>
|
||||
<h2>Backup status</h2>
|
||||
<span class="backup-card-hint">System config and every installed app's latest backup. System config always first — a bare-metal restore needs it.</span>
|
||||
</div>
|
||||
<!-- The "System config" tile is rendered FIRST inside this grid
|
||||
by renderDashboard() / renderSystemTile(), styled the same
|
||||
as an app tile but with a server icon and two inline action
|
||||
buttons (back up / restore). Folding both into one grid
|
||||
gives a single at-a-glance checklist instead of two
|
||||
parallel sections. -->
|
||||
<div class="backup-app-grid" id="backup-app-grid"></div>
|
||||
</div>
|
||||
<div class="backup-card">
|
||||
@ -96,31 +102,6 @@
|
||||
<div class="backup-repo-list" id="backup-repo-list-summary"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="backup-card backup-system-card">
|
||||
<div class="backup-card-header">
|
||||
<h2>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="opacity:.7;vertical-align:-3px;margin-right:7px">
|
||||
<rect x="2" y="3" width="20" height="6" rx="1"></rect>
|
||||
<rect x="2" y="9" width="20" height="6" rx="1"></rect>
|
||||
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
||||
<line x1="6" y1="12" x2="6.01" y2="12"></line>
|
||||
</svg>System config
|
||||
</h2>
|
||||
<span class="backup-card-hint">Global settings, WebUI login & backup-location credentials</span>
|
||||
</div>
|
||||
<div class="backup-app-tile-meta" id="backup-system-status" style="margin:0 0 10px">
|
||||
<span class="backup-status-dot none"></span><span>No backup yet</span>
|
||||
</div>
|
||||
<p class="backup-card-hint" style="margin:0 0 12px">
|
||||
Snapshot the LibrePortal system config to every enabled location so a bare-metal
|
||||
restore is self-sufficient — without it, the credentials needed to reach your own
|
||||
backups live only on this box. Runs automatically with “Backup all apps” too.
|
||||
</p>
|
||||
<div class="backup-system-actions" style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<button type="button" class="backup-primary-btn" data-action="backup-system">Back up now</button>
|
||||
<button type="button" class="backup-secondary-btn" data-action="restore-system">Restore…</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="backup-tabpanel" id="backup-panel-backups">
|
||||
|
||||
@ -456,7 +456,7 @@ class BackupPage {
|
||||
|
||||
subtitleFor(tab) {
|
||||
return {
|
||||
dashboard: 'Per-app status and storage at a glance.',
|
||||
dashboard: 'Backup status — system config + every app — at a glance.',
|
||||
backups: 'Every snapshot across every enabled location.',
|
||||
locations: 'Where backups are stored. Add, edit, or remove destinations.',
|
||||
migrate: 'Restore an app from another LibrePortal that shares one of your backup locations.',
|
||||
@ -586,20 +586,14 @@ class BackupPage {
|
||||
${this.tile('Total stored', this.formatBytes(totalSize), 'deduplicated, encrypted')}
|
||||
`;
|
||||
|
||||
// System config tile is rendered FIRST so the bare-metal-restore
|
||||
// prerequisite is always at eye-level — without it, the user's
|
||||
// backups exist but the credentials needed to reach them don't.
|
||||
const systemTileHtml = this.renderSystemTile(d.system || {});
|
||||
if (!apps.length) {
|
||||
appGrid.innerHTML = `<div class="backup-empty-state">No apps installed yet.</div>`;
|
||||
appGrid.innerHTML = systemTileHtml + `<div class="backup-empty-state">No apps installed yet.</div>`;
|
||||
} else {
|
||||
appGrid.innerHTML = apps.map(app => this.renderAppTile(app)).join('');
|
||||
}
|
||||
|
||||
const sysStatus = document.getElementById('backup-system-status');
|
||||
if (sysStatus) {
|
||||
const sys = d.system || {};
|
||||
const hasSys = !!sys.latest_snapshot;
|
||||
sysStatus.innerHTML = `
|
||||
<span class="backup-status-dot ${hasSys ? 'ok' : 'none'}"></span>
|
||||
<span>${hasSys ? 'Last backed up ' + this.formatRelative(sys.latest_time) : 'No backup yet'}</span>
|
||||
`;
|
||||
appGrid.innerHTML = systemTileHtml + apps.map(app => this.renderAppTile(app)).join('');
|
||||
}
|
||||
|
||||
if (!locs.length) {
|
||||
@ -620,6 +614,50 @@ class BackupPage {
|
||||
}
|
||||
}
|
||||
|
||||
// System config tile — same shape as an app tile but with a server icon
|
||||
// and two inline action buttons (the standalone System config card used
|
||||
// to host these). Rendered first in the Backup status grid so it always
|
||||
// sits at eye-level.
|
||||
renderSystemTile(sys) {
|
||||
const has = !!sys.latest_snapshot;
|
||||
const dot = has ? 'ok' : 'none';
|
||||
const when = has ? 'Last backed up ' + this.formatRelative(sys.latest_time) : 'No backup yet';
|
||||
return `
|
||||
<div class="backup-app-tile backup-app-tile--system" data-system="1" style="grid-column: 1 / -1; display:flex; align-items:center; gap:14px">
|
||||
<div class="backup-app-tile-icon" style="display:flex; align-items:center; justify-content:center; opacity:.8">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="2" y="3" width="20" height="6" rx="1"></rect>
|
||||
<rect x="2" y="9" width="20" height="6" rx="1"></rect>
|
||||
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
||||
<line x1="6" y1="12" x2="6.01" y2="12"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="backup-app-tile-text" style="flex:1; min-width:0">
|
||||
<div class="backup-app-tile-name">System config</div>
|
||||
<div class="backup-app-tile-meta">
|
||||
<span class="backup-status-dot ${dot}"></span>
|
||||
<span>${this.escape(when)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="backup-system-actions" style="display:flex; gap:6px; flex-shrink:0">
|
||||
<button type="button" class="backup-secondary-btn" data-action="backup-system" title="Snapshot the LibrePortal system config to every enabled location" style="padding:6px 10px; font-size:.85em">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="17 8 12 3 7 8"></polyline>
|
||||
<line x1="12" y1="3" x2="12" y2="15"></line>
|
||||
</svg>Back up
|
||||
</button>
|
||||
<button type="button" class="backup-secondary-btn" data-action="restore-system" title="Restore the latest system-config snapshot into a staging folder for review" style="padding:6px 10px; font-size:.85em">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px">
|
||||
<polyline points="23 4 23 10 17 10"></polyline>
|
||||
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
|
||||
</svg>Restore
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
tile(label, value, detail) {
|
||||
return `
|
||||
<div class="backup-summary-tile">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user