Data seeding, filter overhaul, UI scaling fixes, sanitized AlarmAnalysis copy

Data & simulation:
- simulation_tags.json: re-prioritize 10 tags to Medium so all four
  priorities appear in live data (backfilled journal history to match)
- SimHarness probe P2: ack-user/includeData ground truth + filtered-bundle
  verification against the live journal

Data layer (PrimeControls.calc/alarms):
- filters now drive every metric: queryStatus rows (Active Now/Unacked/
  Standing) filtered via calc.apply_status_filters; event_count counts only
  filtered instances (per-instance n_events); dropdown options enumerate
  unfiltered data so choices never collapse
- build_bundle refactored into _assemble(); when filters are active an
  unfiltered mirror is attached as bundle.overview - the Overview tab stays
  a plant-wide summary while all other consumers bind filtered sections
- _fetch_journal now honors includeData (required for ackUserName; without
  it ack attribution is always None); enabled for journal rows + source
  detail so Top Ack Users and the Ack By column populate

FilterBar/Dashboard:
- root-cause fix: bidirectional bindings never wrote dropdown selections
  back to session props, so filters silently did nothing; Apply now pulls
  values directly from the sibling controls, Clear resets both
- multi-select dropdowns cap at 280px and wrap chips; filter bar row is
  auto-height so wrapped chips push tabs down instead of overlapping
- filter bar hidden on the Overview tab (not applicable there)

UI scaling:
- Header: Prime logo added; KpiCard compacted to fit the 71px KPI row
  (basis-95% overflow fix, chip hugs text, embeds clipped) - no scrollbars
- Overview timeline: thinned x labels (minDistance 140), labels anchored
  below the axis, smaller legend markers
- Bad Actors focus chip shows the full source string with the clear X
- popup repeaters (Daily Activity, ScoreBars) no longer overflow
  (useDefaultViewWidth/Height off, taller strip); 5px table cell padding

Tooling/tests:
- lint_project.py: accept propConfig params.* as param declarations
  (Designer saves strip null params entries)
- tests: 31 -> 34 (status-filter semantics, overview mirror, filtered
  event counts)
- .gitignore: runtime churn (valueStore.idb, local-system-properties,
  migration logs, thumbnails, .schemas)

New project: AlarmAnalysis - submission copy of PrimeBAT with client-visible
Prime Controls branding removed (logo, subtitle, project title, shift report
heading); PrimeControls organizational namespaces retained per spec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 16:27:48 -05:00
parent b70b4d6991
commit d353c5001e
165 changed files with 13988 additions and 525 deletions

View File

@@ -2343,6 +2343,11 @@
},
"selection": {
"enableRowSelection": false
},
"cells": {
"style": {
"padding": "5px"
}
}
},
"type": "ia.display.table"
@@ -2455,4 +2460,4 @@
},
"type": "ia.container.flex"
}
}
}

View File

@@ -4,7 +4,14 @@
"restricted": false,
"overridable": true,
"files": [
"view.json"
"view.json",
"thumbnail.png"
],
"attributes": {}
}
"attributes": {
"lastModificationSignature": "7504c7695ab45f2fc1d0d6dc8071e96746ac068f99e878d3ca1dcf804c9eea76",
"lastModification": {
"actor": "admin",
"timestamp": "2026-07-16T20:38:41Z"
}
}
}

View File

@@ -1,8 +1,6 @@
{
"custom": {},
"params": {
"bundle": null
},
"params": {},
"propConfig": {
"params.bundle": {
"paramDirection": "input",
@@ -11,7 +9,6 @@
},
"props": {
"defaultSize": {
"height": 800,
"width": 1600
}
},
@@ -151,6 +148,11 @@
}
},
"props": {
"cells": {
"style": {
"padding": "5px"
}
},
"columns": [
{
"field": "source",
@@ -206,15 +208,15 @@
"header": {
"title": "Share of Total"
},
"render": "number",
"number": "progress",
"progressBar": {
"min": 0,
"max": 100,
"bar": {
"color": "#3B7DD8"
}
},
"max": 100,
"min": 0
},
"render": "number",
"width": 2.4
},
{
@@ -228,8 +230,7 @@
}
],
"pager": {
"bottom": false,
"top": false
"bottom": false
},
"rows": {
"height": 34
@@ -275,8 +276,7 @@
},
"position": {
"basis": "320px",
"grow": 1,
"shrink": 1
"grow": 1
},
"props": {
"direction": "column",
@@ -316,9 +316,16 @@
}
},
"props": {
"text": ""
"style": {
"whiteSpace": "nowrap"
}
},
"type": "ia.display.label"
"type": "ia.display.label",
"position": {
"basis": "auto",
"grow": 0,
"shrink": 0
}
},
{
"events": {
@@ -336,6 +343,7 @@
"name": "icoClearFocus"
},
"position": {
"basis": "20px",
"shrink": 0
},
"props": {
@@ -491,6 +499,11 @@
}
},
"props": {
"cells": {
"style": {
"padding": "5px"
}
},
"columns": [
{
"field": "source",
@@ -552,8 +565,7 @@
}
],
"pager": {
"bottom": false,
"top": false
"bottom": false
},
"rows": {
"height": 34
@@ -695,6 +707,11 @@
}
},
"props": {
"cells": {
"style": {
"padding": "5px"
}
},
"columns": [
{
"field": "source",
@@ -746,8 +763,7 @@
}
],
"pager": {
"bottom": false,
"top": false
"bottom": false
},
"rows": {
"height": 34
@@ -904,6 +920,11 @@
}
},
"props": {
"cells": {
"style": {
"padding": "5px"
}
},
"columns": [
{
"field": "source",
@@ -956,8 +977,7 @@
}
],
"pager": {
"bottom": false,
"top": false
"bottom": false
},
"rows": {
"height": 34
@@ -1020,11 +1040,9 @@
},
"position": {
"basis": "280px",
"grow": 1,
"shrink": 1
"grow": 1
},
"props": {
"alignItems": "stretch",
"style": {
"gap": "12px"
}
@@ -1063,7 +1081,6 @@
"type": "ia.container.flex"
}
],
"custom": {},
"meta": {
"name": "root"
},
@@ -1075,4 +1092,4 @@
},
"type": "ia.container.flex"
}
}
}

View File

@@ -408,6 +408,11 @@
"pager": {
"bottom": false,
"top": false
},
"cells": {
"style": {
"padding": "5px"
}
}
},
"type": "ia.display.table"
@@ -471,4 +476,4 @@
},
"type": "ia.container.flex"
}
}
}

View File

@@ -32,7 +32,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn not (int(value['meta']['event_count']) > 0)\n\texcept:\n\t\treturn True",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn not (int(value['meta']['event_count']) > 0)\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -67,7 +67,7 @@
},
"transforms": [
{
"code": "\trows = []\n\ttry:\n\t\tfor r in (value['priority']['raw'] or []):\n\t\t\ttry:\n\t\t\t\trows.append({'name': r['name'], 'level': int(r['level']), 'count': int(r['count'])})\n\t\t\texcept:\n\t\t\t\tpass\n\texcept:\n\t\trows = []\n\trows.sort(key=lambda r: -r['level'])\n\ttotal = 0\n\tfor r in rows:\n\t\ttotal = total + r['count']\n\tout = []\n\tfor r in rows:\n\t\tif total > 0:\n\t\t\tp = 100.0 * r['count'] / total\n\t\telse:\n\t\t\tp = 0.0\n\t\tout.append({'priority_name': r['name'], 'count': r['count'], 'pct': p})\n\treturn out",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\trows = []\n\ttry:\n\t\tfor r in (value['priority']['raw'] or []):\n\t\t\ttry:\n\t\t\t\trows.append({'name': r['name'], 'level': int(r['level']), 'count': int(r['count'])})\n\t\t\texcept:\n\t\t\t\tpass\n\texcept:\n\t\trows = []\n\trows.sort(key=lambda r: -r['level'])\n\ttotal = 0\n\tfor r in rows:\n\t\ttotal = total + r['count']\n\tout = []\n\tfor r in rows:\n\t\tif total > 0:\n\t\t\tp = 100.0 * r['count'] / total\n\t\telse:\n\t\t\tp = 0.0\n\t\tout.append({'priority_name': r['name'], 'count': r['count'], 'pct': p})\n\treturn out",
"type": "script"
}
],
@@ -110,7 +110,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['active_now']\n\texcept:\n\t\treturn None",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn value['kpis']['active_now']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
@@ -124,7 +124,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['active_now']['value'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['active_now']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
@@ -156,7 +156,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['unacked_now']\n\texcept:\n\t\treturn None",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn value['kpis']['unacked_now']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
@@ -170,7 +170,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['unacked_now']['value'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['unacked_now']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
@@ -202,7 +202,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['shelved_now']\n\texcept:\n\t\treturn None",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn value['kpis']['shelved_now']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
@@ -216,7 +216,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['shelved_now']['value'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['shelved_now']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
@@ -248,7 +248,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['kpis']['standing_count']\n\texcept:\n\t\treturn None",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn value['kpis']['standing_count']\n\texcept:\n\t\treturn None",
"type": "script"
}
],
@@ -262,7 +262,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['standing_count']['value'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn PrimeControls.fmt.num(value['kpis']['standing_count']['value'])\n\texcept:\n\t\treturn '--'",
"type": "script"
}
],
@@ -361,7 +361,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['rate']['bins']) > 0\n\texcept:\n\t\treturn False",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn len(value['rate']['bins']) > 0\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -375,7 +375,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\trate = value['rate']\n\t\tbins = rate['bins'] or []\n\texcept:\n\t\treturn []\n\ttry:\n\t\ttarget = float(rate['target_per_bin'])\n\texcept:\n\t\ttarget = None\n\ttry:\n\t\tuse_day = float(value['meta']['window_hours']) > 24\n\texcept:\n\t\tuse_day = False\n\tout = []\n\tfor b in bins:\n\t\ttry:\n\t\t\tt0 = b['t0']\n\t\t\tc = int(b['count'])\n\t\texcept:\n\t\t\tcontinue\n\t\ttry:\n\t\t\tflood = bool(b['flood'])\n\t\texcept:\n\t\t\tflood = False\n\t\tif use_day:\n\t\t\tlbl = PrimeControls.fmt.day_clock(t0)\n\t\telse:\n\t\t\tlbl = PrimeControls.fmt.clock(t0)\n\t\trow = {'t': lbl, 'count_base': (0 if flood else c), 'count_flood': (c if flood else 0)}\n\t\tif target is not None:\n\t\t\trow['target'] = target\n\t\tout.append(row)\n\treturn out",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\trate = value['rate']\n\t\tbins = rate['bins'] or []\n\texcept:\n\t\treturn []\n\ttry:\n\t\ttarget = float(rate['target_per_bin'])\n\texcept:\n\t\ttarget = None\n\ttry:\n\t\tuse_day = float(value['meta']['window_hours']) > 24\n\texcept:\n\t\tuse_day = False\n\tout = []\n\tfor b in bins:\n\t\ttry:\n\t\t\tt0 = b['t0']\n\t\t\tc = int(b['count'])\n\t\texcept:\n\t\t\tcontinue\n\t\ttry:\n\t\t\tflood = bool(b['flood'])\n\t\texcept:\n\t\t\tflood = False\n\t\tif use_day:\n\t\t\tlbl = PrimeControls.fmt.day_clock(t0)\n\t\telse:\n\t\t\tlbl = PrimeControls.fmt.clock(t0)\n\t\trow = {'t': lbl, 'count_base': (0 if flood else c), 'count_flood': (c if flood else 0)}\n\t\tif target is not None:\n\t\t\trow['target'] = target\n\t\tout.append(row)\n\treturn out",
"type": "script"
}
],
@@ -426,7 +426,7 @@
"labels": {
"font": {
"color": "",
"size": 16,
"size": 12,
"weight": 400
},
"text": "[bold]{name}[/]"
@@ -439,14 +439,14 @@
"topRight": 0
},
"enabled": true,
"height": 20,
"height": 12,
"icon": {
"color": "",
"height": 20,
"height": 12,
"horizontalCenter": "left",
"path": "",
"verticalCenter": "top",
"width": 20
"width": 12
},
"mirrorLookOfSeries": true,
"stroke": {
@@ -454,7 +454,7 @@
"opacity": 0,
"width": 1
},
"width": 20
"width": 12
},
"position": "bottom"
},
@@ -1301,13 +1301,13 @@
{
"appearance": {
"font": {
"size": "",
"size": 11,
"weight": 500
},
"grid": {
"color": "",
"dashArray": "",
"minDistance": 60,
"minDistance": 140,
"opacity": 0,
"position": 0.5
},
@@ -1317,7 +1317,7 @@
"horizontalCenter": "middle",
"opacity": 1,
"rotation": 0,
"verticalCenter": "middle"
"verticalCenter": "top"
},
"opposite": false
},
@@ -1390,7 +1390,7 @@
{
"appearance": {
"font": {
"size": "",
"size": 11,
"weight": 500
},
"grid": {
@@ -1496,7 +1496,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['rate']['bins']) == 0\n\texcept:\n\t\treturn True",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn len(value['rate']['bins']) == 0\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -1565,7 +1565,7 @@
},
"transforms": [
{
"code": "\tout = []\n\ttry:\n\t\trows = value['insights'] or []\n\texcept:\n\t\trows = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tout.append({'severity': int(r['severity']), 'icon': r['icon'], 'text': r['text'], 'tab': r['tab']})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\tout = []\n\ttry:\n\t\trows = value['insights'] or []\n\texcept:\n\t\trows = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tout.append({'severity': int(r['severity']), 'icon': r['icon'], 'text': r['text'], 'tab': r['tab']})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"type": "script"
}
],
@@ -1605,7 +1605,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['insights']) == 0\n\texcept:\n\t\treturn True",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn len(value['insights']) == 0\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -1671,7 +1671,7 @@
},
"transforms": [
{
"code": "\tout = []\n\ttry:\n\t\trows = value['top_sources'] or []\n\texcept:\n\t\trows = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tout.append({'rank': int(r['rank']), 'source': r['source'], 'label': r['label'], 'count': int(r['count']), 'pct': float(r['pct'])})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\tout = []\n\ttry:\n\t\trows = value['top_sources'] or []\n\texcept:\n\t\trows = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tout.append({'rank': int(r['rank']), 'source': r['source'], 'label': r['label'], 'count': int(r['count']), 'pct': float(r['pct'])})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"type": "script"
}
],
@@ -1711,7 +1711,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['top_sources']) == 0\n\texcept:\n\t\treturn True",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn len(value['top_sources']) == 0\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -1776,7 +1776,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn int(value['meta']['event_count']) > 0\n\texcept:\n\t\treturn False",
"code": "\ttry:\n\t\tif value['overview']:\n\t\t\tvalue = value['overview']\n\texcept:\n\t\tpass\n\ttry:\n\t\treturn int(value['meta']['event_count']) > 0\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -1804,4 +1804,4 @@
},
"type": "ia.container.flex"
}
}
}