Add multi-user web server variant (browser UI behind a reverse proxy)

New web/ subfolder: a Node http server that serves the SAME tooling as the
Electron app to any browser, with per-session MCMS credentials so several
operators can use it at once behind a TLS reverse proxy. Mobile-responsive.

Not a fork — it reuses the core and the UI:
- serves renderer/app.js + app.css verbatim and rewrites index.html on the
  fly (mobile viewport + browser window.api shim + responsive overlay)
- web/public/api-web.js: a drop-in window.api over fetch + NDJSON streaming;
  Electron file dialogs -> <input type=file>, CSV-to-Downloads -> Blob
- web/server.js: per-session McmsClient (cookie pfw_sid), idle expiry,
  routes mirroring the IPC handlers, NDJSON for the 6 streaming ops
- pure Node http, no new deps (borrows ../node_modules tough-cookie)

Shared improvements (benefit both apps):
- src/dashboard.js: extracted, pure dashboard aggregation (main.js now uses
  it); adds abnormal-Tx detection alongside abnormal-Rx
- renderer: dashboard health stats are now clickable — abnormal Rx / Tx /
  lasers-off pop a list of the offending devices (like the iOS app), via a
  new showListModal

Docs: web/README.md (run + reverse-proxy + security), CLAUDE.md §16.

Verified: node --check all; started the server and confirmed transformed
index, shared-asset serving, 401 auth gate, login (per-session client), and
NDJSON wiring; rendered login + dashboard drilldown + mobile over HTTP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jon Vanvik 2026-06-23 14:07:23 +02:00
parent 9106e5a071
commit 96b0264179
10 changed files with 1096 additions and 109 deletions

53
web/public/web.css Normal file
View file

@ -0,0 +1,53 @@
/* Web-only overlay, loaded AFTER the shared renderer app.css. Two jobs:
(1) let the page scroll normally in a browser tab (the Electron layout
pins everything to 100vh), and (2) make it usable on phones/tablets. */
/* Tap targets a bit comfier for touch without changing the desktop look. */
button, .tab, .dash-row.tappable, .list-modal-item { -webkit-tap-highlight-color: transparent; }
/* ----- Tablet / phone ----- */
@media (max-width: 860px) {
html, body { height: auto; min-height: 100%; }
/* Topbar wraps; tabs drop to their own full-width row and scroll. */
.topbar { flex-wrap: wrap; gap: 8px 12px; padding: 10px 12px; }
.topbar .session { order: 2; font-size: 11px; }
#btn-logout { order: 2; }
.tabs {
order: 3;
margin-left: 0;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.tabs .tab { flex: 1 0 auto; }
/* Stack the two-pane layout vertically and let the document scroll. */
.view { flex-direction: column; height: auto; min-height: calc(100vh - 52px); }
.panel-left {
width: auto;
border-right: none;
border-bottom: 1px solid var(--border);
overflow: visible;
}
.panel-main { overflow: visible; }
/* Tables: keep columns readable by scrolling sideways, not squishing. */
.fleet-table-wrap { max-height: 70vh; }
.fleet-table { min-width: 720px; }
/* Dashboard tiles go single-column; modals near full-width. */
.dash-grid { grid-template-columns: 1fr; }
.dash-scroll { overflow: visible; }
.dash-traffic { gap: 24px; }
.modal, .list-modal { width: 94vw; }
#view-login { padding-top: 24px; }
.card { width: min(440px, 92vw); }
}
/* ----- Small phones ----- */
@media (max-width: 520px) {
.tile .tile-value { font-size: 28px; }
.dash-traffic .t-val { font-size: 22px; }
.topbar .brand { font-size: 13px; letter-spacing: 1px; }
}