diff --git a/frontend/src/components/CoverageSummaryCard.tsx b/frontend/src/components/CoverageSummaryCard.tsx index b5279b7..3a074de 100644 --- a/frontend/src/components/CoverageSummaryCard.tsx +++ b/frontend/src/components/CoverageSummaryCard.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from "react"; +import MetricTooltip from "./MetricTooltip"; interface CoverageSummaryCardProps { title: string; @@ -7,6 +8,8 @@ interface CoverageSummaryCardProps { icon: ReactNode; colorClass: string; bgClass: string; + /** Optional tooltip explaining this metric to non-technical users */ + tooltip?: { description: string; context?: string }; } export default function CoverageSummaryCard({ @@ -16,6 +19,7 @@ export default function CoverageSummaryCard({ icon, colorClass, bgClass, + tooltip, }: CoverageSummaryCardProps) { const percentage = total && total > 0 ? ((value / total) * 100).toFixed(1) : null; @@ -23,7 +27,16 @@ export default function CoverageSummaryCard({
{title}
+
+ {title}
+ {tooltip && (
+
{value}
{percentage !== null && ({percentage}% of total
diff --git a/frontend/src/components/MetricTooltip.tsx b/frontend/src/components/MetricTooltip.tsx new file mode 100644 index 0000000..3e1b4c0 --- /dev/null +++ b/frontend/src/components/MetricTooltip.tsx @@ -0,0 +1,58 @@ +/** + * MetricTooltip — a small ⓘ icon that shows a plain-language explanation + * of a metric on hover. Designed for executive dashboards where not everyone + * knows what "MTTD" or "partial coverage" means. + */ + +interface MetricTooltipProps { + title: string; + description: string; + /** Optional extra context line (e.g. "Why it matters") */ + context?: string; + /** Positioning hint — defaults to 'below' */ + position?: "below" | "above" | "left"; +} + +export default function MetricTooltip({ + title, + description, + context, + position = "below", +}: MetricTooltipProps) { + const posClass = + position === "above" + ? "bottom-full mb-2 left-0" + : position === "left" + ? "right-full mr-2 top-0" + : "top-full mt-2 left-0"; + + return ( + + {/* The ⓘ icon */} + + i + + + {/* Tooltip panel */} + + {/* Arrow */} + {position !== "above" && position !== "left" && ( + + )} +{title}
+{description}
+ {context && ( ++ {context} +
+ )} + + + ); +} diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index b982bc9..0217992 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -42,6 +42,7 @@ import { import { getCoverageEvolution } from "../api/snapshots"; import CoverageSummaryCard from "../components/CoverageSummaryCard"; import TacticCoverageChart from "../components/TacticCoverageChart"; +import MetricTooltip from "../components/MetricTooltip"; import type { TestState } from "../types/models"; /* ── Badge colours (reused from TestsPage) ─────────────────────────── */ @@ -199,6 +200,7 @@ export default function DashboardPage() { icon={