Skip to content

Commit 964d79d

Browse files
authored
Merge pull request #4142 from Dokploy/2267-add-a-disk-space-pie-chart
feat(dashboard): enhance monitoring charts with new Docker disk usage…
2 parents b7adb7f + 1730f42 commit 964d79d

File tree

9 files changed

+656
-419
lines changed

9 files changed

+656
-419
lines changed
Lines changed: 90 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,103 @@
11
import { format } from "date-fns";
2+
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts";
23
import {
3-
Area,
4-
AreaChart,
5-
CartesianGrid,
6-
Legend,
7-
ResponsiveContainer,
8-
Tooltip,
9-
YAxis,
10-
} from "recharts";
4+
type ChartConfig,
5+
ChartContainer,
6+
ChartLegend,
7+
ChartLegendContent,
8+
ChartTooltip,
9+
ChartTooltipContent,
10+
} from "@/components/ui/chart";
1111
import type { DockerStatsJSON } from "./show-free-container-monitoring";
1212

1313
interface Props {
1414
accumulativeData: DockerStatsJSON["block"];
1515
}
1616

17+
const chartConfig = {
18+
readMb: {
19+
label: "Read (MB)",
20+
color: "hsl(var(--chart-1))",
21+
},
22+
writeMb: {
23+
label: "Write (MB)",
24+
color: "hsl(var(--chart-2))",
25+
},
26+
} satisfies ChartConfig;
27+
1728
export const DockerBlockChart = ({ accumulativeData }: Props) => {
18-
const transformedData = accumulativeData.map((item, index) => {
19-
return {
20-
time: item.time,
21-
name: `Point ${index + 1}`,
22-
readMb: item.value.readMb,
23-
writeMb: item.value.writeMb,
24-
};
25-
});
29+
const transformedData = accumulativeData.map((item, index) => ({
30+
time: item.time,
31+
name: `Point ${index + 1}`,
32+
readMb: item.value.readMb,
33+
writeMb: item.value.writeMb,
34+
}));
2635

2736
return (
28-
<div className="mt-6 w-full h-[10rem]">
29-
<ResponsiveContainer>
30-
<AreaChart
31-
data={transformedData}
32-
margin={{
33-
top: 10,
34-
right: 30,
35-
left: 0,
36-
bottom: 0,
37-
}}
38-
>
39-
<defs>
40-
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
41-
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
42-
<stop offset="95%" stopColor="#8884d8" stopOpacity={0} />
43-
</linearGradient>
44-
<linearGradient id="colorWrite" x1="0" y1="0" x2="0" y2="1">
45-
<stop offset="5%" stopColor="#82ca9d" stopOpacity={0.8} />
46-
<stop offset="95%" stopColor="#82ca9d" stopOpacity={0} />
47-
</linearGradient>
48-
</defs>
49-
<YAxis stroke="#A1A1AA" />
50-
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
51-
{/* @ts-ignore */}
52-
<Tooltip content={<CustomTooltip />} />
53-
<Legend />
54-
<Area
55-
type="monotone"
56-
dataKey="readMb"
57-
stroke="#27272A"
58-
fillOpacity={1}
59-
fill="url(#colorUv)"
60-
name="Read Mb"
61-
/>
62-
<Area
63-
type="monotone"
64-
dataKey="writeMb"
65-
stroke="#82ca9d"
66-
fillOpacity={1}
67-
fill="url(#colorWrite)"
68-
name="Write Mb"
69-
/>
70-
</AreaChart>
71-
</ResponsiveContainer>
72-
</div>
37+
<ChartContainer config={chartConfig} className="mt-4 h-[10rem] w-full">
38+
<AreaChart
39+
data={transformedData}
40+
margin={{ top: 10, right: 10, left: 0, bottom: 0 }}
41+
>
42+
<defs>
43+
<linearGradient id="fillBlockRead" x1="0" y1="0" x2="0" y2="1">
44+
<stop
45+
offset="5%"
46+
stopColor="var(--color-readMb)"
47+
stopOpacity={0.8}
48+
/>
49+
<stop
50+
offset="95%"
51+
stopColor="var(--color-readMb)"
52+
stopOpacity={0.1}
53+
/>
54+
</linearGradient>
55+
<linearGradient id="fillBlockWrite" x1="0" y1="0" x2="0" y2="1">
56+
<stop
57+
offset="5%"
58+
stopColor="var(--color-writeMb)"
59+
stopOpacity={0.8}
60+
/>
61+
<stop
62+
offset="95%"
63+
stopColor="var(--color-writeMb)"
64+
stopOpacity={0.1}
65+
/>
66+
</linearGradient>
67+
</defs>
68+
<CartesianGrid vertical={false} />
69+
<YAxis tickLine={false} axisLine={false} />
70+
<ChartTooltip
71+
cursor={false}
72+
content={
73+
<ChartTooltipContent
74+
labelFormatter={(_, payload) => {
75+
const time = payload?.[0]?.payload?.time;
76+
return time ? format(new Date(time), "PPpp") : "";
77+
}}
78+
formatter={(value, name) => {
79+
const label = name === "readMb" ? "Read" : "Write";
80+
return [`${value} MB`, label];
81+
}}
82+
/>
83+
}
84+
/>
85+
<Area
86+
type="monotone"
87+
dataKey="readMb"
88+
stroke="var(--color-readMb)"
89+
fill="url(#fillBlockRead)"
90+
strokeWidth={2}
91+
/>
92+
<Area
93+
type="monotone"
94+
dataKey="writeMb"
95+
stroke="var(--color-writeMb)"
96+
fill="url(#fillBlockWrite)"
97+
strokeWidth={2}
98+
/>
99+
<ChartLegend content={<ChartLegendContent />} />
100+
</AreaChart>
101+
</ChartContainer>
73102
);
74103
};
75-
interface CustomTooltipProps {
76-
active: boolean;
77-
payload?: {
78-
color?: string;
79-
dataKey?: string;
80-
value?: number;
81-
payload: {
82-
time: string;
83-
readMb: number;
84-
writeMb: number;
85-
};
86-
}[];
87-
}
88-
89-
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
90-
if (active && payload && payload.length && payload[0]) {
91-
return (
92-
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
93-
{payload[0].payload.time && (
94-
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
95-
)}
96-
<p>{`Read ${payload[0].payload.readMb} `}</p>
97-
<p>{`Write: ${payload[0].payload.writeMb} `}</p>
98-
</div>
99-
);
100-
}
101-
102-
return null;
103-
};
Lines changed: 69 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,81 @@
11
import { format } from "date-fns";
2+
import { Area, AreaChart, CartesianGrid, YAxis } from "recharts";
23
import {
3-
Area,
4-
AreaChart,
5-
CartesianGrid,
6-
Legend,
7-
ResponsiveContainer,
8-
Tooltip,
9-
YAxis,
10-
} from "recharts";
4+
type ChartConfig,
5+
ChartContainer,
6+
ChartLegend,
7+
ChartLegendContent,
8+
ChartTooltip,
9+
ChartTooltipContent,
10+
} from "@/components/ui/chart";
1111
import type { DockerStatsJSON } from "./show-free-container-monitoring";
1212

1313
interface Props {
1414
accumulativeData: DockerStatsJSON["cpu"];
1515
}
1616

17+
const chartConfig = {
18+
usage: {
19+
label: "CPU Usage",
20+
color: "hsl(var(--chart-1))",
21+
},
22+
} satisfies ChartConfig;
23+
1724
export const DockerCpuChart = ({ accumulativeData }: Props) => {
18-
const transformedData = accumulativeData.map((item, index) => {
19-
return {
20-
name: `Point ${index + 1}`,
21-
time: item.time,
22-
usage: item.value.toString().split("%")[0],
23-
};
24-
});
25+
const transformedData = accumulativeData.map((item, index) => ({
26+
name: `Point ${index + 1}`,
27+
time: item.time,
28+
usage: item.value.toString().split("%")[0],
29+
}));
30+
2531
return (
26-
<div className="mt-6 w-full h-[10rem]">
27-
<ResponsiveContainer>
28-
<AreaChart
29-
data={transformedData}
30-
margin={{
31-
top: 10,
32-
right: 30,
33-
left: 0,
34-
bottom: 0,
35-
}}
36-
>
37-
<defs>
38-
<linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
39-
<stop offset="5%" stopColor="#27272A" stopOpacity={0.8} />
40-
<stop offset="95%" stopColor="white" stopOpacity={0} />
41-
</linearGradient>
42-
</defs>
43-
<YAxis stroke="#A1A1AA" domain={[0, 100]} />
44-
<CartesianGrid strokeDasharray="3 3" stroke="#27272A" />
45-
{/* @ts-ignore */}
46-
<Tooltip content={<CustomTooltip />} />
47-
<Legend />
48-
<Area
49-
type="monotone"
50-
dataKey="usage"
51-
stroke="#27272A"
52-
fillOpacity={1}
53-
fill="url(#colorUv)"
54-
/>
55-
</AreaChart>
56-
</ResponsiveContainer>
57-
</div>
32+
<ChartContainer config={chartConfig} className="mt-4 h-[10rem] w-full">
33+
<AreaChart
34+
data={transformedData}
35+
margin={{ top: 10, right: 10, left: 0, bottom: 0 }}
36+
>
37+
<defs>
38+
<linearGradient id="fillCpu" x1="0" y1="0" x2="0" y2="1">
39+
<stop
40+
offset="5%"
41+
stopColor="var(--color-usage)"
42+
stopOpacity={0.8}
43+
/>
44+
<stop
45+
offset="95%"
46+
stopColor="var(--color-usage)"
47+
stopOpacity={0.1}
48+
/>
49+
</linearGradient>
50+
</defs>
51+
<CartesianGrid vertical={false} />
52+
<YAxis
53+
tickFormatter={(value) => `${value}%`}
54+
domain={[0, 100]}
55+
tickLine={false}
56+
axisLine={false}
57+
/>
58+
<ChartTooltip
59+
cursor={false}
60+
content={
61+
<ChartTooltipContent
62+
labelFormatter={(_, payload) => {
63+
const time = payload?.[0]?.payload?.time;
64+
return time ? format(new Date(time), "PPpp") : "";
65+
}}
66+
formatter={(value) => [`${value}%`, "CPU Usage"]}
67+
/>
68+
}
69+
/>
70+
<Area
71+
type="monotone"
72+
dataKey="usage"
73+
stroke="var(--color-usage)"
74+
fill="url(#fillCpu)"
75+
strokeWidth={2}
76+
/>
77+
<ChartLegend content={<ChartLegendContent />} />
78+
</AreaChart>
79+
</ChartContainer>
5880
);
5981
};
60-
61-
interface CustomTooltipProps {
62-
active: boolean;
63-
payload?: {
64-
color?: string;
65-
dataKey?: string;
66-
value?: number;
67-
payload: {
68-
time: string;
69-
usage: number;
70-
};
71-
}[];
72-
}
73-
74-
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
75-
if (active && payload && payload.length && payload[0]) {
76-
return (
77-
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
78-
{payload[0].payload.time && (
79-
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
80-
)}
81-
<p>{`CPU Usage: ${payload[0].payload.usage}%`}</p>
82-
</div>
83-
);
84-
}
85-
86-
return null;
87-
};

0 commit comments

Comments
 (0)