Heatmap drill-down to Journal, layout fixes, healthy-plant sim mode (B grade)
Heatmap -> Journal drill-down (PrimeBAT only): - clicking an Activations-by-hour/day cell jumps to the Journal filtered to that recurring day-of-week + hour (new query.filterDow/filterHour session props; same local-time bucketing as calc.heatmap) - Journal shows a "Time filter: Thu 12:00-12:59" chip with an X to clear; filter composes with existing filters and is included in CSV export - getJournalPage clamps out-of-range pages when a filter shrinks the set Layout: - filter bar moved below the tab strip so the tabs no longer shift when the bar hides on Overview (tab bar y verified pixel-stable across tabs) - popup titles (AlarmDetail/EventDetail) auto-shrink their font to fit long source paths on one line without colliding with the state/priority chips Alarm health -> B (score ~88): - alarmsim gains a MODE flag: "healthy" (default) generates ~12 activations/hr with an 80/15/5 priority mix and no chatter/standing/fleeting/floods; "chaos" restores the original stress profile - SimHarness gains a SimReset one-shot timer (disabled) that clears all sim tags; probe P3 reports health-grade ground truth for the 8h window - Dashboard onStartup now re-anchors relative range presets (4h/8h/24h/7d) to now on session start - fixes stale Designer-baked startMs/endMs pinning every new session to an old window Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,11 +5,11 @@
|
||||
"custom.detail": {
|
||||
"binding": {
|
||||
"config": {
|
||||
"expression": "{view.params.source} + \u0027|\u0027 + {session.custom.PrimeControls.query.startMs} + \u0027|\u0027 + {session.custom.PrimeControls.query.endMs}"
|
||||
"expression": "{view.params.source} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs}"
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -47,7 +47,21 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
"type": "property"
|
||||
}
|
||||
},
|
||||
"props.style.fontSize": {
|
||||
"binding": {
|
||||
"config": {
|
||||
"path": "this.props.text"
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\tn = len(value or '')\n\texcept:\n\t\tn = 0\n\tif n <= 34:\n\t\treturn '28px'\n\tsize = int(28.0 * 34 / n)\n\tif size < 12:\n\t\tsize = 12\n\treturn '%dpx' % size",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -57,10 +71,17 @@
|
||||
},
|
||||
"props": {
|
||||
"style": {
|
||||
"classes": "PrimeControls/Text/Big"
|
||||
"classes": "PrimeControls/Text/Big",
|
||||
"minWidth": "0px",
|
||||
"whiteSpace": "nowrap"
|
||||
}
|
||||
},
|
||||
"type": "ia.display.label"
|
||||
"type": "ia.display.label",
|
||||
"position": {
|
||||
"basis": "auto",
|
||||
"grow": 1,
|
||||
"shrink": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"meta": {
|
||||
@@ -74,7 +95,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn value[\u0027area\u0027] or \u0027\u0027\n\texcept:\n\t\treturn \u0027\u0027",
|
||||
"code": "\ttry:\n\t\treturn value['area'] or ''\n\texcept:\n\t\treturn ''",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -121,7 +142,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value[\u0027stats\u0027][\u0027count\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['count'])\n\texcept:\n\t\treturn '--'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -153,7 +174,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value[\u0027stats\u0027][\u0027avg_tta_ms\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_tta_ms'])\n\texcept:\n\t\treturn '--'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -185,7 +206,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value[\u0027stats\u0027][\u0027avg_active_ms\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_active_ms'])\n\texcept:\n\t\treturn '--'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -217,7 +238,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value[\u0027stats\u0027][\u0027fleeting_count\u0027])\n\texcept:\n\t\treturn \u0027--\u0027",
|
||||
"code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['fleeting_count'])\n\texcept:\n\t\treturn '--'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -281,7 +302,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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]",
|
||||
"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]",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -317,7 +338,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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'",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -382,7 +403,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 0\n\texcept:\n\t\treturn False",
|
||||
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 0\n\texcept:\n\t\treturn False",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -396,7 +417,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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 ''",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -428,7 +449,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 1\n\texcept:\n\t\treturn False",
|
||||
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 1\n\texcept:\n\t\treturn False",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -442,7 +463,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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 ''",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -474,7 +495,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003e 2\n\texcept:\n\t\treturn False",
|
||||
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 2\n\texcept:\n\t\treturn False",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -488,7 +509,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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 ''",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -520,7 +541,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\treturn len(value[\u0027stats\u0027][\u0027top_ack_users\u0027]) \u003d\u003d 0\n\texcept:\n\t\treturn True",
|
||||
"code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) == 0\n\texcept:\n\t\treturn True",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -600,7 +621,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -686,7 +707,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\tif value is None:\n\t\treturn False\n\ttry:\n\t\treturn not value[\u0027error\u0027]\n\texcept:\n\t\treturn True",
|
||||
"code": "\tif value is None:\n\t\treturn False\n\ttry:\n\t\treturn not value['error']\n\texcept:\n\t\treturn True",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -717,7 +738,7 @@
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\tif value is None:\n\t\treturn True\n\ttry:\n\t\treturn bool(value[\u0027error\u0027])\n\texcept:\n\t\treturn False",
|
||||
"code": "\tif value is None:\n\t\treturn True\n\ttry:\n\t\treturn bool(value['error'])\n\texcept:\n\t\treturn False",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
@@ -741,7 +762,7 @@
|
||||
"component": {
|
||||
"onActionPerformed": {
|
||||
"config": {
|
||||
"script": "\tsystem.perspective.closePopup(\u0027PC_AlarmDetail\u0027)"
|
||||
"script": "\tsystem.perspective.closePopup('PC_AlarmDetail')"
|
||||
},
|
||||
"scope": "G",
|
||||
"type": "script"
|
||||
@@ -787,4 +808,4 @@
|
||||
},
|
||||
"type": "ia.container.flex"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
"name": "lblTitle"
|
||||
},
|
||||
"position": {
|
||||
"grow": 1
|
||||
"basis": "auto",
|
||||
"grow": 1,
|
||||
"shrink": 1
|
||||
},
|
||||
"propConfig": {
|
||||
"props.text": {
|
||||
@@ -56,11 +58,27 @@
|
||||
],
|
||||
"type": "property"
|
||||
}
|
||||
},
|
||||
"props.style.fontSize": {
|
||||
"binding": {
|
||||
"config": {
|
||||
"path": "this.props.text"
|
||||
},
|
||||
"transforms": [
|
||||
{
|
||||
"code": "\ttry:\n\t\tn = len(value or '')\n\texcept:\n\t\tn = 0\n\tif n <= 24:\n\t\treturn '28px'\n\tsize = int(28.0 * 24 / n)\n\tif size < 12:\n\t\tsize = 12\n\treturn '%dpx' % size",
|
||||
"type": "script"
|
||||
}
|
||||
],
|
||||
"type": "property"
|
||||
}
|
||||
}
|
||||
},
|
||||
"props": {
|
||||
"style": {
|
||||
"classes": "PrimeControls/Text/Big"
|
||||
"classes": "PrimeControls/Text/Big",
|
||||
"minWidth": "0px",
|
||||
"whiteSpace": "nowrap"
|
||||
}
|
||||
},
|
||||
"type": "ia.display.label"
|
||||
|
||||
Reference in New Issue
Block a user