From 5ed2a70d2ee627424ef4b34c5b6b3d833f18ae99 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 26 Dec 2025 10:30:45 +0000 Subject: [PATCH] feat(backups): add column visibility toggle with Comment column - Add useColumnVisibility hook to Backups table - Add ColumnPicker component for toggling columns - Add Comment column for PBS backups (hidden by default) - Owner, Size, Storage, Verified columns now toggleable - Column visibility persisted to localStorage PBS backups with comments now show the comment when the column is enabled via the Columns picker. --- .../src/components/Backups/UnifiedBackups.tsx | 68 ++++++++++++++++--- frontend-modern/src/types/backups.ts | 1 + frontend-modern/src/utils/localStorage.ts | 1 + 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/frontend-modern/src/components/Backups/UnifiedBackups.tsx b/frontend-modern/src/components/Backups/UnifiedBackups.tsx index 898642bd28..a133b79407 100644 --- a/frontend-modern/src/components/Backups/UnifiedBackups.tsx +++ b/frontend-modern/src/components/Backups/UnifiedBackups.tsx @@ -11,9 +11,11 @@ import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; import { SectionHeader } from '@/components/shared/SectionHeader'; import { showTooltip, hideTooltip } from '@/components/shared/Tooltip'; +import { ColumnPicker } from '@/components/shared/ColumnPicker'; import type { BackupType, GuestType, UnifiedBackup } from '@/types/backups'; import { usePersistentSignal } from '@/hooks/usePersistentSignal'; import { useDebouncedValue } from '@/hooks/useDebouncedValue'; +import { useColumnVisibility, type ColumnDef } from '@/hooks/useColumnVisibility'; import { logger } from '@/utils/logger'; type BackupSortKey = keyof Pick< @@ -162,6 +164,31 @@ const UnifiedBackups: Component = () => { false, // Default to absolute time ); + // Column visibility definitions for the backup table + const BACKUP_COLUMNS: ColumnDef[] = [ + { id: 'vmid', label: 'VMID/ID', priority: 'essential' }, + { id: 'type', label: 'Type', priority: 'essential' }, + { id: 'name', label: 'Name', priority: 'essential' }, + { id: 'node', label: 'Node', priority: 'essential' }, + { id: 'owner', label: 'Owner', priority: 'secondary', toggleable: true }, + { id: 'backupTime', label: 'Time', priority: 'essential' }, + { id: 'size', label: 'Size', priority: 'secondary', toggleable: true }, + { id: 'backupType', label: 'Backup Type', priority: 'essential' }, + { id: 'storage', label: 'Location', priority: 'secondary', toggleable: true }, + { id: 'verified', label: 'Verified', priority: 'secondary', toggleable: true }, + { id: 'comment', label: 'Comment', priority: 'supplementary', toggleable: true }, + { id: 'details', label: 'Details', priority: 'essential' }, + ]; + + // Column visibility with persistence - hide less useful columns by default + const columnVisibility = useColumnVisibility( + STORAGE_KEYS.BACKUPS_HIDDEN_COLUMNS, + BACKUP_COLUMNS, + ['comment'] // Comment hidden by default (often empty) + ); + const visibleColumns = columnVisibility.visibleColumns; + const isColumnVisible = (id: string) => visibleColumns().some(col => col.id === id); + // Helper functions const getDaySuffix = (day: number) => { if (day >= 11 && day <= 13) return 'th'; @@ -456,6 +483,7 @@ const UnifiedBackups: Component = () => { protected: backup.protected || false, encrypted: isEncrypted, owner: backup.owner, + comment: backup.comment, }); }); @@ -2003,6 +2031,16 @@ const UnifiedBackups: Component = () => { setUseRelativeTime={setUseRelativeTime} /> + {/* Column Visibility Toggle */} +
+ +
+ {/* Table */}
@@ -2107,7 +2145,7 @@ const UnifiedBackups: Component = () => { > Node {sortKey() === 'node' && (sortDirection() === 'asc' ? '▲' : '▼')} - + handleSort('owner')} @@ -2121,7 +2159,7 @@ const UnifiedBackups: Component = () => { > Time {sortKey() === 'backupTime' && (sortDirection() === 'asc' ? '▲' : '▼')} - + handleSort('size')} @@ -2136,7 +2174,7 @@ const UnifiedBackups: Component = () => { Backup{' '} {sortKey() === 'backupType' && (sortDirection() === 'asc' ? '▲' : '▼')} - + handleSort('storage')} @@ -2145,7 +2183,7 @@ const UnifiedBackups: Component = () => { {sortKey() === 'storage' && (sortDirection() === 'asc' ? '▲' : '▼')} - + handleSort('verified')} @@ -2154,6 +2192,11 @@ const UnifiedBackups: Component = () => { {sortKey() === 'verified' && (sortDirection() === 'asc' ? ' ▲' : ' ▼')} + + + Comment + + @@ -2202,7 +2245,7 @@ const UnifiedBackups: Component = () => { {item.node} @@ -2214,7 +2257,7 @@ const UnifiedBackups: Component = () => { > {formatTime(item.backupTime * 1000)} - + @@ -2286,7 +2329,7 @@ const UnifiedBackups: Component = () => {
- + {item.storage || (item.datastore && @@ -2298,7 +2341,7 @@ const UnifiedBackups: Component = () => { @@ -2346,6 +2389,15 @@ const UnifiedBackups: Component = () => { )} + + + {item.comment || '-'} + + { diff --git a/frontend-modern/src/types/backups.ts b/frontend-modern/src/types/backups.ts index 42eded54b4..789b23cf20 100644 --- a/frontend-modern/src/types/backups.ts +++ b/frontend-modern/src/types/backups.ts @@ -20,4 +20,5 @@ export interface UnifiedBackup { protected: boolean; encrypted?: boolean; owner?: string; + comment?: string; // PBS backup comment (only available from direct PBS) } diff --git a/frontend-modern/src/utils/localStorage.ts b/frontend-modern/src/utils/localStorage.ts index 05acfdfa40..ad84c490dd 100644 --- a/frontend-modern/src/utils/localStorage.ts +++ b/frontend-modern/src/utils/localStorage.ts @@ -114,6 +114,7 @@ export const STORAGE_KEYS = { DASHBOARD_HIDDEN_COLUMNS: 'dashboardHiddenColumns', HOSTS_HIDDEN_COLUMNS: 'hostsHiddenColumns', DOCKER_HIDDEN_COLUMNS: 'dockerHiddenColumns', + BACKUPS_HIDDEN_COLUMNS: 'backupsHiddenColumns', // Resources search RESOURCES_SEARCH_HISTORY: 'resourcesSearchHistory',