setExpanded((v) => !v) : undefined}
- >
- {/* Identity + actions */}
-
-
-
-
-
- {node.users_online ?? 0}
-
-
- {getCountryFlag(node.country_code)}
-
-
{node.name}
- {(providerLabel || providerFavicon) && (
-
- {providerFavicon && (
- {
- e.currentTarget.style.display = 'none';
- }}
- />
- )}
- {providerLabel && {providerLabel} }
+ <>
+ setExpanded((v) => !v) : undefined}
+ >
+ {/* Identity + actions */}
+
+
+
+
+
+ {node.users_online ?? 0}
- )}
-
+
+ {getCountryFlag(node.country_code)}
+
+
{node.name}
+ {(providerLabel || providerFavicon) && (
+
+ {providerFavicon && (
+ {
+ e.currentTarget.style.display = 'none';
+ }}
+ />
+ )}
+ {providerLabel && {providerLabel} }
+
+ )}
+
-
- {canGeoCheck && (
+
+ {canGeoCheck && (
+
{
+ e.stopPropagation();
+ setGeoCheckOpen(true);
+ }}
+ disabled={node.is_disabled || !node.is_connected}
+ className="rounded-lg bg-dark-700 p-1.5 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 disabled:cursor-not-allowed disabled:opacity-50"
+ title={t('admin.remnawave.geoCheck.title', 'GeoCheck')}
+ aria-label={t('admin.remnawave.geoCheck.title', 'GeoCheck')}
+ >
+
+
+ )}
{
e.stopPropagation();
- setGeoCheckOpen(true);
+ onAction(node.uuid, 'restart');
}}
- disabled={node.is_disabled || !node.is_connected}
+ disabled={isLoading || node.is_disabled}
className="rounded-lg bg-dark-700 p-1.5 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 disabled:cursor-not-allowed disabled:opacity-50"
- title={t('admin.remnawave.geoCheck.title', 'GeoCheck')}
- aria-label={t('admin.remnawave.geoCheck.title', 'GeoCheck')}
+ title={t('admin.remnawave.nodes.restart', 'Restart')}
>
-
+
- )}
-
{
- e.stopPropagation();
- onAction(node.uuid, 'restart');
- }}
- disabled={isLoading || node.is_disabled}
- className="rounded-lg bg-dark-700 p-1.5 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 disabled:cursor-not-allowed disabled:opacity-50"
- title={t('admin.remnawave.nodes.restart', 'Restart')}
- >
-
-
-
{
- e.stopPropagation();
- onAction(node.uuid, node.is_disabled ? 'enable' : 'disable');
- }}
- disabled={isLoading}
- className={`rounded-lg p-1.5 transition-colors disabled:opacity-50 ${
- node.is_disabled
- ? 'bg-success-500/20 text-success-400 hover:bg-success-500/30'
- : 'bg-error-500/20 text-error-400 hover:bg-error-500/30'
- }`}
- title={
- node.is_disabled
- ? t('admin.remnawave.nodes.enable', 'Enable')
- : t('admin.remnawave.nodes.disable', 'Disable')
- }
- >
- {node.is_disabled ? (
-
- ) : (
-
- )}
-
- {hasBreakdown && (
-
{
+ e.stopPropagation();
+ onAction(node.uuid, node.is_disabled ? 'enable' : 'disable');
+ }}
+ disabled={isLoading}
+ className={`rounded-lg p-1.5 transition-colors disabled:opacity-50 ${
+ node.is_disabled
+ ? 'bg-success-500/20 text-success-400 hover:bg-success-500/30'
+ : 'bg-error-500/20 text-error-400 hover:bg-error-500/30'
}`}
- />
- )}
-
-
-
- {/* Address + traffic + uptime */}
-
-
-
- {node.address}
-
-
- {formatBytes(used)}
- {trafficPct !== null && (
-
-
+ {node.is_disabled ? (
+
+ ) : (
+
+ )}
+
+ {hasBreakdown && (
+
+ )}
+
+
+
+ {/* Address + traffic + uptime */}
+
+
+
+ {node.address}
+
+
+ {formatBytes(used)}
+ {trafficPct !== null && (
+
+
+
+ )}
+ / {limit > 0 ? formatBytes(limit) : '∞'}
+
+ {node.xray_uptime > 0 && (
+
+
+ {formatUptime(node.xray_uptime)}
)}
- / {limit > 0 ? formatBytes(limit) : '∞'}
-
- {node.xray_uptime > 0 && (
-
-
- {formatUptime(node.xray_uptime)}
-
+
+
+ {/* Live metrics — mobile: 3 fixed rows so wrapping speeds don't reflow;
+ desktop (sm+): the original single wrap row, wide enough not to jump. */}
+ {(ramPct !== null || loadAvg || rx > 0 || tx > 0 || node.versions) && (
+ <>
+ {/* Mobile: processor · traffic · versions */}
+
+ {(loadAvg || ramPct !== null) && (
+
+ {loadAvg && (
+
+
+ {loadAvg}
+
+ )}
+ {ramPct !== null && (
+
+
+ {ramPct}%
+
+
+
+
+ )}
+
+ )}
+ {(rx > 0 || tx > 0) && (
+
+
+
+ {formatSpeed(rx)}
+
+
+
+ {formatSpeed(tx)}
+
+
+ )}
+ {(node.versions?.node || node.versions?.xray) && (
+
+ {node.versions?.node && (
+
+
+ {node.versions.node}
+
+ )}
+ {node.versions?.xray && (
+
+
+ {node.versions.xray}
+
+ )}
+
+ )}
+
+
+ {/* Desktop: single wrap row (original) */}
+
+ {ramPct !== null && (
+
+
+ {ramPct}%
+
+
+
+
+ )}
+ {loadAvg && (
+
+
+ {loadAvg}
+
+ )}
+
+
+
+ {formatSpeed(rx)}
+
+
+
+ {formatSpeed(tx)}
+
+
+ {(node.versions?.node || node.versions?.xray) && (
+
+ {node.versions?.node && (
+
+
+ {node.versions.node}
+
+ )}
+ {node.versions?.xray && (
+
+
+ {node.versions.xray}
+
+ )}
+
+ )}
+
+ >
+ )}
+
+ {/* Per-node traffic accordion (merged from the former Traffic tab) */}
+ {expanded && hasBreakdown && (
+ e.stopPropagation()}
+ >
+ {inbounds.length > 0 && (
+
+ )}
+ {outbounds.length > 0 && (
+
+ )}
+
)}
- {/* Live metrics — mobile: 3 fixed rows so wrapping speeds don't reflow;
- desktop (sm+): the original single wrap row, wide enough not to jump. */}
- {(ramPct !== null || loadAvg || rx > 0 || tx > 0 || node.versions) && (
- <>
- {/* Mobile: processor · traffic · versions */}
-
- {(loadAvg || ramPct !== null) && (
-
- {loadAvg && (
-
-
- {loadAvg}
-
- )}
- {ramPct !== null && (
-
-
- {ramPct}%
-
-
-
-
- )}
-
- )}
- {(rx > 0 || tx > 0) && (
-
-
-
- {formatSpeed(rx)}
-
-
-
- {formatSpeed(tx)}
-
-
- )}
- {(node.versions?.node || node.versions?.xray) && (
-
- {node.versions?.node && (
-
-
- {node.versions.node}
-
- )}
- {node.versions?.xray && (
-
-
- {node.versions.xray}
-
- )}
-
- )}
-
-
- {/* Desktop: single wrap row (original) */}
-
- {ramPct !== null && (
-
-
- {ramPct}%
-
-
-
-
- )}
- {loadAvg && (
-
-
- {loadAvg}
-
- )}
-
-
-
- {formatSpeed(rx)}
-
-
-
- {formatSpeed(tx)}
-
-
- {(node.versions?.node || node.versions?.xray) && (
-
- {node.versions?.node && (
-
-
- {node.versions.node}
-
- )}
- {node.versions?.xray && (
-
-
- {node.versions.xray}
-
- )}
-
- )}
-
- >
- )}
-
- {/* Per-node traffic accordion (merged from the former Traffic tab) */}
- {expanded && hasBreakdown && (
-
e.stopPropagation()}
- >
- {inbounds.length > 0 && (
-
- )}
- {outbounds.length > 0 && (
-
- )}
-
- )}
-
{geoCheckOpen &&
setGeoCheckOpen(false)} />}
-