"use client"; import NetworkChartLoading from "@/app/[locale]/(main)/ClientComponents/NetworkChartLoading"; import { NezhaAPIMonitor, ServerMonitorChart, } from "@/app/[locale]/types/nezha-api"; import { BackIcon } from "@/components/Icon"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; import getEnv from "@/lib/env-entry"; import { formatTime, nezhaFetcher } from "@/lib/utils"; import { formatRelativeTime } from "@/lib/utils"; import { useLocale } from "next-intl"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import * as React from "react"; import { useCallback, useMemo } from "react"; import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"; import useSWR from "swr"; interface ResultItem { created_at: number; [key: string]: number | null; } export function NetworkChartClient({ server_id, show, }: { server_id: number; show: boolean; }) { const t = useTranslations("NetworkChartClient"); const { data, error } = useSWR( `/api/monitor?server_id=${server_id}`, nezhaFetcher, { refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 15000, isPaused: () => !show, }, ); if (error) { return ( <>

{error.message}

{t("chart_fetch_error_message")}

); } if (!data) return ; const transformedData = transformData(data); const formattedData = formatData(data); const initChartConfig = { avg_delay: { label: t("avg_delay"), }, } satisfies ChartConfig; const chartDataKey = Object.keys(transformedData); return ( ); } export const NetworkChart = React.memo(function NetworkChart({ chartDataKey, chartConfig, chartData, serverName, formattedData, }: { chartDataKey: string[]; chartConfig: ChartConfig; chartData: ServerMonitorChart; serverName: string; formattedData: ResultItem[]; }) { const t = useTranslations("NetworkChart"); const router = useRouter(); const locale = useLocale(); const defaultChart = "All"; const [activeChart, setActiveChart] = React.useState(defaultChart); const handleButtonClick = useCallback( (chart: string) => { setActiveChart((prev) => (prev === chart ? defaultChart : chart)); }, [defaultChart], ); const getColorByIndex = useCallback( (chart: string) => { const index = chartDataKey.indexOf(chart); return `hsl(var(--chart-${(index % 10) + 1}))`; }, [chartDataKey], ); const chartButtons = useMemo( () => chartDataKey.map((key) => ( )), [chartDataKey, activeChart, chartData, handleButtonClick], ); const chartLines = useMemo(() => { if (activeChart !== defaultChart) { return ( ); } return chartDataKey.map((key) => ( )); }, [activeChart, defaultChart, chartDataKey, getColorByIndex]); return (
{serverName} {chartDataKey.length} {t("ServerMonitorCount")}
{chartButtons}
formatRelativeTime(value)} /> `${value}ms`} /> { return formatTime(payload[0].payload.created_at); }} /> } /> {activeChart === defaultChart && ( } /> )} {chartLines}
); }); const transformData = (data: NezhaAPIMonitor[]) => { const monitorData: ServerMonitorChart = {}; data.forEach((item) => { const monitorName = item.monitor_name; if (!monitorData[monitorName]) { monitorData[monitorName] = []; } for (let i = 0; i < item.created_at.length; i++) { monitorData[monitorName].push({ created_at: item.created_at[i], avg_delay: item.avg_delay[i], }); } }); return monitorData; }; const formatData = (rawData: NezhaAPIMonitor[]) => { const result: { [time: number]: ResultItem } = {}; const allTimes = new Set(); rawData.forEach((item) => { item.created_at.forEach((time) => allTimes.add(time)); }); const allTimeArray = Array.from(allTimes).sort((a, b) => a - b); rawData.forEach((item) => { const { monitor_name, created_at, avg_delay } = item; allTimeArray.forEach((time) => { if (!result[time]) { result[time] = { created_at: time }; } const timeIndex = created_at.indexOf(time); result[time][monitor_name] = timeIndex !== -1 ? avg_delay[timeIndex] : null; }); }); return Object.values(result).sort((a, b) => a.created_at - b.created_at); };