fix(admin-remnawave): lay node metrics in 3 fixed rows (processor/traffic/versions)

The metrics sat in one flex-wrap, so when realtime speeds change width (Kb/s<->Mb/s, large values) elements reflowed and jumped between lines, and the card height shifted. Split into 3 fixed rows: processor (CPU load + RAM), traffic (down/up), versions (remnanode + xray). Traffic uses a 2-column grid so a wide value never pushes its sibling; tabular-nums keeps digit widths constant.
This commit is contained in:
c0mrade
2026-06-01 14:52:28 +03:00
parent 1b1046bb5c
commit 43acb70ab9

View File

@@ -325,62 +325,75 @@ function NodeCard({ node, providerName, realtime, onAction, isLoading }: NodeCar
)} )}
</div> </div>
{/* Live metrics: RAM · load · speeds · versions */} {/* Live metrics in 3 fixed rows (processor · traffic · versions) so the
changing speed/value widths never reflow or jump between lines. */}
{(ramPct !== null || loadAvg || rx > 0 || tx > 0 || node.versions) && ( {(ramPct !== null || loadAvg || rx > 0 || tx > 0 || node.versions) && (
<div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 border-t border-dark-700/60 pt-2 font-mono text-[10.5px] text-dark-500"> <div className="mt-2 space-y-1 border-t border-dark-700/60 pt-2 font-mono text-[10.5px] tabular-nums text-dark-500">
{ramPct !== null && ( {/* Row 1 — Processor: CPU load + RAM */}
<span className="flex items-center gap-1.5" title="RAM"> {(loadAvg || ramPct !== null) && (
<MemoryIcon className="h-3 w-3 text-dark-500" /> <div className="flex items-center gap-3">
<span {loadAvg && (
className={ <span className="flex items-center gap-1" title="load average 1 / 5 / 15 min">
ramPct > 85 <CpuIcon className="h-3 w-3 shrink-0 text-dark-500" />
? 'text-error-400' {loadAvg}
: ramPct > 65 </span>
? 'text-warning-400' )}
: 'text-dark-400' {ramPct !== null && (
} <span className="flex items-center gap-1.5" title="RAM">
> <MemoryIcon className="h-3 w-3 shrink-0 text-dark-500" />
{ramPct}% <span
</span> className={
<span className="h-1 w-10 overflow-hidden rounded-full bg-dark-700"> ramPct > 85
<span ? 'text-error-400'
className="block h-full rounded-full bg-dark-400" : ramPct > 65
style={{ width: `${ramPct}%` }} ? 'text-warning-400'
/> : 'text-dark-400'
</span> }
</span> >
{ramPct}%
</span>
<span className="h-1 w-10 overflow-hidden rounded-full bg-dark-700">
<span
className="block h-full rounded-full bg-dark-400"
style={{ width: `${ramPct}%` }}
/>
</span>
</span>
)}
</div>
)} )}
{loadAvg && (
<span className="flex items-center gap-1" title="load average 1 / 5 / 15 min"> {/* Row 2 — Traffic: down / up speeds (2 fixed columns so a wide value
<CpuIcon className="h-3 w-3 text-dark-500" /> never pushes the other) */}
{loadAvg} {(rx > 0 || tx > 0) && (
</span> <div className="grid grid-cols-2 gap-3">
<span className="flex items-center gap-1">
<DownloadIcon className="h-3 w-3 shrink-0 text-success-400/70" />
{formatSpeed(rx)}
</span>
<span className="flex items-center gap-1">
<UploadIcon className="h-3 w-3 shrink-0 text-accent-400/70" />
{formatSpeed(tx)}
</span>
</div>
)} )}
<span className="flex items-center gap-2">
<span className="flex items-center gap-0.5"> {/* Row 3 — Versions: remnanode + xray core */}
<DownloadIcon className="h-3 w-3 text-success-400/70" />
{formatSpeed(rx)}
</span>
<span className="flex items-center gap-0.5">
<UploadIcon className="h-3 w-3 text-accent-400/70" />
{formatSpeed(tx)}
</span>
</span>
{(node.versions?.node || node.versions?.xray) && ( {(node.versions?.node || node.versions?.xray) && (
<span className="flex w-full items-center gap-2.5 text-dark-600 sm:ml-auto sm:w-auto"> <div className="flex items-center gap-3 text-dark-600">
{node.versions?.node && ( {node.versions?.node && (
<span className="flex items-center gap-1" title="remnanode"> <span className="flex items-center gap-1" title="remnanode">
<RemnawaveIcon className="h-3 w-3" /> <RemnawaveIcon className="h-3 w-3 shrink-0" />
{node.versions.node} {node.versions.node}
</span> </span>
)} )}
{node.versions?.xray && ( {node.versions?.xray && (
<span className="flex items-center gap-1" title="xray core"> <span className="flex items-center gap-1" title="xray core">
<XrayIcon className="h-3 w-3" /> <XrayIcon className="h-3 w-3 shrink-0" />
{node.versions.xray} {node.versions.xray}
</span> </span>
)} )}
</span> </div>
)} )}
</div> </div>
)} )}