diff --git a/templates/servers/view.twig b/templates/servers/view.twig
index c4165a0..3546b57 100644
--- a/templates/servers/view.twig
+++ b/templates/servers/view.twig
@@ -247,7 +247,8 @@
{% if clients|length > 0 %}
-
+
+
| {{ t('clients.name') }} |
@@ -375,6 +376,7 @@
{% endfor %}
+
{% else %}
{{ t('clients.no_clients') }}
{% endif %}
@@ -878,6 +880,39 @@ if (document.getElementById('cpuSparkline')) {
// Update client speeds
let clientCharts = {};
+function prepareSparklineSeries(values) {
+ const cleaned = values.map(v => {
+ const n = Number(v);
+ return Number.isFinite(n) && n > 0 ? n : 0;
+ });
+
+ const nonZero = cleaned.filter(v => v > 0).sort((a, b) => a - b);
+ let capped = cleaned;
+
+ // Suppress single extreme spikes that make the mini-chart unreadable.
+ if (nonZero.length >= 5) {
+ const p95Index = Math.floor((nonZero.length - 1) * 0.95);
+ const p95 = nonZero[p95Index] || 0;
+ const cap = p95 > 0 ? p95 * 2 : 0;
+ if (cap > 0) {
+ capped = cleaned.map(v => Math.min(v, cap));
+ }
+ }
+
+ // Small moving average to reduce jitter on tiny sparklines.
+ return capped.map((_, i, arr) => {
+ const from = Math.max(0, i - 1);
+ const to = Math.min(arr.length - 1, i + 1);
+ let sum = 0;
+ let count = 0;
+ for (let j = from; j <= to; j++) {
+ sum += arr[j];
+ count++;
+ }
+ return count > 0 ? sum / count : 0;
+ });
+}
+
async function updateClientSpeeds() {
const clientRows = document.querySelectorAll('[id^="client-speed-"]');
@@ -899,8 +934,10 @@ async function updateClientSpeeds() {
// 1. Render/Update Chart
if (canvas) {
const labels = metrics.map((_, i) => i);
- const dataUp = metrics.map(m => (parseFloat(m.speed_up_kbps) / 1000)); // Mbps
- const dataDown = metrics.map(m => (parseFloat(m.speed_down_kbps) / 1000)); // Mbps
+ const rawUp = metrics.map(m => (parseFloat(m.speed_up_kbps) / 1000)); // Mbps
+ const rawDown = metrics.map(m => (parseFloat(m.speed_down_kbps) / 1000)); // Mbps
+ const dataUp = prepareSparklineSeries(rawUp);
+ const dataDown = prepareSparklineSeries(rawDown);
if (clientCharts[clientId]) {
// Update existing chart