Node status
This commit is contained in:
Generated
+27
@@ -26,6 +26,7 @@
|
|||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
|
"systeminformation": "^5.28.2",
|
||||||
"tailwind-merge": "^3.4.0"
|
"tailwind-merge": "^3.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -3982,6 +3983,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/systeminformation": {
|
||||||
|
"version": "5.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.28.2.tgz",
|
||||||
|
"integrity": "sha512-AWrPnmbIcfjLX7wiQMd7r6bl3PDaGoqvrfn8pCLJbk9CiB+vQXTk8RVxNs2vQRTezYlhb9skxEIyAPTm1If5bQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32",
|
||||||
|
"freebsd",
|
||||||
|
"openbsd",
|
||||||
|
"netbsd",
|
||||||
|
"sunos",
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"systeminformation": "lib/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "Buy me a coffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/systeminfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwind-merge": {
|
"node_modules/tailwind-merge": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
|
"systeminformation": "^5.28.2",
|
||||||
"tailwind-merge": "^3.4.0"
|
"tailwind-merge": "^3.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import testAuth from "../auth";
|
||||||
|
import { StatusCodes } from "http-status-codes";
|
||||||
|
import si from "systeminformation";
|
||||||
|
|
||||||
|
export async function GET(req: NextRequest): Promise<NextResponse> {
|
||||||
|
const auth = await testAuth(req);
|
||||||
|
|
||||||
|
if (auth) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: auth },
|
||||||
|
{ status: StatusCodes.UNAUTHORIZED }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [cpu, mem, load, disk, network] = await Promise.all([
|
||||||
|
si.cpu(),
|
||||||
|
si.mem(),
|
||||||
|
si.currentLoad(),
|
||||||
|
si.fsSize(),
|
||||||
|
si.networkStats(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
message: "ok",
|
||||||
|
liveData: {
|
||||||
|
cpu: {
|
||||||
|
manufacturer: cpu.manufacturer,
|
||||||
|
brand: cpu.brand,
|
||||||
|
cores: cpu.cores,
|
||||||
|
usage: load.currentLoad,
|
||||||
|
},
|
||||||
|
memory: {
|
||||||
|
total: mem.total,
|
||||||
|
used: mem.used,
|
||||||
|
free: mem.free,
|
||||||
|
usage: ((mem.total - mem.free) / mem.total) * 100,
|
||||||
|
},
|
||||||
|
disk: disk.map((d) => ({
|
||||||
|
fs: d.fs,
|
||||||
|
size: d.size,
|
||||||
|
used: d.used,
|
||||||
|
usage: d.use,
|
||||||
|
})),
|
||||||
|
network: network.map((n) => ({
|
||||||
|
iface: n.iface,
|
||||||
|
rx: n.rx_bytes,
|
||||||
|
tx: n.tx_bytes,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
+18
-10
@@ -87,13 +87,19 @@ const applications = [
|
|||||||
memory: 48,
|
memory: 48,
|
||||||
status: "pending" as const,
|
status: "pending" as const,
|
||||||
},
|
},
|
||||||
];
|
].slice(-5);
|
||||||
|
|
||||||
export default function OverviewPage() {
|
export default function OverviewPage() {
|
||||||
const [nodes, setNodes] = useState<NodeLiveData[]>([]);
|
const [nodes, setNodes] = useState<NodeLiveData[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getLiveNodes().then(setNodes);
|
const fetchNodes = async () => {
|
||||||
|
const nodes = await getLiveNodes();
|
||||||
|
setNodes(nodes);
|
||||||
|
};
|
||||||
|
fetchNodes();
|
||||||
|
const interval = setInterval(fetchNodes, 3000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -228,7 +234,7 @@ export default function OverviewPage() {
|
|||||||
>
|
>
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-3 gap-2">
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-3 gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<StatusIndicator status={node.liveData.status} />
|
<StatusIndicator status={"running"} />
|
||||||
<span className="font-mono text-sm">{node.name}</span>
|
<span className="font-mono text-sm">{node.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-muted-foreground font-mono">
|
<span className="text-xs text-muted-foreground font-mono">
|
||||||
@@ -238,25 +244,27 @@ export default function OverviewPage() {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between text-xs">
|
<div className="flex items-center justify-between text-xs">
|
||||||
<span className="text-muted-foreground">CPU</span>
|
<span className="text-muted-foreground">CPU</span>
|
||||||
<span className="font-mono">{node.liveData.cpu}%</span>
|
<span className="font-mono">
|
||||||
|
{node.liveData.cpu.usage.toFixed(0)}%
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Progress
|
<Progress
|
||||||
value={node.liveData.cpu}
|
value={node.liveData.cpu.usage}
|
||||||
className="[&>div]:bg-chart-1"
|
className="[&>div]:bg-chart-1"
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center justify-between text-xs">
|
<div className="flex items-center justify-between text-xs">
|
||||||
<span className="text-muted-foreground">Memory</span>
|
<span className="text-muted-foreground">Memory</span>
|
||||||
<span className="font-mono">{node.liveData.memory}%</span>
|
<span className="font-mono">
|
||||||
|
{node.liveData.memory.usage.toFixed(0)}%
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Progress
|
<Progress
|
||||||
value={node.liveData.memory}
|
value={node.liveData.memory.usage}
|
||||||
className="w-full [&>div]:bg-chart-3"
|
className="w-full [&>div]:bg-chart-3"
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center justify-between text-xs pt-2 border-t border-border mt-2">
|
<div className="flex items-center justify-between text-xs pt-2 border-t border-border mt-2">
|
||||||
<span className="text-muted-foreground">Containers</span>
|
<span className="text-muted-foreground">Containers</span>
|
||||||
<span className="font-mono">
|
<span className="font-mono">{6}</span>
|
||||||
{node.liveData.containers}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+23
-5
@@ -11,10 +11,28 @@ export interface NodeLiveData {
|
|||||||
ip: string;
|
ip: string;
|
||||||
key: string;
|
key: string;
|
||||||
liveData: {
|
liveData: {
|
||||||
status: "running" | "pending" | "error";
|
cpu: {
|
||||||
cpu: number;
|
manufacturer: string;
|
||||||
memory: number;
|
brand: string;
|
||||||
disk: number;
|
cores: number;
|
||||||
containers: number;
|
usage: number;
|
||||||
|
};
|
||||||
|
memory: {
|
||||||
|
total: number;
|
||||||
|
used: number;
|
||||||
|
free: number;
|
||||||
|
usage: number;
|
||||||
|
};
|
||||||
|
disk: {
|
||||||
|
fs: string;
|
||||||
|
size: number;
|
||||||
|
used: number;
|
||||||
|
usage: number;
|
||||||
|
}[];
|
||||||
|
network: {
|
||||||
|
iface: string;
|
||||||
|
rx: number;
|
||||||
|
tx: number;
|
||||||
|
}[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user