diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 0580afbca..7dabc3124 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -1227,6 +1227,12 @@ should present alert-triggered and anomaly-triggered Patrol toggles as distinct controls, and `frontend-modern/src/components/patrol/PatrolStatusBar.tsx` should render compact activity breakdown and scoped-trigger-state copy from the shared transport rather than leaving busy Patrol periods as unexplained noise. +On the main Patrol page, though, that same governed activity context belongs +inside `frontend-modern/src/features/patrol/PatrolIntelligenceSummary.tsx` +alongside the verification readout rather than as a second full-width band +above the findings workspace. If `PatrolStatusBar.tsx` is reused elsewhere, it +must stay a compact factual support surface and must not reintroduce a parallel +page-level verdict strip once the summary shell already owns that explanation. Shared primitive consumers that split status-dot tone and status-text tone must now keep both values routed through the same exported presentation helper. diff --git a/frontend-modern/src/components/shared/DensityMap.tsx b/frontend-modern/src/components/shared/DensityMap.tsx index d113b25f7..f28e7c118 100644 --- a/frontend-modern/src/components/shared/DensityMap.tsx +++ b/frontend-modern/src/components/shared/DensityMap.tsx @@ -107,27 +107,6 @@ export const DensityMap: Component = (props) => { )} - - {(path) => ( -
- -
- )} -
)} diff --git a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts index 686447610..8ff5ecfd9 100644 --- a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts +++ b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts @@ -651,13 +651,11 @@ describe('shared primitive guardrails', () => { expect(densityMapSource).not.toContain('Top activity overview'); expect(densityMapSource).not.toContain('detail().currentValue'); expect(densityMapSource).toContain('data-density-map-tooltip="true"'); - expect(densityMapSource).toContain('data-density-map-tooltip-sparkline="true"'); + expect(densityMapSource).not.toContain('data-density-map-tooltip-sparkline="true"'); expect(densityMapSource).toContain('grid-cols-[auto_minmax(0,1fr)_auto]'); expect(densityMapSource).not.toContain('max-w-[94px]'); expect(densityMapSource).toContain('whitespace-nowrap text-[11px] font-semibold text-emerald-400'); expect(densityMapSource).toContain('whitespace-nowrap text-[11px] font-semibold text-base-content'); - expect(densityMapSource).toContain('mt-1 flex justify-end'); - expect(densityMapSource).toContain('w-[72px] overflow-visible'); expect(densityMapSource).not.toContain('timeRangeToMs'); expect(densityMapSource).not.toContain('createSignal'); expect(densityMapSource).not.toContain('ctx.fillRect'); @@ -673,6 +671,8 @@ describe('shared primitive guardrails', () => { expect(densityMapModelSource).toContain('formatDensityMapHoverTime'); expect(densityMapModelSource).toContain('getDensityMapColumnIndexForTimestamp'); expect(densityMapModelSource).toContain('getDensityMapCellOpacity'); + expect(densityMapModelSource).not.toContain('buildDensityMapFocusSparklinePath'); + expect(densityMapModelSource).not.toContain('sparklinePath: string | null;'); expect(densityMapModelSource).not.toContain('currentValue:'); expect(densityMapModelSource).not.toContain('hoveredValue:'); }); diff --git a/frontend-modern/src/components/shared/__tests__/DensityMap.test.tsx b/frontend-modern/src/components/shared/__tests__/DensityMap.test.tsx index 3c8d0ffc3..7fd569272 100644 --- a/frontend-modern/src/components/shared/__tests__/DensityMap.test.tsx +++ b/frontend-modern/src/components/shared/__tests__/DensityMap.test.tsx @@ -92,7 +92,7 @@ describe('DensityMap', () => { expect(screen.getByText('Current')).toBeInTheDocument(); expect(screen.getByText('Peak')).toBeInTheDocument(); expect(document.querySelector('[data-density-map-tooltip="true"]')).not.toBeNull(); - expect(document.querySelector('[data-density-map-tooltip-sparkline="true"]')).not.toBeNull(); + expect(document.querySelector('[data-density-map-tooltip-sparkline="true"]')).toBeNull(); }); it('publishes synchronized hover identity and clears it on leave', () => { @@ -214,7 +214,6 @@ describe('DensityMap', () => { seriesName: 'Alpha', peakValue: 32, }); - expect(detail?.sparklinePath).toContain('M'); }); it('keeps the density-map card free of persistent focus chrome while preserving overview count', () => { diff --git a/frontend-modern/src/components/shared/densityMapModel.ts b/frontend-modern/src/components/shared/densityMapModel.ts index 803f3c306..b10f7e73a 100644 --- a/frontend-modern/src/components/shared/densityMapModel.ts +++ b/frontend-modern/src/components/shared/densityMapModel.ts @@ -33,7 +33,6 @@ export interface DensityMapFocusDetail { seriesColor: string; seriesId: string; seriesName: string; - sparklinePath: string | null; } export interface DensityMapChartData { @@ -281,54 +280,14 @@ export function buildDensityMapFocusDetail(options: { peakValue = peakValue === null ? point.value : Math.max(peakValue, point.value); } - const sparklinePath = buildDensityMapFocusSparklinePath({ - points, - rangeMs: options.data.rangeMs, - windowStart: options.data.windowStart, - }); - return { peakValue, seriesColor: series.color, seriesId, seriesName: series.name || 'Unknown', - sparklinePath, }; } export function hasDensityMapFocusActivity(detail: DensityMapFocusDetail): boolean { return detail.peakValue !== null; } - -const buildDensityMapFocusSparklinePath = (options: { - points: Array<{ timestamp: number; value: number }>; - rangeMs: number; - windowStart: number; -}): string | null => { - const { points, rangeMs, windowStart } = options; - if (points.length < 2 || rangeMs <= 0) { - return null; - } - - const width = 64; - const height = 22; - let maxValue = 0; - for (const point of points) { - if (point.value > maxValue) { - maxValue = point.value; - } - } - if (maxValue <= 0) { - return null; - } - - const commands: string[] = []; - for (let index = 0; index < points.length; index += 1) { - const point = points[index]; - const x = clampDensityMapValue((point.timestamp - windowStart) / rangeMs, 0, 1) * width; - const y = height - clampDensityMapValue(point.value / maxValue, 0, 1) * height; - commands.push(`${index === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`); - } - - return commands.join(' '); -}; diff --git a/tests/integration/tests/48-summary-hover-selection.spec.ts b/tests/integration/tests/48-summary-hover-selection.spec.ts index bbc7aad76..a6a0a2361 100644 --- a/tests/integration/tests/48-summary-hover-selection.spec.ts +++ b/tests/integration/tests/48-summary-hover-selection.spec.ts @@ -797,7 +797,7 @@ test.describe.serial("Summary hover selection", () => { .toEqual(resolvedBaselineCounts); }); - test("keeps density-map detail inside the hover tooltip instead of card chrome", async ({ + test("keeps density-map detail inside the hover tooltip without extra chart chrome", async ({ page, }, testInfo) => { test.skip( @@ -826,6 +826,6 @@ test.describe.serial("Summary hover selection", () => { await expect(tooltip).toContainText("Peak"); await expect( tooltip.locator('[data-density-map-tooltip-sparkline="true"]'), - ).toBeVisible(); + ).toHaveCount(0); }); });