Merge claude/2

This commit is contained in:
librelad 2026-05-27 00:42:58 +01:00
commit 420964c6e8
2 changed files with 59 additions and 40 deletions

View File

@ -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 &amp; 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">

View File

@ -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">