From 92e693cfe6aad7e9fdb1d6d546f222f33656e0a7 Mon Sep 17 00:00:00 2001 From: Dillard Blom Date: Tue, 13 Oct 2026 11:02:18 +0200 Subject: [PATCH] Runs list: show the total size of each backup next to what it uploaded --- CHANGELOG.md | 7 +++++++ lib/Command/Status.php | 16 ++++++++++++++-- src/components/Backups.vue | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47868a4..10dbe8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ the app store accepts a `-beta` suffix, but Nextcloud servers then only offer th beta/daily update channel, which would hide the app from most admins. The stability stage is instead carried by the app description, the git tag, the release, and this file. +## [Unreleased] + +### Added +- The list of backup runs (web interface and `occ backup:status`) shows the total size of each + backup next to what it uploaded: an incremental backup of 1 TB that uploads 800 MB now shows + both. `occ backup:status` shows sizes in GiB where that reads better than MiB. + ## [0.9.5-beta.6] - 2026-10-12 Bugfix release for SFTP locations and large repositories. Tested on a production instance with a diff --git a/lib/Command/Status.php b/lib/Command/Status.php index d698e6b..be7247c 100644 --- a/lib/Command/Status.php +++ b/lib/Command/Status.php @@ -48,10 +48,11 @@ final class Status extends Command { $s = json_decode($r->getStats() ?? '{}', true)['files'] ?? []; $rows[] = [$r->getId(), $names[$r->getTargetId()] ?? '#' . $r->getTargetId(), $r->getKind(), $r->getStatus() . ($r->getStatus() === 'running' ? ' (' . $r->getPhase() . self::percent($r) . ')' : ''), date('Y-m-d H:i', $r->getStartedAt()), $r->getFinishedAt() ? gmdate('H:i:s', $r->getFinishedAt() - $r->getStartedAt()) : '', - $s['files'] ?? '', isset($s['uploaded']) ? sprintf('%.1f MiB', $s['uploaded'] / 1048576) : '', mb_strimwidth((string)$r->getError(), 0, 50, '…')]; + $s['files'] ?? '', isset($s['bytes']) ? self::size((int)$s['bytes']) : '', + isset($s['uploaded']) ? self::size((int)$s['uploaded']) : '', mb_strimwidth((string)$r->getError(), 0, 50, '…')]; } if ($rows !== []) { - (new Table($output))->setHeaders(['run', 'location', 'kind', 'status', 'started', 'took', 'files', 'uploaded', 'error'])->setRows($rows)->render(); + (new Table($output))->setHeaders(['run', 'location', 'kind', 'status', 'started', 'took', 'files', 'size', 'uploaded', 'error'])->setRows($rows)->render(); } foreach ($this->verify->progress() as $targetId => $state) { $output->writeln(sprintf('Verify of %s on %s: %s', mb_strimwidth((string)($state['what'] ?? ''), 0, 40, '…'), @@ -61,6 +62,17 @@ final class Status extends Command { } /** " 68%", or " ~68%" when estimated from the file cache; empty without an estimate */ + private static function size(int $bytes): string { + $b = (float)$bytes; + foreach (['B', 'KiB', 'MiB', 'GiB'] as $u) { + if ($b < 1024) { + return $u === 'B' ? "$bytes B" : sprintf('%.1f %s', $b, $u); + } + $b /= 1024.0; + } + return sprintf('%.1f TiB', $b); + } + private static function percent(\OCA\NgBackup\Db\Run $r): string { $p = \OCA\NgBackup\Job\BackupRun::progressOf($r); return $p === null ? '' : sprintf(' %s%d%%', $p['approximate'] ? '~' : '', (int)floor($p['fraction'] * 100.0)); diff --git a/src/components/Backups.vue b/src/components/Backups.vue index 547c9dd..39c7605 100644 --- a/src/components/Backups.vue +++ b/src/components/Backups.vue @@ -40,6 +40,7 @@ {{ t('ng_backup', 'Restore point') }} {{ t('ng_backup', 'Status') }} {{ t('ng_backup', 'Files') }} + {{ t('ng_backup', 'Size') }} {{ t('ng_backup', 'Uploaded') }} @@ -51,6 +52,7 @@ {{ run.snapshot ? new Date(run.snapshot.createdAt * 1000).toLocaleString() + (run.snapshot.label ? ' – ' + run.snapshot.label : '') : '' }} {{ run.status }}{{ run.status === 'running' ? ' (' + run.phase + percent(run) + ')' : '' }}{{ run.error ? ': ' + run.error : '' }} {{ run.stats?.files?.files ?? run.stats?.restored ?? '' }} + {{ run.stats?.files ? formatSize(run.stats.files.bytes) : '' }} {{ run.stats?.files ? formatSize(run.stats.files.uploaded) : '' }}