diff --git a/src/components/admin/tabs/OverviewTab.tsx b/src/components/admin/tabs/OverviewTab.tsx index f893b5836..ca4f550ca 100644 --- a/src/components/admin/tabs/OverviewTab.tsx +++ b/src/components/admin/tabs/OverviewTab.tsx @@ -42,7 +42,7 @@ import Link from "next/link"; import type { FleetHealthItem } from "@/app/api/admin/fleet-health/route"; import type { AuditEvent } from "@/lib/audit"; import { useEffectiveTheme } from "@/hooks/use-effective-theme"; -import { chartTooltipStyle } from "@/lib/charts/palette"; +import { chartTheme, chartTooltipStyle } from "@/lib/charts/palette"; // ─── Animation Variants ───────────────────────────────────────────────────── @@ -432,6 +432,7 @@ function HeroStatusBanner({ fleetLoading: boolean; onRefresh: () => void; }) { + const { grid } = chartTheme(useEffectiveTheme()); const animatedScore = useAnimatedCounter(healthScore); const animatedConns = useAnimatedCounter(connections.length); const animatedQueries = useAnimatedCounter(queryStats.total); @@ -488,7 +489,7 @@ function HeroStatusBanner({ startAngle={90} endAngle={-270} > - + @@ -851,6 +852,7 @@ function MetricGauge({ color: string; maxValue?: number; }) { + const { grid } = chartTheme(useEffectiveTheme()); const pct = Math.round((value / maxValue) * 100); const animatedValue = useAnimatedCounter(value); const gaugeData = [{ value: pct, fill: color }]; @@ -867,7 +869,7 @@ function MetricGauge({ startAngle={90} endAngle={-270} > - +
diff --git a/tests/components/admin/OverviewTab.test.tsx b/tests/components/admin/OverviewTab.test.tsx index 80260e84d..0214aaa2e 100644 --- a/tests/components/admin/OverviewTab.test.tsx +++ b/tests/components/admin/OverviewTab.test.tsx @@ -749,4 +749,33 @@ describe("OverviewTab", () => { expect(bg).toBe("#ffffff"); expect(color).toBe("#3f3f46"); }); + + // ── Radial health gauge track ───────────────────────────────────────────── + + /** + * The radial health gauge track background also cannot read CSS tokens and must + * receive the theme-aware grid token, ensuring contrast in both themes. + */ + async function radialBarTrackUnderTheme(theme: "dark" | "light") { + document.documentElement.classList.remove("dark", "light"); + document.documentElement.classList.add(theme); + mockGlobalFetch({ "/api/admin/audit": { ok: true, json: { events: [] } } }); + + let result: ReturnType; + await act(async () => { + result = render(); + }); + const radialBar = result!.container.querySelector("[data-testid='mock-radial-bar']"); + return radialBar?.getAttribute("data-track-fill"); + } + + test("the radial health gauge track uses the dark grid tone in the dark theme", async () => { + const track = await radialBarTrackUnderTheme("dark"); + expect(track).toBe("#222222"); + }); + + test("and the light grid tone in the light theme", async () => { + const track = await radialBarTrackUnderTheme("light"); + expect(track).toBe("#e4e4e7"); + }); }); diff --git a/tests/helpers/mock-monaco.ts b/tests/helpers/mock-monaco.ts index 01577844f..7866b0c5d 100644 --- a/tests/helpers/mock-monaco.ts +++ b/tests/helpers/mock-monaco.ts @@ -73,7 +73,18 @@ export function setupRechartssMock() { Area: () => null, Bar: () => null, Line: () => null, - RadialBar: () => null, + RadialBar: ({ background }: { background?: { fill?: string } | boolean }) => + React.createElement("div", { + "data-testid": "mock-radial-bar", + "data-track-fill": + typeof background === "object" && background !== null + ? (background.fill as string | undefined) + : undefined, + "data-bg": + typeof background === "object" && background !== null + ? (background.fill as string | undefined) + : undefined, + }), XAxis: () => null, YAxis: () => null, CartesianGrid: () => null,