-
+
{data.percentage}% {data.name}
{data.change !== undefined && (
-
+
{data.change > 0 ? "+" : ""}
{data.change}%
@@ -145,14 +154,19 @@ export function DonutChart({
{formattedValue}
{centerLabel.label}
diff --git a/ui/components/graphs/horizontal-bar-chart.tsx b/ui/components/graphs/horizontal-bar-chart.tsx
index b0ea53e747..7af8556b65 100644
--- a/ui/components/graphs/horizontal-bar-chart.tsx
+++ b/ui/components/graphs/horizontal-bar-chart.tsx
@@ -26,7 +26,12 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {
{title && (
-
{title}
+
+ {title}
+
)}
@@ -48,8 +53,9 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {
>
{isHovered && (
-
+
-
+
{item.value.toLocaleString()} {item.name} Risk
{item.newFindings !== undefined && (
-
-
+
+
{item.newFindings} New Findings
)}
{item.change !== undefined && (
-
+
{item.change > 0 ? "+" : ""}
{item.change}%
@@ -102,14 +126,15 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {
{item.percentage}%
- •
+ •
{item.value.toLocaleString()}
diff --git a/ui/components/graphs/line-chart.tsx b/ui/components/graphs/line-chart.tsx
index ce4327010d..51b0a31b48 100644
--- a/ui/components/graphs/line-chart.tsx
+++ b/ui/components/graphs/line-chart.tsx
@@ -48,8 +48,16 @@ const CustomLineTooltip = ({
const totalValue = typedPayload.reduce((sum, item) => sum + item.value, 0);
return (
-
-
{label}
+
+
+ {label}
+
@@ -67,18 +75,23 @@ const CustomLineTooltip = ({
className="h-2 w-2 rounded-full"
style={{ backgroundColor: item.stroke }}
/>
-
{item.value}
+
+ {item.value}
+
{newFindings !== undefined && (
-
-
+
+
{newFindings} New Findings
)}
{change !== undefined && typeof change === "number" && (
-
+
{change > 0 ? "+" : ""}
{change}%
diff --git a/ui/components/graphs/radar-chart.tsx b/ui/components/graphs/radar-chart.tsx
index 5855f624b0..b0fb6936c2 100644
--- a/ui/components/graphs/radar-chart.tsx
+++ b/ui/components/graphs/radar-chart.tsx
@@ -36,15 +36,27 @@ const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
const data = payload[0];
return (
-
-
+
+
{data.payload.category}
{data.payload.change !== undefined && (
-
+
{data.payload.change > 0 ? "+" : ""}
{data.payload.change}%
diff --git a/ui/components/graphs/sankey-chart.tsx b/ui/components/graphs/sankey-chart.tsx
index c93deb8353..2208b69576 100644
--- a/ui/components/graphs/sankey-chart.tsx
+++ b/ui/components/graphs/sankey-chart.tsx
@@ -66,10 +66,23 @@ const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
const data = payload[0].payload;
return (
-
-
{data.name}
+
+
+ {data.name}
+
{data.value && (
-
Value: {data.value}
+
+ Value: {data.value}
+
)}
);
@@ -143,7 +156,7 @@ const CustomNode = (props: any) => {
x={isOut ? x - 6 : x + width + 6}
y={y + height / 2}
fontSize="14"
- className="fill-white stroke-white"
+ fill={CHART_COLORS.textPrimary}
>
{nodeName}
@@ -152,8 +165,7 @@ const CustomNode = (props: any) => {
x={isOut ? x - 6 : x + width + 6}
y={y + height / 2 + 13}
fontSize="12"
- className="fill-slate-400 stroke-slate-400"
- strokeOpacity="0.5"
+ fill={CHART_COLORS.textSecondary}
>
{payload.value}
diff --git a/ui/components/graphs/scatter-plot.tsx b/ui/components/graphs/scatter-plot.tsx
index d137a6ccdf..0b8cf7b8fd 100644
--- a/ui/components/graphs/scatter-plot.tsx
+++ b/ui/components/graphs/scatter-plot.tsx
@@ -45,9 +45,23 @@ const CustomTooltip = ({ active, payload }: any) => {
const severityColor = getSeverityColorByRiskScore(data.x);
return (
-
-
{data.name}
-
+
+
+ {data.name}
+
+
{data.x} Risk Score
diff --git a/ui/components/graphs/shared/chart-legend.tsx b/ui/components/graphs/shared/chart-legend.tsx
index 11066aa54a..2efea3ea85 100644
--- a/ui/components/graphs/shared/chart-legend.tsx
+++ b/ui/components/graphs/shared/chart-legend.tsx
@@ -9,14 +9,22 @@ interface ChartLegendProps {
export function ChartLegend({ items }: ChartLegendProps) {
return (
-
+
{items.map((item, index) => (
-
{item.label}
+
+ {item.label}
+
))}
diff --git a/ui/components/graphs/shared/constants.ts b/ui/components/graphs/shared/constants.ts
index 44e2d50414..4aadd4aac0 100644
--- a/ui/components/graphs/shared/constants.ts
+++ b/ui/components/graphs/shared/constants.ts
@@ -21,7 +21,7 @@ export const STATUS_COLORS = {
export const CHART_COLORS = {
tooltipBorder: "var(--chart-border-emphasis)",
tooltipBackground: "var(--chart-background)",
- textPrimary: "#ffffff",
+ textPrimary: "var(--chart-text-primary)",
textSecondary: "var(--chart-text-secondary)",
gridLine: "var(--chart-border-emphasis)",
backgroundTrack: "rgba(51, 65, 85, 0.5)", // slate-700 with 50% opacity
diff --git a/ui/components/graphs/threat-map.tsx b/ui/components/graphs/threat-map.tsx
index ee74f7426f..571bba221c 100644
--- a/ui/components/graphs/threat-map.tsx
+++ b/ui/components/graphs/threat-map.tsx
@@ -118,29 +118,41 @@ function MapTooltip({
location: LocationPoint;
position: { x: number; y: number };
}) {
+ const CHART_COLORS = {
+ tooltipBorder: "var(--chart-border-emphasis)",
+ tooltipBackground: "var(--chart-background)",
+ textPrimary: "var(--chart-text-primary)",
+ textSecondary: "var(--chart-text-secondary)",
+ };
+
return (
-
-
+
+
{location.name}
-
+
{location.totalFindings.toLocaleString()} Fail Findings
{location.change !== undefined && (
-
+
{location.change > 0 ? "+" : ""}
{location.change}%
@@ -153,11 +165,23 @@ function MapTooltip({
}
function EmptyState() {
+ const CHART_COLORS = {
+ tooltipBorder: "var(--chart-border-emphasis)",
+ tooltipBackground: "var(--chart-background)",
+ textSecondary: "var(--chart-text-secondary)",
+ };
+
return (
-
+
-
-
+
+
Select a location on the map to view details
@@ -166,10 +190,16 @@ function EmptyState() {
}
function LoadingState({ height }: { height: number }) {
+ const CHART_COLORS = {
+ textSecondary: "var(--chart-text-secondary)",
+ };
+
return (
-
Loading map...
+
+ Loading map...
+
);
@@ -350,17 +380,34 @@ export function ThreatMap({
isLoadingMap,
]);
+ const CHART_COLORS = {
+ tooltipBorder: "var(--chart-border-emphasis)",
+ tooltipBackground: "var(--chart-background)",
+ textPrimary: "var(--chart-text-primary)",
+ textSecondary: "var(--chart-text-secondary)",
+ };
+
return (
{/* Map Section */}
-
Threat Map
+
+ Threat Map
+
{isLoadingMap ? (
@@ -401,7 +453,10 @@ export function ThreatMap({
-
+
{filteredLocations.length} Locations
@@ -414,15 +469,27 @@ export function ThreatMap({
{selectedLocation ? (
-
+
-
+
{selectedLocation.name}
-
+
{selectedLocation.totalFindings.toLocaleString()} Total Findings
diff --git a/ui/components/overview/scatter-plot-with-selection.tsx b/ui/components/overview/scatter-plot-with-selection.tsx
index 558eaac37e..ad9a0b6b17 100644
--- a/ui/components/overview/scatter-plot-with-selection.tsx
+++ b/ui/components/overview/scatter-plot-with-selection.tsx
@@ -1,5 +1,7 @@
"use client";
+import { useState } from "react";
+
import { ScatterPlot } from "@/components/graphs";
interface DataPoint {
@@ -23,12 +25,16 @@ export function ScatterPlotWithSelection({
xLabel = "Risk Score",
yLabel = "Compliance %",
}: ScatterPlotWithSelectionProps) {
+ const [selectedPoint, setSelectedPoint] = useState
(null);
+
return (
);
}
diff --git a/ui/styles/globals.css b/ui/styles/globals.css
index f87555e889..3265d97c4f 100644
--- a/ui/styles/globals.css
+++ b/ui/styles/globals.css
@@ -2,7 +2,7 @@
@config "../tailwind.config.js";
@theme {
- /* Chart Severity Colors */
+ /* Chart Severity Colors - Dark Theme */
--chart-info: #2e51b2;
--chart-warning: #fdd34f;
--chart-warning-emphasis: #ff7d19;
@@ -22,7 +22,8 @@
--chart-provider-azure: #00bcd4;
--chart-provider-google: #EA4335;
- /* Chart UI Colors */
+ /* Chart UI Colors - Dark Theme (defaults) */
+ --chart-text-primary: #ffffff;
--chart-text-secondary: #94a3b8;
--chart-border: #475569;
--chart-border-emphasis: #334155;
@@ -35,6 +36,24 @@
@layer base {
:root {
+ /* Light Theme Chart Colors */
+ --chart-info: #1e40af;
+ --chart-warning: #d97706;
+ --chart-warning-emphasis: #dc2626;
+ --chart-danger: #dc2626;
+ --chart-danger-emphasis: #991b1b;
+ --chart-success-color: #16a34a;
+ --chart-fail: #dc2626;
+ --chart-radar-primary: #9d174d;
+ --chart-text-primary: #1f2937;
+ --chart-text-secondary: #6b7280;
+ --chart-border: #d1d5db;
+ --chart-border-emphasis: #9ca3af;
+ --chart-background: #f9fafb;
+ --chart-alert-bg: #fecdd3;
+ --chart-alert-text: #be123c;
+
+ /* Chart HSL values */
--chart-success: 146 80% 35%;
--chart-fail: 339 90% 51%;
--chart-muted: 45 93% 47%;
@@ -49,6 +68,24 @@
}
.dark {
+ /* Dark Theme Chart Colors */
+ --chart-info: #2e51b2;
+ --chart-warning: #fdd34f;
+ --chart-warning-emphasis: #ff7d19;
+ --chart-danger: #ff3077;
+ --chart-danger-emphasis: #971348;
+ --chart-success-color: #86da26;
+ --chart-fail: #db2b49;
+ --chart-radar-primary: #b51c80;
+ --chart-text-primary: #ffffff;
+ --chart-text-secondary: #94a3b8;
+ --chart-border: #475569;
+ --chart-border-emphasis: #334155;
+ --chart-background: #1e293b;
+ --chart-alert-bg: #432232;
+ --chart-alert-text: #f54280;
+
+ /* Chart HSL values */
--chart-success: 146 80% 35%;
--chart-fail: 339 90% 51%;
--chart-muted: 45 93% 47%;