Skip to content

Commit 1f28e9c

Browse files
adityathebemoshloop
authored andcommitted
feat: shadcn piechart and group as "Others"
1 parent 57918da commit 1f28e9c

File tree

1 file changed

+55
-52
lines changed

1 file changed

+55
-52
lines changed

src/pages/audit-report/components/View/panels/PieChartPanel.tsx

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import React from "react";
2-
import {
3-
PieChart,
4-
Pie,
5-
Cell,
6-
ResponsiveContainer,
7-
Tooltip,
8-
Legend
9-
} from "recharts";
1+
import React, { useMemo } from "react";
2+
import { PieChart, Pie, Cell } from "recharts";
103
import { PanelResult } from "../../../types";
114
import { COLOR_PALETTE, getSeverityOfText, severityToHex } from "./utils";
5+
import {
6+
ChartConfig,
7+
ChartContainer,
8+
ChartLegend,
9+
ChartLegendContent,
10+
ChartTooltip,
11+
ChartTooltipContent
12+
} from "@flanksource-ui/components/ui/chart";
1213

1314
interface PieChartPanelProps {
1415
summary: PanelResult;
@@ -19,22 +20,17 @@ interface PieChartPanelProps {
1920
*/
2021
export const generatePieChartData = (
2122
rows: Record<string, any>[],
22-
customColors?: Record<string, string>
23+
customColors?: Record<string, string>,
24+
maxSlices = 6
2325
) => {
24-
return rows.map((row, index) => {
26+
const entries = rows.map((row, index) => {
2527
const { count, ...rest } = row;
2628
const labelKey = Object.keys(rest)[0];
2729
const labelValue = rest[labelKey];
28-
29-
if (!labelValue) {
30-
return {
31-
name: "Unknown",
32-
value: count,
33-
fill: COLOR_PALETTE[index % COLOR_PALETTE.length]
34-
};
35-
}
36-
37-
const customColor = customColors?.[labelValue];
30+
const parsedValue = Number(count);
31+
const value = Number.isFinite(parsedValue) ? parsedValue : 0;
32+
const name = labelValue ? String(labelValue) : "Unknown";
33+
const customColor = customColors?.[name];
3834
let fill: string;
3935

4036
if (customColor) {
@@ -49,34 +45,32 @@ export const generatePieChartData = (
4945
}
5046

5147
return {
52-
name: labelValue,
53-
value: count,
48+
name,
49+
value,
5450
fill
5551
};
5652
});
57-
};
5853

59-
/**
60-
* Custom legend renderer for the pie chart displaying color indicators with labels.
61-
* @param props - Recharts legend props containing payload array
62-
* @returns JSX element rendering the legend
63-
*/
64-
const renderLegend = (props: any) => {
65-
const { payload } = props;
54+
if (entries.length <= maxSlices) {
55+
return entries;
56+
}
6657

67-
return (
68-
<ul className="mt-1 flex flex-wrap justify-center gap-1 text-xs text-gray-600">
69-
{payload.map((entry: any, index: number) => (
70-
<li key={`item-${index}`} className="flex items-center">
71-
<span
72-
className="mr-1 h-1.5 w-1.5 rounded-full"
73-
style={{ backgroundColor: entry.color }}
74-
/>
75-
<span>{entry.value}</span>
76-
</li>
77-
))}
78-
</ul>
79-
);
58+
const sorted = [...entries].sort((a, b) => b.value - a.value);
59+
const keep = sorted.slice(0, Math.max(maxSlices - 1, 1));
60+
const overflow = sorted.slice(keep.length);
61+
const overflowValue = overflow.reduce((sum, item) => sum + item.value, 0);
62+
63+
const othersFill =
64+
customColors?.others || COLOR_PALETTE[keep.length % COLOR_PALETTE.length];
65+
66+
return [
67+
...keep,
68+
{
69+
name: "others",
70+
value: overflowValue,
71+
fill: othersFill
72+
}
73+
];
8074
};
8175

8276
/**
@@ -92,10 +86,16 @@ const renderLegend = (props: any) => {
9286
* @param props.summary - Panel data containing rows, title, description, and chart config
9387
*/
9488
const PieChartPanel: React.FC<PieChartPanelProps> = ({ summary }) => {
95-
const chartData = generatePieChartData(
96-
summary.rows || [],
97-
summary.piechart?.colors
98-
);
89+
const chartData = useMemo(() => {
90+
return generatePieChartData(summary.rows || [], summary.piechart?.colors);
91+
}, [summary.rows, summary.piechart?.colors]);
92+
93+
const chartConfig = useMemo<ChartConfig>(() => {
94+
return chartData.reduce<ChartConfig>((acc, item) => {
95+
acc[item.name] = { label: item.name, color: item.fill };
96+
return acc;
97+
}, {});
98+
}, [chartData]);
9999

100100
return (
101101
<div className="flex h-full min-h-[300px] w-full flex-col overflow-hidden rounded-lg border border-gray-200 bg-white p-4">
@@ -104,8 +104,12 @@ const PieChartPanel: React.FC<PieChartPanelProps> = ({ summary }) => {
104104
<p className="mb-3 text-xs text-gray-500">{summary.description}</p>
105105
)}
106106
<div className="flex flex-1 items-center justify-center">
107-
<ResponsiveContainer width="100%" height="100%">
107+
<ChartContainer
108+
config={chartConfig}
109+
className="flex h-full min-h-[240px] w-full flex-1 items-center justify-center"
110+
>
108111
<PieChart>
112+
<ChartTooltip content={<ChartTooltipContent nameKey="name" />} />
109113
<Pie
110114
data={chartData}
111115
dataKey="value"
@@ -121,10 +125,9 @@ const PieChartPanel: React.FC<PieChartPanelProps> = ({ summary }) => {
121125
<Cell key={`cell-${entryIndex}`} fill={entry.fill} />
122126
))}
123127
</Pie>
124-
<Tooltip allowEscapeViewBox={{ x: true, y: true }} />
125-
<Legend content={renderLegend} />
128+
<ChartLegend content={<ChartLegendContent nameKey="name" />} />
126129
</PieChart>
127-
</ResponsiveContainer>
130+
</ChartContainer>
128131
</div>
129132
</div>
130133
);

0 commit comments

Comments
 (0)