mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 09:31:55 +08:00
feat: enhance ServiceTracker with detailed uptime and delay visualization
This commit is contained in:
parent
94eb966d65
commit
0f81ef2f25
@ -19,10 +19,16 @@ export function ServiceTracker({ serverList }: { serverList: NezhaServer[] }) {
|
||||
})
|
||||
|
||||
const processServiceData = (serviceData: ServiceData) => {
|
||||
const days = serviceData.up.map((up, index) => ({
|
||||
completed: up > serviceData.down[index],
|
||||
date: new Date(Date.now() - (29 - index) * 24 * 60 * 60 * 1000),
|
||||
}))
|
||||
const days = serviceData.up.map((up, index) => {
|
||||
const totalChecks = up + serviceData.down[index]
|
||||
const dailyUptime = totalChecks > 0 ? (up / totalChecks) * 100 : 0
|
||||
return {
|
||||
completed: up > serviceData.down[index],
|
||||
date: new Date(Date.now() - (29 - index) * 24 * 60 * 60 * 1000),
|
||||
uptime: dailyUptime,
|
||||
delay: serviceData.delay[index] || 0
|
||||
}
|
||||
})
|
||||
|
||||
const totalUp = serviceData.up.reduce((a, b) => a + b, 0)
|
||||
const totalChecks = serviceData.up.reduce((a, b) => a + b, 0) + serviceData.down.reduce((a, b) => a + b, 0)
|
||||
|
@ -1,13 +1,20 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
import React from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip"
|
||||
import { Separator } from "./ui/separator"
|
||||
|
||||
interface ServiceTrackerProps {
|
||||
days: Array<{
|
||||
completed: boolean
|
||||
date?: Date
|
||||
uptime: number
|
||||
delay: number
|
||||
}>
|
||||
className?: string
|
||||
title?: string
|
||||
@ -18,6 +25,25 @@ interface ServiceTrackerProps {
|
||||
export const ServiceTrackerClient: React.FC<ServiceTrackerProps> = ({ days, className, title, uptime = 100, avgDelay = 0 }) => {
|
||||
const { t } = useTranslation()
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const getUptimeColor = (uptime: number) => {
|
||||
if (uptime >= 99) return "text-emerald-500"
|
||||
if (uptime >= 95) return "text-amber-500"
|
||||
return "text-rose-500"
|
||||
}
|
||||
|
||||
const getDelayColor = (delay: number) => {
|
||||
if (delay < 100) return "text-emerald-500"
|
||||
if (delay < 300) return "text-amber-500"
|
||||
return "text-rose-500"
|
||||
}
|
||||
|
||||
const getStatusColor = (uptime: number) => {
|
||||
if (uptime >= 99) return "bg-emerald-500"
|
||||
if (uptime >= 95) return "bg-amber-500"
|
||||
return "bg-rose-500"
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@ -30,27 +56,63 @@ export const ServiceTrackerClient: React.FC<ServiceTrackerProps> = ({ days, clas
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-5 h-5 rounded-full bg-green-600 flex items-center justify-center">
|
||||
<div className="w-3 h-3 rounded-full bg-white dark:bg-black" />
|
||||
</div>
|
||||
<div className={cn("w-2.5 h-2.5 rounded-full transition-colors", getStatusColor(uptime))} />
|
||||
<span className="font-medium text-sm">{title}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-stone-600 dark:text-stone-400 font-medium text-sm">{avgDelay.toFixed(0)}ms</span>
|
||||
<Separator className="h-4 mx-0" orientation="vertical" />
|
||||
<span className="text-green-600 font-medium text-sm">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className={cn(
|
||||
"font-medium text-sm transition-colors",
|
||||
getDelayColor(avgDelay)
|
||||
)}>
|
||||
{avgDelay.toFixed(0)}ms
|
||||
</span>
|
||||
<Separator className="h-4" orientation="vertical" />
|
||||
<span className={cn(
|
||||
"font-medium text-sm transition-colors",
|
||||
getUptimeColor(uptime)
|
||||
)}>
|
||||
{uptime.toFixed(1)}% {t("serviceTracker.uptime")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-[2px]">
|
||||
<div className="flex gap-[3px] bg-muted/30 p-1 rounded-lg">
|
||||
{days.map((day, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cn("flex-1 h-6 rounded-[5px] transition-colors", day.completed ? "bg-green-600" : "bg-red-500/60")}
|
||||
title={day.date ? day.date.toLocaleDateString() : `Day ${index + 1}`}
|
||||
/>
|
||||
<TooltipProvider delayDuration={50} key={index}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex-1 h-7 rounded-[4px] transition-all duration-200 cursor-help",
|
||||
"before:absolute before:inset-0 before:rounded-[4px] before:opacity-0 hover:before:opacity-100 before:bg-white/10 before:transition-opacity",
|
||||
"after:absolute after:inset-0 after:rounded-[4px] after:shadow-[inset_0_1px_theme(colors.white/10%)]",
|
||||
day.completed
|
||||
? "bg-gradient-to-b from-green-500/90 to-green-600 shadow-[0_1px_2px_theme(colors.green.600/30%)]"
|
||||
: "bg-gradient-to-b from-red-500/80 to-red-600/90 shadow-[0_1px_2px_theme(colors.red.600/30%)]"
|
||||
)}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="p-0 overflow-hidden">
|
||||
<div className="px-3 py-2 bg-popover">
|
||||
<p className="font-medium text-sm mb-2">{day.date?.toLocaleDateString()}</p>
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-xs text-muted-foreground">{t("serviceTracker.uptime")}:</span>
|
||||
<span className={cn("text-xs font-medium", day.uptime > 95 ? "text-green-500" : "text-red-500")}>
|
||||
{day.uptime.toFixed(1)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-xs text-muted-foreground">{t("serviceTracker.delay")}:</span>
|
||||
<span className={cn("text-xs font-medium", day.delay < 100 ? "text-green-500" : day.delay < 300 ? "text-yellow-500" : "text-red-500")}>
|
||||
{day.delay.toFixed(0)}ms
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
"serviceTracker": {
|
||||
"noService": "No service data",
|
||||
"uptime": "Uptime",
|
||||
"delay": "Delay",
|
||||
"daysAgo": "days ago",
|
||||
"today": "Today",
|
||||
"loading": "Loading..."
|
||||
|
@ -44,8 +44,9 @@
|
||||
"nextUpdate": "下次更新"
|
||||
},
|
||||
"serviceTracker": {
|
||||
"noService": "没有服务监测数据",
|
||||
"uptime": "可用率",
|
||||
"noService": "无服务数据",
|
||||
"uptime": "在线率",
|
||||
"delay": "延迟",
|
||||
"daysAgo": "天前",
|
||||
"today": "今天",
|
||||
"loading": "加载中..."
|
||||
|
@ -44,8 +44,9 @@
|
||||
"nextUpdate": "下次更新"
|
||||
},
|
||||
"serviceTracker": {
|
||||
"noService": "沒有服務監控數據",
|
||||
"uptime": "可用率",
|
||||
"noService": "無服務數據",
|
||||
"uptime": "在線率",
|
||||
"delay": "延遲",
|
||||
"daysAgo": "天前",
|
||||
"today": "今天",
|
||||
"loading": "載入中..."
|
||||
|
Loading…
x
Reference in New Issue
Block a user