From b83219bbf2203324d788aad0528a6b13f014fa04 Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Sat, 19 Oct 2024 02:09:04 +0800 Subject: [PATCH] feat: detail info --- .../ServerDetailChartClient.tsx | 423 ++++++++++++++---- .../ClientComponents/ServerDetailClient.tsx | 179 +++----- app/[locale]/(main)/detail/[id]/page.tsx | 2 + bun.lockb | Bin 445857 -> 445857 bytes .../ui/animated-circular-progress-bar.tsx | 7 +- lib/utils.ts | 1 + 6 files changed, 399 insertions(+), 213 deletions(-) diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx index 74fdcf3e8..5f308580c 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx @@ -4,10 +4,10 @@ import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progr import { Card, CardContent } from "@/components/ui/card"; import useSWR from "swr"; import { NezhaAPISafe } from "../../types/nezha-api"; -import { formatRelativeTime, formatTime, nezhaFetcher } from "@/lib/utils"; +import { formatNezhaInfo, formatRelativeTime, formatTime, nezhaFetcher } from "@/lib/utils"; import getEnv from "@/lib/env-entry"; import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; -import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import { Area, AreaChart, CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"; import { useEffect, useState } from "react"; @@ -16,6 +16,18 @@ type cpuChartData = { cpu: number; } +type memChartData = { + timeStamp: string; + mem: number; + swap: number; +} + +type networkChartData = { + timeStamp: string; + upload: number; + download: number; +} + export default function ServerDetailChartClient({ server_id, }: { @@ -29,22 +41,6 @@ export default function ServerDetailChartClient({ }, ); - const [chartData, setChartData] = useState([] as cpuChartData[]); - - useEffect(() => { - if (data) { - const timestamp = Date.now().toString(); - const newData = [ - ...chartData, - { timeStamp: timestamp, cpu: data.status.CPU }, - ]; - if (newData.length > 30) { - newData.shift(); - } - setChartData(newData); - } - }, [data]); - if (error) { return ( <> @@ -60,6 +56,33 @@ export default function ServerDetailChartClient({ } if (!data) return null; + return ( +
+ + + +
+ ) +} + +function CpuChart({ data }: { data: NezhaAPISafe }) { + const [cpuChartData, setCpuChartData] = useState([] as cpuChartData[]); + + const { cpu } = formatNezhaInfo(data); + + useEffect(() => { + if (data) { + const timestamp = Date.now().toString(); + const newData = [ + ...cpuChartData, + { timeStamp: timestamp, cpu: cpu }, + ]; + if (newData.length > 30) { + newData.shift(); + } + setCpuChartData(newData); + } + }, [data]); const chartConfig = { cpu: { @@ -68,73 +91,303 @@ export default function ServerDetailChartClient({ } satisfies ChartConfig return ( -
- - -
-
-

- CPU + + +

+
+

+ CPU +

+
+

+ {cpu.toFixed(0)}%

-
-

- {data?.status.CPU.toFixed(0)}% -

- -
-
- - - - - formatRelativeTime(value)} - /> - `${value}%`} - /> - {/* { - return formatTime(Number(payload[0].payload.timeStamp)); - }} />} - /> */} - - - -
- - -
+ +
+ + + + + formatRelativeTime(value)} + /> + `${value}%`} + /> + + + + + + + ) +} + +function MemChart({ data }: { data: NezhaAPISafe }) { + const [memChartData, setMemChartData] = useState([] as memChartData[]); + + const { mem, swap } = formatNezhaInfo(data); + + useEffect(() => { + if (data) { + const timestamp = Date.now().toString(); + const newData = [ + ...memChartData, + { timeStamp: timestamp, mem: mem, swap: swap }, + ]; + if (newData.length > 30) { + newData.shift(); + } + setMemChartData(newData); + } + }, [data]); + + const chartConfig = { + mem: { + label: "Mem", + }, + swap: { + label: "Swap", + }, + } satisfies ChartConfig + + return ( + + +
+
+
+
+

Mem

+
+ +

+ {mem.toFixed(0)}% +

+
+
+
+

Swap

+
+ +

+ {swap.toFixed(0)}% +

+
+
+ +
+
+ + + + formatRelativeTime(value)} + /> + `${value}%`} + /> + + + + +
+
+
+ ) + +} + + +function NetworkChart({ data }: { data: NezhaAPISafe }) { + const [networkChartData, setNetworkChartData] = useState([] as networkChartData[]); + + const { up, down } = formatNezhaInfo(data); + + useEffect(() => { + if (data) { + const timestamp = Date.now().toString(); + const newData = [ + ...networkChartData, + { timeStamp: timestamp, upload: up, download: down }, + ]; + if (newData.length > 30) { + newData.shift(); + } + setNetworkChartData(newData); + } + }, [data]); + + let maxDownload = Math.max(...networkChartData.map((item) => item.download)); + maxDownload = Math.ceil(maxDownload); + if (maxDownload < 1) { + maxDownload = 1; + } + + const chartConfig = { + upload: { + label: "Upload", + }, + download: { + label: "Download", + }, + } satisfies ChartConfig + + return ( + + +
+
+
+
+

Upload

+
+ +

+ {up.toFixed(2)} M/s +

+
+
+
+

Download

+
+ +

+ {down.toFixed(2)} M/s +

+
+
+ +
+
+ + + + formatRelativeTime(value)} + /> + `${value.toFixed(0)}M/s`} + /> + + + + +
+
+
) } \ No newline at end of file diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx index 2a076b818..02f1d3769 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx @@ -6,7 +6,7 @@ import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progr import { Badge } from "@/components/ui/badge"; import { Card, CardContent } from "@/components/ui/card"; import getEnv from "@/lib/env-entry"; -import { cn, nezhaFetcher } from "@/lib/utils"; +import { cn, formatBytes, nezhaFetcher } from "@/lib/utils"; import { useLocale } from "next-intl"; import { useRouter } from "next/navigation"; import useSWR from "swr"; @@ -51,10 +51,10 @@ export default function ServerDetailClient({ {data?.name}
- + -
-

Status

+
+

Status

- + -
-

Uptime

- +
+

Uptime

+
{" "} {(data?.status.Uptime / 86400).toFixed(0)} Days{" "} - -
- - - - -
-

Arch

- - {" "} - {data?.host.Arch || "Unknown"}{" "} - +
- + -
-

Version

- - {" "} +
+

Version

+
{data?.host.Version || "Unknown"}{" "} - -
- - -
-
- - -
-

System

- {data?.host.Platform ? ( -
- {" "} - {data?.host.Platform || "Unknown"} -{" "} - {data?.host.PlatformVersion}{" "} -
- ) : ( -
Unknown
- )} +
- + -
-

CPU

- {data?.host.CPU ? ( -
- {" "} - {data?.host.CPU || "Unknown"} -
- ) : ( -
Unknown
- )} +
+

Arch

+
+ {data?.host.Arch || "Unknown"}{" "} +
-
- {/*
- + -
-

CPU

-

- {data?.status.CPU.toFixed(0)}% -

- +
+

Mem

+
+ {formatBytes(data?.host.MemTotal)} +
- + -
-

Mem

-

- {((data?.status.MemUsed / data?.host.MemTotal) * 100).toFixed( - 0, - )} - % -

- +
+

Disk

+
+ {formatBytes(data?.host.DiskTotal)} +
- +
+
+ -
-

Swap

-

- {data?.status.SwapUsed - ? ( - (data?.status.SwapUsed / data?.host.SwapTotal) * - 100 - ).toFixed(0) - : 0} - % -

- +
+

System

+ {data?.host.Platform ? ( +
+ {" "} + {data?.host.Platform || "Unknown"} -{" "} + {data?.host.PlatformVersion}{" "} +
) :
Unknown
}
- + -
-

Disk

-

- {((data?.status.DiskUsed / data?.host.DiskTotal) * 100).toFixed( - 0, - )} - % -

- +
+

CPU

+ {data?.host.CPU ? ( +
+ {" "} + {data?.host.CPU} +
) :
Unknown
}
-
*/} +
); } diff --git a/app/[locale]/(main)/detail/[id]/page.tsx b/app/[locale]/(main)/detail/[id]/page.tsx index f0254089b..21e17b60d 100644 --- a/app/[locale]/(main)/detail/[id]/page.tsx +++ b/app/[locale]/(main)/detail/[id]/page.tsx @@ -1,9 +1,11 @@ import ServerDetailClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailClient"; import ServerDetailChartClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailChartClient"; +import { Separator } from "@/components/ui/separator"; export default function Page({ params }: { params: { id: string } }) { return
+
; diff --git a/bun.lockb b/bun.lockb index 0c25b049f2ee017ee864de29a45eccb04b45d695..35a64c1e5a989e9aebe1b9765fc37b439e990674 100755 GIT binary patch delta 43 vcmZ2DTYBMa>4p}@7N!>FEi9e^Y)lLwFx_w!i)edF01FVaZchndv#kXH94`z{ delta 39 tcmZ2DTYBMa>4p}@7N!>FEi9e^?2K`SdWL!i?EwKSK+L*5Ab>5f76AQ$3+Mm< diff --git a/components/ui/animated-circular-progress-bar.tsx b/components/ui/animated-circular-progress-bar.tsx index bdb7b4a41..dd96fe8d3 100644 --- a/components/ui/animated-circular-progress-bar.tsx +++ b/components/ui/animated-circular-progress-bar.tsx @@ -5,12 +5,14 @@ interface Props { value: number; min: number; className?: string; + primaryColor?: string; } export default function AnimatedCircularProgressBar({ max = 100, min = 0, value = 0, + primaryColor, className, }: Props) { const circumference = 2 * Math.PI * 45; @@ -74,9 +76,12 @@ export default function AnimatedCircularProgressBar({ strokeDashoffset="0" strokeLinecap="round" strokeLinejoin="round" - className="opacity-100 stroke-current" + className={cn("opacity-100 stroke-current", { + "stroke-[var(--stroke-primary-color)]": primaryColor, + })} style={ { + "--stroke-primary-color": primaryColor, "--stroke-percent": currentPercent, strokeDasharray: "calc(var(--stroke-percent) * var(--percent-to-px)) var(--circumference)", diff --git a/lib/utils.ts b/lib/utils.ts index a65328dd4..4987b0f12 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -14,6 +14,7 @@ export function formatNezhaInfo(serverInfo: NezhaAPISafe) { down: serverInfo.status.NetInSpeed / 1024 / 1024, online: serverInfo.online_status, mem: (serverInfo.status.MemUsed / serverInfo.host.MemTotal) * 100, + swap: (serverInfo.status.SwapUsed / serverInfo.host.SwapTotal) * 100, stg: (serverInfo.status.DiskUsed / serverInfo.host.DiskTotal) * 100, country_code: serverInfo.host.CountryCode, };