mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
feat: merge details and network pages
This commit is contained in:
parent
a8358e04e4
commit
dff839e0da
@ -37,7 +37,13 @@ interface ResultItem {
|
|||||||
[key: string]: number | null;
|
[key: string]: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NetworkChartClient({ server_id }: { server_id: number }) {
|
export function NetworkChartClient({
|
||||||
|
server_id,
|
||||||
|
show,
|
||||||
|
}: {
|
||||||
|
server_id: number;
|
||||||
|
show: boolean;
|
||||||
|
}) {
|
||||||
const t = useTranslations("NetworkChartClient");
|
const t = useTranslations("NetworkChartClient");
|
||||||
const { data, error } = useSWR<NezhaAPIMonitor[]>(
|
const { data, error } = useSWR<NezhaAPIMonitor[]>(
|
||||||
`/api/monitor?server_id=${server_id}`,
|
`/api/monitor?server_id=${server_id}`,
|
||||||
@ -45,6 +51,7 @@ export function NetworkChartClient({ server_id }: { server_id: number }) {
|
|||||||
{
|
{
|
||||||
refreshInterval:
|
refreshInterval:
|
||||||
Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 15000,
|
Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 15000,
|
||||||
|
isPaused: () => !show,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -55,8 +55,10 @@ type connectChartData = {
|
|||||||
|
|
||||||
export default function ServerDetailChartClient({
|
export default function ServerDetailChartClient({
|
||||||
server_id,
|
server_id,
|
||||||
|
show,
|
||||||
}: {
|
}: {
|
||||||
server_id: number;
|
server_id: number;
|
||||||
|
show: boolean;
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations("ServerDetailChartClient");
|
const t = useTranslations("ServerDetailChartClient");
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ export default function ServerDetailChartClient({
|
|||||||
nezhaFetcher,
|
nezhaFetcher,
|
||||||
{
|
{
|
||||||
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 5000,
|
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 5000,
|
||||||
|
isPaused: () => !show,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
38
app/[locale]/(main)/[id]/page.tsx
Normal file
38
app/[locale]/(main)/[id]/page.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { NetworkChartClient } from "@/app/[locale]/(main)/ClientComponents/NetworkChart";
|
||||||
|
import ServerDetailChartClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailChartClient";
|
||||||
|
import ServerDetailClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailClient";
|
||||||
|
import TabSwitch from "@/components/TabSwitch";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function Page({ params }: { params: { id: string } }) {
|
||||||
|
const t = useTranslations("TabSwitch");
|
||||||
|
|
||||||
|
const tabs = [t("Detail"), t("Network")];
|
||||||
|
const [currentTab, setCurrentTab] = useState(tabs[0]);
|
||||||
|
return (
|
||||||
|
<div className="mx-auto grid w-full max-w-5xl gap-2">
|
||||||
|
<ServerDetailClient server_id={Number(params.id)} />
|
||||||
|
<section className="flex items-center my-2 w-full">
|
||||||
|
<Separator className="flex-1" />
|
||||||
|
<div className="flex justify-center w-full max-w-[200px]">
|
||||||
|
<TabSwitch
|
||||||
|
tabs={tabs}
|
||||||
|
currentTab={currentTab}
|
||||||
|
setCurrentTab={setCurrentTab}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Separator className="flex-1" />
|
||||||
|
</section>
|
||||||
|
{currentTab === tabs[0] && (
|
||||||
|
<ServerDetailChartClient server_id={Number(params.id)} show={true} />
|
||||||
|
)}
|
||||||
|
{currentTab === tabs[1] && (
|
||||||
|
<NetworkChartClient server_id={Number(params.id)} show={true} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import ServerDetailChartClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailChartClient";
|
|
||||||
import ServerDetailClient from "@/app/[locale]/(main)/ClientComponents/ServerDetailClient";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
|
||||||
return (
|
|
||||||
<div className="mx-auto grid w-full max-w-5xl gap-2">
|
|
||||||
<ServerDetailClient server_id={Number(params.id)} />
|
|
||||||
<Separator className="mt-1 mb-2" />
|
|
||||||
<ServerDetailChartClient server_id={Number(params.id)} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
import { NetworkChartClient } from "@/app/[locale]/(main)/ClientComponents/NetworkChart";
|
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
|
||||||
return (
|
|
||||||
<div className="mx-auto grid w-full max-w-5xl gap-4 md:gap-6">
|
|
||||||
<NetworkChartClient server_id={Number(params.id)} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -33,15 +33,15 @@ export default function ServerCard({
|
|||||||
return online ? (
|
return online ? (
|
||||||
<Card
|
<Card
|
||||||
className={
|
className={
|
||||||
"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 cursor-pointer"
|
||||||
}
|
}
|
||||||
|
onClick={() => {
|
||||||
|
router.push(`/${locale}/${id}`);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
className="grid items-center gap-2 lg:w-28 cursor-pointer"
|
className="grid items-center gap-2 lg:w-28 "
|
||||||
style={{ gridTemplateColumns: "auto auto 1fr" }}
|
style={{ gridTemplateColumns: "auto auto 1fr" }}
|
||||||
onClick={() => {
|
|
||||||
router.push(`/${locale}/detail/${id}`);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span className="h-2 w-2 shrink-0 rounded-full bg-green-500 self-center"></span>
|
<span className="h-2 w-2 shrink-0 rounded-full bg-green-500 self-center"></span>
|
||||||
<div
|
<div
|
||||||
@ -61,12 +61,7 @@ export default function ServerCard({
|
|||||||
{name}
|
{name}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<div
|
<div className="flex flex-col gap-2">
|
||||||
onClick={() => {
|
|
||||||
router.push(`/${locale}/network/${id}`);
|
|
||||||
}}
|
|
||||||
className="flex flex-col gap-2 cursor-pointer"
|
|
||||||
>
|
|
||||||
<section className={"grid grid-cols-5 items-center gap-3"}>
|
<section className={"grid grid-cols-5 items-center gap-3"}>
|
||||||
<div className={"flex w-14 flex-col"}>
|
<div className={"flex w-14 flex-col"}>
|
||||||
<p className="text-xs text-muted-foreground">{t("CPU")}</p>
|
<p className="text-xs text-muted-foreground">{t("CPU")}</p>
|
||||||
|
48
components/TabSwitch.tsx
Normal file
48
components/TabSwitch.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
export default function TabSwitch({
|
||||||
|
tabs,
|
||||||
|
currentTab,
|
||||||
|
setCurrentTab,
|
||||||
|
}: {
|
||||||
|
tabs: string[];
|
||||||
|
currentTab: string;
|
||||||
|
setCurrentTab: (tab: string) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="z-50 flex flex-col items-start overflow-x-scroll rounded-[50px]">
|
||||||
|
<div className="flex items-center gap-1 rounded-[50px] bg-stone-100 p-[3px] dark:bg-stone-800">
|
||||||
|
{tabs.map((tab: string) => (
|
||||||
|
<div
|
||||||
|
key={tab}
|
||||||
|
onClick={() => setCurrentTab(tab)}
|
||||||
|
className={cn(
|
||||||
|
"relative cursor-pointer rounded-3xl px-2.5 py-[8px] text-[13px] font-[600] transition-all duration-500",
|
||||||
|
currentTab === tab
|
||||||
|
? "text-black dark:text-white"
|
||||||
|
: "text-stone-400 dark:text-stone-500",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{currentTab === tab && (
|
||||||
|
<motion.div
|
||||||
|
layoutId="tab-switch"
|
||||||
|
className="absolute inset-0 z-10 h-full w-full content-center bg-white shadow-lg shadow-black/5 dark:bg-stone-700 dark:shadow-white/5"
|
||||||
|
style={{
|
||||||
|
originY: "0px",
|
||||||
|
borderRadius: 46,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="relative z-20 flex items-center gap-1">
|
||||||
|
<p className="whitespace-nowrap">{tab}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -19,6 +19,10 @@
|
|||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
"Offline": "Offline"
|
"Offline": "Offline"
|
||||||
},
|
},
|
||||||
|
"TabSwitch": {
|
||||||
|
"Detail": "Detail",
|
||||||
|
"Network": "Network"
|
||||||
|
},
|
||||||
"ServerCardPopover": {
|
"ServerCardPopover": {
|
||||||
"System": "System",
|
"System": "System",
|
||||||
"CPU": "CPU",
|
"CPU": "CPU",
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
"Download": "Download",
|
"Download": "Download",
|
||||||
"Offline": "Offline"
|
"Offline": "Offline"
|
||||||
},
|
},
|
||||||
|
"TabSwitch": {
|
||||||
|
"Detail": "詳細",
|
||||||
|
"Network": "ネットワーク"
|
||||||
|
},
|
||||||
"ServerCardPopover": {
|
"ServerCardPopover": {
|
||||||
"System": "システム",
|
"System": "システム",
|
||||||
"CPU": "CPU",
|
"CPU": "CPU",
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
"Download": "下載",
|
"Download": "下載",
|
||||||
"Offline": "離線"
|
"Offline": "離線"
|
||||||
},
|
},
|
||||||
|
"TabSwitch": {
|
||||||
|
"Detail": "詳細",
|
||||||
|
"Network": "網路"
|
||||||
|
},
|
||||||
"ServerCardPopover": {
|
"ServerCardPopover": {
|
||||||
"System": "系統",
|
"System": "系統",
|
||||||
"CPU": "CPU",
|
"CPU": "CPU",
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
"Download": "下载",
|
"Download": "下载",
|
||||||
"Offline": "离线"
|
"Offline": "离线"
|
||||||
},
|
},
|
||||||
|
"TabSwitch": {
|
||||||
|
"Detail": "详情",
|
||||||
|
"Network": "网络"
|
||||||
|
},
|
||||||
"ServerCardPopover": {
|
"ServerCardPopover": {
|
||||||
"System": "系统",
|
"System": "系统",
|
||||||
"CPU": "CPU",
|
"CPU": "CPU",
|
||||||
|
Loading…
Reference in New Issue
Block a user