From 431e89493af271cb96a18e2a844841d7887a476f Mon Sep 17 00:00:00 2001 From: dborup Date: Fri, 16 Oct 2026 11:03:21 +0200 Subject: [PATCH 1/3] fix(perf): theme the WebSocket-history Period select like Analytics The Period control on #/perf had only inline min-height/padding, so the browser drew its native grey box (hardcoded system colours, square corners, 13.3px/400) next to themed cards, and the "Period" text was body-sized. - Rename .analytics-time-window-select to .time-window-select and use it for Analytics (time window + scatter axes) and the Perf Period select: one definition of the control. - "Period" uses the existing .region-filter-label, as "Region:" does on Analytics; the heading gets the chart-line icon like other sections. - Touch screens (pointer: coarse) get a 44px select, Analytics included. Tests: unit checks for class/no-inline-style/icon and the shared CSS rule; Playwright compares the computed Period style with the real Analytics select in light and dark, and asserts a 44px touch target. Co-Authored-By: Claude Opus 5.5 --- public/analytics.js | 6 +++--- public/perf.js | 3 ++- public/style.css | 8 ++++++-- test-perf-ws-clients.js | 26 ++++++++++++++++++++++++++ test-perf-ws-history-e2e.js | 27 +++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/public/analytics.js b/public/analytics.js index 355724dd1..7ef877b3a 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -216,7 +216,7 @@
- @@ -3194,10 +3194,10 @@

Units — Usefulness: the #672 composite (0.30 bridge + 0.25 coverage + 0.25 redundancy + 0.20 traffic). Traffic share: % of non-advert traffic relayed. Bridge/Coverage/Redundancy: 0–100% (network-normalized). Relays (1h/24h) and Adverts: packet counts. Axes auto-scale to the data.

${points.length} repeater${points.length === 1 ? '' : 's'}
diff --git a/public/perf.js b/public/perf.js index 26f1f2fd5..ad1ded1fa 100644 --- a/public/perf.js +++ b/public/perf.js @@ -297,7 +297,8 @@ function renderVersionCard(health) { // rebuild, preserving keyboard focus and an open native select menu. app.innerHTML = '

Performance Dashboard

' + '
' + - '

WebSocket clients

' + '
Loading history…
Loading...
'; const selector = document.getElementById('wsHistoryRange'); diff --git a/public/style.css b/public/style.css index e55500588..ddffe07bf 100644 --- a/public/style.css +++ b/public/style.css @@ -3714,12 +3714,16 @@ button.region-pill-active:hover { opacity: 0.85; color: var(--text-on-accent); } margin-right: 2px; user-select: none; white-space: nowrap; flex-shrink: 0; } .analytics-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0; } -.analytics-time-window-select { +/* The one time-window / metric ]*>/) || [''])[0]; + assert.ok(/class="time-window-select"/.test(select), 'select must use .time-window-select: ' + select); + assert.ok(!/style=/.test(select), 'select must not carry inline styles: ' + select); + assert.ok(/Period<\/span>/.test(appHtml), 'label text must use .region-filter-label'); + const heading = (appHtml.match(/

[\s\S]*?<\/h3>/) || [''])[0]; + assert.ok(/
+
${escapeHtml(server.totalRequests)}
Total Requests
+
${escapeHtml(server.avgMs)}ms
Avg Response
+
${escapeHtml(health ? health.uptimeHuman : Math.round(server.uptime / 60) + 'm')}
Uptime
+
${server.slowQueries.length}
Slow (>100ms)
+ ${renderVersionCard(health)} +
`; + } + async function render(app) { // The selector stays outside perfContent's existing five-second DOM // rebuild, preserving keyboard focus and an open native select menu. - app.innerHTML = '

Performance Dashboard

' + + app.innerHTML = '

Performance Dashboard

' + '
' + '

WebSocket clients

' + '