Skip to content

Commit eaec5ae

Browse files
committed
dashboard enhancement and API
Signed-off-by: hiirrxnn <[email protected]>
1 parent 08a0f8f commit eaec5ae

File tree

7 files changed

+651
-500
lines changed

7 files changed

+651
-500
lines changed

frontend/src/components/Charts/JobStatusPieChart.jsx

Lines changed: 84 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,94 @@
1-
import React from "react";
2-
import { Box, Typography, Grid } from "@mui/material";
3-
import { Doughnut } from "react-chartjs-2";
4-
import { Chart as ChartJS, ArcElement, Tooltip, Legend, Title } from "chart.js";
1+
import React from 'react';
2+
import { Box, Card, CardContent, Typography, Chip, Paper, Fade, alpha } from '@mui/material';
3+
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';
54

6-
ChartJS.register(ArcElement, Tooltip, Legend, Title);
7-
8-
const JobStatusPieChart = ({ data }) => {
9-
if (!data || !Array.isArray(data)) {
10-
return (
11-
<Box sx={{ height: 300, width: "100%", position: "relative" }}>
12-
<Typography>No data available</Typography>
13-
</Box>
14-
);
15-
}
16-
17-
const statusCounts = data.reduce(
18-
(acc, job) => {
19-
const status = job.status;
20-
if (status?.succeeded) {
21-
acc.Completed++;
22-
} else if (
23-
status?.state?.phase === "Running" ||
24-
status?.state?.phase === "Pending"
25-
) {
26-
acc.Running++;
27-
} else if (status?.state?.phase === "Failed") {
28-
acc.Failed++;
29-
}
30-
return acc;
31-
},
32-
{
33-
Completed: 0,
34-
Running: 0,
35-
Failed: 0,
36-
},
37-
);
38-
39-
const total = Object.values(statusCounts).reduce((a, b) => a + b, 0);
40-
const colors = {
41-
Completed: "#4caf50",
42-
Running: "#2196f3",
43-
Failed: "#f44336",
44-
};
45-
46-
const chartData = {
47-
labels: Object.keys(statusCounts),
48-
datasets: [
49-
{
50-
data: Object.values(statusCounts),
51-
backgroundColor: Object.values(colors),
52-
borderColor: "white",
53-
borderWidth: 2,
54-
hoverBorderColor: "white",
55-
hoverBorderWidth: 3,
56-
},
57-
],
58-
};
59-
60-
const options = {
61-
responsive: true,
62-
maintainAspectRatio: false,
63-
cutout: "70%",
64-
plugins: {
65-
legend: {
66-
display: false,
67-
},
68-
tooltip: {
69-
enabled: false,
70-
},
71-
},
5+
const JobStatusPieChart = ({ jobStatusData, colors }) => {
6+
const CustomTooltip = ({ active, payload }) => {
7+
if (active && payload && payload.length) {
8+
const data = payload[0].payload;
9+
return (
10+
<Paper sx={{
11+
p: 2,
12+
bgcolor: colors.white,
13+
boxShadow: '0 8px 32px rgba(0,0,0,0.12)',
14+
border: '1px solid rgba(0,0,0,0.1)',
15+
borderRadius: 2
16+
}}>
17+
<Typography variant="body2" fontWeight="bold" sx={{ color: data.color }}>
18+
{data.name}: {data.value} jobs
19+
</Typography>
20+
</Paper>
21+
);
22+
}
23+
return null;
7224
};
7325

74-
const hasData = Object.values(statusCounts).some((count) => count > 0);
75-
7626
return (
77-
<Box
78-
sx={{
79-
height: "100%",
80-
display: "flex",
81-
flexDirection: "column",
82-
}}
83-
>
84-
<Typography variant="h6" align="center" sx={{ mb: 1 }}>
85-
Jobs Status
86-
</Typography>
87-
88-
<Box
89-
sx={{
90-
display: "flex",
91-
flexDirection: "row",
92-
justifyContent: "space-between",
93-
alignItems: "flex-start",
94-
flexWrap: "wrap",
95-
gap: 2,
96-
width: "100%",
97-
}}
98-
>
99-
<Box
100-
sx={{
101-
flex: 1,
102-
minWidth: "250px", // Ensure that the chart is not too small
103-
height: "300px", // Fixed height to adapt to various screens
104-
position: "relative",
105-
display: "flex",
106-
alignItems: "center",
107-
justifyContent: "center",
108-
}}
109-
>
110-
<Doughnut
111-
data={chartData}
112-
options={{
113-
...options,
114-
maintainAspectRatio: false,
115-
}}
116-
/>
117-
<Typography
118-
variant="h4"
119-
sx={{
120-
position: "absolute",
121-
top: "50%",
122-
left: "50%",
123-
transform: "translate(-50%, -50%)",
124-
textAlign: "center",
125-
}}
126-
>
127-
{total}
27+
<Fade in={true} timeout={1000}>
28+
<Card sx={{
29+
height: 400,
30+
bgcolor: colors.white,
31+
borderRadius: 3,
32+
boxShadow: '0 4px 20px rgba(0,0,0,0.08)',
33+
border: `1px solid ${alpha(colors.primary, 0.1)}`
34+
}}>
35+
<CardContent sx={{ p: 4 }}>
36+
<Typography variant="h6" fontWeight="bold" gutterBottom sx={{ color: colors.secondary, textAlign: 'center' }}>
37+
Job Status Distribution
12838
</Typography>
129-
</Box>
130-
131-
<Box
132-
sx={{
133-
flex: 1,
134-
minWidth: "250px",
135-
display: "flex",
136-
flexDirection: "column",
137-
justifyContent: "flex-start",
138-
alignItems: "flex-start",
139-
textAlign: "left",
140-
}}
141-
>
142-
{Object.entries(statusCounts).map(([status, count]) => (
143-
<Box
144-
key={status}
145-
sx={{
146-
display: "flex",
147-
alignItems: "center",
148-
mb: 1.5,
149-
}}
150-
>
151-
<Box
152-
sx={{
153-
width: 12,
154-
height: 12,
155-
borderRadius: "50%",
156-
backgroundColor: colors[status],
157-
mr: 1,
158-
}}
159-
/>
160-
<Typography
161-
variant="body2"
162-
sx={{ mr: 2, minWidth: 70 }}
163-
>
164-
{status}
165-
</Typography>
166-
<Typography variant="body2" color="text.secondary">
167-
{count} (
168-
{total > 0
169-
? ((count / total) * 100).toFixed(1)
170-
: 0}
171-
%)
39+
{jobStatusData.length > 0 ? (
40+
<Box display="flex" flexDirection="column" alignItems="center" height="100%">
41+
<ResponsiveContainer width="100%" height={240}>
42+
<PieChart>
43+
<Pie
44+
data={jobStatusData}
45+
cx="50%"
46+
cy="50%"
47+
outerRadius={80}
48+
innerRadius={35}
49+
paddingAngle={3}
50+
dataKey="value"
51+
>
52+
{jobStatusData.map((entry, index) => (
53+
<Cell
54+
key={`cell-${index}`}
55+
fill={entry.color}
56+
stroke={colors.white}
57+
strokeWidth={2}
58+
/>
59+
))}
60+
</Pie>
61+
<Tooltip content={<CustomTooltip />} />
62+
</PieChart>
63+
</ResponsiveContainer>
64+
65+
{/* Centered Legend */}
66+
<Box display="flex" justifyContent="center" gap={2} mt={1}>
67+
{jobStatusData.map((item) => (
68+
<Chip
69+
key={item.name}
70+
label={`${item.name}: ${item.value}`}
71+
sx={{
72+
bgcolor: alpha(item.color, 0.1),
73+
color: item.color,
74+
fontWeight: 500,
75+
border: `1px solid ${alpha(item.color, 0.2)}`
76+
}}
77+
variant="outlined"
78+
/>
79+
))}
80+
</Box>
81+
</Box>
82+
) : (
83+
<Box display="flex" alignItems="center" justifyContent="center" height={280}>
84+
<Typography color="text.secondary" variant="body1">
85+
No job data available
17286
</Typography>
17387
</Box>
174-
))}
175-
</Box>
176-
</Box>
177-
</Box>
88+
)}
89+
</CardContent>
90+
</Card>
91+
</Fade>
17892
);
17993
};
18094

0 commit comments

Comments
 (0)