Updated chart for mobile

This commit is contained in:
2025-12-28 03:51:13 +01:00
parent 471e731d2f
commit fd6742c7c5
4 changed files with 103 additions and 59 deletions
+1 -6
View File
@@ -2,12 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import testAuth from "../auth";
import { StatusCodes } from "http-status-codes";
import si from "systeminformation";
function average<T>(values: Array<T>, p: (v: T) => number) {
return values.length > 0
? values.reduce((sum, value) => sum + p(value), 0) / values.length
: 0;
}
import { average } from "@/lib/format";
type Usage = {
cpu: number;
+78 -40
View File
@@ -7,6 +7,11 @@ import { type ChartConfig } from "@/components/ui/chart";
import GradientAreaChart from "@/components/GradientAreaChart";
import { getMetrics } from "@/core/client/metrics";
import { useEffect, useState } from "react";
import { useIsMobile } from "@/hooks/use-mobile";
import RadialChart from "@/components/RadialChart";
import { Node, NodeLiveData } from "@/lib/types";
import { getLiveNodes } from "@/core/client/node";
import { average } from "@/lib/format";
const containerMetrics = [
{ name: "api-gateway-1", cpu: 45, memory: 62, network: "12.4 MB/s" },
@@ -42,6 +47,24 @@ export default function MonitoringPage() {
out: number;
}[]
>([]);
const isMobile = useIsMobile();
const [liveData, setLiveData] = useState<{
cpuUsage: number;
ramUsage: number;
}>();
useEffect(() => {
const fetchNodes = async () => {
const nodes = await getLiveNodes();
setLiveData({
cpuUsage: average(nodes, (n) => n.liveData.cpu.usage),
ramUsage: average(nodes, (n) => n.liveData.memory.usage),
});
};
fetchNodes();
const interval = setInterval(fetchNodes, 3000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
async function fetchMetrics() {
@@ -61,46 +84,61 @@ export default function MonitoringPage() {
subtitle="Resource utilization and metrics"
>
{/* Summary Stats */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Cluster CPU
</div>
<div className="stat-value">68%</div>
<Progress value={68} className="w-full" />
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Cluster Memory
</div>
<div className="stat-value">71%</div>
<Progress value={71} className="w-full" />
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Network In
</div>
<div className="stat-value">38 MB/s</div>
<div className="text-xs text-success mt-1">↑ 12% from avg</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Network Out
</div>
<div className="stat-value">28 MB/s</div>
<div className="text-xs text-muted-foreground mt-1">
↓ 5% from avg
</div>
</CardContent>
</Card>
</div>
{isMobile ? (
<div className="grid grid-cols-2 gap-4 mb-6">
<Card>
<CardContent className="px-4">
<RadialChart value={liveData?.cpuUsage || 0}>CPU</RadialChart>
</CardContent>
</Card>
<Card>
<CardContent className="px-4">
<RadialChart value={liveData?.ramUsage || 0}>RAM</RadialChart>
</CardContent>
</Card>
</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Cluster CPU
</div>
<div className="stat-value">68%</div>
<Progress value={68} className="w-full" />
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Cluster Memory
</div>
<div className="stat-value">71%</div>
<Progress value={71} className="w-full" />
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Network In
</div>
<div className="stat-value">38 MB/s</div>
<div className="text-xs text-success mt-1">↑ 12% from avg</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="text-xs text-muted-foreground uppercase tracking-wider mb-1">
Network Out
</div>
<div className="stat-value">28 MB/s</div>
<div className="text-xs text-muted-foreground mt-1">
↓ 5% from avg
</div>
</CardContent>
</Card>
</div>
)}
{/* CPU & Memory Charts */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6">
+18 -13
View File
@@ -2,7 +2,7 @@
import {
Label,
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
RadialBar,
RadialBarChart,
@@ -15,6 +15,8 @@ const chartConfig = {
},
} satisfies ChartConfig;
const INNER_RADIUS = 80;
export default function RadialChart({
value,
children,
@@ -23,22 +25,25 @@ export default function RadialChart({
children?: React.ReactNode;
}) {
const chartData = [{ value, fill: "var(--color-chart-1)" }];
const startAngle = 230;
const totalSweep = 280;
return (
<ChartContainer config={chartConfig} className="size-30">
<ChartContainer config={chartConfig} className="w-full aspect-square">
<RadialBarChart
data={chartData}
startAngle={-50}
endAngle={(value / 100) * 230}
innerRadius="65%"
outerRadius="100%"
startAngle={startAngle}
endAngle={startAngle - (value / 100) * totalSweep}
innerRadius={INNER_RADIUS}
outerRadius={INNER_RADIUS + 30}
>
<PolarGrid
gridType="circle"
radialLines={false}
stroke="none"
className=""
polarRadius={[86, 74]}
<PolarAngleAxis
type="number"
domain={[0, 100]}
tick={false}
tickLine={false}
axisLine={false}
ticks={[]}
/>
<RadialBar dataKey="value" background cornerRadius={10} />
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
@@ -57,7 +62,7 @@ export default function RadialChart({
y={viewBox.cy}
className="fill-foreground text-xl font-bold"
>
{chartData[0].value.toLocaleString()}
{chartData[0].value.toFixed(1)}%
</tspan>
<tspan
x={viewBox.cx}
+6
View File
@@ -9,3 +9,9 @@ export function formatBytes(bytes: number, decimals = 2) {
sizes[i]
}`;
}
export function average<T>(values: Array<T>, p: (v: T) => number) {
return values.length > 0
? values.reduce((sum, value) => sum + p(value), 0) / values.length
: 0;
}