Adds an ONU info page and splits the ONU tab into two sub-tabs (Info / stats,
Fleet & upgrade). The ONU tab now lands on Info; campaign/verify keep the
Fleet sub-tab lit.
ONU info page (#view-onu-info): master-detail over the already-loaded fleet
(search + status filter, no new bulk fetch). Per-ONU detail shows identity,
link/optical + FEC (read from the merged ONU-STATE), firmware, and a CPE card.
CPE (customer router):
- McmsClient.getCpe — GET /api/cpe/onu/<id>/ (unversioned, [status,doc] tuple).
- src/cpe.js (pure, shared): summarizeCpe + leaseHealth. Renewal rule —
<50% of the lease remaining => "renewal overdue" (amber), past end =>
expired. v4 expiry = DHCP "Remove Time"; v6 spans Last Success ->
Preferred Lifetime (T1 midpoint), with Prefix Delegation surfaced.
- api:getOnuCpe (main.js + web/server.js, exposed in both bridges).
OUI vendor (src/oui.js, pure, shared): lazy fetch of the IEEE oui.csv,
prefix->org map, cached in memory ~30 days + best-effort to disk
(PFW_CACHE_DIR / temp; PrivateTmp makes /tmp writable). Resolved server-side
in getOnuCpe; every failure degrades to "unknown OUI". CPE itself is not
TTL-cached (lease must be live); only the OUI list is.
Dashboard abnormal Rx/Tx rows are now clickable -> deep-link to that ONU's
info page (showListModal gained per-item onClick).
Docs: CLAUDE.md §17 + IPC table + intro; README.
Verified: node --check; cpe.js/oui.js unit-tested (15/15: lease ok/warn/
expired/unknown + 50% boundary, v6 prefix parse, OUI quoted-CSV parse +
lookup); ONU info page + CPE card rendered offscreen over HTTP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generalises the OLT bulk tool from flood-mode-only to arbitrary NNI-service
edits. DHCP modes live nested under each NNI entry's Filter object
(Filter.DHCPv4 / Filter.DHCPv6, e.g. "pass" <-> "umt"), confirmed from a
real OLT-CFG paste-back.
- src/mcms-api.js: planFloodChange -> planNniEdit(oltCfg, {tagPattern, flood,
dhcpv4, dhcpv6}); each concern optional. DHCP is value-replacement,
replace-only-when-present (never invents the key; leaves EAPOL/PPPoE/NDP).
Still non-mutating (clones the entry AND the Filter). Returns changes with
per-entry edits[]. summarizeOltNniNetworks surfaces dhcpv4/dhcpv6; new
dhcpModeOfNni helper.
- main.js + web/server.js: executeFloodChange handler passes flood/dhcpv4/
dhcpv6 ops through (channel name kept for wire compat).
- renderer: OLT inspector now has three action dropdowns (Flooding / DHCPv4 /
DHCPv6, defaults flood private->auto + DHCP pass->umt); table shows DHCP
chips + per-service "will change (flood, DHCPv4, …)"; flood-mode filter
defaults to Any so DHCP-on-pass auto-flood OLTs still show; CSV report
lists every per-NNI edit (pon-olt-nni-*.csv).
Verified: node --check; planNniEdit unit-tested against the real fixture +
a pass variant (13/13: no-mutation, EAPOL/PPPoE/NDP preserved,
replace-when-present, flood/DHCP independence); OLT view rendered offscreen
showing correct per-service "will change" markers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web server's dashboardStats now reports how stale its shared cache
snapshot is — data.cache = { enabled, ttlMs, ageMs }, using the age of the
oldest dataset feeding the view (OLT-STATE, plus ONU-STATE under detailed
scan). cache.js gains ageOf(key).
The dashboard renders a live-ticking badge from it (renderCacheBadge):
- within TTL -> "◷ cached Ns ago" (info)
- past TTL -> same, warn-coloured (next load will refetch)
- no cache -> "● live" (Electron app, or PFW_CACHE_TTL_SECONDS=0)
The Dashboard Refresh button now sends fresh:true to bypass the cache and
reset the age; the detailed-stats toggle and auto-loads use the cache.
Shared renderer change, so the Electron app shows "live" (it sends no cache
field). Verified offscreen over HTTP: cached / stale / live states render
with the right text + colour.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructure the UI behind top-level tabs (Dashboard / ONU / OLT) so more
features have room to land. showView() now drives the active tab via a
VIEW_TO_TAB map, so sub-views (campaign/verify) keep the ONU tab lit.
Tabs appear on login (landing on Dashboard) and hide on logout.
Dashboard: a read-only network telemetry view modeled on the PONGo iOS
app's DashboardViewModel. New api:dashboardStats aggregates, all in
main.js (renderer just formats):
- counts: ONUs, OLTs, controllers (controllers best-effort via
/v3/controllers/configs/)
- aggregate traffic (OLT TX BW = downstream, RX BW = upstream)
- health: OLTs with laser off; abnormal-Rx count (rx < -28 || > -10)
- ONU registration-state breakdown (clicking a state deep-links to the
ONU tab pre-filtered)
- opt-in detailed scan: per-ONU optical + FEC-health distribution
fmtBps is a port of the iOS Format.bps.
Edge glow: #edge-glow draws a neon conic-gradient beam masked to a 3px
border ring and spins an @property --beam-angle 0->360deg, so a glow
travels around the screen edge. Honors prefers-reduced-motion.
mcms-api: add listAllControllerConfigs.
Docs: CLAUDE.md section 15 + README + IPC table.
Verified: npm run check passes; rendered the Dashboard + tabs + edge beam
offscreen (beam frozen on the right edge to confirm it follows the border).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a second bulk workflow alongside the firmware upgrader: changing
PON flooding mode (private<->auto) on OLT NNI services across many OLTs.
Flooding mode is encoded by the presence of the "PON FLOOD ID" key on
each OLT-CFG["NNI Networks"] entry (present = private, absent = auto).
private->auto deletes the key; auto->private sets it to 0. The rest of
the OLT-CFG is preserved (PUT-as-replace, same as ONU-CFG).
- src/mcms-api.js: listAllOltConfigs / getOltConfig / putOltConfig, plus
pure helpers floodModeOfNni, summarizeOltNniNetworks, planFloodChange
(planFloodChange clones and never mutates its input)
- main.js: api:listOlts + api:executeFloodChange IPC handlers
(concurrency 3, GET->plan->PUT, streams olt-flood:progress)
- preload.js: expose both channels + onFloodProgress
- renderer: OLT inspector view (#view-olts), two-step APPLY confirm,
auto-saved pon-olt-flood-*.csv result report
- Restore README.md (lost to a filesystem error) and document the new
feature in README.md and CLAUDE.md (new section 14)
Verified: npm run check passes; pure helpers unit-tested for the
no-mutation, idempotency, and rollback invariants.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>