ponfw/preload.js
Jon Vanvik 276c3e9faa onu detail: parent OLT + LLDP switch + traffic history + alarms + UNI; single-ONU upgrade
De-compacts the ONU info page into a responsive card grid and enriches it
with one new endpoint (api:getOnuDetail) summarized by the pure, shared
src/onudetail.js:
- Parent OLT (name/model/FW/PON) — follows the OLT MAC from the ONU
  alarm-history doc to its OLT-CFG.
- Upstream switch (LLDP neighbour of the OLT NNI) from the alarm-history
  Switch block: system name, port, IPv4, chassis.
- Traffic (last ~hour) with current + peak down/up and inline SVG
  sparklines, from /onus/stats/ (down = OLT TX rate, up = OLT RX rate).
- UNI-ETH ports (speed/duplex/enable) + last Ethernet LOS (LAN-LOS alarm).
- Alarms: active-first, severity-sorted with raised counts + last raised.
- CPE card folded into the same single fetch.

New client methods getOnuAlarms + getOnuStatsSeries; api:getOnuDetail in
main.js + web/server.js, exposed in both bridges. Not TTL-cached (live).

Single-ONU upgrade: the Firmware card gets a firmware picker + "Upgrade this
ONU" button reusing the bulk per-ONU path (executePerOnu with one id,
Procedure 7 inactive-bank write), behind a typed UPGRADE confirm; refreshes
the detail on success.

Docs: CLAUDE.md §17 + §5.11 (stats endpoint now used for the sparkline) +
IPC table.

Verified: node --check; onudetail.js unit-tested 11/11 against the real
alarm-history / cfg / stats / OLT-cfg fixtures (firmware banks, UNI, alarm
sort, LAN-LOS, OLT active-bank FW, LLDP switch, traffic skip-nontraffic +
down/up mapping + current/peak); card grid rendered offscreen (9 cards, 2
sparklines, upgrade button).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:47:50 +02:00

82 lines
3.1 KiB
JavaScript

// Preload: the only bridge between renderer and main. Everything the UI
// can do is enumerated here — the renderer has no direct node access.
const { contextBridge, ipcRenderer } = require('electron');
function call(channel, args) {
return ipcRenderer.invoke(channel, args);
}
contextBridge.exposeInMainWorld('api', {
login: (opts) => call('api:login', opts),
logout: () => call('api:logout'),
listOnuConfigs: (opts) => call('api:listOnuConfigs', opts),
listFleet: (opts) => call('api:listFleet', opts),
fetchStates: (opts) => call('api:fetchStates', opts),
getOnuConfig: (opts) => call('api:getOnuConfig', opts),
getOnuCpe: (opts) => call('api:getOnuCpe', opts),
getOnuDetail: (opts) => call('api:getOnuDetail', opts),
listOnuFirmware: () => call('api:listOnuFirmware'),
uploadFirmware: () => call('api:uploadFirmware'),
planUpgrade: (opts) => call('api:planUpgrade', opts),
executePerOnu: (opts) => call('api:executePerOnu', opts),
executeBulkTask: (opts) => call('api:executeBulkTask', opts),
getTaskConfig: (opts) => call('api:getTaskConfig', opts),
getUpgradeStatus: (opts) => call('api:getUpgradeStatus', opts),
deleteOnus: (opts) => call('api:deleteOnus', opts),
dashboardStats: (opts) => call('api:dashboardStats', opts),
listOlts: (opts) => call('api:listOlts', opts),
executeFloodChange: (opts) => call('api:executeFloodChange', opts),
onFloodProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('olt-flood:progress', fn);
return () => ipcRenderer.removeListener('olt-flood:progress', fn);
},
fetchFecHealth: (opts) => call('api:fetchFecHealth', opts),
fetchOnuSnapshot: (opts) => call('api:fetchOnuSnapshot', opts),
savePlanCsv: (opts) => call('api:savePlanCsv', opts),
saveCsvFile: (opts) => call('api:saveCsvFile', opts),
openCsvFile: () => call('api:openCsvFile'),
// Streaming FEC pre-flight progress (one event per ONU resolved).
onFecProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('fec:progress', fn);
return () => ipcRenderer.removeListener('fec:progress', fn);
},
// Streaming verify-snapshot progress.
onVerifyProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('verify:progress', fn);
return () => ipcRenderer.removeListener('verify:progress', fn);
},
// Live progress events from the main process while executePerOnu runs.
onUpgradeProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('upgrade:progress', fn);
return () => ipcRenderer.removeListener('upgrade:progress', fn);
},
// Streaming state-fetch progress (Equipment ID population).
onStatesProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('states:progress', fn);
return () => ipcRenderer.removeListener('states:progress', fn);
},
// Streaming delete progress.
onDeleteProgress: (handler) => {
const fn = (_ev, payload) => handler(payload);
ipcRenderer.on('delete:progress', fn);
return () => ipcRenderer.removeListener('delete:progress', fn);
},
});