mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 17:41:56 +08:00
feat: net transfer badge
This commit is contained in:
parent
48b2d1493a
commit
3f0c2ed39d
@ -11,9 +11,7 @@ export default function GroupSwitch({
|
|||||||
setCurrentTab: (tab: string) => void;
|
setCurrentTab: (tab: string) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="scrollbar-hidden z-50 flex flex-col items-start overflow-x-scroll rounded-[50px]">
|
||||||
className="scrollbar-hidden 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">
|
<div className="flex items-center gap-1 rounded-[50px] bg-stone-100 p-[3px] dark:bg-stone-800">
|
||||||
{tabs.map((tab: string) => (
|
{tabs.map((tab: string) => (
|
||||||
<div
|
<div
|
||||||
|
@ -6,6 +6,8 @@ import { NezhaServer } from "@/types/nezha-api";
|
|||||||
import { Card } from "./ui/card";
|
import { Card } from "./ui/card";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Badge } from "./ui/badge";
|
||||||
|
import { formatBytes } from "@/lib/format";
|
||||||
|
|
||||||
export default function ServerCard({
|
export default function ServerCard({
|
||||||
now,
|
now,
|
||||||
@ -101,6 +103,20 @@ export default function ServerCard({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section className={"flex items-center justify-between gap-1"}>
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
className="items-center flex-1 justify-center rounded-[8px] text-nowrap text-[11px] border-muted-50 shadow-md shadow-neutral-200/30 dark:shadow-none"
|
||||||
|
>
|
||||||
|
{t("Upload")}:{formatBytes(serverInfo.state.net_out_transfer)}
|
||||||
|
</Badge>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="items-center flex-1 justify-center rounded-[8px] text-nowrap text-[11px] shadow-md shadow-neutral-200/30 dark:shadow-none"
|
||||||
|
>
|
||||||
|
{t("Download")}:{formatBytes(serverInfo.state.net_in_transfer)}
|
||||||
|
</Badge>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</section>
|
</section>
|
||||||
|
@ -87,10 +87,10 @@ export default function ServerDetailChart({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CpuChart({ now,data }: { now: number;data: NezhaServer }) {
|
function CpuChart({ now, data }: { now: number; data: NezhaServer }) {
|
||||||
const [cpuChartData, setCpuChartData] = useState([] as cpuChartData[]);
|
const [cpuChartData, setCpuChartData] = useState([] as cpuChartData[]);
|
||||||
|
|
||||||
const { cpu } = formatNezhaInfo(now,data);
|
const { cpu } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -189,7 +189,7 @@ function ProcessChart({ now, data }: { now: number; data: NezhaServer }) {
|
|||||||
[] as processChartData[],
|
[] as processChartData[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { process } = formatNezhaInfo(now,data);
|
const { process } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -276,11 +276,11 @@ function ProcessChart({ now, data }: { now: number; data: NezhaServer }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MemChart({ now,data }: { now: number;data: NezhaServer }) {
|
function MemChart({ now, data }: { now: number; data: NezhaServer }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [memChartData, setMemChartData] = useState([] as memChartData[]);
|
const [memChartData, setMemChartData] = useState([] as memChartData[]);
|
||||||
|
|
||||||
const { mem, swap } = formatNezhaInfo(now,data);
|
const { mem, swap } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -406,11 +406,11 @@ function MemChart({ now,data }: { now: number;data: NezhaServer }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DiskChart({ now,data }: { now: number;data: NezhaServer }) {
|
function DiskChart({ now, data }: { now: number; data: NezhaServer }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [diskChartData, setDiskChartData] = useState([] as diskChartData[]);
|
const [diskChartData, setDiskChartData] = useState([] as diskChartData[]);
|
||||||
|
|
||||||
const { disk } = formatNezhaInfo(now,data);
|
const { disk } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -503,13 +503,13 @@ function DiskChart({ now,data }: { now: number;data: NezhaServer }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function NetworkChart({ now,data }: { now: number;data: NezhaServer }) {
|
function NetworkChart({ now, data }: { now: number; data: NezhaServer }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [networkChartData, setNetworkChartData] = useState(
|
const [networkChartData, setNetworkChartData] = useState(
|
||||||
[] as networkChartData[],
|
[] as networkChartData[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { up, down } = formatNezhaInfo(now,data);
|
const { up, down } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -632,12 +632,12 @@ function NetworkChart({ now,data }: { now: number;data: NezhaServer }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConnectChart({ now,data }: { now: number;data: NezhaServer }) {
|
function ConnectChart({ now, data }: { now: number; data: NezhaServer }) {
|
||||||
const [connectChartData, setConnectChartData] = useState(
|
const [connectChartData, setConnectChartData] = useState(
|
||||||
[] as connectChartData[],
|
[] as connectChartData[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { tcp, udp } = formatNezhaInfo(now,data);
|
const { tcp, udp } = formatNezhaInfo(now, data);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -4,10 +4,11 @@ import ServerFlag from "@/components/ServerFlag";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { useWebSocketContext } from "@/hooks/use-websocket-context";
|
import { useWebSocketContext } from "@/hooks/use-websocket-context";
|
||||||
import { cn, formatBytes, formatNezhaInfo } from "@/lib/utils";
|
import { cn, formatNezhaInfo } from "@/lib/utils";
|
||||||
import { NezhaWebsocketResponse } from "@/types/nezha-api";
|
import { NezhaWebsocketResponse } from "@/types/nezha-api";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { formatBytes } from "@/lib/format";
|
||||||
|
|
||||||
export default function ServerDetailOverview({
|
export default function ServerDetailOverview({
|
||||||
server_id,
|
server_id,
|
||||||
@ -37,7 +38,10 @@ export default function ServerDetailOverview({
|
|||||||
return <ServerDetailLoading />;
|
return <ServerDetailLoading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, online, uptime, version } = formatNezhaInfo(nezhaWsData.now,server);
|
const { name, online, uptime, version } = formatNezhaInfo(
|
||||||
|
nezhaWsData.now,
|
||||||
|
server,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { cn, formatBytes } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { formatBytes } from "@/lib/format";
|
||||||
|
|
||||||
type ServerOverviewProps = {
|
type ServerOverviewProps = {
|
||||||
online: number;
|
online: number;
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
export function formatBytes(bytes: number, decimals = 2): string {
|
export function formatBytes(bytes: number, decimals: number = 2) {
|
||||||
if (bytes === 0) return "0 B";
|
if (!+bytes) return "0 Bytes";
|
||||||
|
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
const dm = decimals < 0 ? 0 : decimals;
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
const sizes = [
|
||||||
|
"Bytes",
|
||||||
|
"KiB",
|
||||||
|
"MiB",
|
||||||
|
"GiB",
|
||||||
|
"TiB",
|
||||||
|
"PiB",
|
||||||
|
"EiB",
|
||||||
|
"ZiB",
|
||||||
|
"YiB",
|
||||||
|
];
|
||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ export function cn(...inputs: ClassValue[]) {
|
|||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatNezhaInfo(now: number,serverInfo: NezhaServer) {
|
export function formatNezhaInfo(now: number, serverInfo: NezhaServer) {
|
||||||
const lastActiveTime = parseISOTimestamp(serverInfo.last_active);
|
const lastActiveTime = parseISOTimestamp(serverInfo.last_active);
|
||||||
return {
|
return {
|
||||||
...serverInfo,
|
...serverInfo,
|
||||||
@ -27,28 +27,6 @@ export function formatNezhaInfo(now: number,serverInfo: NezhaServer) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatBytes(bytes: number, decimals: number = 2) {
|
|
||||||
if (!+bytes) return "0 Bytes";
|
|
||||||
|
|
||||||
const k = 1024;
|
|
||||||
const dm = decimals < 0 ? 0 : decimals;
|
|
||||||
const sizes = [
|
|
||||||
"Bytes",
|
|
||||||
"KiB",
|
|
||||||
"MiB",
|
|
||||||
"GiB",
|
|
||||||
"TiB",
|
|
||||||
"PiB",
|
|
||||||
"EiB",
|
|
||||||
"ZiB",
|
|
||||||
"YiB",
|
|
||||||
];
|
|
||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
||||||
|
|
||||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDaysBetweenDates(date1: string, date2: string): number {
|
export function getDaysBetweenDates(date1: string, date2: string): number {
|
||||||
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
|
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
|
||||||
const firstDate = new Date(date1);
|
const firstDate = new Date(date1);
|
||||||
|
@ -57,11 +57,13 @@ export default function Servers() {
|
|||||||
|
|
||||||
const totalServers = nezhaWsData?.servers?.length || 0;
|
const totalServers = nezhaWsData?.servers?.length || 0;
|
||||||
const onlineServers =
|
const onlineServers =
|
||||||
nezhaWsData?.servers?.filter((server) => formatNezhaInfo(nezhaWsData.now,server).online)
|
nezhaWsData?.servers?.filter(
|
||||||
?.length || 0;
|
(server) => formatNezhaInfo(nezhaWsData.now, server).online,
|
||||||
|
)?.length || 0;
|
||||||
const offlineServers =
|
const offlineServers =
|
||||||
nezhaWsData?.servers?.filter((server) => !formatNezhaInfo(nezhaWsData.now,server).online)
|
nezhaWsData?.servers?.filter(
|
||||||
?.length || 0;
|
(server) => !formatNezhaInfo(nezhaWsData.now, server).online,
|
||||||
|
)?.length || 0;
|
||||||
const up =
|
const up =
|
||||||
nezhaWsData?.servers?.reduce(
|
nezhaWsData?.servers?.reduce(
|
||||||
(total, server) => total + server.state.net_out_transfer,
|
(total, server) => total + server.state.net_out_transfer,
|
||||||
@ -112,7 +114,11 @@ export default function Servers() {
|
|||||||
{showServices && <ServiceTracker />}
|
{showServices && <ServiceTracker />}
|
||||||
<section className="grid grid-cols-1 gap-2 md:grid-cols-2 mt-6">
|
<section className="grid grid-cols-1 gap-2 md:grid-cols-2 mt-6">
|
||||||
{filteredServers.map((serverInfo) => (
|
{filteredServers.map((serverInfo) => (
|
||||||
<ServerCard now={nezhaWsData.now} key={serverInfo.id} serverInfo={serverInfo} />
|
<ServerCard
|
||||||
|
now={nezhaWsData.now}
|
||||||
|
key={serverInfo.id}
|
||||||
|
serverInfo={serverInfo}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user