From 72472f7cc1a5e2dd4497f87467e7de128a8845ac Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Thu, 26 Dec 2024 13:48:19 +0800
Subject: [PATCH] feat: detail chart history point
---
.../detail/ServerDetailChartClient.tsx | 217 +++++++++++++++---
app/lib/server-data-context.tsx | 4 +-
2 files changed, 188 insertions(+), 33 deletions(-)
diff --git a/app/(main)/ClientComponents/detail/ServerDetailChartClient.tsx b/app/(main)/ClientComponents/detail/ServerDetailChartClient.tsx
index dc2f7e0..f0ad7d1 100644
--- a/app/(main)/ClientComponents/detail/ServerDetailChartClient.tsx
+++ b/app/(main)/ClientComponents/detail/ServerDetailChartClient.tsx
@@ -1,6 +1,6 @@
"use client"
-import { useServerData } from "@/app/lib/server-data-context"
+import { ServerDataWithTimestamp, useServerData } from "@/app/lib/server-data-context"
import { NezhaAPISafe } from "@/app/types/nezha-api"
import { ServerDetailChartLoading } from "@/components/loading/ServerDetailLoading"
import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progress-bar"
@@ -8,7 +8,7 @@ import { Card, CardContent } from "@/components/ui/card"
import { ChartConfig, ChartContainer } from "@/components/ui/chart"
import { formatBytes, formatNezhaInfo, formatRelativeTime } from "@/lib/utils"
import { useTranslations } from "next-intl"
-import { useEffect, useState } from "react"
+import { useEffect, useRef, useState } from "react"
import { Area, AreaChart, CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"
type cpuChartData = {
@@ -52,7 +52,7 @@ export default function ServerDetailChartClient({
}) {
const t = useTranslations("ServerDetailChartClient")
- const { data: serverList, error } = useServerData()
+ const { data: serverList, error, history } = useServerData()
const data = serverList?.result?.find((item) => item.id === server_id)
@@ -70,23 +70,46 @@ export default function ServerDetailChartClient({
return (
)
}
-function CpuChart({ data }: { data: NezhaAPISafe }) {
+function CpuChart({ history, data }: { history: ServerDataWithTimestamp[]; data: NezhaAPISafe }) {
const [cpuChartData, setCpuChartData] = useState([] as cpuChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { cpu } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ cpu: cpu,
+ }
+ })
+ .filter((item): item is cpuChartData => item !== null)
+ .reverse() // 保持时间顺序
+
+ setCpuChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { cpu } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as cpuChartData[]
if (cpuChartData.length === 0) {
@@ -102,7 +125,7 @@ function CpuChart({ data }: { data: NezhaAPISafe }) {
}
setCpuChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
const chartConfig = {
cpu: {
@@ -171,15 +194,43 @@ function CpuChart({ data }: { data: NezhaAPISafe }) {
)
}
-function ProcessChart({ data }: { data: NezhaAPISafe }) {
+function ProcessChart({
+ data,
+ history,
+}: {
+ data: NezhaAPISafe
+ history: ServerDataWithTimestamp[]
+}) {
const t = useTranslations("ServerDetailChartClient")
-
const [processChartData, setProcessChartData] = useState([] as processChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { process } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ process: process,
+ }
+ })
+ .filter((item): item is processChartData => item !== null)
+ .reverse()
+
+ setProcessChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { process } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as processChartData[]
if (processChartData.length === 0) {
@@ -195,7 +246,7 @@ function ProcessChart({ data }: { data: NezhaAPISafe }) {
}
setProcessChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
const chartConfig = {
process: {
@@ -250,15 +301,38 @@ function ProcessChart({ data }: { data: NezhaAPISafe }) {
)
}
-function MemChart({ data }: { data: NezhaAPISafe }) {
+function MemChart({ data, history }: { data: NezhaAPISafe; history: ServerDataWithTimestamp[] }) {
const t = useTranslations("ServerDetailChartClient")
-
const [memChartData, setMemChartData] = useState([] as memChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { mem, swap } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ mem: mem,
+ swap: swap,
+ }
+ })
+ .filter((item): item is memChartData => item !== null)
+ .reverse()
+
+ setMemChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { mem, swap } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as memChartData[]
if (memChartData.length === 0) {
@@ -274,7 +348,7 @@ function MemChart({ data }: { data: NezhaAPISafe }) {
}
setMemChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
const chartConfig = {
mem: {
@@ -379,15 +453,37 @@ function MemChart({ data }: { data: NezhaAPISafe }) {
)
}
-function DiskChart({ data }: { data: NezhaAPISafe }) {
+function DiskChart({ data, history }: { data: NezhaAPISafe; history: ServerDataWithTimestamp[] }) {
const t = useTranslations("ServerDetailChartClient")
-
const [diskChartData, setDiskChartData] = useState([] as diskChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { disk } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ disk: disk,
+ }
+ })
+ .filter((item): item is diskChartData => item !== null)
+ .reverse()
+
+ setDiskChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { disk } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as diskChartData[]
if (diskChartData.length === 0) {
@@ -403,7 +499,7 @@ function DiskChart({ data }: { data: NezhaAPISafe }) {
}
setDiskChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
const chartConfig = {
disk: {
@@ -477,15 +573,44 @@ function DiskChart({ data }: { data: NezhaAPISafe }) {
)
}
-function NetworkChart({ data }: { data: NezhaAPISafe }) {
+function NetworkChart({
+ data,
+ history,
+}: {
+ data: NezhaAPISafe
+ history: ServerDataWithTimestamp[]
+}) {
const t = useTranslations("ServerDetailChartClient")
-
const [networkChartData, setNetworkChartData] = useState([] as networkChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { up, down } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ upload: up,
+ download: down,
+ }
+ })
+ .filter((item): item is networkChartData => item !== null)
+ .reverse()
+
+ setNetworkChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { up, down } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as networkChartData[]
if (networkChartData.length === 0) {
@@ -501,7 +626,7 @@ function NetworkChart({ data }: { data: NezhaAPISafe }) {
}
setNetworkChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
let maxDownload = Math.max(...networkChartData.map((item) => item.download))
maxDownload = Math.ceil(maxDownload)
@@ -595,13 +720,43 @@ function NetworkChart({ data }: { data: NezhaAPISafe }) {
)
}
-function ConnectChart({ data }: { data: NezhaAPISafe }) {
+function ConnectChart({
+ data,
+ history,
+}: {
+ data: NezhaAPISafe
+ history: ServerDataWithTimestamp[]
+}) {
const [connectChartData, setConnectChartData] = useState([] as connectChartData[])
+ const hasInitialized = useRef(false)
+ const [historyLoaded, setHistoryLoaded] = useState(false)
+
+ useEffect(() => {
+ if (!hasInitialized.current && history.length > 0) {
+ const historyData = history
+ .map((msg) => {
+ const server = msg.data?.result?.find((item) => item.id === data.id)
+ if (!server) return null
+ const { tcp, udp } = formatNezhaInfo(server)
+ return {
+ timeStamp: msg.timestamp.toString(),
+ tcp: tcp,
+ udp: udp,
+ }
+ })
+ .filter((item): item is connectChartData => item !== null)
+ .reverse()
+
+ setConnectChartData(historyData)
+ hasInitialized.current = true
+ setHistoryLoaded(true)
+ }
+ }, [])
const { tcp, udp } = formatNezhaInfo(data)
useEffect(() => {
- if (data) {
+ if (data && historyLoaded) {
const timestamp = Date.now().toString()
let newData = [] as connectChartData[]
if (connectChartData.length === 0) {
@@ -617,7 +772,7 @@ function ConnectChart({ data }: { data: NezhaAPISafe }) {
}
setConnectChartData(newData)
}
- }, [data])
+ }, [data, historyLoaded])
const chartConfig = {
tcp: {
diff --git a/app/lib/server-data-context.tsx b/app/lib/server-data-context.tsx
index 98a8377..d72feab 100644
--- a/app/lib/server-data-context.tsx
+++ b/app/lib/server-data-context.tsx
@@ -6,7 +6,7 @@ import { nezhaFetcher } from "@/lib/utils"
import { ReactNode, createContext, useContext, useEffect, useState } from "react"
import useSWR from "swr"
-interface ServerDataWithTimestamp {
+export interface ServerDataWithTimestamp {
timestamp: number
data: ServerApi
}
@@ -27,7 +27,7 @@ export function ServerDataProvider({ children }: { children: ReactNode }) {
const { data, error, isLoading } = useSWR("/api/server", nezhaFetcher, {
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000,
- dedupingInterval: 500,
+ dedupingInterval: 1000,
})
useEffect(() => {