diff --git a/docs/release-control/v6/internal/subsystems/storage-recovery.md b/docs/release-control/v6/internal/subsystems/storage-recovery.md index eac04fc11..d56fda2e7 100644 --- a/docs/release-control/v6/internal/subsystems/storage-recovery.md +++ b/docs/release-control/v6/internal/subsystems/storage-recovery.md @@ -344,6 +344,12 @@ fields instead of one ambiguous "primary" label. The summary may still surface platform breadth and cross-platform protected items, but the recovery page must read item-first so the unified recovery model is not visually anchored to one platform family. +That same item-first rule also applies to the protected inventory table: +`RecoveryProtectedInventorySection.tsx` must surface protected item type as a +first-class column in the main inventory grid rather than leaving platform as +the only structural classifier beside the item label. Platform badges remain +important supporting operator context, especially for Proxmox-heavy fleets, +but the table frame itself must make protected item class explicit. The recovery table presentation helper now owns the canonical subject-type label fallback for recovery rows and delegates its title-casing to the shared `frontend-modern/src/utils/textPresentation.ts` helper rather than keeping a diff --git a/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx b/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx index d365de2c9..05509af37 100644 --- a/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx +++ b/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx @@ -45,7 +45,7 @@ import { getSourcePlatformLabel, normalizeSourcePlatformQueryValue } from '@/uti import { titleCaseDelimitedLabel } from '@/utils/textPresentation'; type VerificationFilter = 'all' | 'verified' | 'unverified' | 'unknown'; -type ProtectedSortCol = 'subject' | 'source' | 'lastBackup' | 'outcome'; +type ProtectedSortCol = 'subject' | 'type' | 'source' | 'lastBackup' | 'outcome'; type SortDir = 'asc' | 'desc'; interface RecoveryRollupSummary { @@ -122,6 +122,15 @@ export const RecoveryProtectedInventorySection: Component< const rightLabel = getRecoveryRollupSubjectLabel(right, resourceIndex).toLowerCase(); return multiplier * leftLabel.localeCompare(rightLabel); } + case 'type': { + const leftType = getRecoveryItemTypePresentation( + left.display?.itemType || left.display?.subjectType || left.subjectRef?.type, + )?.label.toLowerCase(); + const rightType = getRecoveryItemTypePresentation( + right.display?.itemType || right.display?.subjectType || right.subjectRef?.type, + )?.label.toLowerCase(); + return multiplier * (leftType || '').localeCompare(rightType || ''); + } case 'source': { const leftSource = (left.providers || []) .map((provider) => getSourcePlatformLabel(String(provider))) @@ -308,13 +317,14 @@ export const RecoveryProtectedInventorySection: Component<
{( [ ['subject', getRecoveryArtifactColumnLabel('subject', 'Subject')], + ['type', 'Item Type'], ['source', getRecoveryArtifactColumnLabel('source', 'Source')], ['lastBackup', 'Latest Point'], ['outcome', 'Outcome'], @@ -322,8 +332,10 @@ export const RecoveryProtectedInventorySection: Component< ).map(([column, label]) => (