refactor(recovery): remove legacy runtime column aliases

This commit is contained in:
rcourtman
2026-03-26 12:27:17 +00:00
parent 383c7d3b29
commit 4855b85e82
6 changed files with 14 additions and 13 deletions
@@ -703,6 +703,11 @@ shape. `frontend-modern/src/utils/recoveryPlatformModel.ts`,
transport display aliases like `subjectLabel` and `subjectType` into canonical
runtime `itemLabel` and `itemType` fields before recovery presenters consume
the model.
The same shared recovery-column boundary must keep legacy `subject` and
`source` column ids at migration-only scope once
`frontend-modern/src/hooks/useColumnVisibility.ts` owns alias rewrites.
Recovery table runtime helpers and render switches should operate on canonical
`item` and `platform` ids rather than carrying the deleted ids as live cases.
That same shared recovery state owner now also keeps `platform` as the
canonical route and transport filter name for operator-facing recovery links,
while any accepted legacy `provider` aliases remain parser compatibility only.
@@ -180,7 +180,9 @@ canonical as well. Recovery inventory and event-history columns should use
`item` and `platform` identities rather than preserving `subject` and `source`
as the primary runtime model, and any saved legacy column IDs must migrate at
the shared column-visibility boundary instead of forcing recovery renderers to
carry deleted column identities indefinitely.
carry deleted column identities indefinitely. Once that migration exists,
recovery tables and shared table presenters should not continue accepting
legacy `subject` and `source` ids in the live runtime path.
That same runtime-helper contract should prefer `item` terminology in shared
recovery presenters too. Helper exports that resolve labels or item-type badges
should expose canonical item-facing names, while any retained `subject` aliases
@@ -225,7 +225,6 @@ export const RecoveryHistoryTable: Component<RecoveryHistoryTableProps> = (props
</TableCell>
);
case 'item':
case 'subject':
return (
<TableCell
class="max-w-[420px] whitespace-nowrap px-3 py-0.5 text-base-content"
@@ -294,8 +293,7 @@ export const RecoveryHistoryTable: Component<RecoveryHistoryTableProps> = (props
{namespace || '—'}
</TableCell>
);
case 'platform':
case 'source': {
case 'platform': {
const badge = getSourcePlatformBadge(platform);
return (
<TableCell class="whitespace-nowrap px-3 py-0.5 text-center">
@@ -402,6 +402,8 @@ describe('Recovery', () => {
const historyTable = tables[tables.length - 1];
expect(within(historyTable).getByText('Item')).toBeInTheDocument();
expect(within(historyTable).getByText('Platform')).toBeInTheDocument();
expect(within(historyTable).queryByText('Subject')).not.toBeInTheDocument();
expect(within(historyTable).queryByText('Source')).not.toBeInTheDocument();
expect(within(historyTable).queryByText('Cluster / Site')).not.toBeInTheDocument();
});
@@ -43,20 +43,18 @@ describe('recoveryTablePresentation', () => {
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.type).toBe('Item Type');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.item).toBe('Item');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.platform).toBe('Platform');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.subject).toBe('Item');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.source).toBe('Platform');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.cluster).toBe('Cluster / Site');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.nodeAgent).toBe('Host / Agent');
expect(RECOVERY_ARTIFACT_COLUMN_LABELS.namespace).toBe('Namespace / Group');
expect(getRecoveryArtifactColumnLabel('type', 'Type')).toBe('Item Type');
expect(getRecoveryArtifactColumnLabel('item', 'Item')).toBe('Item');
expect(getRecoveryArtifactColumnLabel('platform', 'Platform')).toBe('Platform');
expect(getRecoveryArtifactColumnLabel('subject', 'Subject')).toBe('Item');
expect(getRecoveryArtifactColumnLabel('source', 'Source')).toBe('Platform');
expect(getRecoveryArtifactColumnLabel('cluster', 'Cluster')).toBe('Cluster / Site');
expect(getRecoveryArtifactColumnLabel('nodeAgent', 'Node')).toBe('Host / Agent');
expect(getRecoveryArtifactColumnLabel('namespace', 'Namespace')).toBe('Namespace / Group');
expect(getRecoveryArtifactColumnLabel('outcome', 'Outcome')).toBe('Outcome');
expect(getRecoveryArtifactColumnLabel('subject', 'Subject')).toBe('Subject');
expect(getRecoveryArtifactColumnLabel('source', 'Source')).toBe('Source');
});
it('derives time text classes from event recency', () => {
@@ -111,7 +109,7 @@ describe('recoveryTablePresentation', () => {
expect(getRecoveryArtifactColumnHeaderClass('time')).toContain('text-right');
expect(getRecoveryArtifactColumnHeaderClass('type')).toContain('w-[96px]');
expect(getRecoveryArtifactColumnHeaderClass('item')).toContain('w-[248px]');
expect(getRecoveryArtifactColumnHeaderClass('subject')).toContain('w-[248px]');
expect(getRecoveryArtifactColumnHeaderClass('subject')).toBe('');
expect(getRecoveryArtifactTableMinWidth(['time', 'item', 'outcome'])).toBe('980px');
expect(
getRecoveryArtifactTableMinWidth([
@@ -28,8 +28,6 @@ export const RECOVERY_ARTIFACT_COLUMN_LABELS: Record<string, string> = {
type: 'Item Type',
item: 'Item',
platform: 'Platform',
subject: 'Item',
source: 'Platform',
};
const RECOVERY_ARTIFACT_COLUMN_SPECS: Record<string, { headerClass: string; minWidthPx: number }> = {
@@ -37,12 +35,10 @@ const RECOVERY_ARTIFACT_COLUMN_SPECS: Record<string, { headerClass: string; minW
type: { headerClass: 'w-[96px] text-center', minWidthPx: 96 },
item: { headerClass: 'w-[248px]', minWidthPx: 248 },
platform: { headerClass: 'w-[78px] text-center', minWidthPx: 78 },
subject: { headerClass: 'w-[248px]', minWidthPx: 248 },
entityId: { headerClass: 'w-[84px]', minWidthPx: 84 },
cluster: { headerClass: 'w-[120px]', minWidthPx: 120 },
nodeAgent: { headerClass: 'w-[120px]', minWidthPx: 120 },
namespace: { headerClass: 'w-[120px]', minWidthPx: 120 },
source: { headerClass: 'w-[78px] text-center', minWidthPx: 78 },
verified: { headerClass: 'w-[56px] text-center', minWidthPx: 56 },
size: { headerClass: 'w-[92px] text-right', minWidthPx: 92 },
method: { headerClass: 'w-[84px] text-center', minWidthPx: 84 },