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 e1a60a8ea..027568f5b 100644 --- a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md +++ b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md @@ -39,33 +39,38 @@ regression protection. 17. `frontend-modern/src/components/Dashboard/StackedMemoryBar.tsx` 18. `frontend-modern/src/components/Dashboard/stackedMemoryBarModel.ts` 19. `frontend-modern/src/components/Dashboard/useStackedMemoryBarState.ts` -20. `frontend-modern/src/components/Dashboard/DiskList.tsx` -21. `frontend-modern/src/components/Dashboard/diskListModel.ts` -22. `frontend-modern/src/components/Dashboard/useDiskListState.ts` -23. `frontend-modern/src/components/Dashboard/GuestRow.tsx` -24. `frontend-modern/src/components/Dashboard/guestRowModel.tsx` -25. `frontend-modern/src/components/Dashboard/useGuestRowState.ts` -26. `frontend-modern/src/components/Dashboard/GuestDrawer.tsx` -27. `frontend-modern/src/components/Dashboard/guestDrawerModel.ts` -28. `frontend-modern/src/components/Dashboard/useGuestDrawerState.ts` -29. `frontend-modern/src/components/Dashboard/workloadSelectors.ts` -30. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` -31. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` -32. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` -33. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` -34. `frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx` -35. `frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx` -36. `frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts` -37. `frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx` -38. `frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts` -39. `frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx` -40. `frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx` -41. `frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx` -42. `frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx` -43. `frontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsx` -44. `frontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsx` -45. `frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx` -46. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx` +20. `frontend-modern/src/components/Dashboard/MetricBar.tsx` +21. `frontend-modern/src/components/Dashboard/metricBarModel.ts` +22. `frontend-modern/src/components/Dashboard/useMetricBarState.ts` +23. `frontend-modern/src/components/Dashboard/DiskList.tsx` +24. `frontend-modern/src/components/Dashboard/diskListModel.ts` +25. `frontend-modern/src/components/Dashboard/useDiskListState.ts` +26. `frontend-modern/src/components/Dashboard/GuestRow.tsx` +27. `frontend-modern/src/components/Dashboard/guestRowModel.tsx` +28. `frontend-modern/src/components/Dashboard/useGuestRowState.ts` +29. `frontend-modern/src/components/Dashboard/GuestDrawer.tsx` +30. `frontend-modern/src/components/Dashboard/guestDrawerModel.ts` +31. `frontend-modern/src/components/Dashboard/useGuestDrawerState.ts` +32. `frontend-modern/src/components/Dashboard/workloadSelectors.ts` +33. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` +34. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` +35. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` +36. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` +37. `frontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsx` +38. `frontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsx` +39. `frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts` +40. `frontend-modern/src/components/Dashboard/MetricBar.test.tsx` +41. `frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx` +42. `frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx` +43. `frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts` +44. `frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx` +45. `frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx` +46. `frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx` +47. `frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx` +48. `frontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsx` +49. `frontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsx` +50. `frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx` +51. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx` ## Shared Boundaries @@ -92,6 +97,7 @@ regression protection. 13. Extend threshold-slider value-position math, title/label derivation, and drag scroll-lock runtime through `frontend-modern/src/components/Dashboard/thresholdSliderModel.ts` and `frontend-modern/src/components/Dashboard/useThresholdSliderState.ts` rather than rebuilding slider-local state and pointer lifecycle inside `frontend-modern/src/components/Dashboard/ThresholdSlider.tsx` 14. Extend stacked disk-bar capacity math, segment/tooltip derivation, and resize-observer runtime through `frontend-modern/src/components/Dashboard/stackedDiskBarModel.ts` and `frontend-modern/src/components/Dashboard/useStackedDiskBarState.ts` rather than rebuilding disk-bar-local state, mode branching, and tooltip shaping inside `frontend-modern/src/components/Dashboard/StackedDiskBar.tsx` 15. Extend stacked memory-bar capacity math, balloon/swap derivation, and resize-observer runtime through `frontend-modern/src/components/Dashboard/stackedMemoryBarModel.ts` and `frontend-modern/src/components/Dashboard/useStackedMemoryBarState.ts` rather than rebuilding memory-bar-local state, tooltip shaping, and label-fit logic inside `frontend-modern/src/components/Dashboard/StackedMemoryBar.tsx` +16. Extend metric-bar width, label-fit logic, and resize-observer runtime through `frontend-modern/src/components/Dashboard/metricBarModel.ts` and `frontend-modern/src/components/Dashboard/useMetricBarState.ts` rather than rebuilding metric-local state and threshold mapping inside `frontend-modern/src/components/Dashboard/MetricBar.tsx` ## Forbidden Paths @@ -183,6 +189,14 @@ resize-observer plus tooltip lifecycle live in Future memory-bar runtime changes must extend through those owners instead of reintroducing mixed resize state, balloon branching, and tooltip shaping into the shell. +The dashboard metric bar now follows that same pattern: the shell stays in +`frontend-modern/src/components/Dashboard/MetricBar.tsx`, while width, +show-label, sublabel-fit, and threshold-color derivation live in +`frontend-modern/src/components/Dashboard/metricBarModel.ts` and +resize-observer lifecycle lives in +`frontend-modern/src/components/Dashboard/useMetricBarState.ts`. Future +metric-bar runtime changes must extend through those owners instead of +reintroducing mixed resize state and label-fit logic into the shell. The unified resource table hot path is now also governed as explicit performance-owned runtime, with shared ownership against the unified-resource diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json index 2ac0aa61a..79795e7c3 100644 --- a/docs/release-control/v6/internal/subsystems/registry.json +++ b/docs/release-control/v6/internal/subsystems/registry.json @@ -2526,6 +2526,8 @@ "frontend-modern/src/components/Dashboard/guestDrawerModel.ts", "frontend-modern/src/components/Dashboard/GuestRow.tsx", "frontend-modern/src/components/Dashboard/guestRowModel.tsx", + "frontend-modern/src/components/Dashboard/MetricBar.tsx", + "frontend-modern/src/components/Dashboard/metricBarModel.ts", "frontend-modern/src/components/Dashboard/StackedDiskBar.tsx", "frontend-modern/src/components/Dashboard/stackedDiskBarModel.ts", "frontend-modern/src/components/Dashboard/StackedMemoryBar.tsx", @@ -2537,6 +2539,7 @@ "frontend-modern/src/components/Dashboard/useDiskListState.ts", "frontend-modern/src/components/Dashboard/useGuestDrawerState.ts", "frontend-modern/src/components/Dashboard/useGuestRowState.ts", + "frontend-modern/src/components/Dashboard/useMetricBarState.ts", "frontend-modern/src/components/Dashboard/useStackedDiskBarState.ts", "frontend-modern/src/components/Dashboard/useStackedMemoryBarState.ts", "frontend-modern/src/components/Dashboard/useThresholdSliderState.ts", @@ -2558,9 +2561,11 @@ "frontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts", + "frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts", + "frontend-modern/src/components/Dashboard/MetricBar.test.tsx", "frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx", "frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx", "internal/api/router_bench_test.go", @@ -2601,6 +2606,8 @@ "frontend-modern/src/components/Dashboard/guestDrawerModel.ts", "frontend-modern/src/components/Dashboard/GuestRow.tsx", "frontend-modern/src/components/Dashboard/guestRowModel.tsx", + "frontend-modern/src/components/Dashboard/MetricBar.tsx", + "frontend-modern/src/components/Dashboard/metricBarModel.ts", "frontend-modern/src/components/Dashboard/StackedDiskBar.tsx", "frontend-modern/src/components/Dashboard/stackedDiskBarModel.ts", "frontend-modern/src/components/Dashboard/StackedMemoryBar.tsx", @@ -2612,6 +2619,7 @@ "frontend-modern/src/components/Dashboard/useDiskListState.ts", "frontend-modern/src/components/Dashboard/useGuestDrawerState.ts", "frontend-modern/src/components/Dashboard/useGuestRowState.ts", + "frontend-modern/src/components/Dashboard/useMetricBarState.ts", "frontend-modern/src/components/Dashboard/useStackedDiskBarState.ts", "frontend-modern/src/components/Dashboard/useStackedMemoryBarState.ts", "frontend-modern/src/components/Dashboard/useThresholdSliderState.ts", @@ -2630,11 +2638,13 @@ "frontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.ts", + "frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsx", "frontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.ts", "frontend-modern/src/components/Dashboard/__tests__/workloadSelectors.test.ts", "frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx", + "frontend-modern/src/components/Dashboard/MetricBar.test.tsx", "frontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsx", "frontend-modern/src/components/Dashboard/ThresholdSlider.test.tsx", "frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx" diff --git a/frontend-modern/src/components/Dashboard/MetricBar.tsx b/frontend-modern/src/components/Dashboard/MetricBar.tsx index 00046a8b5..c53804144 100644 --- a/frontend-modern/src/components/Dashboard/MetricBar.tsx +++ b/frontend-modern/src/components/Dashboard/MetricBar.tsx @@ -1,74 +1,27 @@ -import { Show, createMemo, createSignal, onMount, onCleanup } from 'solid-js'; +import { Show } from 'solid-js'; import { ProgressBar } from '@/components/shared/ProgressBar'; -import { estimateTextWidth } from '@/utils/format'; -import { getMetricColorClass } from '@/utils/metricThresholds'; -import type { MetricType } from '@/utils/metricThresholds'; - -interface MetricBarProps { - value: number; - label: string; - sublabel?: string; - showLabel?: boolean; - type?: 'cpu' | 'memory' | 'disk' | 'generic'; - resourceId?: string; - class?: string; -} +import { type MetricBarProps } from './metricBarModel'; +import { useMetricBarState } from './useMetricBarState'; export function MetricBar(props: MetricBarProps) { - const width = createMemo(() => Math.min(props.value, 100)); - - // Track container width - const [containerWidth, setContainerWidth] = createSignal(100); - let containerRef: HTMLDivElement | undefined; - - // Set up ResizeObserver to track container width changes - onMount(() => { - if (!containerRef) return; - - setContainerWidth(containerRef.offsetWidth); - - const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - setContainerWidth(entry.contentRect.width); - } - }); - - observer.observe(containerRef); - - onCleanup(() => observer.disconnect()); - }); - - // Determine if sublabel fits based on estimated text width - const showSublabel = createMemo(() => { - if (props.showLabel === false) return false; - if (!props.sublabel) return false; - const fullText = `${props.label} (${props.sublabel})`; - const estimatedWidth = estimateTextWidth(fullText); - return containerWidth() >= estimatedWidth; - }); - - const showLabel = createMemo(() => props.showLabel !== false && props.label.trim().length > 0); - - // Get color class from centralized thresholds - const progressColorClass = createMemo(() => { - const metric = props.type || 'cpu'; - // 'generic' falls back to cpu thresholds - const metricType: MetricType = metric === 'generic' ? 'cpu' : metric; - return getMetricColorClass(props.value, metricType); - }); + const state = useMetricBarState(props); + const presentation = state.presentation; return ( -
+
+ {props.label} - + ({props.sublabel}) 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 7bfb6ba72..39eb049dd 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 @@ -20,6 +20,9 @@ import stackedMemoryBarStateSource from '../useStackedMemoryBarState.ts?raw'; import diskListSource from '../DiskList.tsx?raw'; import diskListModelSource from '../diskListModel.ts?raw'; import diskListStateSource from '../useDiskListState.ts?raw'; +import metricBarSource from '../MetricBar.tsx?raw'; +import metricBarModelSource from '../metricBarModel.ts?raw'; +import metricBarStateSource from '../useMetricBarState.ts?raw'; import guestDrawerSource from '../GuestDrawer.tsx?raw'; import guestDrawerModelSource from '../guestDrawerModel.ts?raw'; import guestRowSource from '../GuestRow.tsx?raw'; @@ -542,6 +545,17 @@ describe('Dashboard performance contract', () => { expect(stackedMemoryBarModelSource).toContain('tooltipRows'); }); + it('keeps metric bar runtime and derivations in canonical owners', () => { + expect(metricBarSource).toContain('useMetricBarState'); + expect(metricBarSource).not.toContain('const [containerWidth, setContainerWidth] ='); + expect(metricBarSource).not.toContain('const progressColorClass = createMemo(() => {'); + expect(metricBarSource).not.toContain('const showSublabel = createMemo(() => {'); + expect(metricBarStateSource).toContain('new ResizeObserver'); + expect(metricBarModelSource).toContain('export function buildMetricBarPresentation'); + expect(metricBarModelSource).toContain('estimateTextWidth'); + expect(metricBarModelSource).toContain('getMetricColorClass'); + }); + it('keeps guest row contract and hot-path state in canonical row owners', () => { expect(guestRowSource).toContain('useGuestRowState'); expect(guestRowSource).not.toContain('export const GUEST_COLUMNS'); diff --git a/frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx b/frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx new file mode 100644 index 000000000..094647bd2 --- /dev/null +++ b/frontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsx @@ -0,0 +1,69 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render } from '@solidjs/testing-library'; +import { useMetricBarState } from '@/components/Dashboard/useMetricBarState'; + +class MockResizeObserver { + callback: ResizeObserverCallback; + disconnect = vi.fn(); + observe = vi.fn(); + + constructor(callback: ResizeObserverCallback) { + this.callback = callback; + } + + trigger(width: number) { + this.callback( + [ + { + contentRect: { width } as DOMRectReadOnly, + } as ResizeObserverEntry, + ], + this as unknown as ResizeObserver, + ); + } +} + +const originalResizeObserver = globalThis.ResizeObserver; + +afterEach(() => { + cleanup(); + globalThis.ResizeObserver = originalResizeObserver; +}); + +describe('useMetricBarState', () => { + it('centralizes metric bar derivations and resize observer cleanup', () => { + const observers: MockResizeObserver[] = []; + globalThis.ResizeObserver = class extends MockResizeObserver { + constructor(callback: ResizeObserverCallback) { + super(callback); + observers.push(this); + } + } as unknown as typeof ResizeObserver; + + let captured: ReturnType | undefined; + + const Harness = () => { + captured = useMetricBarState({ + value: 75, + label: 'Memory', + sublabel: '6 GB / 8 GB', + type: 'memory', + }); + return
; + }; + + const { unmount } = render(() => ); + + expect(captured).toBeDefined(); + expect(observers).toHaveLength(1); + expect(observers[0].observe).toHaveBeenCalled(); + expect(captured!.presentation().progressColorClass).toContain('warning'); + + observers[0].trigger(320); + expect(captured!.presentation().showSublabel).toBe(true); + + unmount(); + expect(observers[0].disconnect).toHaveBeenCalled(); + }); +}); + diff --git a/frontend-modern/src/components/Dashboard/metricBarModel.ts b/frontend-modern/src/components/Dashboard/metricBarModel.ts new file mode 100644 index 000000000..36a0fc7da --- /dev/null +++ b/frontend-modern/src/components/Dashboard/metricBarModel.ts @@ -0,0 +1,42 @@ +import { estimateTextWidth } from '@/utils/format'; +import { getMetricColorClass } from '@/utils/metricThresholds'; +import type { MetricType } from '@/utils/metricThresholds'; + +export interface MetricBarProps { + value: number; + label: string; + sublabel?: string; + showLabel?: boolean; + type?: 'cpu' | 'memory' | 'disk' | 'generic'; + resourceId?: string; + class?: string; +} + +export interface MetricBarPresentation { + progressColorClass: string; + showLabel: boolean; + showSublabel: boolean; + width: number; +} + +export function buildMetricBarPresentation( + props: MetricBarProps, + containerWidth: number, +): MetricBarPresentation { + const width = Math.min(props.value, 100); + const showLabel = props.showLabel !== false && props.label.trim().length > 0; + const showSublabel = + showLabel && + Boolean(props.sublabel) && + containerWidth >= estimateTextWidth(`${props.label} (${props.sublabel})`); + const metric = props.type || 'cpu'; + const metricType: MetricType = metric === 'generic' ? 'cpu' : metric; + + return { + progressColorClass: getMetricColorClass(props.value, metricType), + showLabel, + showSublabel, + width, + }; +} + diff --git a/frontend-modern/src/components/Dashboard/useMetricBarState.ts b/frontend-modern/src/components/Dashboard/useMetricBarState.ts new file mode 100644 index 000000000..52cd0c22f --- /dev/null +++ b/frontend-modern/src/components/Dashboard/useMetricBarState.ts @@ -0,0 +1,37 @@ +import { createMemo, createSignal, onCleanup, onMount } from 'solid-js'; +import { buildMetricBarPresentation, type MetricBarProps } from './metricBarModel'; + +export function useMetricBarState(props: MetricBarProps) { + const [containerWidth, setContainerWidth] = createSignal(100); + let containerRef: HTMLDivElement | undefined; + let resizeObserver: ResizeObserver | undefined; + + const presentation = createMemo(() => buildMetricBarPresentation(props, containerWidth())); + + onMount(() => { + if (!containerRef) { + return; + } + + setContainerWidth(containerRef.offsetWidth); + + resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + setContainerWidth(entry.contentRect.width); + } + }); + resizeObserver.observe(containerRef); + }); + + onCleanup(() => { + resizeObserver?.disconnect(); + }); + + return { + presentation, + setContainerRef: (element: HTMLDivElement) => { + containerRef = element; + }, + }; +} + diff --git a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts index 0d20effd8..a150d1e44 100644 --- a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts +++ b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts @@ -112,6 +112,9 @@ import guestRowStateSource from '@/components/Dashboard/useGuestRowState.ts?raw' import dashboardDiskListSource from '@/components/Dashboard/DiskList.tsx?raw'; import dashboardDiskListModelSource from '@/components/Dashboard/diskListModel.ts?raw'; import dashboardDiskListStateSource from '@/components/Dashboard/useDiskListState.ts?raw'; +import metricBarSource from '@/components/Dashboard/MetricBar.tsx?raw'; +import metricBarModelSource from '@/components/Dashboard/metricBarModel.ts?raw'; +import metricBarStateSource from '@/components/Dashboard/useMetricBarState.ts?raw'; import guestDrawerSource from '@/components/Dashboard/GuestDrawer.tsx?raw'; import guestDrawerModelSource from '@/components/Dashboard/guestDrawerModel.ts?raw'; import guestDrawerStateSource from '@/components/Dashboard/useGuestDrawerState.ts?raw'; @@ -548,6 +551,13 @@ describe('frontend resource type boundaries', () => { 'export function buildStackedMemoryBarPresentation', ); expect(stackedMemoryBarModelSource).toContain('const MEMORY_COLORS'); + expect(metricBarSource).toContain('useMetricBarState'); + expect(metricBarSource).not.toContain('const [containerWidth, setContainerWidth] ='); + expect(metricBarSource).not.toContain('const progressColorClass = createMemo(() => {'); + expect(metricBarSource).not.toContain('const showSublabel = createMemo(() => {'); + expect(metricBarStateSource).toContain('new ResizeObserver'); + expect(metricBarModelSource).toContain('export function buildMetricBarPresentation'); + expect(metricBarModelSource).toContain('estimateTextWidth'); expect(workloadsSummarySource).toContain('normalizeOrgScope(getOrgID())'); expect(workloadsSummarySource).not.toContain("const DEFAULT_ORG_SCOPE = 'default'"); expect(workloadsSummarySource).not.toContain('const normalizeOrgScope ='); diff --git a/scripts/release_control/subsystem_lookup_test.py b/scripts/release_control/subsystem_lookup_test.py index 380115abb..bf399c0d6 100644 --- a/scripts/release_control/subsystem_lookup_test.py +++ b/scripts/release_control/subsystem_lookup_test.py @@ -1981,6 +1981,36 @@ class SubsystemLookupTest(unittest.TestCase): "dashboard-workload-hot-path", ) + def test_lookup_paths_assigns_dashboard_metric_bar_runtime_to_performance_and_scalability(self) -> None: + result = lookup_paths( + [ + "frontend-modern/src/components/Dashboard/MetricBar.tsx", + "frontend-modern/src/components/Dashboard/metricBarModel.ts", + "frontend-modern/src/components/Dashboard/useMetricBarState.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["lane_context"]["lane_id"], "L10") + self.assertEqual( + match["verification_requirement"]["id"], + "dashboard-workload-hot-path", + ) + def test_lookup_paths_assigns_settings_page_shell_to_frontend_primitives(self) -> None: result = lookup_paths(["frontend-modern/src/components/Settings/SettingsPageShell.tsx"]) self.assertEqual(result["unowned_runtime_files"], [])