A NOC wall is the hardest kind of dashboard to build well. Nineteen panels, one stream of events, every panel wanting a different cut of the same data, and all of it updating every second without a repaint storm. Most teams end up with a data layer per panel, a timer per chart and a pile of glue code nobody wants to touch.
This demo does it with one page, one data feed and no glue. It is live at https://toclocoinc.github.io/lattice-grid-demo-noc-umd/ and the source is public at https://github.com/toclocoinc/lattice-grid-demo-noc-umd. Everything below is in that repository.
The wall
The page is a 20 by 20 layout of movable, resizable windows. A branding tile and six KPI tiles run along the top, with two clocks for London and New York. Underneath sit a world map of sites, a core network topology, the active alarms grid, service health, network traffic, link utilisation, incident trend, a site status donut, the top affected sites and a scrolling alarm ticker.
Every one of those windows is fed by the same stream. That is the point of the demo.
The layout component
The layout module gives you a grid of windows and nothing else to think about. Each window is declared with an id, a title, a position and a size:
{ id: 'map', title: 'Global network overview', xPos: 1, yPos: 3, xSize: 8, ySize: 9 }
The module renders the chrome, handles drag, resize, maximise and close, and hands you a body element per window (<id>-body). You mount whatever you like into it: a grid, a chart, a KPI tile, a plain div. Windows that should not move, such as the branding tile, are simply declared movable: false.
There is no framework in the page. It is plain HTML, a handful of script tags from the CDN, and one script block.
The data router
The data router is where the wall stops being nineteen problems and becomes one. Every event in the feed carries a kind: site, alarm, service, sample, element, chip or metric. The router is created once, keyed on that field:
createDataRouter({ key: 'kind', rowKey: 'id', overlap, batch, coalesce })
Then each viewer attaches to the route it wants, before the stream starts:
data.attach(alarmGrid, 'alarm')
data.attach(siteGrid, 'site')
data.attach(serviceGrid, 'service')
data.attach(trafficGrid, 'sample')
That is all the wiring. A row with an existing id is an upsert. Bursts are coalesced. A grid attached to the alarm route gets only alarms, the site grid gets only sites, and neither knows the other exists. When a BGP session flaps for the fourth time the alarm row escalates in place, the KPI counting active incidents ticks up, the ticker prints the update and the incident trend adds a bar. Nobody wrote code to keep those in step.
The best part is derived sources. A chart that wants "the five busiest links" does not need a second feed. It sits on a derived grid:
source: { mode: 'derived', from: linkGrid, sort: [['load', 'desc']], limit: 5 }
The site status donut is a derived grid grouped by status with a count. The top affected sites panel is a derived grid over the alarm grid, grouped by site. Each is a viewer of a viewer, and they stay live for free.
The charts
Six chart types share the wall, and each one is a viewer of a grid, so the charts never hold data of their own.
- World map of every site, drawn with the world geometry pack, marker colour by availability, label by city.
- Network topology with pinned nodes for the internet edge, two cloud regions, four core routers and four regions. Nodes are glyphs from the icon registry, links are coloured by utilisation rules.
- Link utilisation as horizontal bars, coloured by the same rules and labelled with the value.
- Network traffic as a line chart of the sample route, one series per direction.
- Incident trend as a stacked bar per minute, one series per raised severity, on a rolling time axis.
- Site status donut with a named colour scheme, a legend with counts and the total in the centre.
The service health grid uses the grid itself as a chart surface: an icon per service, availability coloured as text by SLA rule, and a sparkline cell rendered from the last few readings. An alarms module sits on that grid and raises its own alarm when availability drops below the SLA thresholds, which feeds the same ticker as the network alarms.
Colour rules are declared once as formatting rules and shared. When a link goes amber in the topology it goes amber in the bar chart, because it is the same rule.
The data source
The feed is real. The backbone is a real carrier (AS3257), its sites are the carrier's PeeringDB facilities, so the world map shows real cities with real coordinates. Route updates come from RIPE RIS Live, the public BGP stream from RIPE's collectors. Internet outage detections come from IODA at Georgia Tech.
Live BGP does not make for a reliable public demo, so the page ships with a ten minute recording of the RIS stream and replays it in a loop. The replay is stamped with the wall clock as it plays, so the per-minute incident trend and the alarm ages behave as though the events were arriving now. The page also supports a live mode that opens the RIS websocket and reads PeeringDB directly, and a simulated mode for offline use.
All of that is in a single data file that produces the events. The router does not care which mode is running.
What the demo drove
Building the wall in public found gaps worth closing, and they shipped in the same week. The geometry packs and every chart gained UMD and CommonJS builds so the map works from a script tag (1.71.1). Bars can be coloured by rule and labelled (1.71.1). Chart series can be coloured by name, legends can show counts and a donut can carry a centre value (1.71.3). Each of those is in the demo today.
Try it
Open the live page, drag the windows around, and watch the alarms grid and the ticker for a minute. Then read the page source. It is one file, and the wiring is shorter than this post.
Live demo: https://toclocoinc.github.io/lattice-grid-demo-noc-umd/
Source: https://github.com/toclocoinc/lattice-grid-demo-noc-umd
Lattice Grid: https://www.latticegrid.dev
Top comments (0)