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

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

View File

@@ -1,20 +1,15 @@
{
"custom": {
"detail": null
},
"params": {
"label": null,
"source": null
},
"custom": {},
"params": {},
"propConfig": {
"custom.detail": {
"binding": {
"config": {
"expression": "{view.params.source} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs}"
"expression": "{view.params.source} + \u0027|\u0027 + {session.custom.PrimeControls.query.startMs} + \u0027|\u0027 + {session.custom.PrimeControls.query.endMs}"
},
"transforms": [
{
"code": "\ttry:\n\t\tsrc = self.view.params.source\n\texcept:\n\t\tsrc = None\n\tif not src:\n\t\treturn None\n\ttry:\n\t\tq = self.session.custom.PrimeControls.query\n\t\treturn PrimeControls.alarms.getSourceDetail(src, q.startMs, q.endMs)\n\texcept:\n\t\treturn None",
"code": "\ttry:\n\t\tsrc \u003d self.view.params.source\n\texcept:\n\t\tsrc \u003d None\n\tif not src:\n\t\treturn None\n\ttry:\n\t\tq \u003d self.session.custom.PrimeControls.query\n\t\treturn PrimeControls.alarms.getSourceDetail(src, q.startMs, q.endMs)\n\texcept:\n\t\treturn None",
"type": "script"
}
],
@@ -52,7 +47,7 @@
},
"transforms": [
{
"code": "\tif value:\n\t\treturn value\n\ttry:\n\t\treturn self.view.params.source or 'Alarm Detail'\n\texcept:\n\t\treturn 'Alarm Detail'",
"code": "\tif value:\n\t\treturn value\n\ttry:\n\t\treturn self.view.params.source or \u0027Alarm Detail\u0027\n\texcept:\n\t\treturn \u0027Alarm Detail\u0027",
"type": "script"
}
],
@@ -79,7 +74,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn value['area'] or ''\n\texcept:\n\t\treturn ''",
"code": "\ttry:\n\t\treturn value[\u0027area\u0027] or \u0027\u0027\n\texcept:\n\t\treturn \u0027\u0027",
"type": "script"
}
],
@@ -126,7 +121,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['count'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value[\u0027stats\u0027][\u0027count\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
"type": "script"
}
],
@@ -158,7 +153,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_tta_ms'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value[\u0027stats\u0027][\u0027avg_tta_ms\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
"type": "script"
}
],
@@ -190,7 +185,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_active_ms'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value[\u0027stats\u0027][\u0027avg_active_ms\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
"type": "script"
}
],
@@ -222,7 +217,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['fleeting_count'])\n\texcept:\n\t\treturn '--'",
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value[\u0027stats\u0027][\u0027fleeting_count\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
"type": "script"
}
],
@@ -247,7 +242,6 @@
"shrink": 0
},
"props": {
"alignItems": "stretch",
"style": {
"gap": "10px"
}
@@ -276,7 +270,7 @@
"name": "repDaily"
},
"position": {
"basis": "30px",
"basis": "72px",
"shrink": 0
},
"propConfig": {
@@ -287,7 +281,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\tdaily = list(value['daily'] or [])\n\texcept:\n\t\tdaily = []\n\tcounts = []\n\tfor d in daily:\n\t\ttry:\n\t\t\tcounts.append(int(d['count']))\n\t\texcept:\n\t\t\tcounts.append(0)\n\tif not counts:\n\t\treturn []\n\tm = max(counts)\n\treturn [{'count': c, 'max': m} for c in counts]",
"code": "\ttry:\n\t\tdaily \u003d list(value[\u0027daily\u0027] or [])\n\texcept:\n\t\tdaily \u003d []\n\tcounts \u003d []\n\tfor d in daily:\n\t\ttry:\n\t\t\tcounts.append(int(d[\u0027count\u0027]))\n\t\texcept:\n\t\t\tcounts.append(0)\n\tif not counts:\n\t\treturn []\n\tm \u003d max(counts)\n\treturn [{\u0027count\u0027: c, \u0027max\u0027: m} for c in counts]",
"type": "script"
}
],
@@ -296,13 +290,15 @@
}
},
"props": {
"direction": "row",
"elementPosition": {
"basis": "12px",
"grow": 1,
"shrink": 1
"basis": "8px"
},
"path": "PrimeControls/Components/HeatmapCell"
"path": "PrimeControls/Components/HeatmapCell",
"style": {
"gap": "2px"
},
"useDefaultViewHeight": false,
"useDefaultViewWidth": false
},
"type": "ia.display.flex-repeater"
},
@@ -321,7 +317,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\tdaily = list(value['daily'] or [])\n\texcept:\n\t\tdaily = []\n\tif not daily:\n\t\treturn 'No activity in range'\n\ttry:\n\t\treturn 'Activations per day, %s - %s' % (PrimeControls.fmt.day_clock(daily[0]['t0']), PrimeControls.fmt.day_clock(daily[-1]['t0']))\n\texcept:\n\t\treturn 'Activations per day'",
"code": "\ttry:\n\t\tdaily \u003d list(value[\u0027daily\u0027] or [])\n\texcept:\n\t\tdaily \u003d []\n\tif not daily:\n\t\treturn \u0027No activity in range\u0027\n\ttry:\n\t\treturn \u0027Activations per day, %s - %s\u0027 % (PrimeControls.fmt.day_clock(daily[0][\u0027t0\u0027]), PrimeControls.fmt.day_clock(daily[-1][\u0027t0\u0027]))\n\texcept:\n\t\treturn \u0027Activations per day\u0027",
"type": "script"
}
],
@@ -386,7 +382,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 0\n\texcept:\n\t\treturn False",
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 0\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -400,7 +396,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\tu = value['stats']['top_ack_users'][0]\n\t\treturn '%s (%d)' % (u['user'], u['count'])\n\texcept:\n\t\treturn ''",
"code": "\ttry:\n\t\tu \u003d value[\u0027stats\u0027][\u0027top_ack_users\u0027][0]\n\t\treturn \u0027%s (%d)\u0027 % (u[\u0027user\u0027], u[\u0027count\u0027])\n\texcept:\n\t\treturn \u0027\u0027",
"type": "script"
}
],
@@ -432,7 +428,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 1\n\texcept:\n\t\treturn False",
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 1\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -446,7 +442,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\tu = value['stats']['top_ack_users'][1]\n\t\treturn '%s (%d)' % (u['user'], u['count'])\n\texcept:\n\t\treturn ''",
"code": "\ttry:\n\t\tu \u003d value[\u0027stats\u0027][\u0027top_ack_users\u0027][1]\n\t\treturn \u0027%s (%d)\u0027 % (u[\u0027user\u0027], u[\u0027count\u0027])\n\texcept:\n\t\treturn \u0027\u0027",
"type": "script"
}
],
@@ -478,7 +474,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 2\n\texcept:\n\t\treturn False",
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 2\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -492,7 +488,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\tu = value['stats']['top_ack_users'][2]\n\t\treturn '%s (%d)' % (u['user'], u['count'])\n\texcept:\n\t\treturn ''",
"code": "\ttry:\n\t\tu \u003d value[\u0027stats\u0027][\u0027top_ack_users\u0027][2]\n\t\treturn \u0027%s (%d)\u0027 % (u[\u0027user\u0027], u[\u0027count\u0027])\n\texcept:\n\t\treturn \u0027\u0027",
"type": "script"
}
],
@@ -524,7 +520,7 @@
},
"transforms": [
{
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) == 0\n\texcept:\n\t\treturn True",
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003d\u003d 0\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -604,7 +600,7 @@
},
"transforms": [
{
"code": "\tout = []\n\ttry:\n\t\trows = list(value['events'] or [])\n\texcept:\n\t\trows = []\n\tfor r in rows[:25]:\n\t\ttry:\n\t\t\tout.append({'time_label': r['time_label'], 'state_label': r['state_label'], 'ack_user': r['ack_user'] or ''})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"code": "\tout \u003d []\n\ttry:\n\t\trows \u003d list(value[\u0027events\u0027] or [])\n\texcept:\n\t\trows \u003d []\n\tfor r in rows[:25]:\n\t\ttry:\n\t\t\tout.append({\u0027time_label\u0027: r[\u0027time_label\u0027], \u0027state_label\u0027: r[\u0027state_label\u0027], \u0027ack_user\u0027: r[\u0027ack_user\u0027] or \u0027\u0027})\n\t\texcept:\n\t\t\tpass\n\treturn out",
"type": "script"
}
],
@@ -613,6 +609,11 @@
}
},
"props": {
"cells": {
"style": {
"padding": "5px"
}
},
"columns": [
{
"field": "time_label",
@@ -649,8 +650,7 @@
}
},
"pager": {
"bottom": false,
"top": false
"bottom": false
}
},
"type": "ia.display.table"
@@ -686,7 +686,7 @@
},
"transforms": [
{
"code": "\tif value is None:\n\t\treturn False\n\ttry:\n\t\treturn not value['error']\n\texcept:\n\t\treturn True",
"code": "\tif value is None:\n\t\treturn False\n\ttry:\n\t\treturn not value[\u0027error\u0027]\n\texcept:\n\t\treturn True",
"type": "script"
}
],
@@ -717,7 +717,7 @@
},
"transforms": [
{
"code": "\tif value is None:\n\t\treturn True\n\ttry:\n\t\treturn bool(value['error'])\n\texcept:\n\t\treturn False",
"code": "\tif value is None:\n\t\treturn True\n\ttry:\n\t\treturn bool(value[\u0027error\u0027])\n\texcept:\n\t\treturn False",
"type": "script"
}
],
@@ -741,7 +741,7 @@
"component": {
"onActionPerformed": {
"config": {
"script": "\tsystem.perspective.closePopup('PC_AlarmDetail')"
"script": "\tsystem.perspective.closePopup(\u0027PC_AlarmDetail\u0027)"
},
"scope": "G",
"type": "script"
@@ -756,7 +756,6 @@
"shrink": 0
},
"props": {
"primary": true,
"text": "Close"
},
"type": "ia.input.button"
@@ -775,7 +774,6 @@
"type": "ia.container.flex"
}
],
"custom": {},
"meta": {
"name": "root"
},

View File

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

View File

@@ -187,7 +187,9 @@
"path": "PrimeControls/Components/ScoreBar",
"style": {
"overflowY": "auto"
}
},
"useDefaultViewWidth": false,
"useDefaultViewHeight": false
},
"type": "ia.display.flex-repeater"
},
@@ -313,4 +315,4 @@
},
"type": "ia.container.flex"
}
}
}