From 9309643b7e200da10e6960e6a298d1dad26c7246 Mon Sep 17 00:00:00 2001 From: c0mrade Date: Mon, 1 Jun 2026 13:08:30 +0300 Subject: [PATCH] feat(admin-remnawave): provider favicon, mobile node card, meaningful icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Render the provider favicon in the node badge (new provider_favicon / provider_name fields), with graceful fallback. - Mobile-friendly node card: stop the versions block from shifting right on wrapped rows, truncate long addresses, cap the provider badge. - Give node-summary cards (total/online/offline/disabled) and traffic-period cards (2d/7d/30d/month/year) distinct, meaningful icons instead of all-the-same globe / bar-chart. - Show traffic as 'used / limit' (e.g. 2.35 TB / ∞). - Route every icon through the central barrel (drop the direct react-icons/pi import). --- src/api/adminRemnawave.ts | 2 + src/pages/AdminRemnawave.tsx | 77 ++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/api/adminRemnawave.ts b/src/api/adminRemnawave.ts index c9e383b..9e86819 100644 --- a/src/api/adminRemnawave.ts +++ b/src/api/adminRemnawave.ts @@ -134,6 +134,8 @@ export interface NodeInfo { created_at?: string; updated_at?: string; provider_uuid?: string; + provider_name?: string | null; + provider_favicon?: string | null; versions?: { xray: string; node: string } | null; system?: { info: { diff --git a/src/pages/AdminRemnawave.tsx b/src/pages/AdminRemnawave.tsx index b34308e..ed0cff7 100644 --- a/src/pages/AdminRemnawave.tsx +++ b/src/pages/AdminRemnawave.tsx @@ -23,6 +23,19 @@ import { ServerIcon, ChartIcon, GlobeIcon, + HeartbeatIcon, + PowerIcon, + WarningCircleIcon, + CalendarIcon, + CalendarBlankIcon, + CalendarStarIcon, + ChartPieIcon, + ChartDonutIcon, + CpuIcon, + MemoryIcon, + PulseIcon, + DevicesIcon, + StatUptimeIcon, UsersIcon, SyncIcon, RefreshIcon, @@ -36,7 +49,6 @@ import { BackIcon, ChevronRightIcon, } from '../components/icons'; -import { PiCpu, PiMemory, PiTimer, PiDevices, PiPulse } from 'react-icons/pi'; const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 B'; @@ -128,6 +140,9 @@ function NodeCard({ node, providerName, onAction, isLoading }: NodeCardProps) { const limit = node.traffic_limit_bytes ?? 0; const trafficPct = limit > 0 ? Math.min(100, (used / limit) * 100) : null; + // Provider name: realtime metrics first, fall back to the node's own provider. + const providerLabel = providerName || node.provider_name; + return (
{/* Identity + actions */} @@ -145,9 +160,19 @@ function NodeCard({ node, providerName, onAction, isLoading }: NodeCardProps) { {getCountryFlag(node.country_code)}

{node.name}

- {providerName && ( - - {providerName} + {(providerLabel || node.provider_favicon) && ( + + {node.provider_favicon && ( + { + e.currentTarget.style.display = 'none'; + }} + /> + )} + {providerLabel && {providerLabel}} )}
@@ -186,9 +211,9 @@ function NodeCard({ node, providerName, onAction, isLoading }: NodeCardProps) { {/* Address + traffic + uptime */}
- - - {node.address} + + + {node.address} {formatBytes(used)} @@ -200,11 +225,11 @@ function NodeCard({ node, providerName, onAction, isLoading }: NodeCardProps) { /> )} - {limit > 0 ? formatBytes(limit) : '∞'} + / {limit > 0 ? formatBytes(limit) : '∞'} {node.xray_uptime > 0 && ( - + {formatUptime(node.xray_uptime)} )} @@ -246,7 +271,7 @@ function NodeCard({ node, providerName, onAction, isLoading }: NodeCardProps) { {(node.versions?.node || node.versions?.xray) && ( - + {node.versions?.node && {node.versions.node}} {node.versions?.xray && xray {node.versions.xray}} @@ -527,20 +552,20 @@ function OverviewTab({ } + icon={} color="accent" /> } + icon={} color={memoryUsedPercent > 80 ? 'red' : memoryUsedPercent > 60 ? 'orange' : 'green'} /> } + icon={} color="blue" />
@@ -556,31 +581,31 @@ function OverviewTab({ } + icon={} color="accent" /> } + icon={} color="blue" /> } + icon={} color="green" /> } + icon={} color="purple" /> } + icon={} color="orange" /> @@ -650,7 +675,7 @@ function OverviewTab({ {devicesStats && (devicesStats.by_platform.length > 0 || devicesStats.by_app.length > 0) && (

- + {t('admin.remnawave.overview.devices', 'Устройства')} ·{' '} {devicesStats.total_hwid_devices} ({devicesStats.average_devices_per_user.toFixed(1)}/ {t('admin.remnawave.overview.perUser', 'юзер')}) @@ -717,7 +742,7 @@ function OverviewTab({ } + icon={} color="blue" /> } + icon={} color={health.event_loop_p99_ms > 50 ? 'red' : 'green'} /> } + icon={} color="accent" />

@@ -809,25 +834,25 @@ function NodesTab({ } + icon={} color="accent" /> } + icon={} color="green" /> } + icon={} color="red" /> } + icon={} color="accent" />