feat(ui): show per-inbound live speed (#5261)

* feat(utils): add speedFormat utility and tests

* feat(inbounds): add InboundSpeedEntry type

* feat(inbounds): add speed column to inbound list

* feat(inbounds): show speed in inbound stats modal

* feat(inbounds): compute inbound speed from traffic deltas

* feat(inbounds): wire inbound speed through page

* feat(i18n): add speed translation for all locales

* refactor(inbounds): dedupe live-speed UI and harden formatting

Extract a shared InboundSpeedTag component and isActiveSpeed guard used by the speed column and stats modal, unify InboundSpeedEntry into a single type, and route speedFormat through sizeFormat.

Also guard sizeFormat against non-finite input (no more "NaN PB/s") and clear stale per-inbound speeds when a traffic poll returns no deltas.

---------

Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
Nikan Zeyaei
2026-06-15 00:09:40 +03:30
committed by GitHub
parent 1c75034957
commit f4bbaf40f0
22 changed files with 198 additions and 5 deletions
+6 -1
View File
@@ -646,7 +646,7 @@ export class SizeFormatter {
static readonly ONE_PB = SizeFormatter.ONE_TB * 1024;
static sizeFormat(size: number | null | undefined): string {
if (size == null || size <= 0) return '0 B';
if (size == null || !Number.isFinite(size) || size <= 0) return '0 B';
if (size < SizeFormatter.ONE_KB) return size.toFixed(0) + ' B';
if (size < SizeFormatter.ONE_MB) return (size / SizeFormatter.ONE_KB).toFixed(2) + ' KB';
if (size < SizeFormatter.ONE_GB) return (size / SizeFormatter.ONE_MB).toFixed(2) + ' MB';
@@ -654,6 +654,11 @@ export class SizeFormatter {
if (size < SizeFormatter.ONE_PB) return (size / SizeFormatter.ONE_TB).toFixed(2) + ' TB';
return (size / SizeFormatter.ONE_PB).toFixed(2) + ' PB';
}
// Same unit ladder as sizeFormat, expressed per-second.
static speedFormat(bps: number | null | undefined): string {
return SizeFormatter.sizeFormat(bps) + '/s';
}
}
export class CPUFormatter {