From 01618589fea4d05fac353a9bb796f9b45045cb58 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 20 May 2026 17:50:25 +0100 Subject: [PATCH] Align Proxmox backup tabs with sibling page conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistency pass after the initial backup-pages rework. Row-dot colours, coverage-strip segments, and filter-chip labels were encoding the same data through three different threshold schemes; all three now share the per-tab SLA buckets so a 14d archive shows amber in the row, sits in the amber stale (7–30d) segment of the strip, and lands under the "Stale" filter chip. Other tightening: hide the single-segment chart legend when there's nothing to disambiguate (Snapshots and Backup files); always render the Error column on Recent tasks (matching Replication, where it shows "—" rather than collapsing); reword the Backup-files strip tail from the ambiguous "guests covered" to "guests with archives"; strip the redundant inner-table border in the snapshot drilldown so it reads like Ceph's borderless sub-tables; terse "X guests" or "X of Y guests" counter on the Snapshots tab matching Replication's "8 jobs" style. Adds classifyArchiveRowAge / classifySnapshotRowAge in the summary module with unit coverage for the threshold breakpoints, and drops a dead archiveMetricMode() reference left over from the earlier patch. --- .../features/proxmox/BackupActivityChart.tsx | 24 ++-- .../features/proxmox/ProxmoxBackupsTable.tsx | 127 +++++++++--------- .../proxmoxBackupSummaryPresentation.test.ts | 35 +++++ .../proxmoxBackupSummaryPresentation.ts | 40 ++++++ 4 files changed, 150 insertions(+), 76 deletions(-) diff --git a/frontend-modern/src/features/proxmox/BackupActivityChart.tsx b/frontend-modern/src/features/proxmox/BackupActivityChart.tsx index d1bb69105a..b59d10a3a9 100644 --- a/frontend-modern/src/features/proxmox/BackupActivityChart.tsx +++ b/frontend-modern/src/features/proxmox/BackupActivityChart.tsx @@ -99,17 +99,19 @@ export const BackupActivityChart: Component = (props)
{props.title}
- - {(kind) => { - const presentation = getBackupActivitySegmentPresentation(kind); - return ( - - - {presentation.label} - - ); - }} - + 1}> + + {(kind) => { + const presentation = getBackupActivitySegmentPresentation(kind); + return ( + + + {presentation.label} + + ); + }} + +
diff --git a/frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx index c13d302fa5..8a40edb3a7 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx @@ -57,12 +57,12 @@ import { buildArchiveCoverageSummary, buildSnapshotCoverageSummary, buildTaskOutcomeSummary, - classifyBackupAge, + classifyArchiveRowAge, + classifySnapshotRowAge, computeMedianTaskDurationSeconds, getBackupAgeBucketPresentation, guestKey, taskDurationSeconds, - type BackupAgeBucket, } from './proxmoxBackupSummaryPresentation'; import { ProxmoxBackupsCoverageStrip } from './ProxmoxBackupsCoverageStrip'; @@ -183,7 +183,7 @@ const SNAPSHOT_FILTERS: FilterOption[] = [ { value: 'all', label: 'All' }, { value: 'recent', - label: 'Recent ≤7d', + label: 'Recent ≤30d', tone: 'success', leading: statusDot('bg-emerald-500'), }, @@ -237,9 +237,9 @@ function InlineProgressBar(props: { ); } -function snapshotAgeBucket(snap: GuestSnapshot, now: number): BackupAgeBucket { - return classifyBackupAge(snap.time, now); -} +// SLA-aligned row swatch helpers exposed for inner-table rendering — both +// the guest row's leftmost dot and the per-snapshot inner row dot use the +// same `classifySnapshotRowAge` so colours match the coverage strip. export const ProxmoxBackupsTable: Component<{ emptyIcon: JSX.Element; @@ -363,7 +363,11 @@ export const ProxmoxBackupsTable: Component<{ withRamCount: number; newestMs: number | undefined; totalBytes: number; - bucket: BackupAgeBucket; + // Filter discriminator aligned with the snapshot coverage strip: any + // newest-snapshot age > 30d is treated as stale (covers strip's stale + // 30–90d and ancient >90d segments). Row-dot colours are derived + // independently from classifySnapshotRowAge in the JSX. + isStale: boolean; } const filteredSnapshotGuests = createMemo(() => { @@ -400,7 +404,7 @@ export const ProxmoxBackupsTable: Component<{ withRamCount: 0, newestMs: undefined, totalBytes: 0, - bucket: 'ancient', + isStale: true, }; byGuest.set(key, row); } @@ -452,15 +456,16 @@ export const ProxmoxBackupsTable: Component<{ if (newest === undefined) return ms; return ms > newest ? ms : newest; }, undefined), - bucket: classifyBackupAge( - visibleSnapshots[0] ? snapshotTimestampMs(visibleSnapshots[0]) : undefined, - now, - ), + isStale: ((): boolean => { + const newest = visibleSnapshots[0] + ? snapshotTimestampMs(visibleSnapshots[0]) + : undefined; + if (newest === undefined) return true; + return now - newest > 30 * 24 * 60 * 60 * 1000; + })(), }; - if (filter === 'recent' && enriched.bucket !== 'recent') continue; - if (filter === 'stale' && enriched.bucket !== 'stale' && enriched.bucket !== 'ancient') { - continue; - } + if (filter === 'recent' && enriched.isStale) continue; + if (filter === 'stale' && !enriched.isStale) continue; if (filter === 'with-ram' && enriched.withRamCount === 0) continue; rows.push(enriched); } @@ -555,9 +560,6 @@ export const ProxmoxBackupsTable: Component<{ }); const visibleSnapshotGuestCount = createMemo(() => filteredSnapshotGuests().length); - const visibleSnapshotItemCount = createMemo(() => - filteredSnapshotGuests().reduce((sum, row) => sum + row.count, 0), - ); return ( 0}> - {archiveCoverage().totalGuests} guests covered ·{' '} + {archiveCoverage().totalGuests} guests with archives ·{' '} {formatBytes(archiveCoverage().totalBytes)} stored } @@ -839,8 +837,12 @@ export const ProxmoxBackupsTable: Component<{ } > - {visibleSnapshotGuestCount()} guests · {visibleSnapshotItemCount()} of{' '} - {snapshots().length} snapshots + {snapshotCoverage().totalGuests} guests} + > + {visibleSnapshotGuestCount()} of {snapshotCoverage().totalGuests} guests +
@@ -888,7 +890,7 @@ export const ProxmoxBackupsTable: Component<{ {(row) => { const isExpanded = () => expandedGuests().has(row.key); - const bucketPresentation = getBackupAgeBucketPresentation(row.bucket); + const rowAge = classifySnapshotRowAge(row.newestMs, nowMs()); return ( <>