pn2eK*A$RfoS%ylF*$sSgbptayAf|!H2v>S#Ka11tz)+M1vFF*j`JG
zRTUS41?lCZo9%s|mOvO5jQF#Guo8h{Yl&WU&r)1Ki#yd0U*;vWX%X+vryv0+*nN(+IbQOdNi
z=7~NAu;|O~rdE`oDlv7$LV`deyD|qT3F1{X@~cxoaVC;|>S{~u$%><{sSmBErJ6NS
zWv8`N{LR*i5>=%MqTmy{J|*?-mS=%fEhHjIIYc>~k2NoQ*VmRbPgeTYm!wuY6DG10
z0;$@Nx=G4$H=q2^uYtQN4AK>dOos_W*#aQ)Bn%%$J_ID%Lnn%*p;<CkF>LDT2ZoU85{`*(azUNVwW_ls^DaZeMVVtEwzoR%ma@c8Ex9^$`PQZKziU+?g91C
z%fh1VO6MjbMqp8)tzsZrI69KOn`&pj>XQY*9;sV%Vi_+?_h
z?))e20dPD1kxQ$tqpCcKIi>J~iG;)50P62XZ80bsi6~oZAjAvAl3#(kyUT{bhq}7a
zI-pKK`VOJ|2t=a+f)lUB?2UFy#>3l&x{(G%y6BRYFEI_>wILx%%47r~aslXp7QO&7
zTn`%8!}_4Uu#tq@l`Np%dJ7b5jsqF)3}^F26NGSH!0y{#E9$CRmVlS64T)^&gN$e3
z(OB8kj2O5J$YX}%K<@4>)!`j&wISVF`XDpRtYY~TsJm8ND@h4&BjTCRJ==|F(bj=u
zcx*WScW4KY(3a-qE)dP2ZW%fs^;DG&a6sq+FA1w}XE(Jn@ESogVGXL41Ju{8(*dCV
zT5ysgLyC8}bA2k6x^k)r?r
zH;J&b*R`U7s&W-PTHr8sU%PT2t^r#bs7)W?w4!V-5KVwU$ACPN)i4*HvcW*KWQ61@
zAaZ?yZUTAg#q@i$UOteg-hOx4#eRuCm=~HT(a2yRkKihxM>+uVs1iTm(eCnrJY~Cq
zL@U$**0HCNK0xFpqPt=sPqiyRp3Y-ZA1%uVa*vLEpjp#YHd#x>-w>@RO;w(GQb;4v
zMA()80FfJEZ@~h80EG2V2m!gp5Fq_{Fi9&LrYdg(C+MY)Si9vaP>NP;Pf{8WHFvU$
z-SMd4K!^oLv_sB`Bk^!miG$bVptc?$l$Ai_%h(8F?aC#fW^#ih7Hn+
zoT{=2JgTPeFP4viQuGsvHC@Px&AW$z!~y$7AQ~=CYdHCR2ow+Gt0N^tcn!AC35h-c
z6n6A+vUjzzkt+L2vyM`gAg9<0ee{){4n%U|C|L}IC1P0MCQz(E2*RNwB&jhFLKkN9
z2_RA)doIwkKthrN`(dE=dKtwMzmdXnx>Z>Rt!T8Wyb9ivqAghL0TA^nJfr(4F+&(e
zxZN@fC{Zh}o5bGN%EqXQlqpGwy@qTXAS@hXD_E=*WvMvNmu0C+z-YG|PK*PANF(?_
z1G~Izv^FR$Svdh_YcMeC-#T8U$Dr}5as?$_^!DMRc;YJqZ^}5ab-@gFyK)7H
zW*R5)k=QG;*@kt6t&aeuG
zd=ALdMdb$QWU#un0`{4q$&d^3P-@h-Xy!_c_7i`
zm&o&H$q>RYBD*MdR>dq*pqtSYyGNnwA@(ZQ}nOcpx{&S5xM&I1~RGJVmr1T8fm
zVPpzg0uKX(1K$TS0s$TnlQip8mCe#pr>Yk3siZrd2QrYO9(3$ubPNu6k~rJ9pQeYd_sAU4R^($5G=faxfus
zb!M2k(eB(k?%X|hu5E!SH{YE*>COeYbgPjr?%W&h+zodwb|&0I?{|_r_r5##z@2M5
z%aEhjGP6|6$=Nt3Y9X_dERCKvbF+}c?16U%Im{k%4d>_%f!s65iPF!IgKvP>^cncS
zo|}c7;GISewnJ&1xv;)gjOVvO$cb}4g{4J6Z80nQV}<jItk0fwzPgWaaSZFQ^yzl~7J1RSdbuQ5ogcP+k!<6f^*oeiWvEe?u`De=qQV
zxm@)BSPlKqbvt7O|C^Md-S$Si?Q0`Lj1Hh=!j47(QQ~*nbX(i@|7Qu7z`w`&(f=c}
zlv?tUz4d!TcTL~?&au;5EMM&(I&oCVu@xUk{T8kLq_FQdPdkHm*!+s#O}o-*WB7oM
z`C%E==2bte)UW=t_W-Y3`{s6h;m6wZHaW`@y;`fozI$oiYU`W#YE0)%rf+fmXII+6
zTSLdq&foLx^e*LBj<~&fn``rLUn~loRq>tIbC-6$#b4k0MppIy>+XN_N{@)uigx~d
zV8Mo#+eg3lg;$lh2U`v=FS_+ilWP4t^m%nt^|y<FKsO5G>wmrGjmv)X+P=h;Z|^OB@mhz{
zk8b;o`8=c3{PU+`4t3IkdRUwdF6AGIZ)a_GrRl1VgCmEXUNelxP5bG>)!kVYOZF%K
z)@#!X7pAo1o9nPA*ksP?vH^T`9p=ZKb-~Ez8;LQnE*LfHfiaCc>Ve@?4~+f9n9i$&
zgRzAe6T`tM;Jb-2DjbaP`e4lD6Y8@8Y!*LEWHt|LfZ{{-Q9P#sis$eXV6bO+L_?6d
zd?t~3yo|`RJSGBUK7W?TbNnKa=Xvu+ATRJjBLBs|A@U+`6A7|_7ZEAsw}~v|og0H_
zyoAV0{1+mNc&{js#e5AB&RI0b%RH4x5#LB;30IncEaeU&%lK9z#k@*WkmWp+$SZs|
zkrmt;15&~#5P6j!Ch{5&iv@X|=M!1UPk`_#u^4cC90t6K&x`}3VH_A&h_QypGy~%d
zF%~srn=H>F#QSnb3r25Ty!cb`%*77y`|+%SWej$Q3Z*F8Df1Qatmoo*=EYk!XWQiy
z)%nmCtUuLI7SBX+>2WFXpb7&4y>rQO!EP?=RK9s3sJ%s25ZVU2;?b!%8V1Fk_@g+%5qKq50%F73RL{ZOIvROIuK
zrXWp5qMafTsR9!5XCO^Snuhcg5|vY(A|w~mCE%H$Kk6O
zmLj_Z=^_5D1SK^zRG~S06KURd{K3C7Rru8%tUj;2lf|*7rR{gJzOt>Ev>c_i(9yQf
zPkqv4^V>INHZ(puAtt&R-?W>}4l-`)xZ+nF3ZHqZQg4}g!=wr-@Sb~E5DVdB_ONd8
z<~6Hnfl2o==k^_eR$>yP0b6Ji{d*g$Thv1!ddtW`
zSL^b#FRY284x(exzSNoTh5#1XIU+-Nn~JiPjpY9OQ7eZg7~Rd!8U4YKF5etLt+?o>
z(P(x$Z}TCAJ>HujY-+$WyQ7oEY=Ylg22}Pd9%5
z06K8+fP*lTc>(ja(UT_TKNuVWx!C9!s4i{e1qUIwpBEiO=MVW&h|5w19(;%eVjGG-
zgxcn9%6`LcJiNES@v~l=W=VRQ7aziK&1;oj17rIhE&t|z2*iuw2J;gTVE+6%$(h$E
zcQ#&nHmP4=7en1RyfoyYhta=o`hX(&n($vi
zZ01eRH!Gfg@UY#fX1WD+?QiqlcbV?tzwypTq1bFb{U{u%KmYJ3It)ha2!iJ(@P|j4
zHQv0)nY#0qW!Z(B4Gk+`O3kaC1A2YZZOHeBFM4`7%DepsDwuaYSLZ*-j$2`C|KHcLYync_xANhDb>AXb_|^A;56bP$Iz>Jwe)@#dwYDH
z_GeMGnW$RCdqIFr;A4pBsHPW2dWXLPM!dL-id#F`G4E#GN?(qO#+o)SqYj@?uT|>`
z{)s3d-$T_F{3i8j-dgS6WY4SCBYUeuAVKswf`?(G=!^zzn_v@1j6rPKxs*GvjMwG#
zhJ--8d42Up#-M)ZTkdKPf#xC_nHOAB4@A+-gVFRyl0z^jvyyXd2y_K_$B-MuL{uqBNGqc3J;M)7r8)IG?{#Jj{
zEt-`M^WA8Uzi|R#T;y%$t=O+u&-Xulx;%#0sjhGVL%7mO2>bJhlUOL`9n@!MZkW<(
zNy{r}xfzU#0X5`>C!uHpUrVGt-+z)t+IrU$H)j5-w(=
zp^jO8FHc0X#w?mwYNK{;4jCEgiZeEPRJECxaaX=Q^5bXZt8ER9uoe8qV?Kc@
z75Eb%HuG}tx$3h{U48B9cby3`xyeXOPUvb^Ajp>TR3M$Kbbu=N_-;t=u@m~ym|HaVpjN>m0j|W$SkII
zRBh-inU{UQfkb10V1yn#t$S5h~;>2}STSBImi^8MJNQBfg%z>y-vGwu-fYeN~cv=4~JV
z@xfbieBQNrl|D4qsn}J`4FpkUz;)X34E$5~A^ju_JGC7Uz*PKKLvP
z35kKZ&CAQ(UrrtN#?`=IWu_mY;w2vTDXXTWVM2VN_p5y4S=NE=;Ob2lr|d`&H!c?P
zUZ1fvn+gA@UuDRzKgUMa{Tl(JrOy1Vn;8B0E6fWIf&bX*W3>1eopj~?H!vmoSghFQ
z(WMo(`1TUW1b+KGh~BrA9&x`#d`Z5*QvOA|HTYX!Kzi2&*7%PWGP*3|6E6R$=O1|C
z=U`UkYe8)0wdhrw(_8PY^q)0YONiod4x9x)Cpn?0&Ag7iuH(Dyziv?B5XtGGSenXX
zZb5DVFNW^sNLKS{U%)ejiZ=67_=iE?)yuBIS7Bioy&U65Z?Uvi|2$Lf`{hfU?!P_QXnb-F#`Z|+?M}^)Ieu>$XK5HZHlUnBtY!_k~`ibrd`V2f`S)2K}
z!1g;Uf5|_ay53XYm(Tp#Kt+_wPfLF=d8Lp5l{luzxet
zLjLdK(eFdx|11Kr$Hf^w;}%X=B5eL+l=&C-{JkBFQ2qPJCOTu6`E?3+!kKuj?^wz|
zt}eI0pLb)8AN>x`aiP4&ZI;AZ@xp4dmA`%)W9!U!-eybjrg8B1@S|1y#qa6B*GYUf
zviaeS?|p-ggnO}OIP_AiGe0cpwdB^V)+GlNrSO!}#z
zr$p+)H~hc?ZRY1Rs&}suIr9!@cqHunA}P_A|4L*$ukj;``>S^V*rfjY9Y6@5{v(EA
z-gZCa-IJ$$J$8>5!xMyVsdjuL1TfqWNp5T}@esD$*7W_4zeykDk(o}
z{Wr@uOgiWhFfZ8ek#2RY|Bc+*Q?iqH`w4BEH}TKS9+48W`0Q?vz!g3d0_-kdN~98J
zHD%*q8P1PURr70rtYNP{JYBdI&zq+DJ$OtFQ#hT6{0w39CjUIIb)(X%w3y-%p2vGZ
z0I#ISkevAy(e5jStE&ZcyyKDE$6tX!g86BHPnG1zE$pR_JObuN0SR3{daq>RyHhv$7}NBkq);Vst)#d`|r
z5=!Wy_ClDos&A`GGNL1%6Pv@W@9_10vQ;iOnD4m5Vp%nQ`woT^&MVvniRBNep`Kg?
zvMs^Vpl9Xeq4M@mzV*Q?6C5>~(m5f6ca!CAOn+Ap$0qS(GHT7|{=cARB{HWDw`
z3khxEYk$FF8_7Q>a){q7Cgmd6*X}+~tmY5V0+)0)@Pu%mFNN)`dKhnW@Fs>9xe#DC_)&Cc`|Fn$>pA-kx_09>A_IB+Z+HeZKags&DtXt{
zIm4$5E9E)MN@B3uSz(CZA$E!*_CoJZD?&CS5
z5byZ$O2Yl|lVeZV{*EtO>G`V}1fjFuoYAV4e{!F77cXh7tPyYZ0R3&_10JAveG2qf
z6nT6n@$n1K1K74F_j?F*oHuyLHnS@H{6jGHSzsZHA~8QL7NyD7c=Pk68+V7FPpjrb
z?}%VBQo#I>>3YT5)(W%2V^Ly0B=f@ZXh1Z!c+szNq;h1O_-OF=PD<~29`B@yD7nL@
z!w<y^QIPNI@yhmEhD_F3v1ecS$|DUloCR
z&HNhfFCD@?uelcaG4o0@?wK8ap}ZVq+mR!d*1puHcYL3J??ns{FW+g74{{q`8=A{f
zHe!;9F;=YLY2H}D-|-k95Px3c3uCmn!>ZOXW6~dkS7p`&KPBPqp^NXb$N^q>5Bee>
zi)z1b1l#g9UpW%%ztBhSC*HTa-(d=!@Vnz9^=#%xYhP{1FC6gY1e|W+ruyTQkmJh~
zImlDzgaZFG24@aR^yv<#qMptC{4RHUzqK1=e+oPFegn1<<26*Z=p*K@?8R>hEh@-Q
zn>zoy9|&sJ!ZZC}yqL$P{J;3Kfo>As}rcUkX5lG=DAi&c3b&@kbwG0V*
z<(swJYS;3}E##pAvNgf{HuK%3J3syG>T63p0taS`A7ei3zxe3MPiCc6cfYq4Bkanm
z@@;6MUdcQmsARW1aIM!8JiE?Fh>oSLwP98K5Q%>ctMR)5a%;LihJSgE%&f_o<1#u9
zK3V@(P{UwzbMpvNALVrpJHw(rlX?-Gs%K
tF2@gTUga=z{MGLAC_UrXLmtR?EtTu?+TCTPw6KT#W1G@%3*})|{u@iHL4W`N
diff --git a/package.json b/package.json
index 3e2a241..09b3c91 100644
--- a/package.json
+++ b/package.json
@@ -19,8 +19,8 @@
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
- "@tanstack/react-query": "^5.61.5",
- "@tanstack/react-query-devtools": "^5.61.5",
+ "@tanstack/react-query": "^5.62.0",
+ "@tanstack/react-query-devtools": "^5.62.0",
"@tanstack/react-table": "^8.20.5",
"@types/luxon": "^3.4.2",
"class-variance-authority": "^0.7.1",
@@ -32,7 +32,7 @@
"luxon": "^3.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-i18next": "^15.1.2",
+ "react-i18next": "^15.1.3",
"react-router-dom": "^7.0.1",
"react-use-websocket": "^4.11.1",
"recharts": "^2.13.3",
@@ -41,13 +41,13 @@
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
- "@eslint/js": "^9.15.0",
+ "@eslint/js": "^9.16.0",
"@types/node": "^22.10.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.7.2",
"autoprefixer": "^10.4.20",
- "eslint": "^9.15.0",
+ "eslint": "^9.16.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.12.0",
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index a3d4623..fa58d08 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -49,6 +49,7 @@ function Header() {
}
function DashboardLink() {
+ const { t } = useTranslation();
const { data: userData } = useQuery({
queryKey: ["login-user"],
queryFn: () => fetchLoginUser(),
@@ -56,8 +57,6 @@ function DashboardLink() {
refetchOnWindowFocus: true,
});
- if (!userData?.data?.id) return null;
-
return (
);
diff --git a/src/components/ServerCard.tsx b/src/components/ServerCard.tsx
index d077ee1..ab3f00f 100644
--- a/src/components/ServerCard.tsx
+++ b/src/components/ServerCard.tsx
@@ -8,14 +8,16 @@ import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
export default function ServerCard({
+ now,
serverInfo,
}: {
+ now: number;
serverInfo: NezhaServer;
}) {
const { t } = useTranslation();
const navigate = useNavigate();
const { name, country_code, online, cpu, up, down, mem, stg } =
- formatNezhaInfo(serverInfo);
+ formatNezhaInfo(now, serverInfo);
const showFlag = true;
diff --git a/src/components/ServerDetailChart.tsx b/src/components/ServerDetailChart.tsx
index 7bb9a81..2f55604 100644
--- a/src/components/ServerDetailChart.tsx
+++ b/src/components/ServerDetailChart.tsx
@@ -77,20 +77,20 @@ export default function ServerDetailChart({
return (
);
}
-function CpuChart({ data }: { data: NezhaServer }) {
+function CpuChart({ now,data }: { now: number;data: NezhaServer }) {
const [cpuChartData, setCpuChartData] = useState([] as cpuChartData[]);
- const { cpu } = formatNezhaInfo(data);
+ const { cpu } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
@@ -183,13 +183,13 @@ function CpuChart({ data }: { data: NezhaServer }) {
);
}
-function ProcessChart({ data }: { data: NezhaServer }) {
+function ProcessChart({ now, data }: { now: number; data: NezhaServer }) {
const { t } = useTranslation();
const [processChartData, setProcessChartData] = useState(
[] as processChartData[],
);
- const { process } = formatNezhaInfo(data);
+ const { process } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
@@ -276,11 +276,11 @@ function ProcessChart({ data }: { data: NezhaServer }) {
);
}
-function MemChart({ data }: { data: NezhaServer }) {
+function MemChart({ now,data }: { now: number;data: NezhaServer }) {
const { t } = useTranslation();
const [memChartData, setMemChartData] = useState([] as memChartData[]);
- const { mem, swap } = formatNezhaInfo(data);
+ const { mem, swap } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
@@ -406,11 +406,11 @@ function MemChart({ data }: { data: NezhaServer }) {
);
}
-function DiskChart({ data }: { data: NezhaServer }) {
+function DiskChart({ now,data }: { now: number;data: NezhaServer }) {
const { t } = useTranslation();
const [diskChartData, setDiskChartData] = useState([] as diskChartData[]);
- const { disk } = formatNezhaInfo(data);
+ const { disk } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
@@ -503,13 +503,13 @@ function DiskChart({ data }: { data: NezhaServer }) {
);
}
-function NetworkChart({ data }: { data: NezhaServer }) {
+function NetworkChart({ now,data }: { now: number;data: NezhaServer }) {
const { t } = useTranslation();
const [networkChartData, setNetworkChartData] = useState(
[] as networkChartData[],
);
- const { up, down } = formatNezhaInfo(data);
+ const { up, down } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
@@ -632,12 +632,12 @@ function NetworkChart({ data }: { data: NezhaServer }) {
);
}
-function ConnectChart({ data }: { data: NezhaServer }) {
+function ConnectChart({ now,data }: { now: number;data: NezhaServer }) {
const [connectChartData, setConnectChartData] = useState(
[] as connectChartData[],
);
- const { tcp, udp } = formatNezhaInfo(data);
+ const { tcp, udp } = formatNezhaInfo(now,data);
useEffect(() => {
if (data) {
diff --git a/src/components/ServerDetailOverview.tsx b/src/components/ServerDetailOverview.tsx
index 22e1b01..6512b19 100644
--- a/src/components/ServerDetailOverview.tsx
+++ b/src/components/ServerDetailOverview.tsx
@@ -37,7 +37,7 @@ export default function ServerDetailOverview({
return ;
}
- const { name, online, uptime, version } = formatNezhaInfo(server);
+ const { name, online, uptime, version } = formatNezhaInfo(nezhaWsData.now,server);
return (
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 4a54168..8414980 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -6,7 +6,7 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
-export function formatNezhaInfo(serverInfo: NezhaServer) {
+export function formatNezhaInfo(now: number,serverInfo: NezhaServer) {
const lastActiveTime = parseISOTimestamp(serverInfo.last_active);
return {
...serverInfo,
@@ -14,7 +14,7 @@ export function formatNezhaInfo(serverInfo: NezhaServer) {
process: serverInfo.state.process_count || 0,
up: serverInfo.state.net_out_speed / 1024 / 1024 || 0,
down: serverInfo.state.net_in_speed / 1024 / 1024 || 0,
- online: Date.now() - lastActiveTime <= 30000,
+ online: now - lastActiveTime <= 30000,
uptime: serverInfo.state.uptime || 0,
version: serverInfo.host.version || null,
tcp: serverInfo.state.tcp_conn_count || 0,
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 2a120e3..f5f6349 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -1,6 +1,8 @@
{
"nezha": "Nezha Monitoring",
"overview": "Overview",
+ "dashboard": "Dashboard",
+ "login": "Login",
"whereTheTimeIs": "Where the time is",
"info": {
"websocketConnecting": "WebSocket connecting",
diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json
index 786323b..3995e5e 100644
--- a/src/locales/zh-CN/translation.json
+++ b/src/locales/zh-CN/translation.json
@@ -1,6 +1,8 @@
{
"nezha": "哪吒监控",
"overview": "概览",
+ "dashboard": "管理后台",
+ "login": "登录",
"whereTheTimeIs": "当前时间",
"info": {
"websocketConnecting": "WebSocket 连接中",
diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json
index 296e5c0..9cececf 100644
--- a/src/locales/zh-TW/translation.json
+++ b/src/locales/zh-TW/translation.json
@@ -1,6 +1,8 @@
{
"nezha": "哪吒監控",
"overview": "概覽",
+ "dashboard": "管理後台",
+ "login": "登錄",
"whereTheTimeIs": "目前時間",
"info": {
"websocketConnecting": "WebSocket 連接中",
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index 9ad833a..86f7ba3 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -57,10 +57,10 @@ export default function Servers() {
const totalServers = nezhaWsData?.servers?.length || 0;
const onlineServers =
- nezhaWsData?.servers?.filter((server) => formatNezhaInfo(server).online)
+ nezhaWsData?.servers?.filter((server) => formatNezhaInfo(nezhaWsData.now,server).online)
?.length || 0;
const offlineServers =
- nezhaWsData?.servers?.filter((server) => !formatNezhaInfo(server).online)
+ nezhaWsData?.servers?.filter((server) => !formatNezhaInfo(nezhaWsData.now,server).online)
?.length || 0;
const up =
nezhaWsData?.servers?.reduce(
@@ -112,7 +112,7 @@ export default function Servers() {
{showServices && }
{filteredServers.map((serverInfo) => (
-
+
))}