feat: add detail page

This commit is contained in:
hamster1963 2024-10-17 23:45:18 +08:00
parent 78da53fbfa
commit fe20952e7b
4 changed files with 76 additions and 57 deletions

View File

@ -28,9 +28,9 @@ import { useLocale } from "next-intl";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import * as React from "react"; import * as React from "react";
import { useCallback, useMemo } from "react";
import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"; import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts";
import useSWR from "swr"; import useSWR from "swr";
import { useMemo, useCallback } from 'react';
interface ResultItem { interface ResultItem {
created_at: number; created_at: number;
@ -64,7 +64,6 @@ export function NetworkChartClient({ server_id }: { server_id: number }) {
if (!data) return <NetworkChartLoading />; if (!data) return <NetworkChartLoading />;
const transformedData = transformData(data); const transformedData = transformData(data);
const formattedData = formatData(data); const formattedData = formatData(data);
@ -109,32 +108,40 @@ export const NetworkChart = React.memo(function NetworkChart({
const [activeChart, setActiveChart] = React.useState(defaultChart); const [activeChart, setActiveChart] = React.useState(defaultChart);
const handleButtonClick = useCallback((chart: string) => { const handleButtonClick = useCallback(
setActiveChart(prev => prev === chart ? defaultChart : chart); (chart: string) => {
}, [defaultChart]); setActiveChart((prev) => (prev === chart ? defaultChart : chart));
},
[defaultChart],
);
const getColorByIndex = useCallback((chart: string) => { const getColorByIndex = useCallback(
const index = chartDataKey.indexOf(chart); (chart: string) => {
return `hsl(var(--chart-${(index % 10) + 1}))`; const index = chartDataKey.indexOf(chart);
}, [chartDataKey]); return `hsl(var(--chart-${(index % 10) + 1}))`;
},
[chartDataKey],
);
const chartButtons = useMemo(() => ( const chartButtons = useMemo(
chartDataKey.map((key) => ( () =>
<button chartDataKey.map((key) => (
key={key} <button
data-active={activeChart === key} key={key}
className={`relative z-30 flex flex-1 flex-col justify-center gap-1 border-b px-6 py-4 text-left data-[active=true]:bg-muted/50 sm:border-l sm:border-t-0 sm:px-6`} data-active={activeChart === key}
onClick={() => handleButtonClick(key)} className={`relative z-30 flex flex-1 flex-col justify-center gap-1 border-b px-6 py-4 text-left data-[active=true]:bg-muted/50 sm:border-l sm:border-t-0 sm:px-6`}
> onClick={() => handleButtonClick(key)}
<span className="whitespace-nowrap text-xs text-muted-foreground"> >
{key} <span className="whitespace-nowrap text-xs text-muted-foreground">
</span> {key}
<span className="text-md font-bold leading-none sm:text-lg"> </span>
{chartData[key][chartData[key].length - 1].avg_delay.toFixed(2)}ms <span className="text-md font-bold leading-none sm:text-lg">
</span> {chartData[key][chartData[key].length - 1].avg_delay.toFixed(2)}ms
</button> </span>
)) </button>
), [chartDataKey, activeChart, chartData, handleButtonClick]); )),
[chartDataKey, activeChart, chartData, handleButtonClick],
);
const chartLines = useMemo(() => { const chartLines = useMemo(() => {
if (activeChart !== defaultChart) { if (activeChart !== defaultChart) {
@ -180,9 +187,7 @@ export const NetworkChart = React.memo(function NetworkChart({
{chartDataKey.length} {t("ServerMonitorCount")} {chartDataKey.length} {t("ServerMonitorCount")}
</CardDescription> </CardDescription>
</div> </div>
<div className="flex flex-wrap"> <div className="flex flex-wrap">{chartButtons}</div>
{chartButtons}
</div>
</CardHeader> </CardHeader>
<CardContent className="px-2 sm:p-6"> <CardContent className="px-2 sm:p-6">
<ChartContainer <ChartContainer
@ -191,7 +196,11 @@ export const NetworkChart = React.memo(function NetworkChart({
> >
<LineChart <LineChart
accessibilityLayer accessibilityLayer
data={activeChart === defaultChart ? formattedData : chartData[activeChart]} data={
activeChart === defaultChart
? formattedData
: chartData[activeChart]
}
margin={{ left: 12, right: 12 }} margin={{ left: 12, right: 12 }}
> >
<CartesianGrid vertical={false} /> <CartesianGrid vertical={false} />
@ -235,7 +244,6 @@ export const NetworkChart = React.memo(function NetworkChart({
); );
}); });
const transformData = (data: NezhaAPIMonitor[]) => { const transformData = (data: NezhaAPIMonitor[]) => {
const monitorData: ServerMonitorChart = {}; const monitorData: ServerMonitorChart = {};
@ -255,7 +263,7 @@ const transformData = (data: NezhaAPIMonitor[]) => {
}); });
return monitorData; return monitorData;
} };
const formatData = (rawData: NezhaAPIMonitor[]) => { const formatData = (rawData: NezhaAPIMonitor[]) => {
const result: { [time: number]: ResultItem } = {}; const result: { [time: number]: ResultItem } = {};
@ -282,4 +290,4 @@ const formatData = (rawData: NezhaAPIMonitor[]) => {
}); });
return Object.values(result).sort((a, b) => a.created_at - b.created_at); return Object.values(result).sort((a, b) => a.created_at - b.created_at);
}; };

View File

@ -0,0 +1,7 @@
export default function Page({ params }: { params: { id: string } }) {
return (
<div className="mx-auto grid w-full max-w-5xl gap-4 md:gap-6">
{params.id}
</div>
);
}

BIN
bun.lockb

Binary file not shown.

View File

@ -36,35 +36,39 @@ export default function ServerCard({
"flex flex-col items-center justify-start gap-3 p-3 md:px-5 lg:flex-row" "flex flex-col items-center justify-start gap-3 p-3 md:px-5 lg:flex-row"
} }
> >
<Popover> {/* <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<section
className="grid items-center gap-2 lg:w-28"
style={{ gridTemplateColumns: "auto 1fr auto" }}
>
<div
className={cn(
"flex items-center justify-center",
showFlag ? "min-w-[17px]" : "min-w-0",
)}
>
{showFlag ? <ServerFlag country_code={country_code} /> : null}
</div>
<p
className={cn(
"break-all font-bold tracking-tight",
showFlag ? "text-xs" : "text-sm",
)}
>
{name}
</p>
<span className="h-2 w-2 shrink-0 rounded-full bg-green-500 self-center"></span>
</section>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent side="top"> <PopoverContent side="top">
<ServerCardPopover status={props.status} host={props.host} /> <ServerCardPopover status={props.status} host={props.host} />
</PopoverContent> </PopoverContent>
</Popover> </Popover> */}
<section
className="grid items-center gap-2 lg:w-28 cursor-pointer"
style={{ gridTemplateColumns: "auto 1fr auto" }}
onClick={() => {
router.push(`/${locale}/detail/${id}`);
}}
>
<div
className={cn(
"flex items-center justify-center",
showFlag ? "min-w-[17px]" : "min-w-0",
)}
>
{showFlag ? <ServerFlag country_code={country_code} /> : null}
</div>
<p
className={cn(
"break-all font-bold tracking-tight",
showFlag ? "text-xs" : "text-sm",
)}
>
{name}
</p>
<span className="h-2 w-2 shrink-0 rounded-full bg-green-500 self-center"></span>
</section>
<div <div
onClick={() => { onClick={() => {
router.push(`/${locale}/${id}`); router.push(`/${locale}/${id}`);