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>
This commit is contained in:
2026-07-16 14:45:17 -05:00
parent ecb10b9b7b
commit 83b23431c6
30 changed files with 8678 additions and 312 deletions

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,269 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": false
}
},
"props": {
"defaultSize": {
"height": 56,
"width": 1600
}
},
"root": {
"children": [
{
"meta": {
"name": "ddPriority"
},
"position": {
"basis": "170px",
"shrink": 0
},
"propConfig": {
"props.options": {
"binding": {
"config": {
"path": "view.params.bundle.meta.priorities_seen"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn [{'value': p['value'], 'label': p['label']} for p in (value or [])]\n\texcept:\n\t\treturn []",
"type": "script"
}
],
"type": "property"
}
},
"props.value": {
"binding": {
"bidirectional": true,
"config": {
"path": "session.custom.PrimeControls.query.priorities"
},
"type": "property"
}
}
},
"props": {
"multiSelect": true,
"placeholder": {
"text": "Priority"
}
},
"type": "ia.input.dropdown"
},
{
"meta": {
"name": "ddArea"
},
"position": {
"basis": "170px",
"shrink": 0
},
"propConfig": {
"props.options": {
"binding": {
"config": {
"path": "view.params.bundle.meta.areas"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn [{'value': a, 'label': a} for a in (value or [])]\n\texcept:\n\t\treturn []",
"type": "script"
}
],
"type": "property"
}
},
"props.value": {
"binding": {
"bidirectional": true,
"config": {
"path": "session.custom.PrimeControls.query.areas"
},
"type": "property"
}
}
},
"props": {
"multiSelect": true,
"placeholder": {
"text": "Area"
}
},
"type": "ia.input.dropdown"
},
{
"meta": {
"name": "ddState"
},
"position": {
"basis": "170px",
"shrink": 0
},
"propConfig": {
"props.value": {
"binding": {
"bidirectional": true,
"config": {
"path": "session.custom.PrimeControls.query.states"
},
"type": "property"
}
}
},
"props": {
"multiSelect": true,
"options": [
{
"label": "Active",
"value": "active"
},
{
"label": "Cleared",
"value": "cleared"
},
{
"label": "Acked",
"value": "acked"
},
{
"label": "Unacked",
"value": "unacked"
}
],
"placeholder": {
"text": "State"
}
},
"type": "ia.input.dropdown"
},
{
"meta": {
"name": "txtSearch"
},
"position": {
"basis": "240px",
"shrink": 1
},
"propConfig": {
"props.text": {
"binding": {
"bidirectional": true,
"config": {
"path": "session.custom.PrimeControls.query.search"
},
"type": "property"
}
}
},
"props": {
"deferUpdates": true,
"placeholder": "Search source/label..."
},
"type": "ia.input.text-field"
},
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tq = self.session.custom.PrimeControls.query\n\tq.refreshToken = q.refreshToken + 1"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "btnApply"
},
"position": {
"basis": "80px",
"shrink": 0
},
"props": {
"primary": true,
"text": "Apply"
},
"type": "ia.input.button"
},
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tq = self.session.custom.PrimeControls.query\n\tq.priorities = []\n\tq.areas = []\n\tq.states = []\n\tq.search = ''\n\tq.refreshToken = q.refreshToken + 1"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "btnClear"
},
"position": {
"basis": "80px",
"shrink": 0
},
"props": {
"primary": false,
"text": "Clear"
},
"type": "ia.input.button"
},
{
"meta": {
"name": "lblEventCount"
},
"position": {
"grow": 1
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\tn = value['meta']['event_count']\n\texcept:\n\t\tn = None\n\tif n is None:\n\t\treturn ''\n\treturn '%s events in range' % PrimeControls.fmt.num(n)",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
},
"textStyle": {
"textAlign": "right"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"alignItems": "center",
"direction": "row",
"style": {
"classes": "PrimeControls/Toolbar",
"gap": "8px"
}
},
"type": "ia.container.flex"
}
}

View File

@@ -0,0 +1,10 @@
{
"scope": "G",
"version": 1,
"restricted": false,
"overridable": true,
"files": [
"view.json"
],
"attributes": {}
}

View File

@@ -0,0 +1,674 @@
{
"custom": {},
"params": {
"bundle": null
},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
"persistent": false
}
},
"props": {
"defaultSize": {
"height": 150,
"width": 1600
}
},
"root": {
"children": [
{
"children": [
{
"children": [
{
"meta": {
"name": "lblTitle"
},
"props": {
"style": {
"classes": "PrimeControls/Text/Big"
},
"text": "Alarm Analysis"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "lblSubtitle"
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted"
},
"text": "Prime Controls Build-a-Thon"
},
"type": "ia.display.label"
}
],
"meta": {
"name": "titles"
},
"position": {
"shrink": 0
},
"props": {
"direction": "column",
"justify": "center"
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "chipTruncated"
},
"position": {
"shrink": 0
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn bool(value['meta']['truncated'])\n\texcept:\n\t\treturn False",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted",
"color": "#E8883A"
},
"text": "data truncated \u2014 narrow the range"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "chipError"
},
"position": {
"shrink": 0
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn bool(value['meta']['error'])\n\texcept:\n\t\treturn False",
"type": "script"
}
],
"type": "property"
}
},
"props.text": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['meta']['error'] or ''\n\texcept:\n\t\treturn ''",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"style": {
"classes": "PrimeControls/Text/Muted",
"color": "#D64550"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "chips"
},
"position": {
"grow": 1
},
"props": {
"alignItems": "center",
"justify": "flex-end",
"style": {
"gap": "8px",
"paddingRight": "12px"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tspans = {'4h': 4, '8h': 8, '24h': 24, '7d': 168}\n\tpreset = event.value\n\tif preset in spans:\n\t\tq = self.session.custom.PrimeControls.query\n\t\tnow = system.date.toMillis(system.date.now())\n\t\tq.endMs = now\n\t\tq.startMs = now - spans[preset] * 3600 * 1000\n\t\tq.refreshToken = q.refreshToken + 1"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "ddRange"
},
"position": {
"basis": "150px",
"shrink": 0
},
"propConfig": {
"props.value": {
"binding": {
"bidirectional": true,
"config": {
"path": "session.custom.PrimeControls.query.rangePreset"
},
"type": "property"
}
}
},
"props": {
"options": [
{
"label": "Last 4 hours",
"value": "4h"
},
{
"label": "Last 8 hours",
"value": "8h"
},
{
"label": "Last 24 hours",
"value": "24h"
},
{
"label": "Last 7 days",
"value": "7d"
}
],
"placeholder": {
"text": "Range"
}
},
"type": "ia.input.dropdown"
},
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tq = self.session.custom.PrimeControls.query\n\tspans = {'4h': 4, '8h': 8, '24h': 24, '7d': 168}\n\tnow = system.date.toMillis(system.date.now())\n\thours = spans.get(q.rangePreset)\n\tif hours is not None:\n\t\tspan = hours * 3600 * 1000\n\telse:\n\t\tspan = q.endMs - q.startMs\n\tif span > 0:\n\t\tq.endMs = now\n\t\tq.startMs = now - span\n\tq.refreshToken = q.refreshToken + 1"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "btnRefresh"
},
"position": {
"basis": "90px",
"shrink": 0
},
"props": {
"primary": false,
"text": "Refresh"
},
"type": "ia.input.button"
},
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tsystem.perspective.openPopup('PC_ShiftReport', 'PrimeControls/Popups/ShiftReport', params = {}, showCloseIcon = True, draggable = True)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "btnShiftReport"
},
"position": {
"basis": "120px",
"shrink": 0
},
"props": {
"primary": true,
"text": "Shift Report"
},
"type": "ia.input.button"
}
],
"meta": {
"name": "controls"
},
"position": {
"shrink": 0
},
"props": {
"alignItems": "center",
"style": {
"gap": "8px"
}
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "rowTop"
},
"position": {
"basis": "52px",
"grow": 0,
"shrink": 0
},
"props": {
"alignItems": "center",
"justify": "space-between",
"style": {
"gap": "12px"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "gauge"
},
"position": {
"basis": "230px",
"shrink": 0
},
"propConfig": {
"props.params.health": {
"binding": {
"config": {
"path": "view.params.bundle.health"
},
"type": "property"
}
}
},
"props": {
"params": {},
"path": "PrimeControls/Components/HealthGauge"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiActivations"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['activations']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['activations']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Activations"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiRate"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['rate_per_hr']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['rate_per_hr']['value'], 1)\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Rate",
"unit": "/hr"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiActiveNow"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['active_now']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['active_now']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Active Now"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiUnacked"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['unacked_now']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['unacked_now']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Unacked"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiMtta"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['mtta_ms']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['kpis']['mtta_ms']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "MTTA"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiFlood"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['flood_pct']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.pct(value['kpis']['flood_pct']['value'], 1)\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Flood Time"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
},
{
"meta": {
"name": "kpiChatter"
},
"position": {
"basis": "100px",
"grow": 1
},
"propConfig": {
"props.params.delta": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['chatter_count']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
"type": "property"
}
},
"props.params.value": {
"binding": {
"config": {
"path": "view.params.bundle"
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['chatter_count']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
"type": "property"
}
}
},
"props": {
"params": {
"label": "Chattering"
},
"path": "PrimeControls/Components/KpiCard"
},
"type": "ia.display.view"
}
],
"meta": {
"name": "rowKpis"
},
"position": {
"grow": 1
},
"props": {
"alignItems": "stretch",
"style": {
"gap": "10px"
}
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"classes": "PrimeControls/Toolbar",
"gap": "8px"
}
},
"type": "ia.container.flex"
}
}