Files
b.peck 83b23431c6 Phase 2: dashboard tabs + popups, chart fixes, shell relocation
Built via parallel Workflow (5 builders + adversarial verifiers), then
live-rendered and fixed in a headless browser against the running gateway.

Tabs (PrimeControls/Tabs/*):
- Overview: priority cards, KPI status row, alarm-rate timeline, insights, top-5
- Analysis: hour x day heatmap, priority donut vs ISA 80/15/5, MTTA/MTTR, floods
- BadActors: chattering/standing/fleeting tables, focus chip, AlarmDetail wiring
- Journal: paginated getJournalPage table, CSV export, EventDetail wiring

Popups (PrimeControls/Popups/*): HealthScore, ShiftReport, AlarmDetail, EventDetail

Chart fixes (verified rendering in-browser):
- Overview timeline: seeded dataSources.rate, switched to static fills, split
  flood bins into their own red stacked series (per-point deriveFieldsFromData
  fill was crashing render with React.cloneElement null).
- BadActors: removed the dual-axis Pareto XY chart (scaling was unusable);
  replaced with a ranked "Top Sources" table (share-of-total progress bar +
  cumulative %). Same insight, no axis scaling to break.

Structural / hygiene:
- Relocated Header + FilterBar from Dashboard/ to Shell/ and updated the two
  embed paths. A Perspective view cannot resolve sub-views nested inside another
  view's folder, so both were rendering as "view does not exist" placeholders.
- Set persistent:false on all view input params. persistent:true caused the
  gateway to bake the live bundle (with sim tag paths) into Tabs/Analysis on
  render; nulled that baked data and reset the session query range to 0.

lint_project.py: 0 failures / 0 warnings.

Verified in-browser: Overview, BadActors. NOT yet live-verified: Analysis,
Journal, and the four popups (schema-verified only). Header content is next
phase (renders now, but a benign cloneElement console warning remains).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 14:45:17 -05:00

319 lines
8.1 KiB
JSON

{
"custom": {},
"events": {
"system": {
"onStartup": {
"config": {
"script": "\tq = self.session.custom.PrimeControls.query\n\tif not q.startMs or q.startMs == 0:\n\t\tnow = system.date.toMillis(system.date.now())\n\t\tq.endMs = now\n\t\tq.startMs = now - 8 * 3600 * 1000\n\t\tq.rangePreset = '8h'"
},
"scope": "G",
"type": "script"
}
}
},
"params": {},
"propConfig": {
"custom.bundle": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.query.refreshToken} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs}"
},
"transforms": [
{
"code": "\tq = self.session.custom.PrimeControls.query\n\tif not q.startMs or not q.endMs:\n\t\treturn None\n\treturn PrimeControls.alarms.getDashboardBundle(q.startMs, q.endMs, {'priorities': list(q.priorities), 'areas': list(q.areas), 'states': list(q.states), 'search': q.search})",
"type": "script"
}
],
"type": "expr"
}
}
},
"props": {
"defaultSize": {
"height": 900,
"width": 1600
}
},
"root": {
"children": [
{
"meta": {
"name": "header"
},
"position": {
"basis": "150px",
"shrink": 0
},
"propConfig": {
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Shell/Header"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "filterBar"
},
"position": {
"basis": "56px",
"shrink": 0
},
"propConfig": {
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Shell/FilterBar"
},
"type": "ia.display.view"
},
{
"children": [
{
"meta": {
"name": "tabBtn0"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 0,
"title": "Overview"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn1"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 1,
"title": "Analysis"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn2"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 2,
"title": "Bad Actors"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBtn3"
},
"position": {
"basis": "140px",
"shrink": 0
},
"props": {
"params": {
"index": 3,
"title": "Journal"
},
"path": "PrimeControls/Components/TabButton"
},
"type": "ia.display.view"
}
],
"meta": {
"name": "tabBar"
},
"position": {
"basis": "42px",
"shrink": 0
},
"props": {
"style": {
"borderBottomColor": "var(--neutral-40)",
"borderBottomStyle": "solid",
"borderBottomWidth": "1px"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "tabOverview"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 0"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Tabs/Overview"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabAnalysis"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 1"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Tabs/Analysis"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabBadActors"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 2"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Tabs/BadActors"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "tabJournal"
},
"position": {
"grow": 1
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"expression": "{session.custom.PrimeControls.ui.selectedTab} = 3"
},
"type": "expr"
}
},
"props.params.bundle": {
"binding": {
"config": {
"path": "view.custom.bundle"
},
"type": "property"
}
}
},
"props": {
"path": "PrimeControls/Tabs/Journal"
},
"type": "ia.display.view"
}
],
"meta": {
"name": "tabContent"
},
"position": {
"grow": 1
},
"props": {
"direction": "column"
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"classes": "PrimeControls/PageBg",
"gap": "10px"
}
},
"type": "ia.container.flex"
}
}