// Auto-extracted from backup-page.js (verbatim) — augments BackupPage.prototype. Loaded after the base. Object.assign(BackupPage.prototype, { renderDashboard() { const summary = document.getElementById('backup-summary-row'); const appGrid = document.getElementById('backup-app-grid'); const locSummary = document.getElementById('backup-repo-list-summary'); if (!summary || !appGrid || !locSummary) return; const d = this.dashboard || {}; const locs = d.locations || []; const apps = d.apps || []; const totalSnapshots = Object.values(this.snapshotsByLoc).reduce((acc, r) => { return acc + (Array.isArray(r?.snapshots) ? r.snapshots.length : 0); }, 0); const protectedApps = apps.filter(a => a.latest_snapshot).length; const totalSize = locs.reduce((acc, r) => acc + (parseInt(r.total_size_bytes) || 0), 0); summary.innerHTML = ` ${this.tile('Apps protected', `${protectedApps} / ${apps.length}`, 'with at least one backup')} ${this.tile('Backups', `${totalSnapshots}`, `across ${locs.length} location${locs.length === 1 ? '' : 's'}`)} ${this.tile('Total stored', this.formatBytes(totalSize), 'deduplicated, encrypted')} `; // Next-run hint in the "Backup status" card header — derived from // CFG_BACKUP_CRONTAB_APP (the cron expression the app-backup // scheduler uses). Pure client-side computation; no backend // surface needed. const nextRunEl = document.getElementById('backup-next-run'); if (nextRunEl) { const cron = (window.systemConfigs?.CFG_BACKUP_CRONTAB_APP || '').trim(); const next = cron ? this.nextCronFireTime(cron) : null; if (next) { nextRunEl.textContent = `Next backup ${this.formatRelativeFuture(next)} · ${this.formatScheduleClock(next)}`; nextRunEl.title = `Next scheduled backup: ${next.toLocaleString()}\nSchedule: ${cron}`; } else if (cron) { nextRunEl.textContent = `Schedule: ${cron}`; nextRunEl.title = `Couldn't parse the schedule "${cron}" to compute the next run.`; } else { nextRunEl.textContent = 'No schedule set'; nextRunEl.title = 'CFG_BACKUP_CRONTAB_APP is empty — backups only run when triggered manually.'; } } // 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 = systemTileHtml + `