From 7117d19fd13be6eca6d4ee4e34749860a44e1e9c Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 6 May 2026 14:45:46 +0200 Subject: [PATCH 1/3] fix: filter view in mobile --- web/html/inbounds.html | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/web/html/inbounds.html b/web/html/inbounds.html index 2c81e0da..c84dc551 100644 --- a/web/html/inbounds.html +++ b/web/html/inbounds.html @@ -182,6 +182,7 @@ {{ i18n "none" }} {{ i18n "subscription.active" @@ -2241,6 +2242,31 @@ #content-layout>.ant-layout-content>.ant-spin-nested-loading>div>.ant-spin { left: 50vw !important; } + + /* Keep filter choices in a single horizontal line on phones. */ + .inbounds-page .mobile-filter-group { + display: flex; + flex-wrap: nowrap; + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + padding-bottom: 2px; + -webkit-overflow-scrolling: touch; + scrollbar-width: thin; + } + .inbounds-page .mobile-filter-group .ant-radio-button-wrapper { + flex: 0 0 auto; + white-space: nowrap; + } + + /* Prevent mobile row content from splitting across multiple lines. */ + .inbounds-page .ant-table-tbody > tr > td { + white-space: nowrap; + } + .inbounds-page .ant-table-tbody > tr > td:nth-child(3) { + overflow: hidden; + text-overflow: ellipsis; + } } /* Protocol cell — wrap tags into a flex grid with consistent gap so From 9be11e109efd523e779be69a4ed4687bedf5e7ca Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 6 May 2026 17:12:08 +0200 Subject: [PATCH 2/3] fix design --- web/html/component/aClientTable.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/component/aClientTable.html b/web/html/component/aClientTable.html index d079d237..1c24e94d 100644 --- a/web/html/component/aClientTable.html +++ b/web/html/component/aClientTable.html @@ -96,7 +96,7 @@
-
[[ SizeFormatter.sizeFormat(getSumStats(record, client.email)) ]]
+
[[ SizeFormatter.sizeFormat(getSumStats(record, client.email)) ]]
From ad30298700d26e1b23b4952c488ad16bf3f9808c Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 6 May 2026 17:28:41 +0200 Subject: [PATCH 3/3] Exclude virtual interfaces from network stats Switch net.IOCounters to per-interface mode and aggregate traffic while excluding loopback and common virtual/tunnel interfaces. Adds isVirtualInterface helper to filter interfaces by exact names and prefixes (docker, veth, tun, wg, tailscale, etc.), sums BytesSent/BytesRecv across valid interfaces, and assigns the totals to status.NetTraffic. Removes the previous warning branch when no counters were found and preserves NetIO rate calculations using lastStatus. --- web/service/server.go | 48 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/web/service/server.go b/web/service/server.go index 0d531e12..3bb93028 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -315,13 +315,21 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status { } // Network stats - ioStats, err := net.IOCounters(false) + ioStats, err := net.IOCounters(true) if err != nil { logger.Warning("get io counters failed:", err) - } else if len(ioStats) > 0 { - ioStat := ioStats[0] - status.NetTraffic.Sent = ioStat.BytesSent - status.NetTraffic.Recv = ioStat.BytesRecv + } else { + var totalSent, totalRecv uint64 + for _, iface := range ioStats { + name := strings.ToLower(iface.Name) + if isVirtualInterface(name) { + continue + } + totalSent += iface.BytesSent + totalRecv += iface.BytesRecv + } + status.NetTraffic.Sent = totalSent + status.NetTraffic.Recv = totalRecv if lastStatus != nil { duration := now.Sub(lastStatus.T) @@ -331,8 +339,6 @@ func (s *ServerService) GetStatus(lastStatus *Status) *Status { status.NetIO.Up = up status.NetIO.Down = down } - } else { - logger.Warning("can not find io counters") } // TCP/UDP connections @@ -860,6 +866,34 @@ func (s *ServerService) GetXrayLogs( return entries } +// isVirtualInterface returns true for loopback and virtual/tunnel interfaces +// that should be excluded from network traffic statistics. +func isVirtualInterface(name string) bool { + // Exact matches + if name == "lo" || name == "lo0" { + return true + } + // Prefix matches for virtual/tunnel interfaces + virtualPrefixes := []string{ + "loopback", + "docker", + "br-", + "veth", + "virbr", + "tun", + "tap", + "wg", + "tailscale", + "zt", + } + for _, prefix := range virtualPrefixes { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} + func logEntryContains(line string, suffixes []string) bool { for _, sfx := range suffixes { if strings.Contains(line, sfx+"]") {