diff --git a/CONTRACT.md b/CONTRACT.md index 5e96298..a56a66f 100644 --- a/CONTRACT.md +++ b/CONTRACT.md @@ -207,7 +207,8 @@ Critical `#D64550`. Accent: `#3B7DD8`. Agents may ADD classes only under ## View ownership (Phase 2/3) -A: `Dashboard/Header` + `Dashboard/FilterBar` · B: `Tabs/Overview` · C: `Tabs/Analysis` · +A: `Shell/Header` + `Shell/FilterBar` (relocated out of `Dashboard/` — a view cannot +nest sub-views under another view's folder) · B: `Tabs/Overview` · C: `Tabs/Analysis` · D: `Tabs/BadActors` · E: `Tabs/Journal` · F: `Popups/HealthScore`+`Popups/ShiftReport` · G: `Popups/AlarmDetail`+`Popups/EventDetail` · H: `Components/HealthGauge` upgrade. Integrator-only: `Dashboard/view.json`, session-props, page-config, shared Components, diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json index eed3c9f..ceb384c 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/session-props/props.json @@ -2,18 +2,18 @@ "custom": { "PrimeControls": { "query": { - "startMs": 0, - "endMs": 0, - "rangePreset": "8h", - "priorities": [], "areas": [], - "states": [], + "endMs": 0, + "priorities": [], + "rangePreset": "8h", + "refreshToken": 0, "search": "", - "refreshToken": 0 + "startMs": 0, + "states": [] }, "ui": { - "selectedTab": 0, - "badActorFocus": "" + "badActorFocus": "", + "selectedTab": 0 } } }, @@ -68,15 +68,28 @@ "props.lastActivity": { "access": "SYSTEM", "persistent": false + }, + "props.offline.capable": { + "access": "SYSTEM", + "persistent": false + }, + "props.offline.enabled": { + "access": "SYSTEM", + "persistent": false + }, + "props.offline.lastSynced": { + "access": "SYSTEM", + "persistent": false } }, "props": { - "address": "172.18.0.5", + "address": "172.23.0.1", "device": {}, "geolocation": {}, "locale": "en-US", + "offline": {}, "securityLevels": [], "theme": "light-cool", - "timeZoneId": "America/Los_Angeles" + "timeZoneId": "America/Chicago" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/EmptyState/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/EmptyState/view.json index a6c80e5..f9dd99b 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/EmptyState/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/EmptyState/view.json @@ -7,11 +7,11 @@ "propConfig": { "params.icon": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.message": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -90,4 +90,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HealthGauge/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HealthGauge/view.json index ddc10ec..fd3c8b3 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HealthGauge/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HealthGauge/view.json @@ -6,7 +6,7 @@ "propConfig": { "params.health": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -134,4 +134,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HeatmapCell/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HeatmapCell/view.json index 27ca01b..5dc1851 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HeatmapCell/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/HeatmapCell/view.json @@ -1,17 +1,17 @@ { "custom": {}, "params": { - "count": 0, - "max": 0 + "count": null, + "max": null }, "propConfig": { "params.count": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.max": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -91,4 +91,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/InsightRow/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/InsightRow/view.json index 6ef9dc2..6072c17 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/InsightRow/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/InsightRow/view.json @@ -2,26 +2,26 @@ "custom": {}, "params": { "icon": null, - "severity": 3, + "severity": null, "tab": null, "text": null }, "propConfig": { "params.icon": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.severity": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.tab": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.text": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -118,4 +118,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/KpiCard/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/KpiCard/view.json index 36c1388..912a05e 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/KpiCard/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/KpiCard/view.json @@ -2,26 +2,26 @@ "custom": {}, "params": { "delta": null, - "label": "KPI", + "label": null, "unit": null, "value": null }, "propConfig": { "params.delta": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.label": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.unit": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.value": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -181,4 +181,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/PriorityCard/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/PriorityCard/view.json index d1e9c8e..5096d0e 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/PriorityCard/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/PriorityCard/view.json @@ -1,22 +1,22 @@ { "custom": {}, "params": { - "count": 0, + "count": null, "pct": null, "priority_name": null }, "propConfig": { "params.count": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.pct": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.priority_name": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -134,4 +134,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/ScoreBar/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/ScoreBar/view.json index 48e5c38..7a9f40a 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/ScoreBar/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/ScoreBar/view.json @@ -10,23 +10,23 @@ "propConfig": { "params.detail": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.key": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.label": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.score": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.weight": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -204,4 +204,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/SourceRow/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/SourceRow/view.json index f4e38d3..86db373 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/SourceRow/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/SourceRow/view.json @@ -1,7 +1,7 @@ { "custom": {}, "params": { - "count": 0, + "count": null, "label": null, "pct": null, "rank": null, @@ -10,23 +10,23 @@ "propConfig": { "params.count": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.label": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.pct": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.rank": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.source": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -189,4 +189,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/TabButton/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/TabButton/view.json index 3bb1009..bab323f 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/TabButton/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Components/TabButton/view.json @@ -1,17 +1,17 @@ { "custom": {}, "params": { - "index": 0, - "title": "Tab" + "index": null, + "title": null }, "propConfig": { "params.index": { "paramDirection": "input", - "persistent": true + "persistent": false }, "params.title": { "paramDirection": "input", - "persistent": true + "persistent": false } }, "props": {}, @@ -66,4 +66,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/FilterBar/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/FilterBar/view.json deleted file mode 100644 index b93af79..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/FilterBar/view.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "custom": {}, - "params": { - "bundle": null - }, - "propConfig": { - "params.bundle": { - "paramDirection": "input", - "persistent": true - } - }, - "props": {}, - "root": { - "children": [ - { - "meta": { - "name": "ph" - }, - "props": { - "style": { - "classes": "PrimeControls/Empty" - }, - "text": "Filter bar - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" - }, - "propConfig": { - "props.text": { - "binding": { - "config": { - "path": "view.params.bundle" - }, - "transforms": [ - { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", - "type": "script" - } - ], - "type": "property" - } - } - }, - "props": { - "style": { - "classes": "PrimeControls/Text/Muted" - } - }, - "type": "ia.display.label" - } - ], - "meta": { - "name": "root" - }, - "props": { - "direction": "column", - "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" - } - }, - "type": "ia.container.flex" - } -} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/Header/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/Header/view.json deleted file mode 100644 index 47cf534..0000000 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/Header/view.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "custom": {}, - "params": { - "bundle": null - }, - "propConfig": { - "params.bundle": { - "paramDirection": "input", - "persistent": true - } - }, - "props": {}, - "root": { - "children": [ - { - "meta": { - "name": "ph" - }, - "props": { - "style": { - "classes": "PrimeControls/Empty" - }, - "text": "Header - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" - }, - "propConfig": { - "props.text": { - "binding": { - "config": { - "path": "view.params.bundle" - }, - "transforms": [ - { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", - "type": "script" - } - ], - "type": "property" - } - } - }, - "props": { - "style": { - "classes": "PrimeControls/Text/Muted" - } - }, - "type": "ia.display.label" - } - ], - "meta": { - "name": "root" - }, - "props": { - "direction": "column", - "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" - } - }, - "type": "ia.container.flex" - } -} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json index 3bbfdf5..10e1923 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/view.json @@ -1,7 +1,5 @@ { - "custom": { - "bundle": null - }, + "custom": {}, "events": { "system": { "onStartup": { @@ -44,7 +42,6 @@ }, "position": { "basis": "150px", - "grow": 0, "shrink": 0 }, "propConfig": { @@ -58,8 +55,7 @@ } }, "props": { - "params": {}, - "path": "PrimeControls/Dashboard/Header" + "path": "PrimeControls/Shell/Header" }, "type": "ia.display.view" }, @@ -69,7 +65,6 @@ }, "position": { "basis": "56px", - "grow": 0, "shrink": 0 }, "propConfig": { @@ -83,8 +78,7 @@ } }, "props": { - "params": {}, - "path": "PrimeControls/Dashboard/FilterBar" + "path": "PrimeControls/Shell/FilterBar" }, "type": "ia.display.view" }, @@ -164,11 +158,9 @@ }, "position": { "basis": "42px", - "grow": 0, "shrink": 0 }, "props": { - "direction": "row", "style": { "borderBottomColor": "var(--neutral-40)", "borderBottomStyle": "solid", @@ -205,7 +197,6 @@ } }, "props": { - "params": {}, "path": "PrimeControls/Tabs/Overview" }, "type": "ia.display.view" @@ -236,7 +227,6 @@ } }, "props": { - "params": {}, "path": "PrimeControls/Tabs/Analysis" }, "type": "ia.display.view" @@ -267,7 +257,6 @@ } }, "props": { - "params": {}, "path": "PrimeControls/Tabs/BadActors" }, "type": "ia.display.view" @@ -298,7 +287,6 @@ } }, "props": { - "params": {}, "path": "PrimeControls/Tabs/Journal" }, "type": "ia.display.view" @@ -328,4 +316,4 @@ }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/FilterBar/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/AlarmDetail/resource.json similarity index 100% rename from ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/FilterBar/resource.json rename to ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/AlarmDetail/resource.json diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/AlarmDetail/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/AlarmDetail/view.json new file mode 100644 index 0000000..81edce1 --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/AlarmDetail/view.json @@ -0,0 +1,792 @@ +{ + "custom": { + "detail": null + }, + "params": { + "label": null, + "source": null + }, + "propConfig": { + "custom.detail": { + "binding": { + "config": { + "expression": "{view.params.source} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {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", + "type": "script" + } + ], + "type": "expr" + } + }, + "params.label": { + "paramDirection": "input", + "persistent": false + }, + "params.source": { + "paramDirection": "input", + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 660, + "width": 720 + } + }, + "root": { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblTitle" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.label" + }, + "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'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Big" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblArea" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['area'] or ''\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "headerCol" + }, + "position": { + "shrink": 0 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "kpiCount" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.value": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['count'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Activations" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "kpiTta" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.value": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_tta_ms'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Avg Time to Ack" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "kpiActive" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.value": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['stats']['avg_active_ms'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Avg Active Time" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "kpiFleeting" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.value": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.num(value['stats']['fleeting_count'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Fleeting" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "statsRow" + }, + "position": { + "basis": "88px", + "shrink": 0 + }, + "props": { + "alignItems": "stretch", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblDailyTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Daily activity" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repDaily" + }, + "position": { + "basis": "30px", + "shrink": 0 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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]", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "row", + "elementPosition": { + "basis": "12px", + "grow": 1, + "shrink": 1 + }, + "path": "PrimeControls/Components/HeatmapCell" + }, + "type": "ia.display.flex-repeater" + }, + { + "meta": { + "name": "lblDailyRange" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "cardDaily" + }, + "position": { + "shrink": 0 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblAckTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Top ack users" + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "ack0" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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 ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Chip/Flat", + "paddingBottom": "2px", + "paddingTop": "2px" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ack1" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 1\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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 ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Chip/Flat", + "paddingBottom": "2px", + "paddingTop": "2px" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ack2" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) > 2\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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 ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Chip/Flat", + "paddingBottom": "2px", + "paddingTop": "2px" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblNoAcks" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['stats']['top_ack_users']) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "No acknowledgements in range" + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "ackRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "6px" + }, + "wrap": "wrap" + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "cardAcks" + }, + "position": { + "shrink": 0 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblEvTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Recent events" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "tblEvents" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.data": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "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", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "columns": [ + { + "field": "time_label", + "header": { + "title": "Time" + }, + "render": "string", + "sortable": false, + "strictWidth": true, + "width": 160 + }, + { + "field": "state_label", + "header": { + "title": "State" + }, + "render": "string", + "sortable": false, + "strictWidth": true, + "width": 110 + }, + { + "field": "ack_user", + "header": { + "title": "Ack by" + }, + "render": "string", + "sortable": false + } + ], + "emptyMessage": { + "noData": { + "text": "No events in range" + } + }, + "pager": { + "bottom": false, + "top": false + } + }, + "type": "ia.display.table" + } + ], + "meta": { + "name": "cardEvents" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "bodyCol" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "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" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "column", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "emptyWrap" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.detail" + }, + "transforms": [ + { + "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" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "notifications_off", + "message": "No journal data for this alarm in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + }, + { + "children": [ + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tsystem.perspective.closePopup('PC_AlarmDetail')" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnClose" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "primary": true, + "text": "Close" + }, + "type": "ia.input.button" + } + ], + "meta": { + "name": "footerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "justify": "flex-end" + }, + "type": "ia.container.flex" + } + ], + "custom": {}, + "meta": { + "name": "root" + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/PageBg", + "gap": "10px", + "padding": "16px" + } + }, + "type": "ia.container.flex" + } +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/Header/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/EventDetail/resource.json similarity index 100% rename from ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Dashboard/Header/resource.json rename to ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/EventDetail/resource.json diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/EventDetail/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/EventDetail/view.json new file mode 100644 index 0000000..40b70ef --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/EventDetail/view.json @@ -0,0 +1,660 @@ +{ + "custom": { + "props": [] + }, + "params": { + "event": null + }, + "propConfig": { + "custom.props": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\tev = value\n\tif not ev:\n\t\treturn []\n\ttry:\n\t\tres = PrimeControls.alarms.getEventData(ev['id'], ev['time_ms'], ev['source'])\n\t\treturn res['props'] or []\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + }, + "params.event": { + "paramDirection": "input", + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 580, + "width": 580 + } + }, + "root": { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblTitle" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['label'] or value['source'] or 'Event Detail'\n\texcept:\n\t\treturn 'Event Detail'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Big" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "chipState" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\treturn value is not None", + "type": "script" + } + ], + "type": "property" + } + }, + "props.style.classes": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ts = value['state']\n\texcept:\n\t\ts = None\n\tif s == 'ack':\n\t\treturn 'PrimeControls/State/Acked'\n\tif s == 'clear':\n\t\treturn 'PrimeControls/State/Cleared'\n\treturn 'PrimeControls/State/Active'", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['state_label'] or ''\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "borderRadius": "10px", + "fontSize": "11px", + "paddingBottom": "2px", + "paddingLeft": "8px", + "paddingRight": "8px", + "paddingTop": "2px" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "chipPriority" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\treturn value is not None", + "type": "script" + } + ], + "type": "property" + } + }, + "props.style.classes": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tp = value['priority_name']\n\texcept:\n\t\tp = None\n\tif p not in ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']:\n\t\tp = 'Diagnostic'\n\treturn 'PrimeControls/Priority/' + p", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['priority_name'] or ''\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "borderRadius": "10px", + "fontSize": "11px", + "paddingBottom": "2px", + "paddingLeft": "8px", + "paddingRight": "8px", + "paddingTop": "2px" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "headerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "children": [ + { + "meta": { + "name": "k" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Time" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "v" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['time_label'] or PrimeControls.fmt.day_clock(value['time_ms'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": {}, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rowTime" + }, + "props": { + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "k" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Source" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "v" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['source'] or '--'\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "overflowWrap": "anywhere" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rowSource" + }, + "props": { + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "k" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Area" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "v" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['area'] or '--'\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": {}, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rowArea" + }, + "props": { + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "k" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Ack by" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "v" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['ack_user'] or '--'\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": {}, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rowAck" + }, + "props": { + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "cardCore" + }, + "position": { + "shrink": 0 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "4px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblPropsTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Event properties" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "tblProps" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.data": { + "binding": { + "config": { + "path": "view.custom.props" + }, + "transforms": [ + { + "code": "\tout = []\n\tfor p in (value or []):\n\t\ttry:\n\t\t\tv = p['value']\n\t\t\tout.append({'name': '%s' % p['name'], 'value': '' if v is None else '%s' % v})\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "columns": [ + { + "field": "name", + "header": { + "title": "Property" + }, + "render": "string", + "sortable": false, + "strictWidth": true, + "width": 180 + }, + { + "field": "value", + "header": { + "title": "Value" + }, + "render": "string", + "sortable": false + } + ], + "emptyMessage": { + "noData": { + "text": "No extended properties for this event" + } + }, + "pager": { + "bottom": false, + "top": false + } + }, + "type": "ia.display.table" + } + ], + "meta": { + "name": "cardProps" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "bodyCol" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\treturn value is not None", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "column", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "emptyWrap" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.event" + }, + "transforms": [ + { + "code": "\treturn value is None", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "info", + "message": "No event selected" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + }, + { + "children": [ + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tsystem.perspective.closePopup('PC_EventDetail')" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnClose" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "primary": true, + "text": "Close" + }, + "type": "ia.input.button" + } + ], + "meta": { + "name": "footerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "justify": "flex-end" + }, + "type": "ia.container.flex" + } + ], + "custom": {}, + "meta": { + "name": "root" + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/PageBg", + "gap": "10px", + "padding": "16px" + } + }, + "type": "ia.container.flex" + } +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/view.json new file mode 100644 index 0000000..d816946 --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/HealthScore/view.json @@ -0,0 +1,316 @@ +{ + "custom": {}, + "params": { + "health": null + }, + "propConfig": { + "params.health": { + "paramDirection": "input", + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 540, + "width": 540 + } + }, + "root": { + "children": [ + { + "children": [ + { + "meta": { + "name": "gradeChip" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.style.classes": { + "binding": { + "config": { + "path": "view.params.health" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tg = value['grade']\n\texcept:\n\t\tg = None\n\treturn 'PrimeControls/Grade/' + (g if g in ['A', 'B', 'C', 'D', 'F'] else 'NA')", + "type": "script" + } + ], + "type": "property" + } + }, + "props.text": { + "binding": { + "config": { + "path": "view.params.health" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['grade'] or 'N/A'\n\texcept:\n\t\treturn 'N/A'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "fontSize": "38px", + "paddingBottom": "4px", + "paddingLeft": "18px", + "paddingRight": "18px", + "paddingTop": "4px", + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "lblTitle" + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Big" + }, + "text": "Alarm Health Score" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblScore" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.health" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ts = value['score']\n\texcept:\n\t\ts = None\n\tif s is None:\n\t\treturn 'No data in selected range'\n\treturn 'Overall score %s / 100' % PrimeControls.fmt.num(s, 1)", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "titleCol" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "justify": "center" + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "headerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "14px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblSubsTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Component scores" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repSubs" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.health" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tsubs = value['subs'] or []\n\texcept:\n\t\tsubs = []\n\tout = []\n\tfor s in subs:\n\t\ttry:\n\t\t\tout.append({'key': s['key'], 'label': s['label'], 'score': s['score'], 'weight': s['weight'], 'detail': s['detail']})\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "column", + "elementPosition": { + "basis": "64px", + "grow": 0, + "shrink": 0 + }, + "path": "PrimeControls/Components/ScoreBar", + "style": { + "overflowY": "auto" + } + }, + "type": "ia.display.flex-repeater" + }, + { + "meta": { + "name": "emptyWrap" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.health" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn not (value and value['subs'])\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "assessment", + "message": "No health data in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardSubs" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblCaption" + }, + "position": { + "grow": 1, + "shrink": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Weighted ISA-18.2 composite: rate, flood, chattering, standing, priority mix" + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tsystem.perspective.closePopup('PC_HealthScore')" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnClose" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "primary": true, + "text": "Close" + }, + "type": "ia.input.button" + } + ], + "meta": { + "name": "footerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "justify": "space-between", + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" + } + ], + "custom": {}, + "meta": { + "name": "root" + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/PageBg", + "gap": "12px", + "padding": "16px" + } + }, + "type": "ia.container.flex" + } +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/view.json new file mode 100644 index 0000000..8592942 --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Popups/ShiftReport/view.json @@ -0,0 +1,204 @@ +{ + "custom": { + "report": null + }, + "params": {}, + "propConfig": { + "custom.report": { + "binding": { + "config": { + "expression": "{session.custom.PrimeControls.query.refreshToken}" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tr = PrimeControls.alarms.getShiftReportText()\n\t\tif r and r['text']:\n\t\t\treturn r\n\texcept:\n\t\tpass\n\treturn {'text': 'Report unavailable', 'start_ms': 0, 'end_ms': 0, 'label': ''}", + "type": "script" + } + ], + "type": "expr" + } + } + }, + "props": { + "defaultSize": { + "height": 560, + "width": 620 + } + }, + "root": { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblTitle" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.report" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['label'] or 'Shift Report'\n\texcept:\n\t\treturn 'Shift Report'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Big" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblWindow" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.report" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ts = value['start_ms']\n\t\te = value['end_ms']\n\texcept:\n\t\treturn ''\n\tif not s or not e:\n\t\treturn ''\n\treturn '%s - %s' % (PrimeControls.fmt.day_clock(s), PrimeControls.fmt.day_clock(e))", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "headerCol" + }, + "position": { + "shrink": 0 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblText" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.report" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['text'] or 'Report unavailable'\n\texcept:\n\t\treturn 'Report unavailable'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "fontFamily": "monospace", + "fontSize": "12px", + "lineHeight": "1.5", + "whiteSpace": "pre-wrap" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "cardText" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "overflowY": "auto" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tsystem.perspective.closePopup('PC_ShiftReport')" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnClose" + }, + "position": { + "basis": "90px", + "shrink": 0 + }, + "props": { + "primary": true, + "text": "Close" + }, + "type": "ia.input.button" + } + ], + "meta": { + "name": "footerRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "justify": "flex-end" + }, + "type": "ia.container.flex" + } + ], + "custom": {}, + "meta": { + "name": "root" + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/PageBg", + "gap": "12px", + "padding": "16px" + } + }, + "type": "ia.container.flex" + } +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/view.json new file mode 100644 index 0000000..ed304ef --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/FilterBar/view.json @@ -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" + } +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/resource.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/resource.json new file mode 100644 index 0000000..276dced --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/resource.json @@ -0,0 +1,10 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json" + ], + "attributes": {} +} diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/view.json new file mode 100644 index 0000000..61a7083 --- /dev/null +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Shell/Header/view.json @@ -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" + } +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Analysis/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Analysis/view.json index 3e1220e..b3fb31d 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Analysis/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Analysis/view.json @@ -6,37 +6,33 @@ "propConfig": { "params.bundle": { "paramDirection": "input", - "persistent": true + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 760, + "width": 1600 } }, - "props": {}, "root": { "children": [ { "meta": { - "name": "ph" + "name": "emptyAll" }, - "props": { - "style": { - "classes": "PrimeControls/Empty" - }, - "text": "Analysis - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" + "position": { + "grow": 1 }, "propConfig": { - "props.text": { + "position.display": { "binding": { "config": { "path": "view.params.bundle" }, "transforms": [ { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", + "code": "\ttry:\n\t\treturn (not value) or value['meta']['event_count'] == 0\n\texcept:\n\t\treturn True", "type": "script" } ], @@ -45,11 +41,2407 @@ } }, "props": { - "style": { - "classes": "PrimeControls/Text/Muted" + "params": { + "icon": "inbox", + "message": "No alarm events in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + }, + { + "children": [ + { + "children": [ + { + "children": [ + { + "meta": { + "name": "hmTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Activations by Hour & Day of Week" + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblMon" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Mon" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repMon" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][0]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowMon" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblTue" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Tue" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repTue" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][1]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowTue" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblWed" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Wed" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repWed" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][2]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowWed" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblThu" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Thu" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repThu" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][3]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowThu" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblFri" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Fri" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repFri" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][4]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowFri" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblSat" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Sat" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repSat" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][5]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowSat" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblSun" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "10px", + "paddingRight": "6px", + "textAlign": "right" + }, + "text": "Sun" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repSun" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\thm = value['heatmap']\n\t\tmx = int(hm['max_count'] or 0)\n\t\treturn [{'count': int(c or 0), 'max': mx} for c in hm['rows'][6]][:24]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "elementPosition": { + "basis": "0px" + }, + "path": "PrimeControls/Components/HeatmapCell", + "style": { + "overflow": "hidden" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "rowSun" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "axSpacer" + }, + "position": { + "basis": "34px", + "shrink": 0 + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax00" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "0" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax03" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "3" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax06" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "6" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax09" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "9" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax12" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "12" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax15" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "15" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax18" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "18" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "ax21" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "fontSize": "9px" + }, + "text": "21" + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "hourAxis" + }, + "position": { + "basis": "14px", + "shrink": 0 + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "hmGrid" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "cardHeatmap" + }, + "position": { + "basis": "0px", + "grow": 3 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "pTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Priority Mix vs ISA 80/15/5" + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "donut" + }, + "position": { + "basis": "95%" + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tp = value['priority']['pct']\n\t\treturn (p['low'] or 0) + (p['medium'] or 0) + (p['high'] or 0) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tp = value['priority']['pct']\n\t\treturn [{'label': 'Low', 'value': round(float(p['low'] or 0), 1)}, {'label': 'Medium', 'value': round(float(p['medium'] or 0), 1)}, {'label': 'High', 'value': round(float(p['high'] or 0), 1)}]\n\texcept:\n\t\treturn []", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "colors": [ + "#5B9BD5", + "#E5C453", + "#E8883A" + ], + "cutoutRadius": 60, + "showLabels": false, + "showLegend": false, + "tooltipFormat": "{category}: {value.value.formatNumber('#.0')}%" + }, + "type": "ia.chart.pie" + }, + { + "meta": { + "name": "donutEmpty" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tp = value['priority']['pct']\n\t\treturn (p['low'] or 0) + (p['medium'] or 0) + (p['high'] or 0) <= 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "pie_chart", + "message": "No priority data in range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "pieWrap" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "chipLow" + }, + "position": { + "basis": "72px", + "shrink": 0 + }, + "props": { + "style": { + "borderRadius": "10px", + "classes": "PrimeControls/Priority/Low", + "fontSize": "11px", + "padding": "2px 8px", + "textAlign": "center" + }, + "text": "Low" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "valLow" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tpr = value['priority']\n\t\treturn '%s now vs %s target' % (PrimeControls.fmt.pct(pr['pct']['low'], 1), PrimeControls.fmt.pct(pr['target']['low'], 0))\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "targetLow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "chipMedium" + }, + "position": { + "basis": "72px", + "shrink": 0 + }, + "props": { + "style": { + "borderRadius": "10px", + "classes": "PrimeControls/Priority/Medium", + "fontSize": "11px", + "padding": "2px 8px", + "textAlign": "center" + }, + "text": "Medium" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "valMedium" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tpr = value['priority']\n\t\treturn '%s now vs %s target' % (PrimeControls.fmt.pct(pr['pct']['medium'], 1), PrimeControls.fmt.pct(pr['target']['medium'], 0))\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "targetMedium" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "chipHigh" + }, + "position": { + "basis": "72px", + "shrink": 0 + }, + "props": { + "style": { + "borderRadius": "10px", + "classes": "PrimeControls/Priority/High", + "fontSize": "11px", + "padding": "2px 8px", + "textAlign": "center" + }, + "text": "High" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "valHigh" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tpr = value['priority']\n\t\treturn '%s now vs %s target' % (PrimeControls.fmt.pct(pr['pct']['high'], 1), PrimeControls.fmt.pct(pr['target']['high'], 0))\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "targetHigh" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "targets" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "justify": "center", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "pBody" + }, + "position": { + "grow": 1 + }, + "props": { + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "pCaption" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tsad = value['priority']['sum_abs_dev']\n\t\tif sad is None:\n\t\t\treturn ''\n\t\treturn 'Deviation from ISA 80/15/5 target: %s pts' % PrimeControls.fmt.num(sad, 1)\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "cardPriority" + }, + "position": { + "basis": "0px", + "grow": 2 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "8px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "rowTop" + }, + "position": { + "basis": "300px", + "grow": 1, + "shrink": 0 + }, + "props": { + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "mtTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Response Times (MTTA / MTTR)" + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblMtta" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "MTTA (mean time to acknowledge)" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "valMtta" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['mtta_mttr']['mtta']['mean_ms'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Kpi" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "subMtta" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tm = value['mtta_mttr']['mtta']\n\t\treturn 'median %s over %s acks' % (PrimeControls.fmt.dur(m['median_ms']), PrimeControls.fmt.num(m['count']))\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "colMtta" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblMttr" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "MTTR (mean time to resolve)" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "valMttr" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn PrimeControls.fmt.dur(value['mtta_mttr']['mttr']['mean_ms'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Kpi" + } + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "subMttr" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tm = value['mtta_mttr']['mttr']\n\t\treturn 'median %s over %s clears' % (PrimeControls.fmt.dur(m['median_ms']), PrimeControls.fmt.num(m['count']))\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "colMttr" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "mtHead" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "gap": "16px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "trendChart" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tfor r in (value['mtta_mttr']['trend'] or []):\n\t\t\tif r['mtta_ms'] is not None or r['mttr_ms'] is not None:\n\t\t\t\treturn True\n\texcept:\n\t\tpass\n\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.dataSources.trend": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\timport time\n\tout = []\n\ttry:\n\t\trows = value['mtta_mttr']['trend'] or []\n\texcept:\n\t\trows = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tt0 = r['t0']\n\t\t\tif t0 is None:\n\t\t\t\tcontinue\n\t\t\tts = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(t0 / 1000.0))\n\t\t\ta = r['mtta_ms']\n\t\t\tc = r['mttr_ms']\n\t\t\tout.append({'t': ts, 'mtta': None if a is None else round(a / 60000.0, 2), 'mttr': None if c is None else round(c / 60000.0, 2)})\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "dataSources": {}, + "legend": { + "labels": { + "font": { + "size": 11 + } + }, + "markers": { + "height": 12, + "width": 12 + } + }, + "scrollBars": { + "horizontal": { + "enabled": false + }, + "vertical": { + "enabled": false + } + }, + "series": [ + { + "candlestick": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + } + }, + "high": { + "x": "", + "y": "" + }, + "low": { + "x": "", + "y": "" + }, + "open": { + "x": "", + "y": "" + } + }, + "column": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "height": null, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "width": null + }, + "open": { + "x": "", + "y": "" + } + }, + "data": { + "source": "trend", + "x": "t", + "y": "mtta" + }, + "defaultState": { + "visible": true + }, + "hiddenInLegend": false, + "label": { + "text": "MTTA" + }, + "line": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": true, + "fill": { + "color": "#3B7DD8", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 3, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY.formatNumber('#,###.#')} min[/]" + } + } + ], + "connect": false, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "#3B7DD8", + "dashArray": "", + "opacity": 1, + "width": 2 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "name": "mtta", + "render": "line", + "stepLine": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": true, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY.formatNumber('#,###.#')} min[/]" + }, + "visible": true, + "xAxis": "t", + "yAxis": "y", + "zIndex": 0 + }, + { + "candlestick": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + } + }, + "high": { + "x": "", + "y": "" + }, + "low": { + "x": "", + "y": "" + }, + "open": { + "x": "", + "y": "" + } + }, + "column": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "height": null, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "width": null + }, + "open": { + "x": "", + "y": "" + } + }, + "data": { + "source": "trend", + "x": "t", + "y": "mttr" + }, + "defaultState": { + "visible": true + }, + "hiddenInLegend": false, + "label": { + "text": "MTTR" + }, + "line": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": true, + "fill": { + "color": "#E8883A", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 3, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY.formatNumber('#,###.#')} min[/]" + } + } + ], + "connect": false, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "#E8883A", + "dashArray": "", + "opacity": 1, + "width": 2 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "name": "mttr", + "render": "line", + "stepLine": { + "appearance": { + "bullets": [], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY.formatNumber('#,###.#')} min[/]" + }, + "visible": true, + "xAxis": "t", + "yAxis": "y", + "zIndex": 0 + } + ], + "xAxes": [ + { + "appearance": { + "font": { + "size": 10, + "weight": 500 + }, + "grid": { + "color": "", + "dashArray": "", + "minDistance": 60, + "opacity": 0.3, + "position": 0.5 + }, + "inside": false, + "labels": { + "color": "", + "horizontalCenter": "middle", + "opacity": 1, + "rotation": 0, + "verticalCenter": "middle" + }, + "opposite": false + }, + "category": { + "break": { + "enabled": false, + "endCategory": "", + "size": 0.05, + "startCategory": "" + } + }, + "date": { + "baseInterval": { + "count": 1, + "enabled": false, + "skipEmptyPeriods": false, + "timeUnit": "hour" + }, + "break": { + "enabled": false, + "endDate": "", + "size": 0.05, + "startDate": "" + }, + "format": "M/d HH:mm", + "inputFormat": "yyyy-MM-dd HH:mm:ss", + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "inversed": false, + "label": { + "color": "", + "enabled": false, + "text": "" + }, + "name": "t", + "render": "date", + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "pointerLength": 4, + "text": "" + }, + "value": { + "break": { + "enabled": false, + "endValue": 100, + "size": 0.05, + "startValue": 0 + }, + "format": "#,###.##", + "logarithmic": false, + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "visible": true + } + ], + "yAxes": [ + { + "appearance": { + "font": { + "size": 10, + "weight": 500 + }, + "grid": { + "color": "", + "dashArray": "", + "minDistance": null, + "opacity": 0.3, + "position": 0.5 + }, + "inside": false, + "labels": { + "color": "", + "horizontalCenter": "middle", + "opacity": 1, + "rotation": 0, + "verticalCenter": "middle" + }, + "opposite": false + }, + "category": { + "break": { + "enabled": false, + "endCategory": "", + "size": 0.05, + "startCategory": "" + } + }, + "date": { + "baseInterval": { + "count": 1, + "enabled": false, + "skipEmptyPeriods": false, + "timeUnit": "hour" + }, + "break": { + "enabled": false, + "endDate": "", + "size": 0.05, + "startDate": "" + }, + "format": "M/d/yyyy HH:mm:ss", + "inputFormat": "yyyy-MM-dd kk:mm:ss", + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "inversed": false, + "label": { + "color": "", + "enabled": true, + "text": "minutes" + }, + "name": "y", + "render": "value", + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": false, + "pointerLength": 4, + "text": "" + }, + "value": { + "break": { + "enabled": false, + "endValue": 100, + "size": 0.05, + "startValue": 0 + }, + "format": "#,###.#", + "logarithmic": false, + "range": { + "max": "", + "min": 0, + "useStrict": false + } + }, + "visible": true + } + ] + }, + "type": "ia.chart.xy" + }, + { + "meta": { + "name": "trendEmpty" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tfor r in (value['mtta_mttr']['trend'] or []):\n\t\t\tif r['mtta_ms'] is not None or r['mttr_ms'] is not None:\n\t\t\t\treturn False\n\texcept:\n\t\tpass\n\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "timeline", + "message": "Not enough ack/clear data for a trend" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardMtta" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "flTitle" + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Flood Episodes" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "flCaption" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\tp = value['floods']['pct_time_in_flood']\n\t\tif p is None:\n\t\t\treturn ''\n\t\treturn '%s of window time in flood' % PrimeControls.fmt.pct(p, 1)\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "flTitleRow" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "justify": "space-between" + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "floodTable" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['floods']['episodes'] or []) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\tout = []\n\ttry:\n\t\teps = value['floods']['episodes'] or []\n\texcept:\n\t\teps = []\n\tfor e in eps:\n\t\ttry:\n\t\t\ttop = e['top_source_label'] or ''\n\t\t\tif top and e['top_source_count'] is not None:\n\t\t\t\ttop = '%s (%s)' % (top, PrimeControls.fmt.num(e['top_source_count']))\n\t\t\tout.append({'start': PrimeControls.fmt.day_clock(e['start_ms']), 'duration': PrimeControls.fmt.dur(e['duration_ms']), 'events': PrimeControls.fmt.num(e['event_count']), 'peak': PrimeControls.fmt.num(e['peak_bin_count']), 'top': top or '--', 'area': e['top_area'] or '--'})\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "columns": [ + { + "align": "center", + "editable": false, + "field": "start", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Start" + }, + "justify": "auto", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 1.3 + }, + { + "align": "center", + "editable": false, + "field": "duration", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Duration" + }, + "justify": "auto", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 1 + }, + { + "align": "center", + "editable": false, + "field": "events", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Events" + }, + "justify": "right", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 0.7 + }, + { + "align": "center", + "editable": false, + "field": "peak", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Peak / 10 min" + }, + "justify": "right", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 0.9 + }, + { + "align": "center", + "editable": false, + "field": "top", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Top Contributor" + }, + "justify": "auto", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 2 + }, + { + "align": "center", + "editable": false, + "field": "area", + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Area" + }, + "justify": "auto", + "render": "string", + "resizable": true, + "sort": "none", + "sortable": false, + "strictWidth": false, + "visible": true, + "width": 1 + } + ], + "pager": { + "bottom": false + }, + "rows": { + "height": 34 + }, + "selection": { + "enableRowSelection": false + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "floodEmpty" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['floods']['episodes'] or []) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "waves", + "message": "No flood episodes in range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardFloods" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "8px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "rowBottom" + }, + "position": { + "basis": "340px", + "grow": 1, + "shrink": 0 + }, + "props": { + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "content" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value) and value['meta']['event_count'] > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } } }, - "type": "ia.display.label" + "props": { + "direction": "column", + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" } ], "meta": { @@ -58,11 +2450,9 @@ "props": { "direction": "column", "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" + "gap": "12px" } }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/BadActors/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/BadActors/view.json index 70dbba3..50f49dc 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/BadActors/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/BadActors/view.json @@ -6,37 +6,33 @@ "propConfig": { "params.bundle": { "paramDirection": "input", - "persistent": true + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 800, + "width": 1600 } }, - "props": {}, "root": { "children": [ { "meta": { - "name": "ph" + "name": "wholeEmpty" }, - "props": { - "style": { - "classes": "PrimeControls/Empty" - }, - "text": "Bad Actors - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" + "position": { + "grow": 1 }, "propConfig": { - "props.text": { + "position.display": { "binding": { "config": { "path": "view.params.bundle" }, "transforms": [ { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", + "code": "\ttry:\n\t\tif not value:\n\t\t\treturn True\n\t\treturn int(value['meta']['event_count'] or 0) == 0\n\texcept:\n\t\treturn True", "type": "script" } ], @@ -45,24 +41,1038 @@ } }, "props": { - "style": { - "classes": "PrimeControls/Text/Muted" + "params": { + "icon": "inbox", + "message": "No alarm events in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblParetoTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Top Sources by Activations" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblParetoCaption" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\trows = value['pareto']['rows'] or []\n\t\ttotal = value['pareto']['total_activations'] or 0\n\texcept:\n\t\trows = []\n\t\ttotal = 0\n\tif not rows or not total:\n\t\treturn 'No activations in the selected range'\n\tn = min(len(rows), 10)\n\ttry:\n\t\tcum = rows[n - 1]['cum_pct']\n\texcept:\n\t\tcum = None\n\tif cum is None:\n\t\treturn 'Top %d sources of %s activations' % (n, PrimeControls.fmt.num(total))\n\treturn 'Top %d sources = %s of all %s activations' % (n, PrimeControls.fmt.pct(cum), PrimeControls.fmt.num(total))", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onRowClick": { + "config": { + "script": "\ttry:\n\t\trow = event.value\n\t\tsrc = row['source']\n\t\tlbl = row['label']\n\texcept:\n\t\treturn\n\ttry:\n\t\tsrc = src['value']\n\texcept:\n\t\tpass\n\ttry:\n\t\tlbl = lbl['value']\n\texcept:\n\t\tpass\n\tif not src:\n\t\treturn\n\ttry:\n\t\tsystem.perspective.openPopup('PC_AlarmDetail', 'PrimeControls/Popups/AlarmDetail', params = {'source': src, 'label': lbl}, showCloseIcon = True, draggable = True)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "tblPareto" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value['pareto']['rows'])\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "struct": { + "bundle": "{view.params.bundle}", + "focus": "{session.custom.PrimeControls.ui.badActorFocus}" + }, + "waitOnAll": false + }, + "transforms": [ + { + "code": "\ttry:\n\t\trows = value['bundle']['pareto']['rows'] or []\n\texcept:\n\t\trows = []\n\ttry:\n\t\ttotal = value['bundle']['pareto']['total_activations'] or 0\n\texcept:\n\t\ttotal = 0\n\ttry:\n\t\tfocus = value['focus'] or ''\n\texcept:\n\t\tfocus = ''\n\thi = {'backgroundColor': 'rgba(59, 125, 216, 0.18)', 'fontWeight': 'bold'}\n\tpri = ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']\n\tout = []\n\trank = 0\n\tfor r in rows[:10]:\n\t\ttry:\n\t\t\trank = rank + 1\n\t\t\tsrc = r['source'] or ''\n\t\t\tcnt = r['count'] or 0\n\t\t\td = {}\n\t\t\td['rank'] = rank\n\t\t\td['source'] = src\n\t\t\td['label'] = r['label'] or src\n\t\t\td['area'] = r['area'] or ''\n\t\t\td['count'] = cnt\n\t\t\tif total > 0:\n\t\t\t\td['share'] = round(cnt * 100.0 / total, 1)\n\t\t\telse:\n\t\t\t\td['share'] = 0\n\t\t\ttry:\n\t\t\t\td['cum'] = PrimeControls.fmt.pct(r['cum_pct'])\n\t\t\texcept:\n\t\t\t\td['cum'] = '--'\n\t\t\tif focus and src == focus:\n\t\t\t\tfor k in ('label', 'area', 'count', 'cum'):\n\t\t\t\t\td[k] = {'value': d[k], 'style': hi}\n\t\t\tpname = r['priority_name'] or ''\n\t\t\tif pname in pri:\n\t\t\t\td['priority'] = {'value': pname, 'style': {'classes': 'PrimeControls/PrioritySoft/' + pname}}\n\t\t\telse:\n\t\t\t\td['priority'] = pname\n\t\t\tout.append(d)\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "expr-struct" + } + } + }, + "props": { + "columns": [ + { + "field": "source", + "header": { + "title": "source" + }, + "visible": false + }, + { + "field": "rank", + "header": { + "justify": "center", + "title": "#" + }, + "justify": "center", + "width": 0.5 + }, + { + "field": "label", + "header": { + "title": "Source" + }, + "width": 3 + }, + { + "field": "area", + "header": { + "title": "Area" + }, + "width": 1.5 + }, + { + "field": "priority", + "header": { + "justify": "center", + "title": "Priority" + }, + "justify": "center", + "width": 1.3 + }, + { + "field": "count", + "header": { + "justify": "right", + "title": "Count" + }, + "justify": "right", + "render": "number", + "width": 1 + }, + { + "field": "share", + "header": { + "title": "Share of Total" + }, + "render": "number", + "number": "progress", + "progressBar": { + "min": 0, + "max": 100, + "bar": { + "color": "#3B7DD8" + } + }, + "width": 2.4 + }, + { + "field": "cum", + "header": { + "justify": "right", + "title": "Cumulative" + }, + "justify": "right", + "width": 1.3 + } + ], + "pager": { + "bottom": false, + "top": false + }, + "rows": { + "height": 34 + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "emptyPareto" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn not value['pareto']['rows']\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "bar_chart", + "message": "No activations in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardPareto" + }, + "position": { + "basis": "320px", + "grow": 1, + "shrink": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "4px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblFocus" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "struct": { + "bundle": "{view.params.bundle}", + "focus": "{session.custom.PrimeControls.ui.badActorFocus}" + }, + "waitOnAll": false + }, + "transforms": [ + { + "code": "\ttry:\n\t\tsrc = value['focus'] or ''\n\texcept:\n\t\tsrc = ''\n\tif not src:\n\t\treturn ''\n\tlabel = src\n\ttry:\n\t\tb = value['bundle']\n\t\tlists = [b['pareto']['rows'], b['chattering'], b['standing']['rows'], b['fleeting']['sources']]\n\t\tfor rows in lists:\n\t\t\tfor r in (rows or []):\n\t\t\t\tif r['source'] == src:\n\t\t\t\t\tlabel = r['label'] or src\n\t\t\t\t\traise StopIteration\n\texcept:\n\t\tpass\n\treturn 'Focused: %s' % label", + "type": "script" + } + ], + "type": "expr-struct" + } + } + }, + "props": { + "text": "" + }, + "type": "ia.display.label" + }, + { + "events": { + "dom": { + "onClick": { + "config": { + "script": "\tself.session.custom.PrimeControls.ui.badActorFocus = ''" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "icoClearFocus" + }, + "position": { + "shrink": 0 + }, + "props": { + "path": "material/close", + "style": { + "cursor": "pointer", + "fontSize": "16px" + } + }, + "type": "ia.display.icon" + } + ], + "meta": { + "name": "chipFocus" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "classes": "PrimeControls/Chip/Flat", + "gap": "6px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "lblFocusHint" + }, + "position": { + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Matching rows are highlighted below \u2014 click the X to clear" + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rowFocus" + }, + "position": { + "basis": "36px", + "shrink": 0 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "expression": "{session.custom.PrimeControls.ui.badActorFocus} != \"\"" + }, + "type": "expr" + } + } + }, + "props": { + "alignItems": "center", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblChatterTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Chattering" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblChatterCaption" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Rapid-cycling alarms (>10/hr, median gap <= 2 min)" + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onRowClick": { + "config": { + "script": "\ttry:\n\t\trow = event.value\n\t\tsrc = row['source']\n\t\tlbl = row['label']\n\texcept:\n\t\treturn\n\ttry:\n\t\tsrc = src['value']\n\texcept:\n\t\tpass\n\ttry:\n\t\tlbl = lbl['value']\n\texcept:\n\t\tpass\n\tif not src:\n\t\treturn\n\ttry:\n\t\tsystem.perspective.openPopup('PC_AlarmDetail', 'PrimeControls/Popups/AlarmDetail', params = {'source': src, 'label': lbl}, showCloseIcon = True, draggable = True)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "tblChatter" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value['chattering'])\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "struct": { + "bundle": "{view.params.bundle}", + "focus": "{session.custom.PrimeControls.ui.badActorFocus}" + }, + "waitOnAll": false + }, + "transforms": [ + { + "code": "\ttry:\n\t\trows = value['bundle']['chattering'] or []\n\texcept:\n\t\trows = []\n\ttry:\n\t\tfocus = value['focus'] or ''\n\texcept:\n\t\tfocus = ''\n\thi = {'backgroundColor': 'rgba(59, 125, 216, 0.18)', 'fontWeight': 'bold'}\n\tpri = ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']\n\tout = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tsrc = r['source'] or ''\n\t\t\td = {}\n\t\t\td['source'] = src\n\t\t\td['label'] = r['label'] or src\n\t\t\td['area'] = r['area'] or ''\n\t\t\td['count'] = r['count'] or 0\n\t\t\td['per_hour'] = PrimeControls.fmt.num(r['per_hour'], 1)\n\t\t\tgap = r['median_gap_s']\n\t\t\tif gap is None:\n\t\t\t\td['gap'] = '--'\n\t\t\telse:\n\t\t\t\td['gap'] = PrimeControls.fmt.dur(gap * 1000.0)\n\t\t\tif focus and src == focus:\n\t\t\t\tfor k in ('label', 'area', 'count', 'per_hour', 'gap'):\n\t\t\t\t\td[k] = {'value': d[k], 'style': hi}\n\t\t\tpname = r['priority_name'] or ''\n\t\t\tif pname in pri:\n\t\t\t\td['priority'] = {'value': pname, 'style': {'classes': 'PrimeControls/PrioritySoft/' + pname}}\n\t\t\telse:\n\t\t\t\td['priority'] = pname\n\t\t\tout.append(d)\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "expr-struct" + } + } + }, + "props": { + "columns": [ + { + "field": "source", + "header": { + "title": "source" + }, + "visible": false + }, + { + "field": "label", + "header": { + "title": "Source" + }, + "width": 3 + }, + { + "field": "area", + "header": { + "title": "Area" + }, + "width": 1.6 + }, + { + "field": "priority", + "header": { + "justify": "center", + "title": "Priority" + }, + "justify": "center", + "width": 1.4 + }, + { + "field": "count", + "header": { + "justify": "right", + "title": "Count" + }, + "justify": "right", + "render": "number", + "width": 1 + }, + { + "field": "per_hour", + "header": { + "justify": "right", + "title": "Per Hr" + }, + "justify": "right", + "width": 1.1 + }, + { + "field": "gap", + "header": { + "justify": "right", + "title": "Med Gap" + }, + "justify": "right", + "width": 1.2 + } + ], + "pager": { + "bottom": false, + "top": false + }, + "rows": { + "height": 34 + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "emptyChatter" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn not value['chattering']\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "check_circle", + "message": "No chattering alarms in range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardChatter" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "4px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblStandingTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Standing / Stale" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblStandingCaption" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "Alarms active for more than 24 h" + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onRowClick": { + "config": { + "script": "\ttry:\n\t\trow = event.value\n\t\tsrc = row['source']\n\t\tlbl = row['label']\n\texcept:\n\t\treturn\n\ttry:\n\t\tsrc = src['value']\n\texcept:\n\t\tpass\n\ttry:\n\t\tlbl = lbl['value']\n\texcept:\n\t\tpass\n\tif not src:\n\t\treturn\n\ttry:\n\t\tsystem.perspective.openPopup('PC_AlarmDetail', 'PrimeControls/Popups/AlarmDetail', params = {'source': src, 'label': lbl}, showCloseIcon = True, draggable = True)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "tblStanding" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value['standing']['rows'])\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "struct": { + "bundle": "{view.params.bundle}", + "focus": "{session.custom.PrimeControls.ui.badActorFocus}" + }, + "waitOnAll": false + }, + "transforms": [ + { + "code": "\ttry:\n\t\trows = value['bundle']['standing']['rows'] or []\n\texcept:\n\t\trows = []\n\ttry:\n\t\tfocus = value['focus'] or ''\n\texcept:\n\t\tfocus = ''\n\thi = {'backgroundColor': 'rgba(59, 125, 216, 0.18)', 'fontWeight': 'bold'}\n\tpri = ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']\n\tout = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tsrc = r['source'] or ''\n\t\t\td = {}\n\t\t\td['source'] = src\n\t\t\td['label'] = r['label'] or src\n\t\t\td['area'] = r['area'] or ''\n\t\t\td['age'] = PrimeControls.fmt.dur(r['age_ms'])\n\t\t\tif r['unacked']:\n\t\t\t\td['unacked'] = {'value': 'Yes', 'style': {'color': '#D64550', 'fontWeight': 'bold'}}\n\t\t\telse:\n\t\t\t\td['unacked'] = ''\n\t\t\tif focus and src == focus:\n\t\t\t\tfor k in ('label', 'area', 'age'):\n\t\t\t\t\td[k] = {'value': d[k], 'style': hi}\n\t\t\tpname = r['priority_name'] or ''\n\t\t\tif pname in pri:\n\t\t\t\td['priority'] = {'value': pname, 'style': {'classes': 'PrimeControls/PrioritySoft/' + pname}}\n\t\t\telse:\n\t\t\t\td['priority'] = pname\n\t\t\tout.append(d)\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "expr-struct" + } + } + }, + "props": { + "columns": [ + { + "field": "source", + "header": { + "title": "source" + }, + "visible": false + }, + { + "field": "label", + "header": { + "title": "Source" + }, + "width": 3 + }, + { + "field": "area", + "header": { + "title": "Area" + }, + "width": 1.6 + }, + { + "field": "priority", + "header": { + "justify": "center", + "title": "Priority" + }, + "justify": "center", + "width": 1.4 + }, + { + "field": "age", + "header": { + "justify": "right", + "title": "Active For" + }, + "justify": "right", + "width": 1.3 + }, + { + "field": "unacked", + "header": { + "justify": "center", + "title": "Unacked" + }, + "justify": "center", + "width": 1.1 + } + ], + "pager": { + "bottom": false, + "top": false + }, + "rows": { + "height": 34 + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "emptyStanding" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn not value['standing']['rows']\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "check_circle", + "message": "No standing alarms over 24 h" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardStanding" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "4px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblFleetingTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Fleeting" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblFleetingCaption" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ttot = value['fleeting']['total']\n\texcept:\n\t\ttot = None\n\tif not tot:\n\t\treturn 'Activations lasting under 10 s'\n\treturn '%s fleeting activations (under 10 s)' % PrimeControls.fmt.num(tot)", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + } + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onRowClick": { + "config": { + "script": "\ttry:\n\t\trow = event.value\n\t\tsrc = row['source']\n\t\tlbl = row['label']\n\texcept:\n\t\treturn\n\ttry:\n\t\tsrc = src['value']\n\texcept:\n\t\tpass\n\ttry:\n\t\tlbl = lbl['value']\n\texcept:\n\t\tpass\n\tif not src:\n\t\treturn\n\ttry:\n\t\tsystem.perspective.openPopup('PC_AlarmDetail', 'PrimeControls/Popups/AlarmDetail', params = {'source': src, 'label': lbl}, showCloseIcon = True, draggable = True)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "tblFleeting" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value['fleeting']['sources'])\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "struct": { + "bundle": "{view.params.bundle}", + "focus": "{session.custom.PrimeControls.ui.badActorFocus}" + }, + "waitOnAll": false + }, + "transforms": [ + { + "code": "\ttry:\n\t\trows = value['bundle']['fleeting']['sources'] or []\n\texcept:\n\t\trows = []\n\ttry:\n\t\tfocus = value['focus'] or ''\n\texcept:\n\t\tfocus = ''\n\thi = {'backgroundColor': 'rgba(59, 125, 216, 0.18)', 'fontWeight': 'bold'}\n\tpri = ['Diagnostic', 'Low', 'Medium', 'High', 'Critical']\n\tout = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tsrc = r['source'] or ''\n\t\t\td = {}\n\t\t\td['source'] = src\n\t\t\td['label'] = r['label'] or src\n\t\t\td['area'] = r['area'] or ''\n\t\t\td['count'] = r['count'] or 0\n\t\t\tmed = r['median_s']\n\t\t\tif med is None:\n\t\t\t\td['median'] = '--'\n\t\t\telse:\n\t\t\t\td['median'] = PrimeControls.fmt.dur(med * 1000.0)\n\t\t\tif focus and src == focus:\n\t\t\t\tfor k in ('label', 'area', 'count', 'median'):\n\t\t\t\t\td[k] = {'value': d[k], 'style': hi}\n\t\t\tpname = r['priority_name'] or ''\n\t\t\tif pname in pri:\n\t\t\t\td['priority'] = {'value': pname, 'style': {'classes': 'PrimeControls/PrioritySoft/' + pname}}\n\t\t\telse:\n\t\t\t\td['priority'] = pname\n\t\t\tout.append(d)\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "expr-struct" + } + } + }, + "props": { + "columns": [ + { + "field": "source", + "header": { + "title": "source" + }, + "visible": false + }, + { + "field": "label", + "header": { + "title": "Source" + }, + "width": 3 + }, + { + "field": "area", + "header": { + "title": "Area" + }, + "width": 1.6 + }, + { + "field": "priority", + "header": { + "justify": "center", + "title": "Priority" + }, + "justify": "center", + "width": 1.4 + }, + { + "field": "count", + "header": { + "justify": "right", + "title": "Count" + }, + "justify": "right", + "render": "number", + "width": 1 + }, + { + "field": "median", + "header": { + "justify": "right", + "title": "Med Dur" + }, + "justify": "right", + "width": 1.2 + } + ], + "pager": { + "bottom": false, + "top": false + }, + "rows": { + "height": 34 + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "emptyFleeting" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn not value['fleeting']['sources']\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "check_circle", + "message": "No fleeting activations in range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardFleeting" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "4px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "rowTables" + }, + "position": { + "basis": "280px", + "grow": 1, + "shrink": 1 + }, + "props": { + "alignItems": "stretch", + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "content" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value) and int(value['meta']['event_count'] or 0) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } } }, - "type": "ia.display.label" + "props": { + "direction": "column", + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" } ], + "custom": {}, "meta": { "name": "root" }, "props": { "direction": "column", "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" + "gap": "12px" } }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Journal/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Journal/view.json index 907da5c..821acba 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Journal/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Journal/view.json @@ -1,55 +1,463 @@ { - "custom": {}, + "custom": { + "page": 0, + "pageData": null + }, "params": { "bundle": null }, "propConfig": { + "custom.pageData": { + "binding": { + "config": { + "expression": "{session.custom.PrimeControls.query.refreshToken} + '|' + {session.custom.PrimeControls.query.startMs} + '|' + {session.custom.PrimeControls.query.endMs} + '|' + {view.custom.page}" + }, + "transforms": [ + { + "code": "\tsafe = {'rows': [], 'total': 0, 'page': 0, 'page_size': 50, 'truncated': False, 'error': None}\n\ttry:\n\t\tq = self.session.custom.PrimeControls.query\n\t\tif not q.startMs or not q.endMs:\n\t\t\treturn safe\n\t\ttry:\n\t\t\tpage = max(0, int(self.view.custom.page or 0))\n\t\texcept:\n\t\t\tpage = 0\n\t\treturn PrimeControls.alarms.getJournalPage(q.startMs, q.endMs, {'priorities': list(q.priorities), 'areas': list(q.areas), 'states': list(q.states), 'search': q.search}, page, 50)\n\texcept:\n\t\timport sys\n\t\tsafe['error'] = '%s' % (sys.exc_info()[1],)\n\t\treturn safe", + "type": "script" + } + ], + "type": "expr" + } + }, "params.bundle": { "paramDirection": "input", - "persistent": true + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 800, + "width": 1600 } }, - "props": {}, "root": { "children": [ { - "meta": { - "name": "ph" - }, - "props": { - "style": { - "classes": "PrimeControls/Empty" + "children": [ + { + "meta": { + "name": "lblTotal" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ttotal = int(value['total'] or 0)\n\texcept:\n\t\ttotal = 0\n\ttry:\n\t\ttxt = '%s events' % PrimeControls.fmt.num(total)\n\texcept:\n\t\ttxt = '%d events' % total\n\ttry:\n\t\tif value['truncated']:\n\t\t\ttxt = txt + ' (truncated)'\n\texcept:\n\t\tpass\n\treturn txt", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "textStyle": { + "fontWeight": "bold" + } + }, + "type": "ia.display.label" }, - "text": "Journal - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" - }, - "propConfig": { - "props.text": { - "binding": { - "config": { - "path": "view.params.bundle" + { + "meta": { + "name": "lblError" + }, + "position": { + "shrink": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn bool(value['error'])\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } }, - "transforms": [ - { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", + "props.text": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['error'] or ''\n\texcept:\n\t\treturn ''", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted", + "color": "#D64550" + } + }, + "type": "ia.display.label" + }, + { + "children": [], + "meta": { + "name": "spacer" + }, + "position": { + "grow": 1 + }, + "props": {}, + "type": "ia.container.flex" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\ttry:\n\t\tp = int(self.view.custom.page or 0)\n\texcept:\n\t\tp = 0\n\tif p > 0:\n\t\tself.view.custom.page = p - 1" + }, + "scope": "G", "type": "script" } - ], - "type": "property" - } + } + }, + "meta": { + "name": "btnPrev" + }, + "position": { + "basis": "80px", + "shrink": 0 + }, + "propConfig": { + "props.enabled": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn int(value['page'] or 0) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "primary": false, + "text": "Prev" + }, + "type": "ia.input.button" + }, + { + "meta": { + "name": "lblPage" + }, + "position": { + "shrink": 0 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ttotal = int(value['total'] or 0)\n\t\tsize = int(value['page_size'] or 50)\n\t\tpage = int(value['page'] or 0)\n\texcept:\n\t\ttotal = 0\n\t\tsize = 50\n\t\tpage = 0\n\tif size < 1:\n\t\tsize = 50\n\tpages = (total + size - 1) // size\n\tif pages < 1:\n\t\tpages = 1\n\ttry:\n\t\treturn 'Page %s of %s' % (PrimeControls.fmt.num(page + 1), PrimeControls.fmt.num(pages))\n\texcept:\n\t\treturn 'Page %d of %d' % (page + 1, pages)", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "textStyle": { + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\ttry:\n\t\tp = int(self.view.custom.page or 0)\n\texcept:\n\t\tp = 0\n\ttry:\n\t\td = self.view.custom.pageData\n\t\ttotal = int(d['total'] or 0)\n\t\tsize = int(d['page_size'] or 50)\n\texcept:\n\t\ttotal = 0\n\t\tsize = 50\n\tif size < 1:\n\t\tsize = 50\n\tpages = (total + size - 1) // size\n\tif pages < 1:\n\t\tpages = 1\n\tif p < pages - 1:\n\t\tself.view.custom.page = p + 1" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnNext" + }, + "position": { + "basis": "80px", + "shrink": 0 + }, + "propConfig": { + "props.enabled": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\ttotal = int(value['total'] or 0)\n\t\tsize = int(value['page_size'] or 50)\n\t\tpage = int(value['page'] or 0)\n\texcept:\n\t\treturn False\n\tif size < 1:\n\t\tsize = 50\n\treturn (page + 1) * size < total", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "primary": false, + "text": "Next" + }, + "type": "ia.input.button" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\ttry:\n\t\tq = self.session.custom.PrimeControls.query\n\t\tcsv = PrimeControls.alarms.journalCsv(q.startMs, q.endMs, {'priorities': list(q.priorities), 'areas': list(q.areas), 'states': list(q.states), 'search': q.search})\n\t\tsystem.perspective.download('alarm_journal.csv', csv)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "btnExport" + }, + "position": { + "basis": "110px", + "shrink": 0 + }, + "props": { + "primary": true, + "text": "Export CSV" + }, + "type": "ia.input.button" } + ], + "meta": { + "name": "toolbar" + }, + "position": { + "shrink": 0 }, "props": { + "alignItems": "center", "style": { - "classes": "PrimeControls/Text/Muted" + "classes": "PrimeControls/Toolbar", + "gap": "8px" } }, - "type": "ia.display.label" + "type": "ia.container.flex" + }, + { + "children": [ + { + "events": { + "component": { + "onRowClick": { + "config": { + "script": "\trow = event.value\n\tevt = {}\n\ttry:\n\t\tfor k in row:\n\t\t\tv = row[k]\n\t\t\ttry:\n\t\t\t\tevt[k] = v['value']\n\t\t\texcept:\n\t\t\t\tevt[k] = v\n\texcept:\n\t\tevt = {}\n\ttry:\n\t\tif evt:\n\t\t\tsystem.perspective.openPopup('PC_EventDetail', 'PrimeControls/Popups/EventDetail', params = {'event': evt}, showCloseIcon = True, draggable = True)\n\texcept:\n\t\tpass" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "tblJournal" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['rows'] or []) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.data": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\tstate_cls = {'active': 'PrimeControls/State/Active', 'ack': 'PrimeControls/State/Acked', 'clear': 'PrimeControls/State/Cleared'}\n\tprio_cls = {'Diagnostic': 'PrimeControls/PrioritySoft/Diagnostic', 'Low': 'PrimeControls/PrioritySoft/Low', 'Medium': 'PrimeControls/PrioritySoft/Medium', 'High': 'PrimeControls/PrioritySoft/High', 'Critical': 'PrimeControls/PrioritySoft/Critical'}\n\ttry:\n\t\trows = value['rows'] or []\n\texcept:\n\t\trows = []\n\tout = []\n\tfor r in rows:\n\t\ttry:\n\t\t\tsc = state_cls.get(r['state'], '')\n\t\t\tpc = prio_cls.get(r['priority_name'], '')\n\t\t\tout.append({'time_label': r['time_label'] or '', 'state_label': {'value': r['state_label'] or '', 'style': {'classes': sc}}, 'priority_name': {'value': r['priority_name'] or '', 'style': {'classes': pc}}, 'label': r['label'] or '', 'area': r['area'] or '', 'ack_user': r['ack_user'] or '', 'id': r['id'] or '', 'time_ms': r['time_ms'] or 0, 'source': r['source'] or '', 'state': r['state'] or '', 'priority': r['priority']})\n\t\texcept:\n\t\t\tpass\n\treturn out", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "columns": [ + { + "field": "time_label", + "header": { + "title": "Time" + }, + "sortable": false, + "strictWidth": true, + "width": 150 + }, + { + "field": "state_label", + "header": { + "title": "State" + }, + "justify": "center", + "sortable": false, + "strictWidth": true, + "width": 110 + }, + { + "field": "priority_name", + "header": { + "title": "Priority" + }, + "justify": "center", + "sortable": false, + "strictWidth": true, + "width": 110 + }, + { + "field": "label", + "header": { + "title": "Alarm" + }, + "sortable": false + }, + { + "field": "area", + "header": { + "title": "Area" + }, + "sortable": false, + "strictWidth": true, + "width": 160 + }, + { + "field": "ack_user", + "header": { + "title": "Ack By" + }, + "sortable": false, + "strictWidth": true, + "width": 120 + }, + { + "field": "id", + "visible": false + }, + { + "field": "time_ms", + "visible": false + }, + { + "field": "source", + "visible": false + }, + { + "field": "state", + "visible": false + }, + { + "field": "priority", + "visible": false + } + ], + "pager": { + "bottom": false, + "top": false + } + }, + "type": "ia.display.table" + }, + { + "meta": { + "name": "empty" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.custom.pageData" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['rows'] or []) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "search", + "message": "No events match the current filters" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardTable" + }, + "position": { + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card" + } + }, + "type": "ia.container.flex" } ], "meta": { @@ -58,11 +466,9 @@ "props": { "direction": "column", "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" + "gap": "12px" } }, "type": "ia.container.flex" } -} +} \ No newline at end of file diff --git a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Overview/view.json b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Overview/view.json index 0087324..c93abaf 100644 --- a/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Overview/view.json +++ b/ignition/gateway/projects/PrimeBAT/com.inductiveautomation.perspective/views/PrimeControls/Tabs/Overview/view.json @@ -6,37 +6,33 @@ "propConfig": { "params.bundle": { "paramDirection": "input", - "persistent": true + "persistent": false + } + }, + "props": { + "defaultSize": { + "height": 900, + "width": 1600 } }, - "props": {}, "root": { "children": [ { "meta": { - "name": "ph" + "name": "emptyWhole" }, - "props": { - "style": { - "classes": "PrimeControls/Empty" - }, - "text": "Overview - built in Phase 2" - }, - "type": "ia.display.label" - }, - { - "meta": { - "name": "evt" + "position": { + "grow": 1 }, "propConfig": { - "props.text": { + "position.display": { "binding": { "config": { "path": "view.params.bundle" }, "transforms": [ { - "code": "\ttry:\n\t\treturn 'bundle: %s events in range' % value['meta']['event_count']\n\texcept:\n\t\treturn 'bundle: not loaded'", + "code": "\ttry:\n\t\treturn not (int(value['meta']['event_count']) > 0)\n\texcept:\n\t\treturn True", "type": "script" } ], @@ -45,11 +41,1756 @@ } }, "props": { - "style": { - "classes": "PrimeControls/Text/Muted" + "params": { + "icon": "inbox", + "message": "No alarm events in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + }, + { + "children": [ + { + "meta": { + "name": "repPriority" + }, + "position": { + "basis": "120px", + "shrink": 0 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "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", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "row", + "elementPosition": { + "basis": "0px", + "grow": 1, + "shrink": 1 + }, + "path": "PrimeControls/Components/PriorityCard", + "style": { + "gap": "10px", + "overflow": "visible" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + }, + { + "children": [ + { + "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": "kpiShelved" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.delta": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['kpis']['shelved_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']['shelved_now']['value'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Shelved" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "kpiStanding" + }, + "position": { + "basis": "100px", + "grow": 1 + }, + "propConfig": { + "props.params.delta": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn value['kpis']['standing_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']['standing_count']['value'])\n\texcept:\n\t\treturn '--'", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "label": "Standing" + }, + "path": "PrimeControls/Components/KpiCard" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "rowStatus" + }, + "position": { + "basis": "104px", + "shrink": 0 + }, + "props": { + "alignItems": "stretch", + "style": { + "gap": "10px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblRateTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Alarm Rate Timeline" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "lblRateCaption" + }, + "position": { + "grow": 1 + }, + "props": { + "style": { + "classes": "PrimeControls/Text/Muted" + }, + "text": "flood bins in red \u00b7 dashed line = ISA target rate", + "textStyle": { + "textAlign": "right" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "rateHeader" + }, + "position": { + "shrink": 0 + }, + "props": { + "alignItems": "center", + "style": { + "gap": "8px" + } + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "chartRate" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['rate']['bins']) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } + }, + "props.dataSources.rate": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "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", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "background": { + "color": "", + "gradient": { + "colors": [], + "direction": "linear", + "rotation": 0 + }, + "opacity": 1, + "render": "none" + }, + "cursor": { + "enabled": true, + "lineX": { + "enabled": true, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 0.4, + "width": 1 + } + }, + "lineY": { + "enabled": false, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 0.4, + "width": 1 + } + }, + "series": "" + }, + "enableTransitions": false, + "legend": { + "absolute": { + "x": 0, + "y": 0 + }, + "enabled": true, + "labels": { + "font": { + "color": "", + "size": 16, + "weight": 400 + }, + "text": "[bold]{name}[/]" + }, + "markers": { + "cornerRadius": { + "bottomLeft": 0, + "bottomRight": 0, + "topLeft": 0, + "topRight": 0 + }, + "enabled": true, + "height": 20, + "icon": { + "color": "", + "height": 20, + "horizontalCenter": "left", + "path": "", + "verticalCenter": "top", + "width": 20 + }, + "mirrorLookOfSeries": true, + "stroke": { + "color": "", + "opacity": 0, + "width": 1 + }, + "width": 20 + }, + "position": "bottom" + }, + "scrollBars": { + "horizontal": { + "enabled": false, + "series": "" + }, + "vertical": { + "enabled": false, + "series": "" + } + }, + "series": [ + { + "candlestick": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + } + }, + "high": { + "x": "", + "y": "" + }, + "low": { + "x": "", + "y": "" + }, + "open": { + "x": "", + "y": "" + } + }, + "column": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "#3B7DD8", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "height": null, + "stacked": true, + "stroke": { + "color": "", + "opacity": 0, + "width": 1 + }, + "width": 80 + }, + "open": { + "x": "", + "y": "" + } + }, + "data": { + "source": "rate", + "x": "t", + "y": "count_base" + }, + "defaultState": { + "visible": true + }, + "hiddenInLegend": false, + "label": { + "text": "Alarms" + }, + "line": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "name": "counts", + "render": "column", + "stepLine": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "pointerLength": 4, + "text": "{categoryX}: [bold]{valueY}[/] alarms" + }, + "visible": true, + "xAxis": "time", + "yAxis": "count", + "zIndex": 0 + }, + { + "candlestick": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + } + }, + "high": { + "x": "", + "y": "" + }, + "low": { + "x": "", + "y": "" + }, + "open": { + "x": "", + "y": "" + } + }, + "column": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "#D64550", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "height": null, + "stacked": true, + "stroke": { + "color": "", + "opacity": 0, + "width": 1 + }, + "width": 80 + }, + "open": { + "x": "", + "y": "" + } + }, + "data": { + "source": "rate", + "x": "t", + "y": "count_flood" + }, + "defaultState": { + "visible": true + }, + "hiddenInLegend": false, + "label": { + "text": "Flood bins" + }, + "line": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "name": "flood", + "render": "column", + "stepLine": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "pointerLength": 4, + "text": "{categoryX}: [bold]{valueY}[/] alarms (flood)" + }, + "visible": true, + "xAxis": "time", + "yAxis": "count", + "zIndex": 1 + }, + { + "candlestick": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "stacked": false, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + } + }, + "high": { + "x": "", + "y": "" + }, + "low": { + "x": "", + "y": "" + }, + "open": { + "x": "", + "y": "" + } + }, + "column": { + "appearance": { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": "", + "min": "" + }, + "height": null, + "stacked": false, + "stroke": { + "color": "", + "opacity": 0, + "width": 1 + }, + "width": 80 + }, + "open": { + "x": "", + "y": "" + } + }, + "data": { + "source": "rate", + "x": "t", + "y": "target" + }, + "defaultState": { + "visible": true + }, + "hiddenInLegend": false, + "label": { + "text": "ISA target" + }, + "line": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "#E8883A", + "dashArray": "6,4", + "opacity": 1, + "width": 2 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "name": "target", + "render": "line", + "stepLine": { + "appearance": { + "bullets": [ + { + "deriveFieldsFromData": { + "fill": { + "color": "", + "opacity": "" + }, + "rotation": "", + "stroke": { + "color": "", + "opacity": "", + "width": "" + } + }, + "enabled": false, + "fill": { + "color": "", + "opacity": 1 + }, + "heatRules": { + "dataField": "", + "enabled": false, + "max": 100, + "min": 2 + }, + "label": { + "hideOversized": true, + "position": { + "dx": 0, + "dy": 0 + }, + "text": "{value}", + "truncate": true + }, + "radius": 5, + "render": "circle", + "rotation": 0, + "stroke": { + "color": "", + "opacity": 1, + "width": 1 + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": true, + "getFillFromObject": true, + "pointerLength": 4, + "text": "{name}: [bold]{valueY}[/]" + } + } + ], + "connect": true, + "fill": { + "color": "", + "opacity": 0 + }, + "minDistance": 0.5, + "stroke": { + "color": "", + "dashArray": "", + "opacity": 1, + "width": 3 + }, + "tensionX": 1, + "tensionY": 1 + }, + "open": { + "x": "", + "y": "" + } + }, + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": false, + "pointerLength": 4, + "text": "" + }, + "visible": true, + "xAxis": "time", + "yAxis": "count", + "zIndex": 2 + } + ], + "style": { + "classes": "" + }, + "subtitle": { + "appearance": { + "color": "", + "font": { + "size": "", + "weight": 500 + }, + "padding": { + "bottom": 0, + "left": 0, + "right": 0, + "top": 0 + } + }, + "text": "" + }, + "title": { + "appearance": { + "color": "", + "font": { + "size": "", + "weight": 700 + }, + "padding": { + "bottom": 0, + "left": 0, + "right": 0, + "top": 0 + } + }, + "text": "" + }, + "xAxes": [ + { + "appearance": { + "font": { + "size": "", + "weight": 500 + }, + "grid": { + "color": "", + "dashArray": "", + "minDistance": 60, + "opacity": 0, + "position": 0.5 + }, + "inside": false, + "labels": { + "color": "", + "horizontalCenter": "middle", + "opacity": 1, + "rotation": 0, + "verticalCenter": "middle" + }, + "opposite": false + }, + "category": { + "break": { + "enabled": false, + "endCategory": "", + "size": 0.05, + "startCategory": "" + } + }, + "date": { + "baseInterval": { + "count": 1, + "enabled": false, + "skipEmptyPeriods": false, + "timeUnit": "hour" + }, + "break": { + "enabled": false, + "endDate": "", + "size": 0.05, + "startDate": "" + }, + "format": "M/d", + "inputFormat": "yyyy-MM-dd kk:mm:ss", + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "inversed": false, + "label": { + "color": "", + "enabled": false, + "text": "" + }, + "name": "time", + "render": "category", + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": false, + "pointerLength": 4, + "text": "" + }, + "value": { + "break": { + "enabled": false, + "endValue": 100, + "size": 0.05, + "startValue": 0 + }, + "format": "#,###.##", + "logarithmic": false, + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "visible": true + } + ], + "yAxes": [ + { + "appearance": { + "font": { + "size": "", + "weight": 500 + }, + "grid": { + "color": "", + "dashArray": "3,3", + "minDistance": 30, + "opacity": 0.4, + "position": 0.5 + }, + "inside": false, + "labels": { + "color": "", + "horizontalCenter": "middle", + "opacity": 1, + "rotation": 0, + "verticalCenter": "middle" + }, + "opposite": false + }, + "category": { + "break": { + "enabled": false, + "endCategory": "", + "size": 0.05, + "startCategory": "" + } + }, + "date": { + "baseInterval": { + "count": 1, + "enabled": false, + "skipEmptyPeriods": false, + "timeUnit": "hour" + }, + "break": { + "enabled": false, + "endDate": "", + "size": 0.05, + "startDate": "" + }, + "format": "M/d", + "inputFormat": "yyyy-MM-dd kk:mm:ss", + "range": { + "max": "", + "min": "", + "useStrict": false + } + }, + "inversed": false, + "label": { + "color": "", + "enabled": true, + "text": "Alarms / 10 min" + }, + "name": "count", + "render": "value", + "tooltip": { + "background": { + "color": "", + "opacity": 1 + }, + "cornerRadius": 3, + "enabled": false, + "pointerLength": 4, + "text": "" + }, + "value": { + "break": { + "enabled": false, + "endValue": 100, + "size": 0.05, + "startValue": 0 + }, + "format": "#,###", + "logarithmic": false, + "range": { + "max": "", + "min": 0, + "useStrict": false + } + }, + "visible": true + } + ], + "dataSources": { + "rate": [] + } + }, + "type": "ia.chart.xy" + }, + { + "meta": { + "name": "emptyRate" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['rate']['bins']) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "bar_chart", + "message": "No rate data in the selected range" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardRate" + }, + "position": { + "basis": "0px", + "grow": 3 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px", + "minHeight": "260px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "lblInsightsTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "What Changed" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repInsights" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "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", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "column", + "elementPosition": { + "basis": "32px", + "grow": 0, + "shrink": 0 + }, + "path": "PrimeControls/Components/InsightRow", + "style": { + "gap": "4px", + "overflow": "auto" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + }, + { + "meta": { + "name": "emptyInsights" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['insights']) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "insights", + "message": "No notable changes in this window" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardInsights" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "lblTopTitle" + }, + "position": { + "shrink": 0 + }, + "props": { + "style": { + "classes": "PrimeControls/CardTitle" + }, + "text": "Top 5 Sources" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "repSources" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "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", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "direction": "column", + "elementPosition": { + "basis": "34px", + "grow": 0, + "shrink": 0 + }, + "path": "PrimeControls/Components/SourceRow", + "style": { + "gap": "4px", + "overflow": "auto" + }, + "useDefaultViewHeight": false, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + }, + { + "meta": { + "name": "emptyTop" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn len(value['top_sources']) == 0\n\texcept:\n\t\treturn True", + "type": "script" + } + ], + "type": "property" + } + } + }, + "props": { + "params": { + "icon": "leaderboard", + "message": "No alarm sources in this window" + }, + "path": "PrimeControls/Components/EmptyState" + }, + "type": "ia.display.view" + } + ], + "meta": { + "name": "cardTop" + }, + "position": { + "basis": "0px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "classes": "PrimeControls/Card", + "gap": "6px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "rowBottom" + }, + "position": { + "basis": "0px", + "grow": 2 + }, + "props": { + "style": { + "gap": "12px", + "minHeight": "200px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "content" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "position.display": { + "binding": { + "config": { + "path": "view.params.bundle" + }, + "transforms": [ + { + "code": "\ttry:\n\t\treturn int(value['meta']['event_count']) > 0\n\texcept:\n\t\treturn False", + "type": "script" + } + ], + "type": "property" + } } }, - "type": "ia.display.label" + "props": { + "direction": "column", + "style": { + "gap": "12px" + } + }, + "type": "ia.container.flex" } ], "meta": { @@ -58,11 +1799,9 @@ "props": { "direction": "column", "style": { - "alignItems": "center", - "classes": "PrimeControls/Card", - "justifyContent": "center" + "gap": "12px" } }, "type": "ia.container.flex" } -} +} \ No newline at end of file