diff --git a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md index 974a41a9b..7f56341e5 100644 --- a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md +++ b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md @@ -290,6 +290,10 @@ regression protection. 23. Extend grouped workload row windowing, reveal-index clamping, overscan math, and per-group visible-slice derivation through `frontend-modern/src/components/Workloads/useGroupedTableWindowing.ts`, and extend viewport event wiring through `frontend-modern/src/components/Workloads/useWorkloadViewportSync.ts` rather than rebuilding scroll handlers, mounted-row budgets, viewport listeners, or group-slice math inside `frontend-modern/src/components/Workloads/useWorkloadsDerivedState.ts` 24. Extend Workloads shell rendering through `frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx`, `frontend-modern/src/components/Workloads/WorkloadsTable.tsx`, and `frontend-modern/src/components/Workloads/WorkloadsStatsStrip.tsx` rather than accreting loading cards, workload table markup, or stats-strip presentation back into `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx` 25. Extend workload table shell ownership through `frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx` and `frontend-modern/src/components/Workloads/WorkloadPanel.tsx` rather than rebuilding sortable header markup, grouped node rows, row expansion, or guest-drawer rendering inside `frontend-modern/src/components/Workloads/WorkloadsTable.tsx` + `WorkloadPanel` owns the mutually exclusive host/guest drawer handoff: + clicking a grouped host row while a guest drawer is open must clear the + selected guest and keep/focus the host summary group so the node drawer can + replace the guest drawer. Compact icon headers inside `WorkloadTableHeader.tsx` may stay visually dense for responsive workload tables, but the icon must be decorative and the column label must remain present through an `sr-only` label so the diff --git a/frontend-modern/src/components/Workloads/WorkloadPanel.tsx b/frontend-modern/src/components/Workloads/WorkloadPanel.tsx index 75edb1ab2..9e79f0997 100644 --- a/frontend-modern/src/components/Workloads/WorkloadPanel.tsx +++ b/frontend-modern/src/components/Workloads/WorkloadPanel.tsx @@ -371,9 +371,17 @@ export function WorkloadPanel(props: WorkloadPanelProps) { }; const handleGroupFocusToggle = () => { const scope = groupSummaryScope(); - props.setFocusedWorkloadGroupScope( - scope && props.focusedSummaryWorkloadGroupId() === scope.id ? null : scope, - ); + const selectedGuestId = props.selectedGuestId(); + const nextFocusedScope = + scope && + props.focusedSummaryWorkloadGroupId() === scope.id && + selectedGuestId === null + ? null + : scope; + if (nextFocusedScope && selectedGuestId !== null) { + props.setSelectedGuestId(null); + } + props.setFocusedWorkloadGroupScope(nextFocusedScope); }; const groupRowInteraction = createSummaryInteractiveRowPreviewHandlers({ onPreview: () => handleGroupHoverChange(groupSummaryScope()), diff --git a/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx b/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx index 3cab33bc4..517088f68 100644 --- a/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx +++ b/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx @@ -1084,6 +1084,9 @@ describe('Workloads performance contract', () => { expect(nodeDrawerModelSource).toContain("metric: 'temperature'"); expect(workloadPanelSource).toContain('NodeDrawer'); expect(workloadPanelSource).toContain('data-inline-node-detail-for'); + expect(workloadPanelSource).toContain('const selectedGuestId = props.selectedGuestId()'); + expect(workloadPanelSource).toContain('props.setSelectedGuestId(null)'); + expect(workloadPanelSource).toContain('selectedGuestId === null'); expect(guestDrawerSource).not.toContain('const guestId = () =>'); expect(guestDrawerSource).not.toContain('const infrastructureHref = () =>'); expect(guestDrawerSource).not.toContain('Filesystems');