diff --git a/BNA8/com.inductiveautomation.perspective/general-properties/data.bin b/BNA8/com.inductiveautomation.perspective/general-properties/data.bin new file mode 100644 index 00000000..d14358dd --- /dev/null +++ b/BNA8/com.inductiveautomation.perspective/general-properties/data.bin @@ -0,0 +1,15 @@ +{ + "updateMode": "Instant", + "updateMessage": "This project has been changed. Please save your work, this session will automatically update in {timeLeft} seconds.", + "updateTimeout": 30, + "locale": "Browser", + "idp": null, + "timezone": "Gateway Timezone", + "desktopPageTimeoutSeconds": 60, + "mobilePageTimeoutSeconds": 600, + "hideFromLaunchListings": false, + "thumbnailPath": "", + "sessionClosedMessage": "This Perspective session has been closed.", + "pageClosedMessage": "This Perspective page has been closed.", + "loggedOutMessage": "You are now logged out of your Perspective session. If you are on a shared device, it is recommended to log out of all other sessions before walking away." +} \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/session-props/props.json b/BNA8/com.inductiveautomation.perspective/session-props/props.json index d0faa9f1..61f621cb 100644 --- a/BNA8/com.inductiveautomation.perspective/session-props/props.json +++ b/BNA8/com.inductiveautomation.perspective/session-props/props.json @@ -221,7 +221,7 @@ } }, "props": { - "address": "127.0.0.1", + "address": "[0:0:0:0:0:0:0:1]", "device": {}, "geolocation": {}, "locale": "en-US", diff --git a/BNA8/com.inductiveautomation.perspective/session-props/resource.json b/BNA8/com.inductiveautomation.perspective/session-props/resource.json index 8c2072a9..33526d02 100644 --- a/BNA8/com.inductiveautomation.perspective/session-props/resource.json +++ b/BNA8/com.inductiveautomation.perspective/session-props/resource.json @@ -9,8 +9,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-30T10:04:26Z" + "timestamp": "2025-10-01T10:13:13Z" }, - "lastModificationSignature": "95051ce3d0db6d2a151ba9b6c8ceb96dbbb8938f6e4693321c33477cf3cc0422" + "lastModificationSignature": "60fb9957e5858b89917d8cb99fa83d3b6bbf8243d51e2b4d33cd3c86030eaf62" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/resource.json index a39740bd..52483c83 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-30T10:05:09Z" + "timestamp": "2025-10-01T12:11:45Z" }, - "lastModificationSignature": "1fd04d570a4c9993a058ef644020eb66bb6a2881aeaf316e9b3d3d9959a95be8" + "lastModificationSignature": "8b3250bd65d1c5c62d6992352ca872434f34f6524bfce631ffa4446eb751adaa" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/thumbnail.png index efc3c27f..650d9c31 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Alarms/RealTime/thumbnail.png differ 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 9f81e6a0..18b12929 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,51 @@ ] }, "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" + } + ], + "placeholder": { + "text": "Filter MCMs..." + }, + "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 +472,7 @@ "name": "FlexContainer" }, "position": { - "basis": "700px", + "basis": "881px", "shrink": 0 }, "props": { @@ -439,7 +502,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 +658,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\talarms.alarm_click.handleClick(myData)\n\t\n\t" }, "scope": "G", "type": "script" @@ -616,13 +679,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 +704,11 @@ "enabled": true, "rate": "3" }, - "queryPath": "autStand/Alarms/GetActiveAlarms" + "queryPath": "autStand/Alarms/Active" }, "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 +723,7 @@ "boolean": "checkbox", "dateFormat": "MM/DD/YYYY", "editable": false, - "field": "NumberID", + "field": "ID", "filter": { "boolean": { "condition": "" @@ -686,9 +757,9 @@ "style": { "classes": "" }, - "title": "Number (ID)" + "title": "" }, - "justify": "left", + "justify": "auto", "nullFormat": { "includeNullStrings": false, "nullFormatValue": "", @@ -737,7 +808,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": 70 + "width": "" }, { "align": "center", @@ -870,7 +941,7 @@ "style": { "classes": "" }, - "title": "" + "title": "Duration" }, "justify": "center", "nullFormat": { @@ -923,6 +994,97 @@ "visible": true, "width": 70 }, + { + "align": "center", + "boolean": "checkbox", + "dateFormat": "MM/DD/YYYY", + "editable": false, + "field": "Location", + "filter": { + "boolean": { + "condition": "" + }, + "date": { + "condition": "", + "value": "" + }, + "enabled": true, + "number": { + "condition": "", + "value": "" + }, + "string": { + "condition": "equals" + }, + "visible": "never" + }, + "footer": { + "align": "center", + "justify": "left", + "style": { + "classes": "" + }, + "title": "" + }, + "header": { + "align": "center", + "justify": "center", + "style": { + "classes": "" + }, + "title": "" + }, + "justify": "center", + "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": 70 + }, { "align": "center", "boolean": "checkbox", @@ -1015,98 +1177,6 @@ "visible": true, "width": 70 }, - { - "align": "center", - "boolean": "checkbox", - "dateFormat": "MM/DD/YYYY", - "editable": false, - "field": "Location", - "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": "center", - "style": { - "classes": "" - }, - "title": "" - }, - "justify": "center", - "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": true, - "strictWidth": false, - "style": { - "classes": "" - }, - "toggleSwitch": { - "color": { - "selected": "", - "unselected": "" - } - }, - "viewParams": {}, - "viewPath": "", - "visible": true, - "width": 70 - }, { "align": "center", "boolean": "checkbox", @@ -1199,98 +1269,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 +1454,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": { @@ -1489,8 +1559,46 @@ "filter": { "enabled": true, "results": { + "data": [ + { + "Description": "S03-CH101 Full 1", + "Device": "S03_CH101", + "Duration": "21:03:27", + "FullTag": "System/MCM02/Chute/S03_CH101/Alarm/Full 1", + "ID": 16, + "Location": "MCM02", + "Priority": "Low", + "StartTimestamp": "Tue Sep 30 2025 18:19:44 GMT+0400 (Georgia Standard Time)", + "Tag": "S03_CH101.HMI.Alarm.Full 1" + }, + { + "Description": "NCS1-1-SOL1 TEST", + "Device": "NCS1_1_SOL1", + "Duration": "21:03:27", + "FullTag": "System/MCM02/SOL/NCS1_1_SOL1/TEST", + "ID": 17, + "Location": "MCM02", + "Priority": "High", + "StartTimestamp": "Tue Sep 30 2025 18:19:44 GMT+0400 (Georgia Standard Time)", + "Tag": "NCS1_1_SOL1.HMI.Alarm.TEST" + }, + { + "Description": "S03-CH101 Full 1", + "Device": "S03_CH101", + "Duration": "47:28:32", + "FullTag": "System/MCM02/Chute/S03_CH101/Alarm/Full 1", + "ID": 14, + "Location": "MCM02", + "Priority": "Low", + "StartTimestamp": "Mon Sep 29 2025 15:54:39 GMT+0400 (Georgia Standard Time)", + "Tag": "S03_CH101.HMI.Alarm.Full 1" + } + ], "enabled": true } + }, + "pager": { + "activeOption": 100 } }, "type": "ia.display.table" @@ -1522,6 +1630,433 @@ "children": [ { "children": [ + { + "children": [ + { + "meta": { + "name": "Label_1" + }, + "position": { + "basis": "100px" + }, + "props": { + "style": { + "fontFamily": "Arial", + "fontWeight": "bold", + "textAlign": "center" + }, + "text": "Period:" + }, + "type": "ia.display.label" + }, + { + "custom": { + "customTime": false, + "endDate": { + "$": [ + "ts", + 192, + 1759319697855 + ], + "$ts": 1759319697855 + }, + "startDate": { + "$": [ + "ts", + 192, + 1759319697855 + ], + "$ts": 1759317897855 + } + }, + "meta": { + "name": "Dropdown" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.value": { + "onChange": { + "enabled": null, + "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 + } + }, + "props": { + "maxMenuHeight": 370, + "options": [ + { + "label": "Past 30 Min", + "value": 30 + }, + { + "label": "Past Hour", + "value": 60 + }, + { + "label": "Past 2 Hour", + "value": 120 + }, + { + "label": "Past 4 Hour", + "value": 240 + }, + { + "label": "Past 8 Hour", + "value": 480 + }, + { + "label": "Current Day", + "value": "currentDay" + }, + { + "label": "Morning", + "value": "morning" + }, + { + "label": "Daylight", + "value": "daylight" + }, + { + "label": "Twilight", + "value": "twilight" + }, + { + "label": "Night", + "value": "night" + }, + { + "label": "Wrap Down", + "value": "wrapDown" + }, + { + "label": "Current Shot", + "value": "currentShot" + }, + { + "label": "Custom", + "value": "custom" + } + ], + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "reset-historical-filters", + "pageScope": true, + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.dropdown" + }, + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "100px" + }, + "props": { + "style": { + "fontFamily": "Arial", + "fontWeight": "bold", + "textAlign": "center" + }, + "text": "Start Date" + }, + "type": "ia.display.label" + }, + { + "custom": { + "max_duration_days": 365 + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tautStand.messaging.message_handler.set_time_from_filters(self)\n\t" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "DateTimeInput", + "tooltip": { + "enabled": true + } + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.enabled": { + "binding": { + "config": { + "path": "../Dropdown.custom.customTime" + }, + "type": "property" + } + }, + "props.maxDate": { + "binding": { + "config": { + "expression": "now()" + }, + "type": "expr" + } + }, + "props.minDate": { + "access": "PUBLIC", + "binding": { + "config": { + "expression": "addDays(now(),-{this.custom.max_duration_days})" + }, + "type": "expr" + } + }, + "props.value": { + "binding": { + "config": { + "path": "../Dropdown.custom.startDate" + }, + "type": "property" + }, + "onChange": { + "enabled": null, + "script": "\tautStand.messaging.message_handler.set_time_from_filters(self)" + } + } + }, + "props": { + "formattedValue": "Oct 1, 2025 3:24 PM", + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "reset-historical-filters", + "pageScope": true, + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.date-time-input" + }, + { + "meta": { + "name": "Label_0" + }, + "position": { + "basis": "89px" + }, + "props": { + "style": { + "fontFamily": "Arial", + "fontWeight": "bold", + "textAlign": "center" + }, + "text": "End Date" + }, + "type": "ia.display.label" + }, + { + "meta": { + "name": "DateTimeInput_0" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.enabled": { + "binding": { + "config": { + "path": "../Dropdown.custom.customTime" + }, + "type": "property" + } + }, + "props.maxDate": { + "binding": { + "config": { + "expression": "now()" + }, + "type": "expr" + } + }, + "props.minDate": { + "binding": { + "config": { + "expression": "addDays(now(),-365)" + }, + "type": "expr" + } + }, + "props.value": { + "binding": { + "config": { + "path": "../Dropdown.custom.endDate" + }, + "type": "property" + }, + "onChange": { + "enabled": null, + "script": "\tautStand.messaging.message_handler.set_time_to_filters(self)" + }, + "persistent": true + } + }, + "props": { + "formattedValue": "Oct 1, 2025 3:54 PM", + "style": { + "margin": 15 + }, + "value": { + "$": [ + "ts", + 192, + 1759319697855 + ], + "$ts": 1759319697855 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "reset-historical-filters", + "pageScope": true, + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.date-time-input" + } + ], + "meta": { + "name": "Time" + }, + "position": { + "basis": 800, + "shrink": 0 + }, + "type": "ia.container.flex" + }, + { + "meta": { + "name": "Dropdown" + }, + "position": { + "basis": "200px" + }, + "propConfig": { + "props.value": { + "persistent": false + } + }, + "props": { + "options": [ + { + "label": "MCM01", + "value": "MCM01" + }, + { + "label": "MCM02", + "value": "MCM02" + } + ], + "placeholder": { + "text": "Filter MCMs..." + }, + "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 \"\"\n\tself.parent.getChild(\"Time\").getChild(\"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": { @@ -1604,14 +2139,26 @@ "grow": 1 }, "propConfig": { + "props.columns[5].filter.string.value": { + "binding": { + "config": { + "path": ".../FlexContainer/Dropdown.props.value" + }, + "type": "property" + } + }, "props.data": { "binding": { "config": { + "parameters": { + "endTime": "{.../FlexContainer/Time/DateTimeInput_0.props.value}", + "startTime": "{.../FlexContainer/Time/DateTimeInput.props.value}" + }, "polling": { "enabled": true, "rate": "3" }, - "queryPath": "autStand/Alarms/GetAlarmsWithCount" + "queryPath": "autStand/Alarms/HitList" }, "transforms": [ { @@ -1824,7 +2371,7 @@ "boolean": "checkbox", "dateFormat": "MM-DD-YYYY HH:mm:ss", "editable": false, - "field": "Count", + "field": "ActivationCount", "filter": { "boolean": { "condition": "" @@ -1858,7 +2405,7 @@ "style": { "classes": "" }, - "title": "" + "title": "Count" }, "justify": "center", "nullFormat": { @@ -1950,7 +2497,7 @@ "style": { "classes": "" }, - "title": "" + "title": "Duration" }, "justify": "center", "nullFormat": { @@ -1986,7 +2533,7 @@ }, "render": "auto", "resizable": true, - "sort": "none", + "sort": "descending", "sortable": true, "strictWidth": false, "style": { @@ -2078,7 +2625,7 @@ }, "render": "auto", "resizable": true, - "sort": "none", + "sort": "ascending", "sortable": true, "strictWidth": false, "style": { @@ -2109,16 +2656,15 @@ "condition": "", "value": "" }, - "enabled": false, + "enabled": true, "number": { "condition": "", "value": "" }, "string": { - "condition": "", - "value": "" + "condition": "equals" }, - "visible": "on-hover" + "visible": "never" }, "footer": { "align": "center", @@ -2571,7 +3117,13 @@ "results": { "enabled": true } - } + }, + "pager": { + "activeOption": 100 + }, + "sortOrder": [ + "Priority" + ] }, "type": "ia.display.table" } @@ -2586,6 +3138,17 @@ "type": "ia.container.flex" } ], + "events": { + "system": { + "onStartup": { + "config": { + "script": "\t\t# View.onStartup\n\ttry:\n\t timeFlex \u003d self.getChild(\"FlexContainer\").getChild(\"Time\")\n\t dd \u003d timeFlex.getChild(\"Dropdown\")\n\t dtStart \u003d timeFlex.getChild(\"DateTimeInput\")\n\t dtEnd \u003d timeFlex.getChild(\"DateTimeInput_0\")\n\t\n\t # Force \"Past 30 Min\" (this triggers your dropdown onChange -\u003e sets dates)\n\t dd.props.value \u003d 30\n\t\n\t # Apply filters 1 second later (after bindings settle)\n\t def applyFilters():\n\t messaging.message_handler.set_time_from_filters(dtStart)\n\t messaging.message_handler.set_time_to_filters(dtEnd)\n\t\n\t system.util.invokeLater(applyFilters, 1000)\n\t\n\texcept Exception as ex:\n\t system.util.getLogger(\"Hit_List\").error(\"Init failed: %s\" % ex)" + }, + "scope": "G", + "type": "script" + } + } + }, "meta": { "name": "Hit_List" }, @@ -2612,7 +3175,7 @@ "component": { "onActionPerformed": { "config": { - "script": "\tpayload \u003d {}\n\tif self.custom.SetFilter \u003d\u003d True:\n\t\tpayload[\"data\"] \u003d False\n\t\tself.custom.SetFilter \u003d False\n\t\t\n\t\n\telif self.custom.SetFilter \u003d\u003d False:\n\t\tpayload[\"data\"] \u003d True\n\t\tself.custom.SetFilter \u003d True\n\t\n\tsystem.perspective.sendMessage(\"show-historical-filters\", payload \u003d payload, scope \u003d \"page\")\n\t" + "script": "\tpayload \u003d {}\n\tif self.custom.SetFilter \u003d\u003d True:\n\t\tpayload[\"data\"] \u003d False\n\t\tself.custom.SetFilter \u003d False\n\t\n\telif self.custom.SetFilter \u003d\u003d False:\n\t\tpayload[\"data\"] \u003d True\n\t\tself.custom.SetFilter \u003d True\n\t\n\tsystem.perspective.sendMessage(\"show-historical-filters\", payload \u003d payload, scope \u003d \"page\")\n\t" }, "scope": "G", "type": "script" @@ -2704,22 +3267,22 @@ }, { "custom": { - "customTime": false, + "customTime": true, "endDate": { "$": [ "ts", 192, - 1755608469647 + 1759319940518 ], - "$ts": 1755608469646 + "$ts": 1759319940517 }, "startDate": { "$": [ "ts", 192, - 1755608469646 + 1759319940517 ], - "$ts": 1755606669646 + "$ts": 1759305540517 } }, "meta": { @@ -2732,7 +3295,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 } @@ -2803,7 +3366,7 @@ { "messageType": "reset-historical-filters", "pageScope": true, - "script": "\treset \u003d payload[\"data\"]\n\tself.props.value \u003d None", + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", "sessionScope": false, "viewScope": false } @@ -2830,7 +3393,7 @@ }, { "custom": { - "max_duration_days": 10 + "max_duration_days": 365 }, "events": { "component": { @@ -2892,7 +3455,7 @@ } }, "props": { - "formattedValue": "Aug 19, 2025 4:31 PM", + "formattedValue": "Sep 16, 2025 11:59 AM", "style": { "margin": 15 } @@ -2904,7 +3467,7 @@ { "messageType": "reset-historical-filters", "pageScope": true, - "script": "\treset \u003d payload[\"data\"]\n\tself.props.value \u003d None", + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", "sessionScope": false, "viewScope": false } @@ -2950,14 +3513,13 @@ "config": { "expression": "now()" }, - "enabled": false, "type": "expr" } }, "props.minDate": { "binding": { "config": { - "expression": "addDays(now(),-10)" + "expression": "addDays(now(),-365)" }, "type": "expr" } @@ -2977,25 +3539,17 @@ } }, "props": { - "formattedValue": "Aug 19, 2025 5:01 PM", - "maxDate": { - "$": [ - "ts", - 192, - 1749542669794 - ], - "$ts": 1749715452000 - }, + "formattedValue": "Oct 1, 2025 3:59 PM", "style": { "margin": 15 }, "value": { "$": [ "ts", - 201, - 1755608469647 + 192, + 1759319940518 ], - "$ts": 1755608469646 + "$ts": 1759319940517 } }, "scripts": { @@ -3005,7 +3559,7 @@ { "messageType": "reset-historical-filters", "pageScope": true, - "script": "\treset \u003d payload[\"data\"]\n\tself.props.value \u003d None", + "script": "#\tsystem.perspective.print(payload)\n#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", "sessionScope": false, "viewScope": false } @@ -3099,13 +3653,121 @@ { "messageType": "reset-historical-filters", "pageScope": true, - "script": "\treset \u003d payload[\"data\"]\n\tself.props.value \u003d None", + "script": "#\treset \u003d payload[\"data\"]\n#\tself.props.value \u003d None\n\tpass", "sessionScope": false, "viewScope": false } ] }, "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" + } + ], + "placeholder": { + "text": "Filter MCMs..." + }, + "style": { + "margin": 15 + } + }, + "scripts": { + "customMethods": [], + "extensionFunctions": null, + "messageHandlers": [ + { + "messageType": "hjsgdfn", + "pageScope": false, + "script": "\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.dropdown" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\tself.getSibling(\"Dropdown_0\").props.value \u003d \"\"\n\tself.getSibling(\"Dropdown\").props.value \u003d \"\"\n\tself.parent.parent.parent.getChild(\"Table\").getChild(\"Table\").custom.priority_filters \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": { @@ -3171,6 +3833,8 @@ "children": [ { "custom": { + "hasNext": false, + "loading": false, "max_duration": { "$": [ "ts", @@ -3179,22 +3843,23 @@ ], "$ts": 1747562336635 }, + "page_size": 100, "priority_filters": "", "time_from_filter": { "$": [ "ts", 192, - 1759143973125 + 1759320109195 ], - "$ts": 1755606669646 + "$ts": 1758009540000 }, "time_to_filter": { "$": [ "ts", 192, - 1759143973125 + 1759319940518 ], - "$ts": 1755608469646 + "$ts": 1759319940517 } }, "events": { @@ -3249,18 +3914,32 @@ "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", + "page_size_plus1": "100+1", + "starttime": "{.../Filters/Time/DateTimeInput.props.value}" + }, "polling": { "enabled": true, "rate": "3" }, - "queryPath": "autStand/Alarms/GetAlarms" + "queryPath": "autStand/Alarms/History" }, "transforms": [ { - "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\treturn data", + "code": "\tfrom system.dataset import toPyDataSet\n\t\n\tds \u003d toPyDataSet(value)\n\tpage_size \u003d int(self.custom.page_size) # your custom.page_size \u003d 100\n\t\n\t# detect \"next page\" — works because SQL returns page_size+1 max\n\trow_count \u003d len(ds) if ds is not None else 0\n\tself.custom.hasNext \u003d (row_count \u003e page_size)\n\t\n\t# display only first page_size rows\n\trows_iter \u003d ds if row_count \u003c\u003d page_size else [ds[i] for i in range(page_size)]\n\t\n\tdata \u003d []\n\tcols \u003d list(ds.columnNames) if row_count else []\n\t\n\tfor row in rows_iter:\n\t pr \u003d row[\"Priority\"]\n\t if pr \u003d\u003d \"High\":\n\t cls \u003d \"Alarms-Styles/High\"\n\t elif pr \u003d\u003d \"Medium\":\n\t cls \u003d \"Alarms-Styles/Medium\"\n\t elif pr \u003d\u003d \"Low\":\n\t cls \u003d \"Alarms-Styles/Low\"\n\t elif pr \u003d\u003d \"Diagnostic\":\n\t cls \u003d \"Alarms-Styles/Diagnostic\"\n\t else:\n\t cls \u003d \"Alarms-Styles/NoAlarm\"\n\t\n\t data.append({c: {\"value\": row[c], \"style\": {\"classes\": cls}} for c in cols})\n\t\n\t# turn loading off when data arrives\n\tself.custom.loading \u003d False\n\t\n\treturn data", "type": "script" } ], @@ -3269,6 +3948,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": [ { @@ -3362,7 +4042,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3453,7 +4133,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3544,7 +4224,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3622,7 +4302,7 @@ }, "render": "auto", "resizable": true, - "sort": "none", + "sort": "ascending", "sortable": true, "strictWidth": false, "style": { @@ -3637,7 +4317,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3729,7 +4409,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3820,7 +4500,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -3842,8 +4522,7 @@ "value": "" }, "string": { - "condition": "equals", - "value": "" + "condition": "equals" }, "visible": "never" }, @@ -3912,7 +4591,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -4004,7 +4683,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 50 }, { "align": "center", @@ -4190,7 +4869,7 @@ "viewParams": {}, "viewPath": "", "visible": true, - "width": "" + "width": 300 } ], "emptyMessage": { @@ -4213,7 +4892,8 @@ }, "style": { "margin": 20 - } + }, + "total": "value" }, "scripts": { "customMethods": [], @@ -4243,7 +4923,7 @@ { "messageType": "reset-historical-filters", "pageScope": true, - "script": "\treset \u003d payload[\"data\"]\n\tif reset \u003d\u003d \"reset\":\n\t\tself.props.data \u003d []\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", + "script": "\tval \u003d payload[\"data\"] if isinstance(payload, dict) and \"data\" in payload else payload\n\tif val \u003d\u003d \"reset\":\n\t self.props.data \u003d []\n\t self.custom.device_filters \u003d None\n\t self.custom.priority_filters \u003d None\n\t self.custom.source_id_filters \u003d None\n\t self.custom.time_from_filter \u003d None\n\t self.custom.time_to_filter \u003d None\n\t self.custom.type_filters \u003d None\n\t self.custom.duration_filter \u003d None\n\t self.props.enabled \u003d True", "sessionScope": false, "viewScope": false }, @@ -4308,6 +4988,9 @@ "basis": "980px", "grow": 1 }, + "props": { + "direction": "column" + }, "scripts": { "customMethods": [], "extensionFunctions": null, @@ -4326,219 +5009,407 @@ { "children": [ { - "custom": { - "download_in_progress": true, - "enable_timeout": false, - "priority_filters": "", - "time_from_filter": { - "$": [ - "ts", - 192, - 1759143973124 - ], - "$ts": 1755606669646 - }, - "time_to_filter": { - "$": [ - "ts", - 192, - 1759143973124 - ], - "$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": "medium", + "time_from_filter": { + "$": [ + "ts", + 192, + 1759316536954 + ], + "$ts": 1756755000000 }, - "scope": "G", - "type": "script" - } + "time_to_filter": { + "$": [ + "ts", + 192, + 1759316533389 + ], + "$ts": 1759271400000 + }, + "type_filters": null + }, + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\t# Historical_tab → Paginate → FlexContainer → Export → onActionPerformed\n\t\n\t# Py2/3 compat for unicode\n\ttry:\n\t unicode\n\texcept NameError:\n\t unicode \u003d str\n\t\n\tdef unwrap_once(cell):\n\t \"\"\"Unwrap a single layer of common wrappers.\"\"\"\n\t # 1) Dict-like with \u0027value\u0027\n\t try:\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t return cell[\"value\"]\n\t except Exception:\n\t pass\n\t # 2) Java Map-like (ObjectWrapper of a map)\n\t try:\n\t if hasattr(cell, \"get\"):\n\t # Some ObjectWrappers act like maps\n\t v \u003d cell.get(\"value\")\n\t if v is not None:\n\t return v\n\t except Exception:\n\t pass\n\t # 3) Object with .value attribute\n\t try:\n\t if hasattr(cell, \"value\"):\n\t return cell.value\n\t except Exception:\n\t pass\n\t return cell\n\t\n\tdef unwrap_deep(cell, max_depth\u003d5):\n\t \"\"\"Peel multiple wrapper layers until we reach a scalar.\"\"\"\n\t v \u003d cell\n\t for _ in range(max_depth):\n\t new_v \u003d unwrap_once(v)\n\t if new_v is v:\n\t break\n\t v \u003d new_v\n\t return v\n\t\n\tdef fmt_ts(v):\n\t \"\"\"Format timestamps as \u0027yyyy-MM-dd HH:mm:ss.S\u0027. None -\u003e \u0027\u0027.\"\"\"\n\t if v is None:\n\t return \"\"\n\t try:\n\t # java.util.Date\n\t if hasattr(v, \"getTime\"):\n\t return system.date.format(v, \"yyyy-MM-dd HH:mm:ss.S\")\n\t except Exception:\n\t pass\n\t try:\n\t # epoch millis\n\t if isinstance(v, (int, long)) and v \u003e 10000000:\n\t return system.date.format(system.date.fromMillis(v), \"yyyy-MM-dd HH:mm:ss.S\")\n\t except Exception:\n\t pass\n\t # string/other\n\t return unicode(v)\n\t\n\tdef fmt_text(v):\n\t return \"\" if v is None else unicode(v)\n\t\n\tdef csv_cell(s):\n\t s \u003d \"\" if s is None else unicode(s)\n\t return s.replace(\",\", \";\").replace(\"\\r\", \" \").replace(\"\\n\", \" \")\n\t\n\ttry:\n\t # Locate the Historical table\n\t root \u003d self.parent.parent.parent # -\u003e Historical_tab/root\n\t table \u003d root.getChild(\"Table\").getChild(\"Table\") # -\u003e the table component\n\t\n\t # Prefer filtered rows ONLY if they actually contain rows; otherwise fallback to props.data\n\t rows \u003d []\n\t try:\n\t if table.props.filter.results.enabled and table.props.filter.results.data and len(table.props.filter.results.data) \u003e 0:\n\t rows \u003d table.props.filter.results.data\n\t except Exception:\n\t pass\n\t if not rows:\n\t rows \u003d table.props.data\n\t\n\t if not rows or len(rows) \u003d\u003d 0:\n\t system.perspective.print(\"Historical export: no data in table.\")\n\t return\n\t\n\t # EXACT column order required\n\t col_order \u003d [\"ID\",\"StartTimestamp\",\"EndTimestamp\",\"Duration\",\"Description\",\"Priority\",\"Location\",\"Tag\",\"FullTag\",\"Device\"]\n\t\n\t # Header\n\t lines \u003d [\",\".join(col_order)]\n\t\n\t # Rows\n\t for row in rows:\n\t out \u003d []\n\t for f in col_order:\n\t raw \u003d row.get(f, \"\")\n\t val \u003d unwrap_deep(raw)\n\t\n\t if f in (\"StartTimestamp\", \"EndTimestamp\"):\n\t val \u003d fmt_ts(val)\n\t else:\n\t val \u003d fmt_text(val)\n\t\n\t out.append(csv_cell(val))\n\t lines.append(\",\".join(out))\n\t\n\t csv \u003d \"\\n\".join(lines).encode(\"utf-8\")\n\t system.perspective.download(\"historical_alarms.csv\", csv)\n\t system.perspective.print(\"Historical export: CSV download started (%d records).\" % len(rows))\n\t\n\texcept Exception as e:\n\t system.perspective.print(\"Historical 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\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-device-filters", + "pageScope": true, + "script": "#\tfilters \u003d payload[\"data\"]\n#\tself.custom.device_filters \u003d filters\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-message-filters", + "pageScope": true, + "script": "#\tfilters \u003d payload[\"data\"]\n#\tself.custom.message_filters \u003d filters\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-priority-filters", + "pageScope": true, + "script": "#\tfilters \u003d payload[\"data\"]\n#\tself.custom.priority_filters \u003d filters\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-from-filters", + "pageScope": true, + "script": "#\ttime \u003d payload[\"data\"]\n#\tself.custom.time_from_filter \u003d time\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-to-filters", + "pageScope": true, + "script": "#\ttime \u003d payload[\"data\"]\n#\tself.custom.time_to_filter \u003d time\n\tpass", + "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\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-type-filters", + "pageScope": true, + "script": "#\tfilters \u003d payload[\"data\"]\n#\tself.custom.type_filters \u003d filters\n\tpass", + "sessionScope": false, + "viewScope": false + }, + { + "messageType": "set-duration-filters", + "pageScope": true, + "script": "#\tduration \u003d payload[\"data\"]\n#\tself.custom.duration_filter \u003d duration\n#\tpass", + "sessionScope": false, + "viewScope": false + } + ] + }, + "type": "ia.input.button" + }, + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "580px", + "grow": 1 + }, + "type": "ia.display.label" + } + ], + "custom": { + "disable": true, + "time_now": { + "$": [ + "ts", + 192, + 1759317510198 + ], + "$ts": 1759317510198 } }, "meta": { - "name": "Export", - "tooltip": { - "enabled": true, - "text": "Exports the data displayed in the table." - } + "name": "FlexContainer" }, "position": { - "basis": "120px", - "shrink": 0 + "basis": "960px" }, - "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": "\troot \u003d self.parent.parent.parent\n\ttable \u003d root.getChild(\"Table\").getChild(\"Table\")\n\t\n\tcur \u003d self.getSibling(\"NumericEntryField\").props.value\n\tif cur \u003e 1 and not getattr(table.custom, \"loading\", False):\n\t table.custom.loading \u003d True\n\t self.getSibling(\"NumericEntryField\").props.value \u003d cur - 1" + }, + "scope": "G", "type": "script" } - ], - "type": "expr" - } - }, - "custom.download_complete": { - "binding": { - "config": { - "path": "session.custom.downloads" + } + }, + "meta": { + "name": "Button", + "tooltip": { + "enabled": true + } + }, + "position": { + "basis": 150 + }, + "propConfig": { + "meta.tooltip.text": { + "binding": { + "config": { + "expression": "if(coalesce({../../../Table/Table.custom.loading}, true),\r\n \"Loading previous page…\",\r\n if({../NumericEntryField.props.value} \u003c\u003d 1,\r\n \"You\u0027re on the first page.\",\r\n \"Go to previous page\"))\r\n" + }, + "type": "expr" + } }, - "transforms": [ - { - "code": "\tif value \u003d\u003d True:\n\t\tself.custom.download_in_progress \u003d False", + "props.enabled": { + "binding": { + "config": { + "expression": "({../NumericEntryField.props.value} \u003e 1)\r\n\u0026\u0026 !coalesce({../../../Table/Table.custom.loading}, true)\r\n" + }, + "type": "expr" + } + } + }, + "props": { + "image": { + "height": 50, + "width": 50 + }, + "primary": false, + "text": "Back" + }, + "type": "ia.input.button" + }, + { + "meta": { + "name": "NumericEntryField", + "tooltip": { + "enabled": true + } + }, + "position": { + "basis": "196px" + }, + "propConfig": { + "meta.tooltip.text": { + "binding": { + "config": { + "expression": "if(coalesce({../../../Table/Table.custom.loading}, true),\r\n \"Page change disabled while loading…\",\r\n \"Enter page number\")\r\n" + }, + "type": "expr" + } + }, + "props.enabled": { + "binding": { + "config": { + "expression": "!coalesce({../../../Table/Table.custom.loading}, true)\r\n" + }, + "type": "expr" + } + } + }, + "props": { + "format": "0,0", + "spinner": { + "enabled": false + }, + "value": 1 + }, + "type": "ia.input.numeric-entry-field" + }, + { + "events": { + "component": { + "onActionPerformed": { + "config": { + "script": "\troot \u003d self.parent.parent.parent\n\ttable \u003d root.getChild(\"Table\").getChild(\"Table\")\n\t\n\tif getattr(table.custom, \"hasNext\", False) and not getattr(table.custom, \"loading\", False):\n\t table.custom.loading \u003d True\n\t cur \u003d self.getSibling(\"NumericEntryField\").props.value\n\t self.getSibling(\"NumericEntryField\").props.value \u003d cur + 1" + }, + "scope": "G", "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" + } + }, + "meta": { + "name": "Button_0", + "tooltip": { + "enabled": true + } + }, + "position": { + "basis": 150 + }, + "propConfig": { + "custom.hasNext": { + "binding": { + "config": { + "expression": "{../../../Table/Table.custom.hasNext} \u0026\u0026 !{../../../Table/Table.custom.loading}\r\n" + }, + "type": "expr" } - ], - "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} " + "meta.tooltip.text": { + "binding": { + "config": { + "expression": "if(coalesce({../../../Table/Table.custom.loading}, true),\r\n \"Loading next page…\",\r\n if(!coalesce({../../../Table/Table.custom.hasNext}, false),\r\n \"You\u0027re on the last page. No more rows to load.\",\r\n \"Go to next page\"))\r\n" + }, + "type": "expr" + } }, - "type": "expr" - } - }, - "props.text": { - "binding": { - "config": { - "expression": "if(!{this.custom.enable_timeout}, \"Export\",\r\nif({this.custom.download_in_progress}, \"Exporting...\",\r\n\"Export\"))" + "props.enabled": { + "binding": { + "config": { + "expression": "coalesce({../../../Table/Table.custom.hasNext}, false)\r\n\u0026\u0026 !coalesce({../../../Table/Table.custom.loading}, true)\r\n" + }, + "type": "expr" + } + } + }, + "props": { + "image": { + "height": 50, + "width": 50 }, - "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 +5423,15 @@ "justify": "space-evenly" }, "type": "ia.container.flex" + }, + { + "meta": { + "name": "FlexContainer_1" + }, + "position": { + "basis": 50 + }, + "type": "ia.container.flex" } ], "meta": { @@ -4593,7 +5473,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": "\t# Tab Container -\u003e props.currentTabIndex : propertyChange\n\t\n\t# 1) Optional: reset filters whenever leaving the first tab\n\tif self.props.currentTabIndex !\u003d 0:\n\t try:\n\t payload \u003d {\"reset\": \"false\"}\n\t # Active alarms/hit list reset\n\t system.perspective.sendMessage(\"reset-filters\", payload\u003dpayload, scope\u003d\"page\")\n\t # Historical widgets reset (if you want them cleared when switching tabs)\n\t system.perspective.sendMessage(\"reset-historical-filters\", payload\u003d\"reset\", scope\u003d\"page\")\n\t except Exception as ex:\n\t system.util.getLogger(\"TabChange\").warn(\"Reset broadcast failed: %s\" % ex)\n\t\n\t# 2) Hit_List (2nd tab, index \u003d 1) -\u003e force last 30 minutes and apply\n\tif currentValue.value \u003d\u003d 1:\n\t try:\n\t hit \u003d self.getChild(\"Hit_List\")\n\t timeFlex \u003d hit.getChild(\"FlexContainer\").getChild(\"Time\")\n\t dd \u003d timeFlex.getChild(\"Dropdown\")\n\t dtStart \u003d timeFlex.getChild(\"DateTimeInput\")\n\t dtEnd \u003d timeFlex.getChild(\"DateTimeInput_0\")\n\t\n\t # Always set to Past 30 Min on entering Hit_List\n\t dd.custom.customTime \u003d False\n\t dd.props.value \u003d 30 # triggers Dropdown onChange -\u003e sets start/end (now-30m..now)\n\t\n\t # Apply your filters after bindings settle\n\t def applyFilters_HitList():\n\t messaging.message_handler.set_time_from_filters(dtStart)\n\t messaging.message_handler.set_time_to_filters(dtEnd)\n\t\n\t system.util.invokeLater(applyFilters_HitList, 1000)\n\t\n\t except Exception as ex:\n\t system.util.getLogger(\"Hit_List_Init\").warn(\"Init failed: %s\" % ex)\n\t\n\t # Your existing Hit_List code (shelved alarms collection)\n\t try:\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 for alarm in alarms:\n\t if alarm.isShelved() and not alarm.isAcked() and not alarm.isCleared():\n\t alarm_path \u003d str(alarm.getSource())\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 for shelved_item in shelved_info:\n\t shelved_str \u003d str(shelved_item)\n\t if alarm_path in shelved_str:\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 expiration\n\t expiration \u003d \"\"\n\t if shelveEntry and \"expiration:\" in shelveEntry:\n\t exp_part \u003d shelveEntry.split(\"expiration:\")[1]\n\t expiration \u003d exp_part.split(\",\")[0].strip() if \",\" in exp_part else exp_part.strip()\n\t\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 except Exception as ex:\n\t system.util.getLogger(\"Hit_List_Shelved\").warn(\"Shelved collection failed: %s\" % ex)\n\t\n\t# 3) Historical_tab (3rd tab, index \u003d 2) -\u003e force last 30 minutes and apply\n\tif currentValue.value \u003d\u003d 2:\n\t try:\n\t hist \u003d self.getChild(\"Historical_tab\")\n\t timeFlex \u003d hist.getChild(\"root\").getChild(\"Filters\").getChild(\"Time\")\n\t dd \u003d timeFlex.getChild(\"Dropdown\")\n\t dtStart \u003d timeFlex.getChild(\"DateTimeInput\")\n\t dtEnd \u003d timeFlex.getChild(\"DateTimeInput_0\")\n\t\n\t # Always set to Past 30 Min on entering Historical\n\t dd.custom.customTime \u003d False\n\t dd.props.value \u003d 30 # triggers Dropdown onChange -\u003e sets start/end (now-30m..now)\n\t\n\t # Apply the filters after bindings settle (table listens to DateTime inputs)\n\t def applyFilters_Historical():\n\t messaging.message_handler.set_time_from_filters(dtStart)\n\t messaging.message_handler.set_time_to_filters(dtEnd)\n\t\n\t system.util.invokeLater(applyFilters_Historical, 1000)\n\t\n\t except Exception as ex:\n\t system.util.getLogger(\"Historical_Init\").warn(\"Init failed: %s\" % ex)\n\t\n\t# 4) Activity Logger (unchanged)\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" } } }, diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/TEST/view.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/TEST/view.json new file mode 100644 index 00000000..9d2a411d --- /dev/null +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/TEST/view.json @@ -0,0 +1,731 @@ +{ + "custom": {}, + "params": {}, + "props": { + "defaultSize": { + "height": 1080, + "width": 1920 + } + }, + "root": { + "children": [ + { + "meta": { + "name": "MCM01" + }, + "position": { + "height": 1080, + "width": 1920 + }, + "props": { + "elements": [ + { + "elements": [ + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path6", + "name": "path6", + "transform": "translate(-2.0833334e-5)", + "type": "path" + }, + { + "type": "group" + } + ], + "id": "clipPath6", + "name": "clipPath6", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path8", + "name": "path8", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath8", + "name": "clipPath8", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path9", + "name": "path9", + "transform": "matrix(1,0,0,-1,-2796,3847)", + "type": "path" + } + ], + "id": "clipPath9", + "name": "clipPath9", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path10", + "name": "path10", + "transform": "matrix(1,0,0,-1,-2822,3855)", + "type": "path" + } + ], + "id": "clipPath10", + "name": "clipPath10", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path12", + "name": "path12", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath12", + "name": "clipPath12", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path13", + "name": "path13", + "transform": "matrix(1,0,0,-1,-2822,3839)", + "type": "path" + } + ], + "id": "clipPath13", + "name": "clipPath13", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path14", + "name": "path14", + "transform": "matrix(1,0,0,-1,-2831,3847)", + "type": "path" + } + ], + "id": "clipPath14", + "name": "clipPath14", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path16", + "name": "path16", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath16", + "name": "clipPath16", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path18", + "name": "path18", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath18", + "name": "clipPath18", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path20", + "name": "path20", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath20", + "name": "clipPath20", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path22", + "name": "path22", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath22", + "name": "clipPath22", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path24", + "name": "path24", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath24", + "name": "clipPath24", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path26", + "name": "path26", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath26", + "name": "clipPath26", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path27", + "name": "path27", + "transform": "matrix(0,-1,-1,0,5714,1994)", + "type": "path" + } + ], + "id": "clipPath27", + "name": "clipPath27", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path29", + "name": "path29", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath29", + "name": "clipPath29", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path31", + "name": "path31", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath31", + "name": "clipPath31", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path33", + "name": "path33", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath33", + "name": "clipPath33", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path35", + "name": "path35", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath35", + "name": "clipPath35", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path37", + "name": "path37", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath37", + "name": "clipPath37", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path39", + "name": "path39", + "transform": "translate(-2.0833334e-5)", + "type": "path" + } + ], + "id": "clipPath39", + "name": "clipPath39", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path40", + "name": "path40", + "transform": "matrix(0,-1,-1,0,4932,2183)", + "type": "path" + } + ], + "id": "clipPath40", + "name": "clipPath40", + "type": "clipPath" + }, + { + "clipPathUnits": "userSpaceOnUse", + "elements": [ + { + "d": "M 1126,0 H 3737 V 5796 H 1126 V 0", + "id": "path23935", + "name": "path23935", + "transform": "matrix(0,-1,-1,0,5714,2172)", + "type": "path" + } + ], + "id": "clipPath23935", + "name": "clipPath23935", + "type": "clipPath" + } + ], + "id": "defs1", + "name": "defs1", + "type": "defs" + }, + { + "elements": [ + { + "d": "m 17.513137,116.02606 h 7.883849 v 35.33131 h -7.925563 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path25072", + "name": "path25072", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 17.578237,115.55245 0.185181,-7.76481 c 1.517289,-4.83339 4.580567,-7.799271 8.864116,-10.344944 l 3.914525,6.935164 c -2.984985,1.33473 -4.229119,3.34824 -4.999076,6.51743 l -0.08744,4.67802 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path26615", + "name": "path26615", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 72.20209,125.20076 h 7.883848 v 53.73674 h -7.925561 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path26618", + "name": "path26618", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 72.261082,115.88006 h 7.883848 v 8.72601 h -7.925561 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27070", + "name": "path27070", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 72.231586,106.67734 h 7.883848 v 8.72601 h -7.925561 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27071", + "name": "path27071", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 72.219369,106.20226 c -0.03623,-9.238512 0.460678,-12.796916 8.960808,-17.991777 l 4.047256,6.905673 c -5.529025,2.473147 -5.25942,6.010384 -5.145507,11.136454 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27072", + "name": "path27072", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 34.461924,92.956423 3.944478,6.826134 -7.555316,4.365833 -3.965348,-6.862253 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27074", + "name": "path27074", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 42.425813,88.355065 3.944478,6.826134 -7.555316,4.365833 -3.965348,-6.862253 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27080", + "name": "path27080", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 60.100764,87.570756 -13.376385,7.447713 -3.959823,-6.887292 1.504291,-0.553046 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27081", + "name": "path27081", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 99.030276,87.61753 -13.464875,7.359226 -3.952449,-7.020023 1.430551,-0.368698 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27082", + "name": "path27082", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 158.56005,79.566794 -0.016,7.760334 -120.794639,-0.04735 0.0159,-7.801393 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27083", + "name": "path27083", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.244431" + }, + "type": "path" + }, + { + "d": "m 267.35173,79.640375 -0.0142,7.780257 -107.74707,-0.04746 0.0141,-7.821422 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27084", + "name": "path27084", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.243285" + }, + "type": "path" + }, + { + "d": "m 399.37485,79.720395 -0.0173,7.737716 -131.17963,-0.0472 0.0172,-7.778656 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27085", + "name": "path27085", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.23373" + }, + "type": "path" + }, + { + "d": "m 400.0944,79.650678 c 5.03604,0.02588 7.95928,-0.266973 12.23378,1.989441 1.65503,0.966601 2.74197,2.075227 3.73794,3.206593 1.85537,2.841276 3.14745,5.859861 3.05039,10.779803 l -8.06562,0.03102 c -0.0803,-1.92185 0.0446,-3.799123 -1.54746,-5.774965 -2.38574,-2.686548 -6.13811,-2.332233 -9.40355,-2.443066 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27086", + "name": "path27086", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 411.25685,96.063667 h 7.88112 v 54.940713 h -7.92282 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27087", + "name": "path27087", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.252742" + }, + "type": "path" + }, + { + "d": "m 411.25883,151.59084 h 7.88385 v 8.72601 h -7.92556 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27088", + "name": "path27088", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 427.45236,179.63321 c -12.30206,0.13237 -16.45431,-5.69061 -16.18738,-18.7973 l 7.85705,2.9e-4 c 0.10669,7.76558 0.23673,10.73714 8.29789,10.94492 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27089", + "name": "path27089", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.25" + }, + "type": "path" + }, + { + "d": "m 448.59365,171.83373 0.13725,7.76254 -20.366,0.0641 -0.13793,-7.8036 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27090", + "name": "path27090", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.268812" + }, + "type": "path" + }, + { + "d": "m 468.70557,171.74638 0.12932,7.77032 -19.19125,0.0641 -0.12998,-7.81142 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27091", + "name": "path27091", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.261075" + }, + "type": "path" + }, + { + "d": "m 481.28798,171.66728 0.06,5.6578 -11.7815,0.0672 -0.0603,-5.68771 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27092", + "name": "path27092", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.246092" + }, + "type": "path" + }, + { + "d": "m 494.42349,171.66846 0.003,5.65425 -12.14703,0.002 -0.003,-5.68414 z", + "fill": { + "opacity": "1", + "paint": "#ffffff" + }, + "id": "path27093", + "name": "path27093", + "stroke": { + "dasharray": "none", + "opacity": "1", + "paint": "#000000", + "width": "0.249796" + }, + "type": "path" + }, + { + "type": "group" + } + ], + "id": "layer1", + "name": "layer1", + "type": "group" + } + ], + "preserveAspectRatio": "none", + "viewBox": "0 0 508 285.75" + }, + "type": "ia.shapes.svg" + } + ], + "events": { + "dom": { + "onClick": { + "config": { + "script": "\tsystem.perspective.print(event.keys())" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "root" + }, + "type": "ia.container.coord" + } +} \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/resource.json index 75c01f9b..0aab0ea8 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-30T14:50:24Z" + "timestamp": "2025-10-01T10:01:09Z" }, - "lastModificationSignature": "6c3bbc1fd97bc7504541fe018dee255fef567c732df15a020e2e691618dd91ea" + "lastModificationSignature": "703b32e2f5d2f02def085075ddc330c86f57bc14a7ac25ce31d6a8af3222dd67" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/thumbnail.png index 30ae5a43..a77bbf5f 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Custom_Views/View-Scaler/thumbnail.png differ diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json index 18c5577d..3dba805c 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-30T14:50:23Z" + "timestamp": "2025-10-01T10:02:46Z" }, - "lastModificationSignature": "cce739592e2d679f1c13c756c2373387402009be88ec55c43ce7c5dff075f1aa" + "lastModificationSignature": "8a2a22c00dd87d5ae0acb6ae123f223dc2e0742cb5bafda2445275cf6e6f82cd" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/thumbnail.png index 46c1c60e..58de48d2 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/thumbnail.png differ diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json index 6ca4c8a7..4c2d6938 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-29T10:24:06Z" + "timestamp": "2025-10-01T10:13:13Z" }, - "lastModificationSignature": "6646652b2a69bb08854bd4a9109a42e5f3ed457f6d254d675371f579c605e114" + "lastModificationSignature": "9116d45470d493a88ae3df94af66ac9f4edee153c2d7d0e9852cd53b10762349" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png index 4d4f186d..e1f2a7ec 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png differ diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/resource.json index 656d0cec..ad226c43 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-29T15:17:13Z" + "timestamp": "2025-10-01T10:01:23Z" }, - "lastModificationSignature": "35fbd9fbe8fb9619aa51b4a40de23a5079c17d1107d251e974a98da478959f2f" + "lastModificationSignature": "9d7c34fdc8a9128e0bc1c2f42b467658724511d9391f25ec1c23304d75c3b6b2" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/thumbnail.png index 307331c0..fc494dac 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM01-FLUID INBOUND/thumbnail.png differ diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/resource.json b/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/resource.json index 90760219..e87102ea 100644 --- a/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/resource.json +++ b/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-09-30T14:51:57Z" + "timestamp": "2025-10-01T10:03:43Z" }, - "lastModificationSignature": "f3a46607418562736242da1164966444593661ec0978fde0cbdea8d58d87901a" + "lastModificationSignature": "a286e0a7925b76d2ed4b0ea8f296f72980f2c1ef42077ae099dbb6ca665bac01" } } \ No newline at end of file diff --git a/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/thumbnail.png b/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/thumbnail.png index d42fec9b..9d9dfcff 100644 Binary files a/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/thumbnail.png and b/BNA8/com.inductiveautomation.perspective/views/autStand/Overview/BNA8/thumbnail.png differ diff --git a/BNA8/ignition/named-query/autStand/Alarms/Active/query.sql b/BNA8/ignition/named-query/autStand/Alarms/Active/query.sql new file mode 100644 index 00000000..751eecea --- /dev/null +++ b/BNA8/ignition/named-query/autStand/Alarms/Active/query.sql @@ -0,0 +1,28 @@ +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, + 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/autStand/Alarms/GetActiveAlarms/query.sql b/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarms/query.sql deleted file mode 100644 index 96d13722..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarms/query.sql +++ /dev/null @@ -1,62 +0,0 @@ -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 , - 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 diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarms/resource.json b/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarms/resource.json deleted file mode 100644 index ff6749c4..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarms/resource.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "scope": "DG", - "version": 2, - "restricted": false, - "overridable": true, - "files": [ - "query.sql" - ], - "attributes": { - "useMaxReturnSize": false, - "autoBatchEnabled": false, - "fallbackValue": "", - "maxReturnSize": 100, - "cacheUnit": "SEC", - "type": "Query", - "enabled": true, - "cacheAmount": 1, - "cacheEnabled": false, - "database": "MariaDB", - "fallbackEnabled": false, - "lastModificationSignature": "e21931e78403e7d61d02415d95a07521861f1a620abea231875105f77528507f", - "permissions": [ - { - "zone": "default", - "role": "" - } - ], - "lastModification": { - "actor": "admin", - "timestamp": "2025-09-29T11:23:02Z" - }, - "parameters": [ - { - "type": "Parameter", - "identifier": "priorityList", - "sqlType": 7 - } - ] - } -} \ No newline at end of file diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/query.sql b/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/query.sql index 6726facc..d8872f40 100644 --- a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/query.sql +++ b/BNA8/ignition/named-query/autStand/Alarms/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/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/resource.json b/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/resource.json index edaa25a7..d575c40c 100644 --- a/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/resource.json +++ b/BNA8/ignition/named-query/autStand/Alarms/GetActiveAlarmsByLocationAndPriority/resource.json @@ -18,7 +18,7 @@ "cacheEnabled": false, "database": "MariaDB", "fallbackEnabled": false, - "lastModificationSignature": "30e5941a41ccb9dc1c9a70392d5bbb2ab39c1c601778316fef83870c620b63e3", + "lastModificationSignature": "a3505bbdb9faa8b6a00129d027b58e7952c5aac5abb1a6843ae8356b6db33e55", "permissions": [ { "zone": "default", @@ -26,8 +26,8 @@ } ], "lastModification": { - "actor": "admin", - "timestamp": "2025-09-26T09:30:18Z" + "actor": "external", + "timestamp": "2025-09-20T08:33:12Z" } } } \ No newline at end of file diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/query.sql b/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/query.sql deleted file mode 100644 index b029688b..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/query.sql +++ /dev/null @@ -1,71 +0,0 @@ -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; diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/resource.json b/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/resource.json deleted file mode 100644 index a0488867..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetAlarms/resource.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "scope": "DG", - "version": 2, - "restricted": false, - "overridable": true, - "files": [ - "query.sql" - ], - "attributes": { - "useMaxReturnSize": false, - "autoBatchEnabled": false, - "fallbackValue": "", - "maxReturnSize": 100, - "cacheUnit": "SEC", - "type": "Query", - "enabled": true, - "cacheAmount": 1, - "cacheEnabled": false, - "database": "MariaDB", - "fallbackEnabled": false, - "lastModificationSignature": "28a5cb6474508ef25ea6c95d49f312634d077d622b543d18289c481fbb8ba3b7", - "permissions": [ - { - "zone": "default", - "role": "" - } - ], - "lastModification": { - "actor": "admin", - "timestamp": "2025-09-26T09:30:18Z" - } - } -} \ No newline at end of file diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/query.sql b/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/query.sql deleted file mode 100644 index 0cd98a19..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/query.sql +++ /dev/null @@ -1,64 +0,0 @@ -SELECT - CONCAT(Active.displaypath, ' - ', SUBSTRING_INDEX(Active.source, ':/alm:', -1)) AS Description, - - SUBSTRING_INDEX(SUBSTRING_INDEX(aed.strValue, '/', 2), '/', -1) AS Location, - - -- 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, - - -- First and last seen times for this alarm - MIN(Active.eventtime) AS FirstTimestamp, - MAX(Active.eventtime) AS LastTimestamp, - - -- 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, - - -- 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; diff --git a/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/resource.json b/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/resource.json deleted file mode 100644 index 6b026aa1..00000000 --- a/BNA8/ignition/named-query/autStand/Alarms/GetAlarmsWithCount/resource.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "scope": "DG", - "version": 2, - "restricted": false, - "overridable": true, - "files": [ - "query.sql" - ], - "attributes": { - "useMaxReturnSize": false, - "autoBatchEnabled": false, - "fallbackValue": "", - "maxReturnSize": 100, - "cacheUnit": "SEC", - "type": "Query", - "enabled": true, - "cacheAmount": 1, - "cacheEnabled": false, - "database": "MariaDB", - "fallbackEnabled": false, - "lastModificationSignature": "731a950ac10a411f50861ee6793ccb10664c7408fb607f40072e1defaaf5c584", - "permissions": [ - { - "zone": "default", - "role": "" - } - ], - "lastModification": { - "actor": "admin", - "timestamp": "2025-09-26T09:30:18Z" - } - } -} \ No newline at end of file diff --git a/BNA8/ignition/named-query/autStand/Alarms/History/query.sql b/BNA8/ignition/named-query/autStand/Alarms/History/query.sql new file mode 100644 index 00000000..9f154d2c --- /dev/null +++ b/BNA8/ignition/named-query/autStand/Alarms/History/query.sql @@ -0,0 +1,73 @@ +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) +-- Pagination support: request one extra row to detect "has next" on the client +LIMIT :page_size_plus1 OFFSET :offset; + diff --git a/BNA8/ignition/named-query/autStand/Alarms/HitList/query.sql b/BNA8/ignition/named-query/autStand/Alarms/HitList/query.sql new file mode 100644 index 00000000..cebf6c6a --- /dev/null +++ b/BNA8/ignition/named-query/autStand/Alarms/HitList/query.sql @@ -0,0 +1,93 @@ +-- Params (can be NULL or empty string '') +-- :startTime DATETIME or NULL +-- :endTime DATETIME or NULL + +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, + + -- First/Last timestamps (clipped if a window is provided) + MIN( + CASE + WHEN NULLIF(:startTime,'') IS NULL AND NULLIF(:endTime,'') IS NULL + THEN ae.eventtime + ELSE GREATEST(ae.eventtime, COALESCE(NULLIF(:startTime,''), ae.eventtime)) + END + ) AS FirstTimestamp, + + MAX( + CASE + WHEN NULLIF(:startTime,'') IS NULL AND NULLIF(:endTime,'') IS NULL + THEN COALESCE(clr.clear_time, NOW()) + ELSE LEAST(COALESCE(clr.clear_time, NOW()), + COALESCE(NULLIF(:endTime,''), COALESCE(clr.clear_time, NOW()))) + END + ) AS LastTimestamp, + + -- Duration within window (full if no window) + DATE_FORMAT( + SEC_TO_TIME( + SUM( + CASE + WHEN NULLIF(:startTime,'') IS NULL AND NULLIF(:endTime,'') IS NULL + THEN TIMESTAMPDIFF(SECOND, ae.eventtime, COALESCE(clr.clear_time, NOW())) + ELSE GREATEST( + TIMESTAMPDIFF( + SECOND, + GREATEST(ae.eventtime, COALESCE(NULLIF(:startTime,''), ae.eventtime)), + LEAST(COALESCE(clr.clear_time, NOW()), + COALESCE(NULLIF(:endTime,''), COALESCE(clr.clear_time, NOW()))) + ), + 0 + ) + END + ) + ), + '%H:%i:%s' + ) AS Duration, + + -- This is the key metric: how many times it was jammed (activations started in window) + CAST(COUNT(*) AS SIGNED) AS ActivationCount, + + + aed.strValue AS FullTag, + ae.displaypath AS Device + +FROM alarm_events ae +LEFT JOIN ( + -- 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%' + + -- Only filter by time if a bound is provided; we count activations STARTED in the window + AND ( + (NULLIF(:startTime,'') IS NULL AND NULLIF(:endTime,'') IS NULL) + OR ( + ae.eventtime >= COALESCE(NULLIF(:startTime,''), ae.eventtime) + AND ae.eventtime <= COALESCE(NULLIF(:endTime,''), ae.eventtime) + ) + ) + +GROUP BY + ae.source, ae.displaypath, aed.strValue +ORDER BY + FirstTimestamp DESC, MIN(ae.id) DESC;