diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 285b3d1f0..c40bbb7a4 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -188,6 +188,11 @@ work extends shared components instead of creating new local variants. grouped resource labels operator-readable: count-led labels may aggregate repeated resources, but uncountable or category-like resource types such as storage must use resource wording instead of naive pluralization. + Infrastructure filter chrome under `frontend-modern/src/features/infrastructure/` + must use mode-oriented labels for table presentation controls: grouped table + mode is `Grouped`, not `Cluster`, because cluster remains a + platform/resource concept for Proxmox, Kubernetes, and similar inventory + details. 2. Route new top-level settings surfaces through the canonical settings shell instead of introducing page-local framing. Shared shells and primitives that need websocket or dark-mode context must diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index 868639ca2..981f7295e 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -137,6 +137,11 @@ cross-source deduplication. infrastructure platform first, while full merged-source detail remains available for tooltips, accessibility metadata, and routing. Agent telemetry is collection-method detail when a provider/API platform is also present. + Infrastructure table presentation controls must describe the table mode + rather than a platform-specific resource concept: the grouped/flat toggle + uses operator-facing `Grouped` and `List` wording, while Proxmox, + Kubernetes, and other platform clusters stay reserved for actual resource + identity, filters, and detail surfaces. Resource detail mappers now reuse the shared `frontend-modern/src/utils/textPresentation.ts` title-case helper for sensor diff --git a/frontend-modern/src/features/infrastructure/InfrastructurePageSurface.tsx b/frontend-modern/src/features/infrastructure/InfrastructurePageSurface.tsx index 319ac0195..fd1a256e0 100644 --- a/frontend-modern/src/features/infrastructure/InfrastructurePageSurface.tsx +++ b/frontend-modern/src/features/infrastructure/InfrastructurePageSurface.tsx @@ -236,7 +236,7 @@ export function InfrastructurePageSurface() { options={[ { value: 'grouped', - title: 'Group by cluster', + title: 'Grouped table view', label: ( <> - Cluster + Grouped ), }, diff --git a/frontend-modern/src/features/infrastructure/__tests__/InfrastructurePageSurface.guardrails.test.ts b/frontend-modern/src/features/infrastructure/__tests__/InfrastructurePageSurface.guardrails.test.ts index 03d8f16c0..9cadf1f12 100644 --- a/frontend-modern/src/features/infrastructure/__tests__/InfrastructurePageSurface.guardrails.test.ts +++ b/frontend-modern/src/features/infrastructure/__tests__/InfrastructurePageSurface.guardrails.test.ts @@ -11,7 +11,9 @@ describe('InfrastructurePageSurface guardrails', () => { it('keeps the feature shell separate from route-sync and page-model ownership', () => { expect(infrastructurePageSurfaceSource).toContain('useInfrastructurePageState'); expect(infrastructurePageSurfaceSource).toContain('useNavigate'); - expect(infrastructurePageSurfaceSource).toContain("import { PageHeader } from '@/components/shared/PageHeader';"); + expect(infrastructurePageSurfaceSource).toContain( + "import { PageHeader } from '@/components/shared/PageHeader';", + ); expect(infrastructurePageSurfaceSource).toContain(' { expect(infrastructurePageRouteStateSource).toContain('buildInfrastructurePath'); expect(infrastructurePageRouteStateSource).toContain('areSearchParamsEquivalent'); - expect(infrastructurePageModelSource).toContain('export function buildInfrastructurePageFilterDerivation'); + expect(infrastructurePageModelSource).toContain( + 'export function buildInfrastructurePageFilterDerivation', + ); expect(infrastructurePageModelSource).toContain('collectAvailableSources'); expect(infrastructurePageModelSource).toContain('collectAvailableStatuses'); expect(infrastructurePageModelSource).toContain('buildStatusOptions'); @@ -45,20 +49,41 @@ describe('InfrastructurePageSurface guardrails', () => { }); it('keeps summary-to-table coordination on the page-state owner', () => { - expect(infrastructurePageSurfaceSource).toContain('showJumpToActiveRow={shouldShowJumpToActiveResourceRow()}'); - expect(infrastructurePageSurfaceSource).toContain('onJumpToActiveRow={jumpToActiveResourceRow}'); - expect(infrastructurePageSurfaceSource).toContain('hoveredGroupScope={hoveredSummaryResourceGroupScope()}'); - expect(infrastructurePageSurfaceSource).toContain('focusedGroupScope={focusedSummaryResourceGroupScope()}'); - expect(infrastructurePageSurfaceSource).toContain('activeSummaryGroupScope={activeSummaryResourceGroupScope()}'); - expect(infrastructurePageSurfaceSource).toContain('hoveredSummaryGroupScope={hoveredSummaryResourceGroupScope()}'); - expect(infrastructurePageSurfaceSource).toContain('focusedSummaryGroupScope={focusedSummaryResourceGroupScope()}'); - expect(infrastructurePageSurfaceSource).toContain('onGroupHoverChange={setHoveredResourceGroupScope}'); + expect(infrastructurePageSurfaceSource).toContain( + 'showJumpToActiveRow={shouldShowJumpToActiveResourceRow()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'onJumpToActiveRow={jumpToActiveResourceRow}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'hoveredGroupScope={hoveredSummaryResourceGroupScope()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'focusedGroupScope={focusedSummaryResourceGroupScope()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'activeSummaryGroupScope={activeSummaryResourceGroupScope()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'hoveredSummaryGroupScope={hoveredSummaryResourceGroupScope()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'focusedSummaryGroupScope={focusedSummaryResourceGroupScope()}', + ); + expect(infrastructurePageSurfaceSource).toContain( + 'onGroupHoverChange={setHoveredResourceGroupScope}', + ); expect(infrastructurePageSurfaceSource).toContain('setSummaryClearSurfaceRootRef'); expect(infrastructurePageSurfaceSource).toContain('setTableRootRef={setSummaryTableRootRef}'); expect(infrastructurePageSurfaceSource).toContain('data-testid="infrastructure-page"'); expect(infrastructurePageSurfaceSource).toContain('ref={setSummaryClearSurfaceRootRef}'); - expect(infrastructurePageSurfaceSource).toContain('data-testid="infrastructure-interaction-surface"'); + expect(infrastructurePageSurfaceSource).toContain( + 'data-testid="infrastructure-interaction-surface"', + ); expect(infrastructurePageSurfaceSource).toContain('data-summary-clear-ignore'); + expect(infrastructurePageSurfaceSource).toContain("title: 'Grouped table view'"); + expect(infrastructurePageSurfaceSource).toContain('Grouped'); + expect(infrastructurePageSurfaceSource).not.toContain("title: 'Group by cluster'"); expect(infrastructurePageSurfaceSource).not.toContain('SummaryScopeBar'); expect(infrastructurePageSurfaceSource).not.toContain('searchTrailing={pinnedScopeFallback()}'); expect(infrastructurePageSurfaceSource).not.toContain('mobileTrailing={pinnedScopeFallback()}'); @@ -80,7 +105,9 @@ describe('InfrastructurePageSurface guardrails', () => { expect(infrastructurePageStateSource).not.toContain('consumeNextFocusedRevealSkip'); expect(infrastructurePageStateSource).not.toContain('setSkipNextFocusedReveal(true)'); expect(infrastructurePageStateSource).not.toContain('querySelector('); - expect(infrastructurePageStateSource).not.toContain('scrollIntoView({ behavior: \'smooth\', block: \'center\' })'); + expect(infrastructurePageStateSource).not.toContain( + "scrollIntoView({ behavior: 'smooth', block: 'center' })", + ); expect(unifiedResourceTableSource).toContain('data-summary-clear-surface'); expect(unifiedResourceTableSource).toContain('data-testid="infrastructure-table-surface"');