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 8025853e7..815312f95 100644 --- a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md +++ b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md @@ -70,39 +70,41 @@ regression protection. 48. `frontend-modern/src/components/Dashboard/useGroupedTableWindowing.ts` 49. `frontend-modern/src/components/Dashboard/workloadSelectors.ts` 50. `frontend-modern/src/components/Dashboard/workloadTopology.ts` -51. `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteModel.ts` -52. `frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts` -53. `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteStateModel.ts` -54. `frontend-modern/src/components/Dashboard/dashboardWorkloadUrlSyncModel.ts` -55. `frontend-modern/src/components/Dashboard/useDashboardWorkloadFilterOptions.ts` -56. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadFilterConfigModel.test.ts` -57. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteModel.test.ts` -58. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteStateModel.test.ts` -59. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadUrlSyncModel.test.ts` -60. `frontend-modern/src/components/Dashboard/__tests__/workloadTopology.test.ts` -61. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` -62. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` -63. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` -64. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` -65. `frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx` -66. `frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx` -67. `frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts` -68. `frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts` -69. `frontend-modern/src/components/Dashboard/MetricBar.test.tsx` -70. `frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx` -71. `frontend-modern/src/components/Dashboard/__tests__/EnhancedCPUBar.test.tsx` -72. `frontend-modern/src/components/Dashboard/__tests__/useEnhancedCPUBarState.test.tsx` -73. `frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx` -74. `frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts` -75. `frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx` -76. `frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx` -77. `frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx` -78. `frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx` -79. `frontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsx` -80. `frontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsx` -81. `frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx` -82. `frontend-modern/src/components/Dashboard/__tests__/useGroupedTableWindowing.test.ts` -83. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx` +51. `frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts` +52. `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteModel.ts` +53. `frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts` +54. `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteStateModel.ts` +55. `frontend-modern/src/components/Dashboard/dashboardWorkloadUrlSyncModel.ts` +56. `frontend-modern/src/components/Dashboard/useDashboardWorkloadFilterOptions.ts` +57. `frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts` +58. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadFilterConfigModel.test.ts` +59. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteModel.test.ts` +60. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteStateModel.test.ts` +61. `frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadUrlSyncModel.test.ts` +62. `frontend-modern/src/components/Dashboard/__tests__/workloadTopology.test.ts` +63. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` +64. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` +65. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` +66. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` +67. `frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx` +68. `frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx` +69. `frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts` +70. `frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts` +71. `frontend-modern/src/components/Dashboard/MetricBar.test.tsx` +72. `frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx` +73. `frontend-modern/src/components/Dashboard/__tests__/EnhancedCPUBar.test.tsx` +74. `frontend-modern/src/components/Dashboard/__tests__/useEnhancedCPUBarState.test.tsx` +75. `frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx` +76. `frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts` +77. `frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx` +78. `frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx` +79. `frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx` +80. `frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx` +81. `frontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsx` +82. `frontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsx` +83. `frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx` +84. `frontend-modern/src/components/Dashboard/__tests__/useGroupedTableWindowing.test.ts` +85. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx` ## Shared Boundaries @@ -126,7 +128,7 @@ regression protection. 10. Extend dashboard drawer derivations and runtime wiring through `frontend-modern/src/components/Dashboard/guestDrawerModel.ts` and `frontend-modern/src/components/Dashboard/useGuestDrawerState.ts`, and extend drawer overview rendering through `frontend-modern/src/components/Dashboard/GuestDrawerOverview.tsx`, rather than rebuilding canonical guest identity, discovery routing, or drawer-local normalization inside `frontend-modern/src/components/Dashboard/GuestDrawer.tsx` 11. Extend dashboard disk-list derivations and fallback runtime wiring through `frontend-modern/src/components/Dashboard/diskListModel.ts` and `frontend-modern/src/components/Dashboard/useDiskListState.ts` rather than rebuilding usage math, progress-state mapping, or tooltip fallback logic inside `frontend-modern/src/components/Dashboard/DiskList.tsx` 12. Extend dashboard guest metadata cache persistence, metadata refresh, org-scope switching, and optimistic custom-URL updates through `frontend-modern/src/components/Dashboard/useDashboardGuestMetadataState.ts` rather than rebuilding dashboard-local storage caches, event listeners, or guest metadata API wiring inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` -13. Extend dashboard deep-link selection, hovered-row continuity, and table scroll preservation through `frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts` rather than rebuilding resource-query parsing, selected-row scroll pinning, or hovered-row invalidation inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` +13. Extend dashboard deep-link selection and hovered-row continuity semantics through `frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts`, and extend table scroll preservation plus reactive selection state through `frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts`, rather than rebuilding resource-query parsing, selected-row scroll pinning, or hovered-row invalidation inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` 14. Extend dashboard workload route ownership, route-driven option catalogs, and toolbar filter config through `frontend-modern/src/components/Dashboard/useDashboardWorkloadRouteState.ts`, `frontend-modern/src/components/Dashboard/useDashboardWorkloadFilterOptions.ts`, `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteModel.ts`, `frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts`, and `frontend-modern/src/components/Dashboard/dashboardWorkloadRouteStateModel.ts`, and extend query-param synchronization plus managed workload URL semantics through `frontend-modern/src/components/Dashboard/useDashboardWorkloadUrlSync.ts` and `frontend-modern/src/components/Dashboard/dashboardWorkloadUrlSyncModel.ts`, rather than rebuilding route sync, alias parsing, option derivation, toolbar callback/config wiring, reset policy, node-selection compatibility rules, param precedence, or managed workload URLs inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` 15. Extend grouped dashboard workload derivation, summary fallbacks, and grouped/windowed table presentation through `frontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts`, and extend node parent mapping through `frontend-modern/src/components/Dashboard/workloadTopology.ts`, rather than rebuilding grouped selectors, summary snapshot math, or topology lookups inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` 16. Extend dashboard control defaults, persistent view preferences, keyboard reset behavior, column-visibility ownership, and tag-search flow through `frontend-modern/src/components/Dashboard/useDashboardControlsState.ts` and `frontend-modern/src/components/Dashboard/dashboardFilterModel.ts` rather than rebuilding sort/search/grouping state, reset drift, or column-toggle plumbing inside `frontend-modern/src/components/Dashboard/useDashboardState.ts` diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json index 4824ca4c4..e8da4d821 100644 --- a/docs/release-control/v6/internal/subsystems/registry.json +++ b/docs/release-control/v6/internal/subsystems/registry.json @@ -2556,6 +2556,7 @@ "frontend-modern/src/components/Dashboard/Dashboard.tsx", "frontend-modern/src/components/Dashboard/DashboardFilter.tsx", "frontend-modern/src/components/Dashboard/dashboardFilterModel.ts", + "frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts", "frontend-modern/src/components/Dashboard/DashboardStateCards.tsx", "frontend-modern/src/components/Dashboard/DashboardStatsStrip.tsx", "frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts", @@ -2617,6 +2618,7 @@ "exact_files": [ "frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx", + "frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadFilterConfigModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteStateModel.test.ts", @@ -2667,6 +2669,7 @@ "frontend-modern/src/components/Dashboard/Dashboard.tsx", "frontend-modern/src/components/Dashboard/DashboardFilter.tsx", "frontend-modern/src/components/Dashboard/dashboardFilterModel.ts", + "frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts", "frontend-modern/src/components/Dashboard/DashboardStateCards.tsx", "frontend-modern/src/components/Dashboard/DashboardStatsStrip.tsx", "frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts", @@ -2724,6 +2727,7 @@ "exact_files": [ "frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx", + "frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadFilterConfigModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteModel.test.ts", "frontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteStateModel.test.ts", diff --git a/frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx b/frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx index af7990e38..93f3cadc0 100644 --- a/frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx +++ b/frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx @@ -13,6 +13,7 @@ import workloadTableHeaderSource from '../WorkloadTableHeader.tsx?raw'; import dashboardFilterModelSource from '../dashboardFilterModel.ts?raw'; import dashboardControlsStateSource from '../useDashboardControlsState.ts?raw'; import dashboardGuestMetadataStateSource from '../useDashboardGuestMetadataState.ts?raw'; +import dashboardSelectionModelSource from '../dashboardSelectionModel.ts?raw'; import dashboardSelectionStateSource from '../useDashboardSelectionState.ts?raw'; import dashboardWorkloadDerivedStateSource from '../useDashboardWorkloadDerivedState.ts?raw'; import dashboardWorkloadFilterOptionsSource from '../useDashboardWorkloadFilterOptions.ts?raw'; @@ -649,10 +650,16 @@ describe('Dashboard performance contract', () => { expect(dashboardWorkloadRouteModelSource).toContain("from './workloadTopology'"); expect(dashboardWorkloadRouteModelSource).toContain('workloadNodeScopeId'); expect(dashboardWorkloadRouteModelSource).toContain('getKubernetesContextKey'); - expect(dashboardSelectionStateSource).toContain('parseWorkloadsLinkSearch'); expect(dashboardSelectionStateSource).toContain('const [selectedGuestId, setSelectedGuestIdRaw]'); expect(dashboardSelectionStateSource).toContain('const [hoveredWorkloadId, setHoveredWorkloadId]'); expect(dashboardSelectionStateSource).toContain('setHandledResourceId(null)'); + expect(dashboardSelectionStateSource).toContain("from './dashboardSelectionModel'"); + expect(dashboardSelectionStateSource).not.toContain('parseWorkloadsLinkSearch'); + expect(dashboardSelectionStateSource).not.toContain('getCanonicalWorkloadId'); + expect(dashboardSelectionModelSource).toContain('parseWorkloadsLinkSearch(search)'); + expect(dashboardSelectionModelSource).toContain('getCanonicalWorkloadId'); + expect(dashboardSelectionModelSource).toContain('resolveDashboardResourceSelection'); + expect(dashboardSelectionModelSource).toContain('dashboardHasHoveredWorkload'); expect(groupedTableWindowingSource).toContain('DEFAULT_WINDOW_SIZE'); expect(groupedTableWindowingSource).toContain('DEFAULT_ENABLE_THRESHOLD'); expect(groupedTableWindowingSource).toContain('DEFAULT_OVERSCAN_ROWS'); diff --git a/frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts b/frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts new file mode 100644 index 000000000..6f1a164f8 --- /dev/null +++ b/frontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from 'vitest'; + +import type { WorkloadGuest } from '@/types/workloads'; + +import { + dashboardHasHoveredWorkload, + resolveDashboardResourceSelection, +} from '../dashboardSelectionModel'; + +describe('dashboardSelectionModel', () => { + it('resolves dashboard resource deep links into selected guest and node scope', () => { + expect(resolveDashboardResourceSelection('?resource=cluster-a:node-1:101')).toEqual({ + resourceId: 'cluster-a:node-1:101', + selectedNode: 'cluster-a-node-1', + }); + expect(resolveDashboardResourceSelection('?resource=guest-1')).toEqual({ + resourceId: 'guest-1', + selectedNode: null, + }); + expect(resolveDashboardResourceSelection('')).toBeNull(); + }); + + it('checks hovered workload continuity against canonical workload ids', () => { + const guests = [ + { + id: 'cluster-a:node-1:101', + name: 'guest-1', + status: 'running', + instance: 'cluster-a', + node: 'node-1', + vmid: 101, + } as unknown as WorkloadGuest, + ]; + + expect(dashboardHasHoveredWorkload(guests, 'cluster-a:node-1:101')).toBe(true); + expect(dashboardHasHoveredWorkload(guests, 'cluster-a:node-1:102')).toBe(false); + }); +}); diff --git a/frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts b/frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts index 4571ee2ac..35b08af66 100644 --- a/frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts +++ b/frontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.ts @@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import type { WorkloadGuest } from '@/types/workloads'; +import { resolveDashboardResourceSelection } from '../dashboardSelectionModel'; import { useDashboardSelectionState } from '../useDashboardSelectionState'; let locationSearch = '?resource=cluster-a:node-1:101'; @@ -43,6 +44,7 @@ describe('useDashboardSelectionState', () => { expect(result.selectedGuestId()).toBe('cluster-a:node-1:101'); expect(setSelectedNode).toHaveBeenCalledWith('cluster-a-node-1'); + expect(resolveDashboardResourceSelection(locationSearch)?.selectedNode).toBe('cluster-a-node-1'); }); it('clears stale hovered workload ids when filtered guests change', () => { diff --git a/frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts b/frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts new file mode 100644 index 000000000..4136b3d9b --- /dev/null +++ b/frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts @@ -0,0 +1,28 @@ +import { parseWorkloadsLinkSearch } from '@/routing/resourceLinks'; +import type { WorkloadGuest } from '@/types/workloads'; +import { getCanonicalWorkloadId } from '@/utils/workloads'; + +export interface DashboardResourceSelection { + resourceId: string; + selectedNode: string | null; +} + +export const resolveDashboardResourceSelection = ( + search: string, +): DashboardResourceSelection | null => { + const { resource: resourceId } = parseWorkloadsLinkSearch(search); + if (!resourceId) return null; + + const [instance, node, vmid] = resourceId.split(':'); + const selectedNode = instance && node && vmid ? `${instance}-${node}` : null; + + return { + resourceId, + selectedNode, + }; +}; + +export const dashboardHasHoveredWorkload = ( + filteredGuests: WorkloadGuest[], + hoveredId: string, +): boolean => filteredGuests.some((guest) => getCanonicalWorkloadId(guest) === hoveredId); diff --git a/frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts b/frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts index e31d7b44c..4626acced 100644 --- a/frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts +++ b/frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts @@ -1,10 +1,11 @@ import { useLocation } from '@solidjs/router'; import { createEffect, createSignal, type Accessor } from 'solid-js'; -import { parseWorkloadsLinkSearch } from '@/routing/resourceLinks'; -import { getCanonicalWorkloadId } from '@/utils/workloads'; - import type { WorkloadGuest } from '@/types/workloads'; +import { + dashboardHasHoveredWorkload, + resolveDashboardResourceSelection, +} from './dashboardSelectionModel'; interface UseDashboardSelectionStateOptions { filteredGuests: Accessor; @@ -48,21 +49,20 @@ export function useDashboardSelectionState(options: UseDashboardSelectionStateOp }; createEffect(() => { - const { resource: resourceId } = parseWorkloadsLinkSearch(location.search); - - if (!resourceId) { + const selection = resolveDashboardResourceSelection(location.search); + if (!selection) { if (handledResourceId() !== null) { setHandledResourceId(null); } return; } + const { resourceId, selectedNode } = selection; if (resourceId === handledResourceId()) return; setSelectedGuestId(resourceId); - const [instance, node, vmid] = resourceId.split(':'); - if (instance && node && vmid) { - options.setSelectedNode(`${instance}-${node}`); + if (selectedNode) { + options.setSelectedNode(selectedNode); } setHandledResourceId(resourceId); }); @@ -70,10 +70,7 @@ export function useDashboardSelectionState(options: UseDashboardSelectionStateOp createEffect(() => { const hoveredId = hoveredWorkloadId(); if (!hoveredId) return; - const exists = options - .filteredGuests() - .some((guest) => getCanonicalWorkloadId(guest) === hoveredId); - if (!exists) { + if (!dashboardHasHoveredWorkload(options.filteredGuests(), hoveredId)) { setHoveredWorkloadId(null); } }); diff --git a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts index d75307e35..b9999ea4b 100644 --- a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts +++ b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts @@ -89,6 +89,7 @@ import workloadTableHeaderSource from '@/components/Dashboard/WorkloadTableHeade import dashboardFilterModelSource from '@/components/Dashboard/dashboardFilterModel.ts?raw'; import dashboardControlsStateSource from '@/components/Dashboard/useDashboardControlsState.ts?raw'; import dashboardGuestMetadataStateSource from '@/components/Dashboard/useDashboardGuestMetadataState.ts?raw'; +import dashboardSelectionModelSource from '@/components/Dashboard/dashboardSelectionModel.ts?raw'; import dashboardSelectionStateSource from '@/components/Dashboard/useDashboardSelectionState.ts?raw'; import dashboardWorkloadDerivedStateSource from '@/components/Dashboard/useDashboardWorkloadDerivedState.ts?raw'; import dashboardWorkloadFilterOptionsSource from '@/components/Dashboard/useDashboardWorkloadFilterOptions.ts?raw'; @@ -668,10 +669,16 @@ describe('frontend resource type boundaries', () => { expect(dashboardWorkloadRouteModelSource).toContain('workloadNodeScopeId'); expect(dashboardWorkloadRouteModelSource).toContain('getKubernetesContextKey'); expect(dashboardWorkloadRouteStateSource).toContain('isWorkloadsRoute,'); - expect(dashboardSelectionStateSource).toContain('parseWorkloadsLinkSearch'); expect(dashboardSelectionStateSource).toContain('const [selectedGuestId, setSelectedGuestIdRaw]'); expect(dashboardSelectionStateSource).toContain('const [hoveredWorkloadId, setHoveredWorkloadId]'); expect(dashboardSelectionStateSource).toContain('setHandledResourceId(null)'); + expect(dashboardSelectionStateSource).toContain("from './dashboardSelectionModel'"); + expect(dashboardSelectionStateSource).not.toContain('parseWorkloadsLinkSearch'); + expect(dashboardSelectionStateSource).not.toContain('getCanonicalWorkloadId'); + expect(dashboardSelectionModelSource).toContain('parseWorkloadsLinkSearch(search)'); + expect(dashboardSelectionModelSource).toContain('getCanonicalWorkloadId'); + expect(dashboardSelectionModelSource).toContain('resolveDashboardResourceSelection'); + expect(dashboardSelectionModelSource).toContain('dashboardHasHoveredWorkload'); expect(dashboardStateSource).not.toContain('const guestId = () => {'); expect(dashboardFilterSource).toContain('useDashboardFilterState'); expect(dashboardFilterSource).not.toContain('const [filtersOpen, setFiltersOpen] ='); diff --git a/scripts/release_control/subsystem_lookup_test.py b/scripts/release_control/subsystem_lookup_test.py index bafe5e623..2aec42df6 100644 --- a/scripts/release_control/subsystem_lookup_test.py +++ b/scripts/release_control/subsystem_lookup_test.py @@ -1970,6 +1970,36 @@ class SubsystemLookupTest(unittest.TestCase): "dashboard-workload-hot-path", ) + def test_lookup_paths_assigns_dashboard_selection_runtime_to_performance_and_scalability( + self, + ) -> None: + result = lookup_paths( + [ + "frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts", + "frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts", + ] + ) + self.assertEqual(result["unowned_runtime_files"], []) + self.assertEqual( + {item["subsystem"] for item in result["impacted_subsystems"]}, + {"performance-and-scalability"}, + ) + for file_entry in result["files"]: + self.assertEqual(file_entry["classification"], "runtime") + self.assertEqual( + {match["subsystem"] for match in file_entry["matches"]}, + {"performance-and-scalability"}, + ) + match = file_entry["matches"][0] + self.assertEqual( + match["contract"], + "docs/release-control/v6/internal/subsystems/performance-and-scalability.md", + ) + self.assertEqual( + match["verification_requirement"]["id"], + "dashboard-workload-hot-path", + ) + def test_lookup_paths_assigns_dashboard_workload_table_runtime_to_performance_and_scalability( self, ) -> None: