-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathPieChartPanel.tsx
More file actions
134 lines (123 loc) · 3.64 KB
/
PieChartPanel.tsx
File metadata and controls
134 lines (123 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import React from "react";
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend
} from "recharts";
import { PanelResult } from "../../../types";
import { COLOR_PALETTE, getSeverityOfText, severityToHex } from "./utils";
import PanelWrapper from "./PanelWrapper";
interface PieChartPanelProps {
summary: PanelResult;
}
/**
* Transforms raw data rows into pie chart compatible format with intelligent color assignment.
*/
export const generatePieChartData = (
rows: Record<string, any>[],
customColors?: Record<string, string>
) => {
return rows.map((row, index) => {
const { count, ...rest } = row;
const labelKey = Object.keys(rest)[0];
const labelValue = rest[labelKey];
if (!labelValue) {
return {
name: "Unknown",
value: count,
fill: COLOR_PALETTE[index % COLOR_PALETTE.length]
};
}
const customColor = customColors?.[labelValue];
let fill: string;
if (customColor) {
fill = customColor;
} else if (typeof labelValue === "string") {
const severity = getSeverityOfText(labelValue);
const hexColors = severityToHex[severity];
const colorInGroup = index % hexColors.length;
fill = hexColors[colorInGroup];
} else {
fill = COLOR_PALETTE[index % COLOR_PALETTE.length];
}
return {
name: labelValue,
value: count,
fill
};
});
};
/**
* Custom legend renderer for the pie chart displaying color indicators with labels.
* @param props - Recharts legend props containing payload array
* @returns JSX element rendering the legend
*/
const renderLegend = (props: any) => {
const { payload } = props;
return (
<ul className="mt-1 flex flex-wrap justify-center gap-1 text-xs text-gray-600">
{payload.map((entry: any, index: number) => (
<li key={`item-${index}`} className="flex items-center">
<span
className="mr-1 h-1.5 w-1.5 rounded-full"
style={{ backgroundColor: entry.color }}
/>
<span>{entry.value}</span>
</li>
))}
</ul>
);
};
/**
* Displays data as an interactive pie chart with intelligent color coding.
*
* Features:
* - Automatic semantic coloring (success=green, error=red, etc.)
* - Support for custom color overrides
* - Optional value labels on chart slices
* - Custom legend with color indicators
*
* @param props - Component props
* @param props.summary - Panel data containing rows, title, description, and chart config
*/
const PieChartPanel: React.FC<PieChartPanelProps> = ({ summary }) => {
const chartData = generatePieChartData(
summary.rows || [],
summary.piechart?.colors
);
return (
<PanelWrapper
title={summary.name}
description={summary.description}
className="min-h-[300px]"
>
<div className="flex flex-1 items-center justify-center">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={chartData}
dataKey="value"
nameKey="name"
stroke={chartData.length === 1 ? "none" : undefined}
label={
summary.piechart?.showLabels === true
? (entry: any) => entry.value
: false
}
>
{chartData.map((entry, entryIndex) => (
<Cell key={`cell-${entryIndex}`} fill={entry.fill} />
))}
</Pie>
<Tooltip allowEscapeViewBox={{ x: true, y: true }} />
<Legend content={renderLegend} />
</PieChart>
</ResponsiveContainer>
</div>
</PanelWrapper>
);
};
export default PieChartPanel;