From 171aaca0265ee0f12ed444aaff92055bb70d1e36 Mon Sep 17 00:00:00 2001 From: nodo kakabadze Date: Thu, 25 Sep 2025 20:19:01 +0400 Subject: [PATCH] Added queries --- .../views/autStand/Alarms/RealTime/view.json | 1132 ++++++++++++----- .../Alarms-autStand/GetActiveAlarms/query.sql | 88 +- .../query.sql | 38 +- .../Alarms-autStand/GetAlarms/query.sql | 142 +-- .../GetAlarmsWithCount/query.sql | 96 +- 5 files changed, 943 insertions(+), 553 deletions(-) diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/view.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/view.json index 9e49f848..af6c43ce 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/view.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/view.json @@ -1,6 +1,24 @@ { - "custom": {}, + "custom": { + "activityLogger": { + "alt_pageid": "alarms", + "pageid": "alarms/ActiveAlarms", + "start_time": { + "$": [ + "ts", + 192, + 1748425447154 + ], + "$ts": 1748425447154 + } + } + }, "params": {}, + "propConfig": { + "custom.activityLogger": { + "persistent": true + } + }, "props": { "defaultSize": { "height": 1080, @@ -384,6 +402,60 @@ ] }, "type": "ia.input.button" + }, + { + "meta": { + "name": "Dropdown" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.value": { + "persistent": false + } + }, + "props": { + "options": [ + { + "label": "MCM01", + "value": "MCM01" + }, + { + "label": "MCM02", + "value": "MCM02" + }, + { + "label": "MCM03", + "value": "MCM03" + }, + { + "label": "MCM04", + "value": "MCM03" + }, + { + "label": "MCM05", + "value": "MCM05" + } + ], + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "hjsgdfn", + "pageScope": false, + "script": "\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.dropdown" } ], "custom": { @@ -409,7 +481,7 @@ "name": "FlexContainer" }, "position": { - "basis": "700px", + "basis": "881px", "shrink": 0 }, "props": { @@ -439,7 +511,7 @@ "component": { "onActionPerformed": { "config": { - "script": "\tpayload \u003d {}\n\tfilter_on \u003d \"false\"\n\tpayload[\"reset\"] \u003d filter_on\n\tsystem.perspective.sendMessage(\"reset-filters\", payload \u003dpayload, scope \u003d \"page\")\n\tdefault_priorities \u003d {\n\t \"diagnostic\": False,\n\t \"low\": False,\n\t \"medium\": False,\n\t \"high\": False,\n\t \"critical\": False\n\t}\n\tself.parent.parent.parent.getChild(\"FlexContainer_0\").getChild(\"Table\").props.filter.text \u003d \"\"\n\tself.parent.parent.getChild(\"FlexContainer\").custom.priorities \u003d default_priorities" + "script": "\tpayload \u003d {}\n\tfilter_on \u003d \"false\"\n\tpayload[\"reset\"] \u003d filter_on\n\tsystem.perspective.sendMessage(\"reset-filters\", payload \u003dpayload, scope \u003d \"page\")\n\tdefault_priorities \u003d {\n\t \"diagnostic\": False,\n\t \"low\": False,\n\t \"medium\": False,\n\t \"high\": False,\n\t \"critical\": False\n\t}\n\tself.parent.parent.parent.getChild(\"FlexContainer_0\").getChild(\"Table\").props.filter.text \u003d \"\"\n\tself.parent.parent.getChild(\"FlexContainer\").custom.priorities \u003d default_priorities\n\tself.parent.parent.getChild(\"FlexContainer\").getChild(\"Dropdown\").props.value \u003d \"\"" }, "scope": "G", "type": "script" @@ -595,7 +667,7 @@ "component": { "onRowDoubleClick": { "config": { - "script": "\n\tmyData \u003d self.props.selection.data\n\n\tautStand.Alarms.handleClick(myData)\n\t\n\t" + "script": "\n\tmyData \u003d self.props.selection.data\n\n\tautstand.Alarms.handleClick(myData)\n\t\n\t" }, "scope": "G", "type": "script" @@ -616,13 +688,21 @@ }, "transforms": [ { - "code": "\t\n\tpriority_to_number \u003d {\n\t \"critical\": 4,\n\t \"high\": 3,\n\t \"medium\": 2,\n\t \"low\": 1,\n\t \"diagnostic\": 0\n\t}\n\t\n\t\n\t# Collect enabled priorities\n\tenabled \u003d [str(priority_to_number[k]) for k, v in value.items() if v]\n\t\n\tresult \u003d \",\".join(enabled)\n\t\n\tif not result:\n\t\treturn \"\"\n\t\n\treturn result\n\t\n", + "code": "\t# value looks like: {\"diagnostic\": True, \"high\": True, \"low\": False, ...}\n\tfrom system.util import jsonEncode, jsonDecode\n\t\n\tprio_map \u003d {\u0027diagnostic\u0027:0,\u0027low\u0027:1,\u0027medium\u0027:2,\u0027high\u0027:3,\u0027critical\u0027:4}\n\t\n\t# Coerce Perspective objects (PyDictionary/Java Map) to a plain Python dict\n\ttry:\n\t d \u003d value if isinstance(value, dict) else jsonDecode(jsonEncode(value))\n\texcept:\n\t d \u003d {}\n\t\n\t# Normalize keys and build CSV (\u0027\u0027 means \"all\")\n\tenabled \u003d [str(prio_map[k]) for k in prio_map if bool(d.get(k, False))]\n\treturn \",\".join(enabled) if enabled else \"\"", "type": "script" } ], "type": "property" } }, + "props.columns[3].filter.string.value": { + "binding": { + "config": { + "path": ".../FlexContainer/FlexContainer/Dropdown.props.value" + }, + "type": "property" + } + }, "props.data": { "binding": { "config": { @@ -633,11 +713,11 @@ "enabled": true, "rate": "3" }, - "queryPath": "Alarms-autStand/GetActiveAlarms" + "queryPath": "GetActiveAlarms" }, "transforms": [ { - "code": "\n\tfrom system.dataset import toPyDataSet\n\n\tds \u003d toPyDataSet(value)\n\tdata \u003d []\n\n\tcolumn_names \u003d [col for col in ds.columnNames if col !\u003d \"EndTimestamp\"]\n\t\n\n\tfor row in ds:\n\t\tpriority \u003d row[\"Priority\"]\n\n\t\t# Use style class names from Perspective\n\t\tif priority \u003d\u003d \"High\":\n\t\t\tclassName \u003d \"Alarms-Styles/High\"\n\t\telif priority \u003d\u003d \"Medium\":\n\t\t\tclassName \u003d \"Alarms-Styles/Medium\"\n\t\telif priority \u003d\u003d \"Low\":\n\t\t\tclassName \u003d \"Alarms-Styles/Low\"\n\t\telif priority \u003d\u003d \"Diagnostic\":\n\t\t\tclassName \u003d \"Alarms-Styles/Diagnostic\"\n\t\telse:\n\t\t\tclassName \u003d \"Alarms-Styles/NoAlarm\"\n\n\t\t# Apply the style class to all cells in the row\n\t\trow_dict \u003d {\n\t\t\tcol: {\n\t\t\t\t\"value\": row[col],\n\t\t\t\t\"style\": { \"classes\": className }\n\t\t\t} for col in column_names\n\t\t}\n\t\tdata.append(row_dict)\n\n\treturn data", + "code": "\n\tfrom system.dataset import toPyDataSet\n\n\tds \u003d toPyDataSet(value)\n\tdata \u003d []\n\n\tcolumn_names \u003d list(ds.columnNames)\n\n\tfor row in ds:\n\t\tpriority \u003d row[\"Priority\"]\n\n\t\t# Use style class names from Perspective\n\t\tif priority \u003d\u003d \"High\":\n\t\t\tclassName \u003d \"Alarms-Styles/High\"\n\t\telif priority \u003d\u003d \"Medium\":\n\t\t\tclassName \u003d \"Alarms-Styles/Medium\"\n\t\telif priority \u003d\u003d \"Low\":\n\t\t\tclassName \u003d \"Alarms-Styles/Low\"\n\t\telif priority \u003d\u003d \"Diagnostic\":\n\t\t\tclassName \u003d \"Alarms-Styles/Diagnostic\"\n\t\telse:\n\t\t\tclassName \u003d \"Alarms-Styles/NoAlarm\"\n\n\t\t# Apply the style class to all cells in the row\n\t\trow_dict \u003d {\n\t\t\tcol: {\n\t\t\t\t\"value\": row[col],\n\t\t\t\t\"style\": { \"classes\": className }\n\t\t\t} for col in column_names\n\t\t}\n\t\tdata.append(row_dict)\n\n\n\treturn data", "type": "script" } ], @@ -652,7 +732,7 @@ "boolean": "checkbox", "dateFormat": "MM/DD/YYYY", "editable": false, - "field": "NumberID", + "field": "ID", "filter": { "boolean": { "condition": "" @@ -686,9 +766,9 @@ "style": { "classes": "" }, - "title": "Number (ID)" + "title": "" }, - "justify": "left", + "justify": "auto", "nullFormat": { "includeNullStrings": false, "nullFormatValue": "", @@ -737,7 +817,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": 70 + "width": "" }, { "align": "center", @@ -928,7 +1008,7 @@ "boolean": "checkbox", "dateFormat": "MM/DD/YYYY", "editable": false, - "field": "Priority", + "field": "Location", "filter": { "boolean": { "condition": "" @@ -937,16 +1017,15 @@ "condition": "", "value": "" }, - "enabled": false, + "enabled": true, "number": { "condition": "", "value": "" }, "string": { - "condition": "", - "value": "" + "condition": "equals" }, - "visible": "on-hover" + "visible": "never" }, "footer": { "align": "center", @@ -1020,7 +1099,7 @@ "boolean": "checkbox", "dateFormat": "MM/DD/YYYY", "editable": false, - "field": "Location", + "field": "Priority", "filter": { "boolean": { "condition": "" @@ -1090,7 +1169,7 @@ }, "render": "auto", "resizable": true, - "sort": "ascending", + "sort": "none", "sortable": true, "strictWidth": false, "style": { @@ -1199,98 +1278,6 @@ "visible": true, "width": 150 }, - { - "align": "center", - "boolean": "checkbox", - "dateFormat": "MM/DD/YYYY", - "editable": false, - "field": "Tag", - "filter": { - "boolean": { - "condition": "" - }, - "date": { - "condition": "", - "value": "" - }, - "enabled": false, - "number": { - "condition": "", - "value": "" - }, - "string": { - "condition": "", - "value": "" - }, - "visible": "on-hover" - }, - "footer": { - "align": "center", - "justify": "left", - "style": { - "classes": "" - }, - "title": "" - }, - "header": { - "align": "center", - "justify": "left", - "style": { - "classes": "" - }, - "title": "" - }, - "justify": "auto", - "nullFormat": { - "includeNullStrings": false, - "nullFormatValue": "", - "strict": false - }, - "number": "value", - "numberFormat": "0,0.##", - "progressBar": { - "bar": { - "color": "", - "style": { - "classes": "" - } - }, - "max": 100, - "min": 0, - "track": { - "color": "", - "style": { - "classes": "" - } - }, - "value": { - "enabled": true, - "format": "0,0.##", - "justify": "center", - "style": { - "classes": "" - } - } - }, - "render": "auto", - "resizable": true, - "sort": "none", - "sortable": true, - "strictWidth": false, - "style": { - "classes": "" - }, - "toggleSwitch": { - "color": { - "selected": "", - "unselected": "" - } - }, - "viewParams": {}, - "viewPath": "", - "visible": true, - "width": 80 - }, { "align": "center", "boolean": "checkbox", @@ -1476,6 +1463,98 @@ "viewPath": "", "visible": true, "width": "" + }, + { + "align": "center", + "boolean": "checkbox", + "dateFormat": "MM/DD/YYYY", + "editable": false, + "field": "NumberID", + "filter": { + "boolean": { + "condition": "" + }, + "date": { + "condition": "", + "value": "" + }, + "enabled": false, + "number": { + "condition": "", + "value": "" + }, + "string": { + "condition": "", + "value": "" + }, + "visible": "on-hover" + }, + "footer": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "" + }, + "header": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "Number (ID)" + }, + "justify": "left", + "nullFormat": { + "includeNullStrings": false, + "nullFormatValue": "", + "strict": false + }, + "number": "value", + "numberFormat": "0,0.##", + "progressBar": { + "bar": { + "color": "", + "style": { + "classes": "" + } + }, + "max": 100, + "min": 0, + "track": { + "color": "", + "style": { + "classes": "" + } + }, + "value": { + "enabled": true, + "format": "0,0.##", + "justify": "center", + "style": { + "classes": "" + } + } + }, + "render": "auto", + "resizable": true, + "sort": "ascending", + "sortable": false, + "strictWidth": false, + "style": { + "classes": "" + }, + "toggleSwitch": { + "color": { + "selected": "", + "unselected": "" + } + }, + "viewParams": {}, + "viewPath": "", + "visible": true, + "width": 70 } ], "emptyMessage": { @@ -1491,6 +1570,9 @@ "results": { "enabled": true } + }, + "pager": { + "activeOption": 100 } }, "type": "ia.display.table" @@ -1522,6 +1604,110 @@ "children": [ { "children": [ + { + "meta": { + "name": "Dropdown" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.value": { + "persistent": false + } + }, + "props": { + "options": [ + { + "label": "MCM01", + "value": "MCM01" + }, + { + "label": "MCM02", + "value": "MCM02" + }, + { + "label": "MCM03", + "value": "MCM03" + }, + { + "label": "MCM04", + "value": "MCM03" + }, + { + "label": "MCM05", + "value": "MCM05" + } + ], + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "hjsgdfn", + "pageScope": false, + "script": "\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.dropdown" + }, + { + "custom": { + "Severity": "Critical", + "background_on": "false" + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tself.getSibling(\"Dropdown\").props.value \u003d \"\"" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "Button" + }, + "position": { + "basis": "120px" + }, + "props": { + "image": { + "icon": { + "color": "#000000", + "path": "material/clear" + } + }, + "primary": false, + "style": { + "margin": 15 + }, + "text": "Reset" + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "button-severity-indicator", + "pageScope": true, + "script": "\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"severity\"]\n\tbutton_severity \u003d self.custom.Severity\n\tif severity \u003d\u003d button_severity:\n\t\tbackground \u003d \"true\"\n\telse:\n\t\tbackground \u003d \"false\"\n\t\n\tself.custom.background_on \u003d background\n\t", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.button" + }, { "events": { "component": { @@ -1589,7 +1775,7 @@ "component": { "onRowDoubleClick": { "config": { - "script": "\t\n\tmyData \u003d self.props.selection.data\n\n\talarms.alarm_click.handleClick(myData)" + "script": "\t\n\tmyData \u003d self.props.selection.data\n\n\tautstand.Alarms.handleClick(myData)" }, "scope": "G", "type": "script" @@ -1604,6 +1790,14 @@ "grow": 1 }, "propConfig": { + "props.columns[5].filter.string.value": { + "binding": { + "config": { + "path": ".../FlexContainer/Dropdown.props.value" + }, + "type": "property" + } + }, "props.data": { "binding": { "config": { @@ -1611,7 +1805,7 @@ "enabled": true, "rate": "3" }, - "queryPath": "Alarms-autStand/GetAlarmsWithCount" + "queryPath": "GetAlarmsWithCount" }, "transforms": [ { @@ -2109,16 +2303,15 @@ "condition": "", "value": "" }, - "enabled": false, + "enabled": true, "number": { "condition": "", "value": "" }, "string": { - "condition": "", - "value": "" + "condition": "equals" }, - "visible": "on-hover" + "visible": "never" }, "footer": { "align": "center", @@ -2571,6 +2764,9 @@ "results": { "enabled": true } + }, + "pager": { + "activeOption": 100 } }, "type": "ia.display.table" @@ -2606,7 +2802,7 @@ "children": [ { "custom": { - "SetFilter": true + "SetFilter": false }, "events": { "component": { @@ -2704,22 +2900,22 @@ }, { "custom": { - "customTime": false, + "customTime": true, "endDate": { "$": [ "ts", 192, - 1755608469647 + 1758185793213 ], - "$ts": 1755608469646 + "$ts": 1758185793212 }, "startDate": { "$": [ "ts", 192, - 1755608469646 + 1758185793212 ], - "$ts": 1755606669646 + "$ts": 1758099600000 } }, "meta": { @@ -2732,7 +2928,7 @@ "props.value": { "onChange": { "enabled": null, - "script": "\n\tstart \u003d \"\"\n\tend \u003d \"\"\n\tnow \u003d system.date.now()\n\tpreviousDay \u003d system.date.addDays(now, -1)\n\tvalue \u003d currentValue.value \n\n\tif value \u003d\u003d \"custom\":\n\t\tself.custom.customTime \u003d True\n\t\treturn\n\telif value \u003d\u003d \"currentDay\":\n\t\tstart \u003d system.date.setTime(now, 0, 0, 0)\n\t\tend \u003d now\n\telif value \u003d\u003d \"morning\":\n\t\tstart \u003d system.date.setTime(now, 2, 30, 0)\n\t\tend \u003d system.date.setTime(now, 7, 30, 0)\n\telif value \u003d\u003d \"daylight\":\n\t\tstart \u003d system.date.setTime(now, 7, 30, 0)\n\t\tend \u003d system.date.setTime(now, 13, 0, 0)\n\telif value \u003d\u003d \"twilight\":\n\t\tstart \u003d system.date.setTime(now, 13, 0, 0)\n\t\tend \u003d now\n\telif value \u003d\u003d \"night\":\n\t\tstart \u003d system.date.setTime(previousDay, 18, 30, 0)\n\t\tend \u003d system.date.setTime(previousDay, 23, 30, 0)\n\telif value \u003d\u003d \"wrapDown\":\n\t\tstart \u003d system.date.setTime(previousDay, 23, 30, 0)\n\t\tend \u003d system.date.setTime(now, 2, 30, 0)\n\telif value \u003d\u003d \"currentShot\":\n\t\tstart \u003d system.date.setTime(now, 13, 0, 0)\n\t\tend \u003d now\n\telse:\n\t\tstart \u003d system.date.addMinutes(now, -int(value))\n\t\tend \u003d now\n\n\tself.custom.customTime \u003d False\n\tself.custom.startDate \u003d start\n\tself.custom.endDate \u003d end" + "script": "\t# e.g. Dropdown onChange / propertyChange\n\tnow \u003d system.date.now()\n\ttoday0 \u003d system.date.setTime(now, 0, 0, 0) # today 00:00:00\n\tyday0 \u003d system.date.addDays(today0, -1) # yesterday 00:00:00\n\t\n\tval \u003d str(currentValue.value or \u0027\u0027).strip()\n\t\n\t# Custom range: let user pick dates, don\u0027t touch start/end.\n\tif val \u003d\u003d \"custom\":\n\t self.custom.customTime \u003d True\n\t return\n\t\n\tself.custom.customTime \u003d False\n\t\n\tdef t(day, h, m, s):\n\t \"\"\"time of day on a given day anchor\"\"\"\n\t return system.date.setTime(day, h, m, s)\n\t\n\tif val \u003d\u003d \"currentDay\":\n\t start, end \u003d today0, now\n\t\n\telif val \u003d\u003d \"morning\": # 02:30–07:30 today\n\t start, end \u003d t(today0, 2, 30, 0), t(today0, 7, 30, 0)\n\t\n\telif val \u003d\u003d \"daylight\": # 07:30–13:00 today\n\t start, end \u003d t(today0, 7, 30, 0), t(today0, 13, 0, 0)\n\t\n\telif val \u003d\u003d \"twilight\": # 13:00–now (if before 13:00, use 13:00 yesterday–now)\n\t if now \u003e\u003d t(today0, 13, 0, 0):\n\t start, end \u003d t(today0, 13, 0, 0), now\n\t else:\n\t start, end \u003d t(yday0, 13, 0, 0), now\n\t\n\telif val \u003d\u003d \"night\": # 18:30–23:30 yesterday (your original intent)\n\t start, end \u003d t(yday0, 18, 30, 0), t(yday0, 23, 30, 0)\n\t\n\telif val \u003d\u003d \"wrapDown\": # 23:30 yesterday – 02:30 today\n\t start, end \u003d t(yday0, 23, 30, 0), t(today0, 2, 30, 0)\n\t\n\telif val \u003d\u003d \"currentShot\": # alias of twilight per your use\n\t if now \u003e\u003d t(today0, 13, 0, 0):\n\t start, end \u003d t(today0, 13, 0, 0), now\n\t else:\n\t start, end \u003d t(yday0, 13, 0, 0), now\n\t\n\telse:\n\t # Treat any other value as \"last N minutes\"\n\t try:\n\t mins \u003d int(val)\n\t except:\n\t mins \u003d 60\n\t end \u003d now\n\t start \u003d system.date.addMinutes(end, -mins)\n\t\n\t# Final assign\n\tself.custom.startDate \u003d start\n\tself.custom.endDate \u003d end" }, "persistent": false } @@ -2830,13 +3026,13 @@ }, { "custom": { - "max_duration_days": 10 + "max_duration_days": 365 }, "events": { "component": { "onActionPerformed": { "config": { - "script": "\tautStand.messaging.message_handler.set_time_from_filters(self)\n\t" + "script": "\tmessaging.message_handler.set_time_from_filters(self)\n\t" }, "scope": "G", "type": "script" @@ -2887,12 +3083,12 @@ }, "onChange": { "enabled": null, - "script": "\tautStand.messaging.message_handler.set_time_from_filters(self)" + "script": "\tmessaging.message_handler.set_time_from_filters(self)" } } }, "props": { - "formattedValue": "Aug 19, 2025 4:31 PM", + "formattedValue": "Sep 17, 2025 1:00 PM", "style": { "margin": 15 } @@ -2950,14 +3146,13 @@ "config": { "expression": "now()" }, - "enabled": false, "type": "expr" } }, "props.minDate": { "binding": { "config": { - "expression": "addDays(now(),-10)" + "expression": "addDays(now(),-365)" }, "type": "expr" } @@ -2971,21 +3166,13 @@ }, "onChange": { "enabled": null, - "script": "\tautStand.messaging.message_handler.set_time_to_filters(self)" + "script": "\tmessaging.message_handler.set_time_to_filters(self)" }, "persistent": true } }, "props": { - "formattedValue": "Aug 19, 2025 5:01 PM", - "maxDate": { - "$": [ - "ts", - 192, - 1749542669794 - ], - "$ts": 1749715452000 - }, + "formattedValue": "Sep 18, 2025 12:56 PM", "style": { "margin": 15 }, @@ -2993,9 +3180,9 @@ "$": [ "ts", 201, - 1755608469647 + 1758185793213 ], - "$ts": 1755608469646 + "$ts": 1758185793212 } }, "scripts": { @@ -3047,7 +3234,7 @@ "component": { "onActionPerformed": { "config": { - "script": "\tautStand.messaging.message_handler.set_priority_filters(self)" + "script": "\tmessaging.message_handler.set_priority_filters(self)" }, "scope": "G", "type": "script" @@ -3106,6 +3293,127 @@ ] }, "type": "ia.input.dropdown" + }, + { + "meta": { + "name": "Label_0" + }, + "position": { + "basis": "100px" + }, + "props": { + "style": { + "fontFamily": "Arial", + "fontWeight": "bold", + "textAlign": "center" + }, + "text": "MCM" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "Dropdown_0" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.value": { + "persistent": false + } + }, + "props": { + "options": [ + { + "label": "MCM01", + "value": "MCM01" + }, + { + "label": "MCM02", + "value": "MCM02" + }, + { + "label": "MCM03", + "value": "MCM03" + }, + { + "label": "MCM04", + "value": "MCM03" + }, + { + "label": "MCM05", + "value": "MCM05" + } + ], + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "hjsgdfn", + "pageScope": false, + "script": "\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.dropdown" + }, + { + "custom": { + "Severity": "Critical", + "background_on": "false" + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tself.getSibling(\"Dropdown_0\").props.value \u003d \"\"" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "Button" + }, + "position": { + "basis": "120px" + }, + "props": { + "image": { + "icon": { + "color": "#000000", + "path": "material/clear" + } + }, + "primary": false, + "style": { + "margin": 15 + }, + "text": "Reset" + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "button-severity-indicator", + "pageScope": true, + "script": "\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"severity\"]\n\tbutton_severity \u003d self.custom.Severity\n\tif severity \u003d\u003d button_severity:\n\t\tbackground \u003d \"true\"\n\telse:\n\t\tbackground \u003d \"false\"\n\t\n\tself.custom.background_on \u003d background\n\t", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.button" } ], "meta": { @@ -3119,13 +3427,14 @@ } ], "custom": { - "ShowFilters": true + "ShowFilters": false }, "meta": { "name": "Filters" }, "position": { "basis": "180px", + "display": false, "grow": 1, "shrink": 0 }, @@ -3171,6 +3480,7 @@ "children": [ { "custom": { + "amount": 0, "max_duration": { "$": [ "ts", @@ -3179,29 +3489,30 @@ ], "$ts": 1747562336635 }, + "page_size": 100, "priority_filters": "", "time_from_filter": { "$": [ "ts", 192, - 1758805747061 + 1758201932138 ], - "$ts": 1755606669646 + "$ts": 1758099600000 }, "time_to_filter": { "$": [ "ts", 192, - 1758805747062 + 1758201932138 ], - "$ts": 1755608469646 + "$ts": 1758185793212 } }, "events": { "component": { "onRowDoubleClick": { "config": { - "script": "\t\n\tmyData \u003d self.props.selection.data\n\n\talarms.alarm_click.handleClick(myData)" + "script": "\t\n\tmyData \u003d self.props.selection.data\n\n\tautstand.alarms.handleClick(myData)" }, "scope": "G", "type": "script" @@ -3249,14 +3560,27 @@ "type": "property" } }, + "props.columns[6].filter.string.value": { + "binding": { + "config": { + "path": ".../Filters/Priority/Dropdown_0.props.value" + }, + "type": "property" + } + }, "props.data": { "binding": { "config": { + "parameters": { + "endtime": "{.../Filters/Time/DateTimeInput_0.props.value}", + "offset": "({.../Paginate/FlexContainer_0/NumericEntryField.props.value}-1)*100", + "starttime": "{.../Filters/Time/DateTimeInput.props.value}" + }, "polling": { "enabled": true, "rate": "3" }, - "queryPath": "Alarms-autStand/GetAlarms" + "queryPath": "GetAlarms" }, "transforms": [ { @@ -3269,6 +3593,7 @@ } }, "props": { + "bekaxui": 50, "box-shadow": "0 4px 20px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)", "columns": [ { @@ -3842,8 +4167,7 @@ "value": "" }, "string": { - "condition": "equals", - "value": "" + "condition": "equals" }, "visible": "never" }, @@ -4213,7 +4537,8 @@ }, "style": { "margin": 20 - } + }, + "total": "value" }, "scripts": { "customMethods": [], @@ -4308,6 +4633,9 @@ "basis": "980px", "grow": 1 }, + "props": { + "direction": "column" + }, "scripts": { "customMethods": [], "extensionFunctions": null, @@ -4326,219 +4654,325 @@ { "children": [ { - "custom": { - "download_in_progress": true, - "enable_timeout": false, - "priority_filters": "", - "time_from_filter": { - "$": [ - "ts", - 192, - 1758805747062 - ], - "$ts": 1755606669646 - }, - "time_to_filter": { - "$": [ - "ts", - 192, - 1758805747062 - ], - "$ts": 1755608469646 - }, - "type_filters": null - }, - "events": { - "component": { - "onActionPerformed": { - "config": { - "script": "\n from datetime import datetime\n def format_date(value):\n\t\tif isinstance(value, (int, long)) and value \u003e 10000000:\n\t\t\ttimestamp \u003d system.date.fromMillis(value)\n\t\t\treturn system.date.format(timestamp, \"yyyy-MM-dd HH:mm:ss\")\n\t\t\t\n\t\t# If value is not a valid timestamp, return as-is\n\t\treturn str(value)\n \n try:\n\n # Get filtered data\n table \u003d self.parent.parent.getChild(\"Table\").getChild(\"Table\")\n filtered_data \u003d table.props.filter.results.data\n\n if not filtered_data or len(filtered_data) \u003d\u003d 0:\n system.perspective.print(\"No filtered data to export.\")\n return\n\n # Get correct column order from the table\u0027s column config\n column_order \u003d [col[\"field\"] for col in table.props.columns if \"field\" in col]\n\n csv_content \u003d \",\".join(column_order) + \"\\n\"\n\n # Build rows\n for row_dict in filtered_data:\n row \u003d []\n for col in column_order:\n raw_val \u003d row_dict.get(col, \"\")\n value \u003d format_date(raw_val)\n value \u003d value.replace(\",\", \";\") # CSV safety\n row.append(value)\n csv_content +\u003d \",\".join(row) + \"\\n\"\n\n # Export CSV\n csv_bytes \u003d csv_content.encode(\"utf-8\")\n system.perspective.download(\"filtered_alarms_history.csv\", csv_bytes)\n\n system.perspective.print(\"CSV export completed successfully. Exported %d records.\" % len(filtered_data))\n\n except Exception as e:\n system.perspective.print(\"Export failed: \" + str(e))" + "children": [ + { + "custom": { + "download_in_progress": true, + "enable_timeout": false, + "priority_filters": "", + "time_from_filter": { + "$": [ + "ts", + 192, + 1758201932138 + ], + "$ts": 1758099600000 }, - "scope": "G", - "type": "script" - } + "time_to_filter": { + "$": [ + "ts", + 192, + 1758201932138 + ], + "$ts": 1758185793212 + }, + "type_filters": null + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\n from datetime import datetime\n def format_date(value):\n\t\tif isinstance(value, (int, long)) and value \u003e 10000000:\n\t\t\ttimestamp \u003d system.date.fromMillis(value)\n\t\t\treturn system.date.format(timestamp, \"yyyy-MM-dd HH:mm:ss\")\n\t\t\t\n\t\t# If value is not a valid timestamp, return as-is\n\t\treturn str(value)\n \n try:\n\n # Get filtered data\n table \u003d self.parent.parent.getChild(\"Table\").getChild(\"Table\")\n filtered_data \u003d table.props.filter.results.data\n\n if not filtered_data or len(filtered_data) \u003d\u003d 0:\n system.perspective.print(\"No filtered data to export.\")\n return\n\n # Get correct column order from the table\u0027s column config\n column_order \u003d [col[\"field\"] for col in table.props.columns if \"field\" in col]\n\n csv_content \u003d \",\".join(column_order) + \"\\n\"\n\n # Build rows\n for row_dict in filtered_data:\n row \u003d []\n for col in column_order:\n raw_val \u003d row_dict.get(col, \"\")\n value \u003d format_date(raw_val)\n value \u003d value.replace(\",\", \";\") # CSV safety\n row.append(value)\n csv_content +\u003d \",\".join(row) + \"\\n\"\n\n # Export CSV\n csv_bytes \u003d csv_content.encode(\"utf-8\")\n system.perspective.download(\"filtered_alarms_history.csv\", csv_bytes)\n\n system.perspective.print(\"CSV export completed successfully. Exported %d records.\" % len(filtered_data))\n\n except Exception as e:\n system.perspective.print(\"Export failed: \" + str(e))" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "Export", + "tooltip": { + "enabled": true, + "text": "Exports the data displayed in the table." + } + }, + "position": { + "basis": "120px", + "shrink": 0 + }, + "propConfig": { + "custom.disable": { + "binding": { + "config": { + "expression": "if(isNull({this.custom.start_time}), False, secondsBetween({this.custom.start_time}, {this.custom.time_now}))" + }, + "transforms": [ + { + "code": "\tif value \u003e 60:\n\t\tself.custom.enable_timeout \u003d False\n\t\treturn False\n\telse:\n\t\treturn True", + "type": "script" + } + ], + "type": "expr" + } + }, + "custom.download_complete": { + "binding": { + "config": { + "path": "session.custom.downloads" + }, + "transforms": [ + { + "code": "\tif value \u003d\u003d True:\n\t\tself.custom.download_in_progress \u003d False", + "type": "script" + } + ], + "type": "property" + } + }, + "custom.priority_filters": { + "persistent": true + }, + "custom.start_time": { + "binding": { + "config": { + "expression": "{this.custom.enable_timeout}" + }, + "transforms": [ + { + "code": "\tif value \u003d\u003d True:\n\t\treturn self.custom.time_now", + "type": "script" + } + ], + "type": "expr" + } + }, + "custom.time_from_filter": { + "persistent": true + }, + "custom.time_now": { + "binding": { + "config": { + "expression": "now()" + }, + "type": "expr" + } + }, + "custom.time_to_filter": { + "persistent": true + }, + "props.enabled": { + "binding": { + "config": { + "expression": "!{this.custom.enable_timeout} || !{this.custom.download_in_progress} " + }, + "type": "expr" + } + }, + "props.text": { + "binding": { + "config": { + "expression": "if(!{this.custom.enable_timeout}, \"Export\",\r\nif({this.custom.download_in_progress}, \"Exporting...\",\r\n\"Export\"))" + }, + "type": "expr" + } + } + }, + "props": { + "image": { + "icon": { + "path": "material/import_export" + } + }, + "primary": false, + "style": { + "margin": 15, + "marginLeft": 20 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "set-source-filters", + "pageScope": true, + "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.source_id_filters \u003d filters", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-device-filters", + "pageScope": true, + "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.device_filters \u003d filters", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-message-filters", + "pageScope": true, + "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.message_filters \u003d filters", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-priority-filters", + "pageScope": true, + "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.priority_filters \u003d filters", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-from-filters", + "pageScope": true, + "script": "\ttime \u003d payload[\"data\"]\n\tself.custom.time_from_filter \u003d time", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-to-filters", + "pageScope": true, + "script": "\ttime \u003d payload[\"data\"]\n\tself.custom.time_to_filter \u003d time", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "reset-historical-filters", + "pageScope": true, + "script": "\taction \u003d payload[\"data\"]\n\tif action \u003d\u003d \"reset\":\n\t\tself.custom.device_filters \u003d None\n\t\tself.custom.priority_filters \u003d None\n\t\tself.custom.source_id_filters \u003d None\n\t\tself.custom.time_from_filter \u003d None\n\t\tself.custom.time_to_filter \u003d None\n\t\tself.custom.type_filters \u003d None\n\t\tself.custom.duration_filter \u003d None\n\t\tself.props.enabled \u003dTrue\n\t\t", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-type-filters", + "pageScope": true, + "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.type_filters \u003d filters", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-duration-filters", + "pageScope": true, + "script": "\tduration \u003d payload[\"data\"]\n\tself.custom.duration_filter \u003d duration", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.button" + }, + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "580px", + "grow": 1 + }, + "type": "ia.display.label" } - }, + ], "meta": { - "name": "Export", - "tooltip": { - "enabled": true, - "text": "Exports the data displayed in the table." - } + "name": "FlexContainer" }, "position": { - "basis": "120px", - "shrink": 0 + "basis": 960 }, - "propConfig": { - "custom.disable": { - "binding": { - "config": { - "expression": "if(isNull({this.custom.start_time}), False, secondsBetween({this.custom.start_time}, {this.custom.time_now}))" - }, - "transforms": [ - { - "code": "\tif value \u003e 60:\n\t\tself.custom.enable_timeout \u003d False\n\t\treturn False\n\telse:\n\t\treturn True", + "type": "ia.container.flex" + }, + { + "children": [ + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\t# Get current page number from NumericEntryField\n\tcurrent_page \u003d self.getSibling(\"NumericEntryField\").props.value\n\t\n\t# Decrease page by 1, but don\u0027t go below 1\n\tif current_page \u003e 1:\n\t\tself.getSibling(\"NumericEntryField\").props.value \u003d current_page - 1" + }, + "scope": "G", "type": "script" } - ], - "type": "expr" - } - }, - "custom.download_complete": { - "binding": { - "config": { - "path": "session.custom.downloads" + } + }, + "meta": { + "name": "Button" + }, + "position": { + "basis": 150 + }, + "props": { + "image": { + "height": 50, + "width": 50 }, - "transforms": [ - { - "code": "\tif value \u003d\u003d True:\n\t\tself.custom.download_in_progress \u003d False", + "primary": false, + "text": "Back" + }, + "type": "ia.input.button" + }, + { + "meta": { + "name": "NumericEntryField" + }, + "position": { + "basis": "196px" + }, + "props": { + "format": "0,0", + "value": 1 + }, + "type": "ia.input.numeric-entry-field" + }, + { + "custom": { + "value": "value" + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\t# Get current value from NumericEntryField\n\tcurrent_value \u003d self.getSibling(\"NumericEntryField\").props.value\n\t\n\t# Increase by 1\n\tself.getSibling(\"NumericEntryField\").props.value \u003d current_value + 1" + }, + "scope": "G", "type": "script" } - ], - "type": "property" - } - }, - "custom.priority_filters": { - "persistent": true - }, - "custom.start_time": { - "binding": { - "config": { - "expression": "{this.custom.enable_timeout}" + } + }, + "meta": { + "name": "Button_0" + }, + "position": { + "basis": 150 + }, + "props": { + "image": { + "height": 50, + "width": 50 }, - "transforms": [ - { - "code": "\tif value \u003d\u003d True:\n\t\treturn self.custom.time_now", - "type": "script" - } - ], - "type": "expr" - } - }, - "custom.time_from_filter": { - "persistent": true - }, - "custom.time_now": { - "binding": { - "config": { - "expression": "now()" - }, - "type": "expr" - } - }, - "custom.time_to_filter": { - "persistent": true - }, - "props.enabled": { - "binding": { - "config": { - "expression": "!{this.custom.enable_timeout} || !{this.custom.download_in_progress} " - }, - "type": "expr" - } - }, - "props.text": { - "binding": { - "config": { - "expression": "if(!{this.custom.enable_timeout}, \"Export\",\r\nif({this.custom.download_in_progress}, \"Exporting...\",\r\n\"Export\"))" - }, - "type": "expr" - } + "primary": false, + "text": "Next" + }, + "type": "ia.input.button" } + ], + "meta": { + "name": "FlexContainer_0" + }, + "position": { + "basis": 960 }, "props": { - "image": { - "icon": { - "path": "material/import_export" - } - }, - "primary": false, - "style": { - "margin": 15, - "marginLeft": 20 - } + "justify": "space-evenly" }, - "scripts": { - "customMethods": [], - "extensionFunctions": null, - "messageHandlers": [ - { - "messageType": "set-source-filters", - "pageScope": true, - "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.source_id_filters \u003d filters", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-device-filters", - "pageScope": true, - "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.device_filters \u003d filters", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-message-filters", - "pageScope": true, - "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.message_filters \u003d filters", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-priority-filters", - "pageScope": true, - "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.priority_filters \u003d filters", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-from-filters", - "pageScope": true, - "script": "\ttime \u003d payload[\"data\"]\n\tself.custom.time_from_filter \u003d time", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-to-filters", - "pageScope": true, - "script": "\ttime \u003d payload[\"data\"]\n\tself.custom.time_to_filter \u003d time", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "reset-historical-filters", - "pageScope": true, - "script": "\taction \u003d payload[\"data\"]\n\tif action \u003d\u003d \"reset\":\n\t\tself.custom.device_filters \u003d None\n\t\tself.custom.priority_filters \u003d None\n\t\tself.custom.source_id_filters \u003d None\n\t\tself.custom.time_from_filter \u003d None\n\t\tself.custom.time_to_filter \u003d None\n\t\tself.custom.type_filters \u003d None\n\t\tself.custom.duration_filter \u003d None\n\t\tself.props.enabled \u003dTrue\n\t\t", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-type-filters", - "pageScope": true, - "script": "\tfilters \u003d payload[\"data\"]\n\tself.custom.type_filters \u003d filters", - "sessionScope": false, - "viewScope": false - }, - { - "messageType": "set-duration-filters", - "pageScope": true, - "script": "\tduration \u003d payload[\"data\"]\n\tself.custom.duration_filter \u003d duration", - "sessionScope": false, - "viewScope": false - } - ] - }, - "type": "ia.input.button" + "type": "ia.container.flex" }, { "meta": { - "name": "Label" + "name": "FlexContainer_1" }, "position": { - "basis": "580px", - "grow": 1 + "basis": 960 }, - "type": "ia.display.label" + "type": "ia.container.flex" } ], "meta": { @@ -4552,6 +4986,15 @@ "justify": "space-evenly" }, "type": "ia.container.flex" + }, + { + "meta": { + "name": "FlexContainer_1" + }, + "position": { + "basis": 50 + }, + "type": "ia.container.flex" } ], "meta": { @@ -4593,7 +5036,7 @@ "props.currentTabIndex": { "onChange": { "enabled": null, - "script": "\n\tif self.props.currentTabIndex !\u003d 0:\n\t\tpayload \u003d {}\n\t\tfilter_on \u003d \"false\"\n\t\tpayload[\"reset\"] \u003d filter_on\n\t\tsystem.perspective.sendMessage(\"reset-filters\", payload \u003dpayload, scope \u003d \"page\")\n\t\t\n\tif currentValue.value \u003d\u003d 1:\n\t shelved_info \u003d system.alarm.getShelvedPaths()\n\t alarms \u003d system.alarm.queryStatus(includeShelved\u003dTrue)\n\t \n\t tableData \u003d []\n\t \n\t for alarm in alarms:\n\t if alarm.isShelved() and not alarm.isAcked() and not alarm.isCleared():\n\t # Get alarm path as string\n\t alarm_path \u003d str(alarm.getSource())\n\t \n\t # Get active time\n\t activeData \u003d alarm.getActiveData()\n\t startTime \u003d activeData.getTimestamp() if activeData else None\n\t \n\t # Find shelved info for this alarm\n\t shelveEntry \u003d \"\"\n\t \n\t for shelved_item in shelved_info:\n\t shelved_str \u003d str(shelved_item)\n\t \n\t if alarm_path in shelved_str:\n\t # Extract the value part (after the first comma)\n\t if \",\" in shelved_str:\n\t start_idx \u003d shelved_str.find(\",\")\n\t shelveEntry \u003d shelved_str[start_idx + 1:].rstrip(\"}\")\n\t break\n\t \n\t # Parse shelved information\n\t expiration \u003d \"\"\n\t \n\t if shelveEntry:\n\t \n\t # Extract expiration (between \"expiration:\" and \",\")\n\t if \"expiration:\" in shelveEntry:\n\t exp_part \u003d shelveEntry.split(\"expiration:\")[1]\n\t if \",\" in exp_part:\n\t expiration \u003d exp_part.split(\",\")[0].strip()\n\t else:\n\t expiration \u003d exp_part.strip()\n\t \n\t tableData.append({\n\t \"name\": alarm.getName(),\n\t \"path\": alarm_path,\n\t \"activeTime\": system.date.format(system.date.fromMillis(startTime), \"yyyy-MM-dd HH:mm:ss\"),\n\t \"expirationTime\": expiration,\n\t \"priority\": str(alarm.getPriority())\n\t })\n\t \n\t self.custom.shelvedAlarms \u003d tableData\n\t \n\t\t\n\ttry:\n\t\tpageid \u003d self.view.custom.activityLogger.alt_pageid + \u0027/\u0027+ self.props.tabs[previousValue.value]\n\t\tpageid \u003d pageid.replace(\u0027 \u0027,\u0027\u0027)\n\t\tpayload \u003d activityLog.productMetrics.createActivityPayload(self.view, \u0027page\u0027, pageid, pageid)\n\t\tself.view.custom.activityLogger.start_time \u003d system.date.now()\n\t\tif payload:\n\t\t\tsystem.perspective.sendMessage(\u0027activityLogger-TabChanged\u0027, payload \u003d payload, scope \u003d \u0027page\u0027)\n\texcept:\n\t\tpass" + "script": "\tif self.props.currentTabIndex !\u003d 0:\n\t payload \u003d {}\n\t filter_on \u003d \"false\"\n\t payload[\"reset\"] \u003d filter_on\n\t system.perspective.sendMessage(\"reset-filters\", payload\u003dpayload, scope\u003d\"page\")\n\t \n\tif currentValue.value \u003d\u003d 1:\n\t shelved_info \u003d system.alarm.getShelvedPaths()\n\t alarms \u003d system.alarm.queryStatus(includeShelved\u003dTrue)\n\t \n\t tableData \u003d []\n\t \n\t for alarm in alarms:\n\t if alarm.isShelved() and not alarm.isAcked() and not alarm.isCleared():\n\t # Get alarm path as string\n\t alarm_path \u003d str(alarm.getSource())\n\t \n\t # Get active time\n\t activeData \u003d alarm.getActiveData()\n\t startTime \u003d activeData.getTimestamp() if activeData else None\n\t \n\t # Find shelved info for this alarm\n\t shelveEntry \u003d \"\"\n\t \n\t for shelved_item in shelved_info:\n\t shelved_str \u003d str(shelved_item)\n\t \n\t if alarm_path in shelved_str:\n\t # Extract the value part (after the first comma)\n\t if \",\" in shelved_str:\n\t start_idx \u003d shelved_str.find(\",\")\n\t shelveEntry \u003d shelved_str[start_idx + 1:].rstrip(\"}\")\n\t break\n\t \n\t # Parse shelved information\n\t expiration \u003d \"\"\n\t \n\t if shelveEntry:\n\t # Extract expiration (between \"expiration:\" and \",\")\n\t if \"expiration:\" in shelveEntry:\n\t exp_part \u003d shelveEntry.split(\"expiration:\")[1]\n\t if \",\" in exp_part:\n\t expiration \u003d exp_part.split(\",\")[0].strip()\n\t else:\n\t expiration \u003d exp_part.strip()\n\t \n\t # Only add if we have a valid start time\n\t if startTime:\n\t tableData.append({\n\t \"name\": alarm.getName(),\n\t \"path\": alarm_path,\n\t \"activeTime\": system.date.format(system.date.fromMillis(startTime), \"yyyy-MM-dd HH:mm:ss\"),\n\t \"expirationTime\": expiration,\n\t \"priority\": str(alarm.getPriority())\n\t })\n\t \n\t self.custom.shelvedAlarms \u003d tableData\n\t\n\ttry:\n\t pageid \u003d self.view.custom.activityLogger.alt_pageid + \u0027/\u0027 + self.props.tabs[previousValue.value]\n\t pageid \u003d pageid.replace(\u0027 \u0027, \u0027\u0027)\n\t payload \u003d activityLog.productMetrics.createActivityPayload(self.view, \u0027page\u0027, pageid, pageid)\n\t self.view.custom.activityLogger.start_time \u003d system.date.now()\n\t if payload:\n\t system.perspective.sendMessage(\u0027activityLogger-TabChanged\u0027, payload\u003dpayload, scope\u003d\u0027page\u0027)\n\texcept:\n\t pass" } } }, @@ -4601,6 +5044,7 @@ "contentStyle": { "classes": "Background-Styles/Grey-Background" }, + "currentTabIndex": 1, "menuType": "modern", "style": { "classes": "Background-Styles/Grey-Background" diff --git a/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarms/query.sql b/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarms/query.sql index 96d13722..751eecea 100644 --- a/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarms/query.sql +++ b/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarms/query.sql @@ -1,62 +1,28 @@ -WITH Active AS ( - SELECT - ae.id, - ae.eventtime, - ae.eventid, - ae.source, - ae.priority, - ae.displaypath, - TIMESTAMPDIFF(SECOND, ae.eventtime, NOW()) AS duration_seconds - FROM alarm_events ae - WHERE ae.eventtype = 0 - AND NOT EXISTS ( - SELECT 1 FROM alarm_events ae_clear - WHERE ae_clear.eventid = ae.eventid - AND ae_clear.eventtype = 1 - ) - AND ae.displaypath NOT LIKE '%System Startup%' - AND ae.source NOT LIKE '%System Startup%' - -- Priority filter using FIND_IN_SET for comma-separated values - AND ( - :priorityList IS NULL - OR :priorityList = '' - OR FIND_IN_SET(ae.priority, :priorityList) > 0 - ) - GROUP BY ae.id -), -SingleMyTag AS ( - SELECT aed.id, aed.strValue - FROM alarm_event_data aed - WHERE aed.propname = 'myTag' - GROUP BY aed.id -) -SELECT - Active.id AS ID, - Active.eventtime AS StartTimestamp, - NULL AS EndTimestamp, -- no end time since it's still active - CONCAT( - LPAD(FLOOR(Active.duration_seconds / 3600), 2, '0'), ':', - LPAD(FLOOR((Active.duration_seconds % 3600) / 60), 2, '0'), ':', - LPAD(Active.duration_seconds % 60, 2, '0') - ) AS Duration, - CONCAT(Active.displaypath, ' - ', SUBSTRING_INDEX(Active.source, ':/alm:', -1)) AS Description, - CASE Active.priority - WHEN 0 THEN 'Diagnostic' - WHEN 1 THEN 'Low' - WHEN 2 THEN 'Medium' - WHEN 3 THEN 'High' - WHEN 4 THEN 'Critical' - ELSE 'Unknown' - END AS Priority, - CONCAT( - Active.displaypath, - '.HMI.', - SUBSTRING_INDEX(aed.strValue, '/', -1) - ) AS Tag, - SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue, '/', 2), '/', -1) AS Location , +SELECT + ae.id AS ID, + ae.eventtime AS StartTimestamp, + CONCAT( + LPAD(FLOOR(TIMESTAMPDIFF(SECOND, ae.eventtime, NOW())/3600), 2, '0'), ':', + LPAD(FLOOR((TIMESTAMPDIFF(SECOND, ae.eventtime, NOW())%3600)/60), 2, '0'), ':', + LPAD( (TIMESTAMPDIFF(SECOND, ae.eventtime, NOW())%60), 2, '0') + ) AS Duration, + CONCAT(REPLACE(ae.displaypath,'_','-'),' ', SUBSTRING_INDEX(ae.source,':/alm:',-1)) AS Description, + CASE ae.priority + WHEN 0 THEN 'Diagnostic' WHEN 1 THEN 'Low' WHEN 2 THEN 'Medium' + WHEN 3 THEN 'High' WHEN 4 THEN 'Critical' ELSE 'Unknown' + END AS Priority, + CONCAT(ae.displaypath,'.HMI.Alarm.', SUBSTRING_INDEX(aed.strValue,'/',-1)) AS Tag, + SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue,'/',2),'/',-1) AS Location, aed.strValue AS FullTag, - Active.displaypath as Device -FROM Active -LEFT JOIN SingleMyTag aed - ON aed.id = Active.id -ORDER BY Active.eventtime DESC; \ No newline at end of file + ae.displaypath AS Device +FROM alarm_events ae +LEFT JOIN alarm_events clr + ON clr.eventid = ae.eventid AND clr.eventtype = 1 +LEFT JOIN alarm_event_data aed + ON aed.id = ae.id AND aed.propname = 'myTag' +WHERE ae.eventtype = 0 + AND clr.eventid IS NULL + AND ae.displaypath NOT LIKE '%System Startup%' + AND ae.source NOT LIKE '%System Startup%' + AND (:priorityList = '' OR FIND_IN_SET(CAST(ae.priority AS CHAR), :priorityList) > 0) +ORDER BY ae.eventtime DESC; diff --git a/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarmsByLocationAndPriority/query.sql b/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarmsByLocationAndPriority/query.sql index 6726facc..d8872f40 100644 --- a/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarmsByLocationAndPriority/query.sql +++ b/BNA8/ignition/named-query/Alarms-autStand/GetActiveAlarmsByLocationAndPriority/query.sql @@ -1,20 +1,3 @@ -WITH Active AS ( - SELECT - ae.id, - ae.eventid, - ae.priority, - aed.strValue - FROM alarm_events ae - LEFT JOIN alarm_event_data aed ON ae.id = aed.id AND aed.propname = 'myTag' - WHERE ae.eventtype = 0 - AND NOT EXISTS ( - SELECT 1 FROM alarm_events ae_clear - WHERE ae_clear.eventid = ae.eventid - AND ae_clear.eventtype = 1 - ) - AND ae.displaypath NOT LIKE '%System Startup%' - AND ae.source NOT LIKE '%System Startup%' -) SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(strValue, '/', 2), '/', -1) AS Location, CASE priority @@ -26,6 +9,25 @@ SELECT ELSE 'Unknown' END AS Priority, COUNT(*) AS Count -FROM Active +FROM ( + SELECT + ae.id, + ae.eventid, + ae.priority, + aed.strValue + FROM alarm_events ae + LEFT JOIN alarm_event_data aed + ON ae.id = aed.id + AND aed.propname = 'myTag' + WHERE ae.eventtype = 0 + AND NOT EXISTS ( + SELECT 1 + FROM alarm_events ae_clear + WHERE ae_clear.eventid = ae.eventid + AND ae_clear.eventtype = 1 + ) + AND ae.displaypath NOT LIKE '%System Startup%' + AND ae.source NOT LIKE '%System Startup%' +) AS Active GROUP BY Location, Priority ORDER BY Location, Priority; diff --git a/BNA8/ignition/named-query/Alarms-autStand/GetAlarms/query.sql b/BNA8/ignition/named-query/Alarms-autStand/GetAlarms/query.sql index b029688b..0d91b16e 100644 --- a/BNA8/ignition/named-query/Alarms-autStand/GetAlarms/query.sql +++ b/BNA8/ignition/named-query/Alarms-autStand/GetAlarms/query.sql @@ -1,71 +1,71 @@ -WITH Active AS ( - SELECT - ae.id, - ae.eventtime, - ae.eventid, - ae.source, - ae.priority, - ae.displaypath, - TIMESTAMPDIFF(SECOND, ae.eventtime, COALESCE(ae_clear.eventtime, NOW())) AS duration_seconds - FROM alarm_events ae - LEFT JOIN alarm_events ae_clear - ON ae.eventid = ae_clear.eventid AND ae_clear.eventtype = 1 - WHERE ae.eventtype = 0 - AND ae.displaypath NOT LIKE '%System Startup%' - AND ae.source NOT LIKE '%System Startup%' - GROUP BY ae.id -- Ensure one row per alarm -), -SingleMyTag AS ( - SELECT aed.id, aed.strValue - FROM alarm_event_data aed - WHERE aed.propname = 'myTag' - GROUP BY aed.id -- Collapse duplicates by id -), -SingleClear AS ( - SELECT eventid, MIN(eventtime) AS eventtime - FROM alarm_events - WHERE eventtype = 1 - GROUP BY eventid -) - -SELECT - Active.id AS ID, - Active.eventtime AS StartTimestamp, - Clear.eventtime AS EndTimestamp, - - CONCAT( - LPAD(FLOOR(Active.duration_seconds / 3600), 2, '0'), ':', - LPAD(FLOOR((Active.duration_seconds % 3600) / 60), 2, '0'), ':', - LPAD(Active.duration_seconds % 60, 2, '0') - ) AS Duration, - - CONCAT(Active.displaypath, ' - ', SUBSTRING_INDEX(Active.source, ':/alm:', -1)) AS Description, - - CASE Active.priority - WHEN 0 THEN 'Diagnostic' - WHEN 1 THEN 'Low' - WHEN 2 THEN 'Medium' - WHEN 3 THEN 'High' - WHEN 4 THEN 'Critical' - ELSE 'Unknown' - END AS Priority, - - CONCAT( - Active.displaypath, - '.HMI.', - SUBSTRING_INDEX(aed.strValue, '/', -1) - ) AS Tag, - - SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue, '/', 2), '/', -1) AS Location , - aed.strValue AS FullTag, - Active.displaypath as Device - -FROM Active - -LEFT JOIN SingleClear Clear - ON Active.eventid = Clear.eventid - -LEFT JOIN SingleMyTag aed - ON aed.id = Active.id - -ORDER BY Active.eventtime DESC; +SELECT + a.id AS ID, + a.eventtime AS StartTimestamp, + clr.eventtime AS EndTimestamp, + + -- Duration calculation (HH:MM:SS format) + CONCAT( + LPAD(FLOOR(TIMESTAMPDIFF(SECOND, a.eventtime, COALESCE(clr.eventtime, NOW())) / 3600), 2, '0'), ':', + LPAD(FLOOR((TIMESTAMPDIFF(SECOND, a.eventtime, COALESCE(clr.eventtime, NOW())) % 3600) / 60), 2, '0'), ':', + LPAD( (TIMESTAMPDIFF(SECOND, a.eventtime, COALESCE(clr.eventtime, NOW())) % 60) , 2, '0') + ) AS Duration, + + -- Description combining display path and alarm name + CONCAT(REPLACE(a.displaypath, '_', '-'), ' ', SUBSTRING_INDEX(a.source, ':/alm:', -1)) AS Description, + + -- Priority mapping + CASE a.priority + WHEN 0 THEN 'Diagnostic' + WHEN 1 THEN 'Low' + WHEN 2 THEN 'Medium' + WHEN 3 THEN 'High' + WHEN 4 THEN 'Critical' + ELSE 'Unknown' + END AS Priority, + + -- Tag information + CONCAT(a.displaypath, '.HMI.Alarm.', SUBSTRING_INDEX(aed.strValue, '/', -1)) AS Tag, + SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue, '/', 2), '/', -1) AS Location, + aed.strValue AS FullTag, + a.displaypath AS Device + +FROM alarm_events a + +-- Join to get the earliest clear event for each alarm +LEFT JOIN ( + SELECT eventid, MIN(eventtime) AS eventtime + FROM alarm_events + WHERE eventtype = 1 + GROUP BY eventid +) AS clr ON clr.eventid = a.eventid + +-- Join to get additional tag data +LEFT JOIN ( + SELECT id, strValue + FROM alarm_event_data + WHERE propname = 'myTag' + GROUP BY id +) AS aed ON aed.id = a.id + +WHERE + -- Only active alarm events (not clear events) + a.eventtype = 0 + + -- Exclude system startup alarms + AND a.displaypath NOT LIKE '%System Startup%' + AND a.source NOT LIKE '%System Startup%' + + -- Simple date filtering using named parameters + AND ( + -- Case 1: Alarm was cleared within the specified time range + (clr.eventtime IS NOT NULL AND clr.eventtime >= :starttime AND clr.eventtime < :endtime) + OR + -- Case 2: Alarm is still active (no clear time) and started within or before the range + (clr.eventtime IS NULL AND a.eventtime < :endtime) + ) + +-- Order by end time (most recent clears first), active alarms (NULL) at top, then by ID +ORDER BY clr.eventtime IS NULL DESC, clr.eventtime DESC, a.id DESC + +-- Pagination support (100 records per page) +LIMIT 100 OFFSET :offset; diff --git a/BNA8/ignition/named-query/Alarms-autStand/GetAlarmsWithCount/query.sql b/BNA8/ignition/named-query/Alarms-autStand/GetAlarmsWithCount/query.sql index 0cd98a19..bcb8e10a 100644 --- a/BNA8/ignition/named-query/Alarms-autStand/GetAlarmsWithCount/query.sql +++ b/BNA8/ignition/named-query/Alarms-autStand/GetAlarmsWithCount/query.sql @@ -1,64 +1,42 @@ -SELECT - CONCAT(Active.displaypath, ' - ', SUBSTRING_INDEX(Active.source, ':/alm:', -1)) AS Description, +SELECT + CONCAT(COALESCE(ae.displaypath,'Unknown'), ' - ', + SUBSTRING_INDEX(COALESCE(ae.source,''), ':/alm:', -1)) AS Description, + SUBSTRING_INDEX(SUBSTRING_INDEX(COALESCE(aed.strValue,''), '/', 2), '/', -1) AS Location, + CONCAT(COALESCE(ae.displaypath,'Unknown'), '.HMI.', + SUBSTRING_INDEX(COALESCE(aed.strValue,''),'/',-1)) AS Tag, + CASE ae.priority + WHEN 0 THEN 'Diagnostic' WHEN 1 THEN 'Low' WHEN 2 THEN 'Medium' + WHEN 3 THEN 'High' WHEN 4 THEN 'Critical' ELSE 'Unknown' + END AS Priority, - SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue, '/', 2), '/', -1) AS Location, + MIN(ae.eventtime) AS FirstTimestamp, + MAX(ae.eventtime) AS LastTimestamp, - -- Formatted OPC-style tag - CONCAT( - Active.displaypath, - '.HMI.', - SUBSTRING_INDEX(aed.strValue, '/', -1) - ) AS Tag, - - CASE Active.priority - WHEN 0 THEN 'Diagnostic' - WHEN 1 THEN 'Low' - WHEN 2 THEN 'Medium' - WHEN 3 THEN 'High' - WHEN 4 THEN 'Critical' - ELSE 'Unknown' - END AS Priority, + -- total duration, formatted HH:MM:SS + DATE_FORMAT( + SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, ae.eventtime, COALESCE(clr.clear_time, NOW())))), + '%H:%i:%s' + ) AS Duration, - -- First and last seen times for this alarm - MIN(Active.eventtime) AS FirstTimestamp, - MAX(Active.eventtime) AS LastTimestamp, + COUNT(*) AS Count, - -- Total duration summed from each active-clear pair - CONCAT( - LPAD(FLOOR(SUM(Active.duration_seconds) / 3600), 2, '0'), ':', - LPAD(FLOOR((SUM(Active.duration_seconds) % 3600) / 60), 2, '0'), ':', - LPAD(SUM(Active.duration_seconds) % 60, 2, '0') - ) AS Duration, + aed.strValue AS FullTag, + ae.displaypath AS Device - -- Total number of activations - COUNT(*) AS Count, - - -- Newly added columns - aed.strValue AS FullTag, - Active.displaypath AS Device - -FROM ( - SELECT - ae.id, - ae.source, - ae.eventid, - ae.eventtime, - ae.priority, - ae.displaypath, - TIMESTAMPDIFF(SECOND, ae.eventtime, COALESCE(ae_clear.eventtime, NOW())) AS duration_seconds - FROM alarm_events ae - LEFT JOIN alarm_events ae_clear - ON ae.eventid = ae_clear.eventid AND ae_clear.eventtype = 1 - WHERE ae.eventtype = 0 - AND ae.displaypath NOT LIKE '%System Startup%' - AND ae.source NOT LIKE '%System Startup%' -) AS Active - --- OPC tag path for building .hmi.Tag output -LEFT JOIN alarm_event_data aed - ON aed.id = Active.id AND aed.propname = 'myTag' - --- 🔹 Group by the full unique alarm key (tag + alarm name) -GROUP BY Active.source, Active.displaypath, aed.strValue - -ORDER BY FirstTimestamp DESC; +FROM alarm_events ae +LEFT JOIN ( + -- get earliest clear per event + SELECT eventid, MIN(eventtime) AS clear_time + FROM alarm_events + WHERE eventtype = 1 + GROUP BY eventid +) clr ON clr.eventid = ae.eventid +LEFT JOIN alarm_event_data aed + ON aed.id = ae.id AND aed.propname = 'myTag' +WHERE ae.eventtype = 0 + AND COALESCE(ae.displaypath,'') NOT LIKE '%System Startup%' + AND COALESCE(ae.source,'') NOT LIKE '%System Startup%' +GROUP BY + ae.source, ae.displaypath, aed.strValue +ORDER BY + FirstTimestamp DESC, MIN(ae.id) DESC;