2025-10-15 01:20:35 +04:00

5762 lines
275 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"custom": {
"activityLogger": {
"alt_pageid": "alarms",
"pageid": "alarms/ActiveAlarms",
"start_time": {
"$": [
"ts",
192,
1748425447154
],
"$ts": 1748425447154
}
}
},
"events": {
"system": {
"onStartup": {
"config": {
"script": "\tself.getChild(\"root\").getChild(\"TabContainer\").getChild(\"Hit_List\").getChild(\"FlexContainer\").getChild(\"Time\").getChild(\"Dropdown\").props.value \u003d 30\n\tself.getChild(\"root\").getChild(\"TabContainer\").getChild(\"Historical_tab\").getChild(\"root\").getChild(\"Filters\").getChild(\"Time\").getChild(\"Dropdown\").props.value \u003d 30"
},
"scope": "G",
"type": "script"
}
}
},
"params": {},
"propConfig": {
"custom.activityLogger": {
"persistent": true
}
},
"props": {
"defaultSize": {
"height": 1080,
"width": 1920
}
},
"root": {
"children": [
{
"children": [
{
"children": [
{
"children": [
{
"children": [
{
"meta": {
"name": "Label_0"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"custom": {
"Severity": "High",
"background_on": "true"
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tpriority \u003d \u0027high\u0027\n\t# Copy and toggle the filter\n\tpriorities \u003d dict(self.parent.custom.priorities)\n\tpriorities[priority] \u003d not priorities.get(priority, False)\n\tself.parent.custom.priorities \u003d priorities\n\t\n\tself.custom.background_on \u003d \"true\" if priorities[priority] else \"false\""
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_0"
},
"position": {
"basis": "120px"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"expression": "if({this.custom.background_on}\u003d\"false\",0,\r\nif({session.custom.colours.colour_impaired},2,1))"
},
"transforms": [
{
"fallback": "",
"inputType": "scalar",
"mappings": [
{
"input": 0,
"output": ""
},
{
"input": 1,
"output": "Alarms-Styles/High"
},
{
"input": 2,
"output": "Alarms-Styles/Alt-Colours/High"
}
],
"outputType": "style-list",
"type": "map"
}
],
"type": "expr"
}
}
},
"props": {
"image": {
"icon": {
"path": "material/priority_high"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "High"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "reset-filters",
"pageScope": true,
"script": "\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"reset\"]\n\tif severity \u003d\u003d \"false\":\n\t\tbackground \u003d \"false\"\n\telse:\n\t\tbackground \u003d \"true\"\n\tself.custom.background_on \u003d background",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Label_1"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "Label_4"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"custom": {
"Severity": "Medium",
"background_on": "true"
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tpriority \u003d \u0027medium\u0027\n\t# Copy and toggle the filter\n\tpriorities \u003d dict(self.parent.custom.priorities)\n\tpriorities[priority] \u003d not priorities.get(priority, False)\n\tself.parent.custom.priorities \u003d priorities\n\t\n\tself.custom.background_on \u003d \"true\" if priorities[priority] else \"false\""
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_1"
},
"position": {
"basis": "120px"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"expression": "if({this.custom.background_on}\u003d\"false\",0,\r\nif({session.custom.colours.colour_impaired},2,1))"
},
"transforms": [
{
"fallback": "Buttons/PB_1",
"inputType": "scalar",
"mappings": [
{
"input": 0,
"output": ""
},
{
"input": 1,
"output": "Alarms-Styles/Medium"
},
{
"input": 2,
"output": "Alarms-Styles/Alt-Colours/Medium"
}
],
"outputType": "style-list",
"type": "map"
}
],
"type": "expr"
}
}
},
"props": {
"image": {
"icon": {
"path": "material/priority_high"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "Medium"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "reset-filters",
"pageScope": true,
"script": "\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"reset\"]\n\tif severity \u003d\u003d \"false\":\n\t\tbackground \u003d \"false\"\n\telse:\n\t\tbackground \u003d \"true\"\n\tself.custom.background_on \u003d background",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Label_2"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"custom": {
"Severity": "Low",
"background_on": "false"
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tpriority \u003d \u0027low\u0027\n\t# Copy and toggle the filter\n\tpriorities \u003d dict(self.parent.custom.priorities)\n\tpriorities[priority] \u003d not priorities.get(priority, False)\n\tself.parent.custom.priorities \u003d priorities\n\t\n\tself.custom.background_on \u003d \"true\" if priorities[priority] else \"false\""
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_2"
},
"position": {
"basis": "120px"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"expression": "if({this.custom.background_on}\u003d\"false\",0,\r\nif({session.custom.colours.colour_impaired},2,1))"
},
"transforms": [
{
"fallback": "Buttons/PB_1",
"inputType": "scalar",
"mappings": [
{
"input": 0,
"output": ""
},
{
"input": 1,
"output": "Alarms-Styles/Low"
},
{
"input": 2,
"output": "Alarms-Styles/Alt-Colours/Low"
}
],
"outputType": "style-list",
"type": "map"
}
],
"type": "expr"
}
}
},
"props": {
"image": {
"icon": {
"path": "material/low_priority"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "Low"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "reset-filters",
"pageScope": true,
"script": "\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"reset\"]\n\tif severity \u003d\u003d \"false\":\n\t\tbackground \u003d \"false\"\n\telse:\n\t\tbackground \u003d \"true\"\n\tself.custom.background_on \u003d background",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Label_3"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"custom": {
"background_on": "false"
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tpriority \u003d \u0027diagnostic\u0027\n\n\tpriorities \u003d dict(self.parent.custom.priorities)\n\tpriorities[priority] \u003d not priorities.get(priority, False)\n\tself.parent.custom.priorities \u003d priorities\n\t\n\tself.custom.background_on \u003d \"true\" if priorities[priority] else \"false\""
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_3"
},
"position": {
"basis": "120px"
},
"propConfig": {
"props.style.classes": {
"binding": {
"config": {
"expression": "if({this.custom.background_on}\u003d\"false\",0,\r\nif({session.custom.colours.colour_impaired},2,1))"
},
"transforms": [
{
"fallback": "Buttons/PB_1",
"inputType": "scalar",
"mappings": [
{
"input": 0,
"output": ""
},
{
"input": 1,
"output": "Alarms-Styles/Diagnostic"
},
{
"input": 2,
"output": "Alarms-Styles/Alt-Colours/Diagnostic"
}
],
"outputType": "style-list",
"type": "map"
}
],
"type": "expr"
}
}
},
"props": {
"image": {
"icon": {
"path": "material/warning"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "Diagnostic"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "reset-filters",
"pageScope": true,
"script": "\t# implement your handler here\n\tbackground \u003d \"false\"\n\tseverity \u003d payload[\"reset\"]\n\tif severity \u003d\u003d \"false\":\n\t\tbackground \u003d \"false\"\n\telse:\n\t\tbackground \u003d \"true\"\n\tself.custom.background_on \u003d background",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Dropdown"
},
"position": {
"basis": "200px"
},
"propConfig": {
"props.value": {
"persistent": false
}
},
"props": {
"options": [
{
"label": "MCM01",
"value": "MCM01"
},
{
"label": "MCM02",
"value": "MCM02"
},
{
"label": "MCM03",
"value": "MCM03"
},
{
"label": "MCM04",
"value": "MCM04"
},
{
"label": "MCM05",
"value": "MCM05"
}
],
"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": {
"priorities": {
"diagnostic": false,
"high": true,
"low": false,
"medium": true
}
},
"events": {
"system": {
"onStartup": {
"config": {
"script": "\tself.custom.priorities \u003d {\n\t \"diagnostic\": False,\n\t \"low\": False,\n\t \"medium\": True,\n\t \"high\": True,\n\t}"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "FlexContainer"
},
"position": {
"basis": "881px",
"shrink": 0
},
"props": {
"style": {
"padding": 0
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "Label"
},
"position": {
"basis": "20px"
},
"type": "ia.display.label"
},
{
"custom": {
"Severity": "Critical",
"background_on": "false"
},
"events": {
"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\n\tself.parent.parent.getChild(\"FlexContainer\").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"
},
{
"meta": {
"name": "Label_2"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"custom": {
"Severity": "High",
"background_on": "true",
"update_on": false
},
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tfrom datetime import datetime\n\ttry:\n\t # Get table data\n\t data \u003d self.parent.parent.parent.getChild(\"FlexContainer_0\").getChild(\"Table\").props.data\n\t \n\t column_order \u003d [\n\t \"ID\",\n\t \"StartTimestamp\", \n\t \"Duration\",\n\t \"Priority\",\n\t \"Location\",\n\t \"Description\",\n\t \"Tag\"\n\t ]\n\t\n\t # CSV header\n\t csv_content \u003d \",\".join(column_order) + \"\\n\"\n\t \n\t def unwrap(v):\n\t\t\tif hasattr(v, \u0027value\u0027):\n\t\t\t\treturn str(v.value)\n\t \t\n\t\t\treturn v\n\t \n\t if data and len(data) \u003e 0:\n\t for item in data:\n\t row_data \u003d []\n\t \n\t for col in column_order:\n\t # Look for the column in the current item\n\t if col in item:\n\t cell \u003d item[col]\n\t # Extract the value from the nested structure\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t raw_value \u003d cell[\"value\"]\n\t else:\n\t raw_value \u003d cell\n\t else:\n\t raw_value \u003d \"\"\n\t \n\t # Process and clean the value\n\t processed_value \u003d unwrap(raw_value).replace(\",\", \";\")\n\t row_data.append(processed_value)\n\t \n\t csv_content +\u003d \",\".join(row_data) + \"\\n\"\n\t else:\n\t csv_content +\u003d \"No alarms in current view\\n\"\n\t\n\texcept Exception as e:\n\t system.perspective.print(\"Export Error: \" + str(e))\n\t csv_content \u003d \"Export failed\\n\"\n\t\n\tcsv_bytes \u003d csv_content.encode(\"utf-8\")\n\tsystem.perspective.download(\"active_alarms.csv\", csv_bytes) \n\t \n\t \n\t \n\t\n#\t if data and len(data) \u003e 0:\n#\t for row in data:\n#\t val \u003d row.get(\"value\", {})\n#\t row_data \u003d [\n#\t str(val.get(\"NumberID\", \"\")),\n#\t str(val.get(\"EventTimestamp\", \"\")),\n#\t str(val.get(\"Duration\", \"\")),\n#\t str(val.get(\"Priority\", \"\")),\n#\t str(val.get(\"Description\", \"\")),\n#\t str(val.get(\"Tag\", \"\"))\n#\t ]\n#\t\n#\t # Escape commas for CSV safety\n#\t row_data \u003d [field.replace(\",\", \";\") for field in row_data]\n#\t csv_content +\u003d \",\".join(row_data) + \"\\n\"\n#\t else:\n#\t csv_content +\u003d \"No alarms in current view\\n\"\n#\t\n#\texcept Exception as e:\n#\t system.perspective.print(\"Error during CSV export: \" + str(e))\n#\t csv_content \u003d \"Error exporting alarm data\\n\"\n#\t\n#\t# Convert to bytes and trigger download\n#\tcsv_bytes \u003d csv_content.encode(\u0027utf-8\u0027)\n#\tsystem.perspective.download(\"active_alarms.csv\", csv_bytes)\n "
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_1"
},
"position": {
"basis": "120px"
},
"props": {
"image": {
"icon": {
"path": "material/import_export"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "Export"
},
"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",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Label_0"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
},
{
"meta": {
"name": "Label_1"
},
"position": {
"basis": "10px"
},
"type": "ia.display.label"
}
],
"meta": {
"name": "FlexContainer_0"
},
"position": {
"basis": "513px",
"shrink": 0
},
"props": {
"style": {
"padding": 0
}
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "FlexContainer"
},
"position": {
"basis": "70px",
"shrink": 0
},
"props": {
"alignContent": "flex-start",
"style": {
"overflow": "visible"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"custom": {
"query": {
"$": [
"ts",
192,
1759905591388
],
"$ts": 1759905591388
}
},
"events": {
"component": {
"onRowDoubleClick": {
"config": {
"script": "\n\tmyData \u003d self.props.selection.data\n\n\talarms.alarm_click.handleClick(myData)\n\t\n\t"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Table"
},
"position": {
"basis": "972.9px"
},
"propConfig": {
"custom.priorities": {
"binding": {
"config": {
"path": ".../FlexContainer/FlexContainer.custom.priorities"
},
"transforms": [
{
"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"
}
},
"custom.query": {
"onChange": {
"enabled": false,
"script": "\tfrom system import date\n\t\n\tdef class_color(cls):\n\t\tm \u003d {\"Error\":\"#FFE5E5\",\"Warning\":\"#FFF7E0\",\"Message\":\"#EAF4FF\"}\n\t\treturn m.get(cls, \"#FFFFFF\")\n\t\n\tdef mk_row(number_id, start_ts, end_ts, duration_hms, cls, area, desc_, tag_):\n\t\treturn {\n\t\t\t\"value\": {\n\t\t\t\t\"NumberID\": number_id,\n\t\t\t\t\"Start Timestamp\": start_ts,\n\t\t\t\t\"End Timestamp\": end_ts,\n\t\t\t\t\"Duration\": duration_hms,\n\t\t\t\t\"Class\": cls,\n\t\t\t\t\"Area\": area,\n\t\t\t\t\"Description\": desc_,\n\t\t\t\t\"Tag\": tag_\n\t\t\t},\n\t\t\t\"style\": {\"backgroundColor\": class_color(cls), \"classes\": \"some-class\"}\n\t\t}\n\t\n\tds_name \u003d \"MariaDB80\"\n\t\n\t# Time window (java.util.Date)\n\tend_dt \u003d getattr(self.custom, \"endTime\", None) or date.now()\n\tstart_dt \u003d getattr(self.custom, \"startTime\", None) or date.addHours(end_dt, -24)\n\t\n\t# Class filter from DropdownMinClass\n\ttry:\n\t\tmin_choice \u003d self.parent.parent.parent.getChild(\"DropdownMinClass\").props.value\n\texcept:\n\t\tmin_choice \u003d \"Message\"\n\t\n\tif min_choice \u003d\u003d \"Error\":\n\t\tclass_list \u003d [\"Error\"]\n\telif min_choice \u003d\u003d \"Warning\":\n\t\tclass_list \u003d [\"Error\",\"Warning\"]\n\telse:\n\t\tclass_list \u003d [\"Error\",\"Warning\",\"Message\"]\n\t\n\tcls1 \u003d class_list[0] if len(class_list)\u003e0 else None\n\tcls2 \u003d class_list[1] if len(class_list)\u003e1 else None\n\tcls3 \u003d class_list[2] if len(class_list)\u003e2 else None\n\t\n\t# Optional priorities CSV from self.custom.priorities\n\tpriorities_csv \u003d getattr(self.custom, \"priorities\", \"\") or \"\"\n\t\n\tsql \u003d u\"\"\"\n\tSELECT\n\t ae.id AS NumberID,\n\t ae.eventtime AS `Start Timestamp`,\n\t clr.eventtime AS `End Timestamp`,\n\t IFNULL(\n\t SEC_TO_TIME(TIMESTAMPDIFF(SECOND, ae.eventtime, clr.eventtime)),\n\t SEC_TO_TIME(TIMESTAMPDIFF(SECOND, ae.eventtime, NOW()))\n\t ) AS Duration,\n\t cls.strvalue AS Class,\n\t loc.strvalue AS Area,\n\t des.strvalue AS Description,\n\t tag.strvalue AS Tag\n\tFROM alarm_events ae\n\tLEFT JOIN alarm_events clr\n\t ON clr.eventid \u003d ae.eventid AND clr.eventtype \u003d 1\n\tLEFT JOIN alarm_event_data cls\n\t ON cls.id \u003d ae.id AND cls.propname \u003d \u0027Class\u0027\n\tLEFT JOIN alarm_event_data loc\n\t ON loc.id \u003d ae.id AND loc.propname \u003d \u0027Area\u0027\n\tLEFT JOIN alarm_event_data des\n\t ON des.id \u003d ae.id AND des.propname \u003d \u0027Description\u0027\n\tLEFT JOIN alarm_event_data tag\n\t ON tag.id \u003d ae.id AND tag.propname \u003d \u0027Tag\u0027\n\tWHERE\n\t ae.eventtype \u003d 0\n\t AND ae.eventtime BETWEEN ? AND ?\n\t AND (\n\t ( ? IS NOT NULL AND cls.strvalue \u003d ? )\n\t OR ( ? IS NOT NULL AND cls.strvalue \u003d ? )\n\t OR ( ? IS NOT NULL AND cls.strvalue \u003d ? )\n\t )\n\t AND ( ? \u003d \u0027\u0027 OR FIND_IN_SET(CAST(ae.priority AS CHAR), ?) \u003e 0 )\n\tORDER BY ae.eventtime DESC\n\t\"\"\"\n\t\n\t# ORDER MATTERS: must match the ? placeholders above\n\tparams \u003d [\n\t\tstart_dt, end_dt,\n\t\tcls1, cls1,\n\t\tcls2, cls2,\n\t\tcls3, cls3,\n\t\tpriorities_csv, priorities_csv\n\t]\n\t\n\trows \u003d system.db.runPrepQuery(sql, params, ds_name)\n\t\n\tdata \u003d []\n\tfor r in rows:\n\t\ttry:\n\t\t\tstart_s \u003d system.date.format(r[\"Start Timestamp\"], \"yyyy-MM-dd HH:mm:ss\") if r[\"Start Timestamp\"] else \"\"\n\t\t\tend_s \u003d system.date.format(r[\"End Timestamp\"], \"yyyy-MM-dd HH:mm:ss\") if r[\"End Timestamp\"] else \"\"\n\t\t\tdur_s \u003d str(r[\"Duration\"]) if r[\"Duration\"] is not None else \"\"\n\t\t\tdata.append(\n\t\t\t\tmk_row(\n\t\t\t\t\tnumber_id \u003d int(r[\"NumberID\"]) + 30000,\n\t\t\t\t\tstart_ts \u003d start_s,\n\t\t\t\t\tend_ts \u003d end_s,\n\t\t\t\t\tduration_hms\u003d dur_s,\n\t\t\t\t\tcls \u003d r[\"Class\"] or \"\",\n\t\t\t\t\tarea \u003d r[\"Area\"] or \"\",\n\t\t\t\t\tdesc_ \u003d r[\"Description\"] or \"\",\n\t\t\t\t\ttag_ \u003d r[\"Tag\"] or \"\"\n\t\t\t\t)\n\t\t\t)\n\t\texcept Exception as ex:\n\t\t\tsystem.perspective.print(\"Row shape error: %s\" % ex)\n\t\n\tself.props.data \u003d data"
}
},
"props.columns[3].filter.string.value": {
"binding": {
"config": {
"path": ".../FlexContainer/FlexContainer/Dropdown.props.value"
},
"type": "property"
}
},
"props.data": {
"binding": {
"config": {
"parameters": {
"priorityList": "{this.custom.priorities}"
},
"polling": {
"enabled": true,
"rate": "3"
},
"queryPath": "GetActiveAlarms"
},
"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\": \"SMC\" if col \u003d\u003d \"Location\" and row[col] \u003d\u003d \"Chute\" else row[col],\n\t\t\t\t\"style\": { \"classes\": className }\n\t\t\t\t\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"
}
],
"type": "query"
}
}
},
"props": {
"columns": [
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "ID",
"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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY HH:mm:ss",
"editable": false,
"field": "StartTimestamp",
"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": "Event Timestamp"
},
"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": 70
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Duration",
"filter": {
"boolean": {
"condition": ""
},
"date": {
"condition": "",
"value": ""
},
"enabled": true,
"number": {
"condition": "",
"value": ""
},
"string": {
"condition": "equals",
"value": ""
},
"visible": "never"
},
"footer": {
"align": "center",
"justify": "left",
"style": {
"classes": ""
},
"title": ""
},
"header": {
"align": "center",
"justify": "center",
"style": {
"classes": ""
},
"title": "Duration"
},
"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": "string",
"resizable": true,
"sort": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"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",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Priority",
"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": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 70
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Description",
"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": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 150
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "FullTag",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Device",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"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": ""
}
],
"emptyMessage": {
"noData": {
"text": "No Active Alarms"
},
"noFilterResults": {
"text": "No Active Alarms"
}
},
"filter": {
"enabled": true,
"results": {
"enabled": true
}
},
"pager": {
"activeOption": 100
}
},
"type": "ia.display.table"
}
],
"meta": {
"name": "FlexContainer_0"
},
"position": {
"basis": "980px",
"grow": 1
},
"props": {
"direction": "column"
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "Active_tab"
},
"props": {
"direction": "column",
"justify": "space-evenly"
},
"type": "ia.container.flex"
},
{
"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,
1760443389071
],
"$ts": 1760443389070
},
"startDate": {
"$": [
"ts",
192,
1760443389071
],
"$ts": 1760441589070
}
},
"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:3007: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:3013: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:00now (if before 13:00, use 13:00 yesterdaynow)\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:3023: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": "\tmessaging.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": "\tmessaging.message_handler.set_time_from_filters(self)"
}
}
},
"props": {
"formattedValue": "Oct 14, 2025 3:33 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": "\tmessaging.message_handler.set_time_to_filters(self)"
},
"persistent": true
}
},
"props": {
"formattedValue": "Oct 14, 2025 4:03 PM",
"style": {
"margin": 15
},
"value": {
"$": [
"ts",
192,
1760443389071
],
"$ts": 1760443389070
}
},
"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": "All",
"value": ""
},
{
"label": "MCM01",
"value": "MCM01"
},
{
"label": "MCM02",
"value": "MCM02"
},
{
"label": "MCM03",
"value": "MCM03"
},
{
"label": "MCM04",
"value": "MCM04"
},
{
"label": "MCM05",
"value": "MCM05"
},
{
"label": "SMC",
"value": "SMC"
}
],
"placeholder": {
"text": "Filter MCMs..."
},
"style": {
"margin": 15
}
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "hjsgdfn",
"pageScope": false,
"script": "\t#hi\n\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": {
"onActionPerformed": {
"config": {
"script": "\tfrom datetime import datetime\n\t\n\ttry:\n\t data \u003d self.parent.parent.getChild(\"FlexContainer_0\").getChild(\"AlarmsTable\").props.data\n\t\n\t column_order \u003d [\n\t \"FirstTimestamp\",\n\t \"LastTimestamp\", \n\t \"Count\",\n\t \"Duration\",\n\t \"Priority\",\n\t \"Location\",\n\t \"Description\",\n\t \"Tag\"\n\t ]\n\t\n\t csv_content \u003d \",\".join(column_order) + \"\\n\"\n\t \t\n\t def unwrap(v):\n\t\t\tif hasattr(v, \u0027value\u0027):\n\t\t\t\treturn str(v.value)\n\t \t\n\t\t\treturn v\n\t \t\n\t if data and len(data) \u003e 0:\n\t for item in data:\n\t row_data \u003d []\n\t \n\t for col in column_order:\n\t # Look for the column in the current item\n\t if col in item:\n\t cell \u003d item[col]\n\t # Extract the value from the nested structure\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t raw_value \u003d cell[\"value\"]\n\t else:\n\t raw_value \u003d cell\n\t else:\n\t raw_value \u003d \"\"\n\t \n\t # Process and clean the value\n\t processed_value \u003d unwrap(raw_value).replace(\",\", \";\")\n\t row_data.append(processed_value)\n\t \n\t csv_content +\u003d \",\".join(row_data) + \"\\n\"\n\t else:\n\t csv_content +\u003d \"No alarms in current view\\n\"\n\t\n\texcept Exception as e:\n\t system.perspective.print(\"Export Error: \" + str(e))\n\t csv_content \u003d \"Export failed\\n\"\n\t\n\tcsv_bytes \u003d csv_content.encode(\"utf-8\")\n\tsystem.perspective.download(\"active_alarms.csv\", csv_bytes)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Button_1"
},
"position": {
"basis": "120px"
},
"props": {
"image": {
"icon": {
"path": "material/import_export"
}
},
"primary": false,
"style": {
"margin": 15
},
"text": "Export"
},
"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",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.input.button"
}
],
"meta": {
"name": "FlexContainer"
},
"position": {
"basis": "70px"
},
"props": {
"alignContent": "flex-start",
"style": {
"overflow": "visible"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"events": {
"component": {
"onRowDoubleClick": {
"config": {
"script": "\t\n\tmyData \u003d self.props.selection.data\n\n\talarms.alarm_click.handleClick(myData)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "AlarmsTable"
},
"position": {
"basis": "1080px",
"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": "10"
},
"queryPath": "GetAlarmsWithCount"
},
"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\t\n\t\trow_dict \u003d {\n\t\t\tcol: {\n\t\t\t\t\"value\": \"SMC\" if col \u003d\u003d \"Location\" and row[col] \u003d\u003d \"Chute\" else row[col],\n\t\t\t\t\"style\": { \"classes\": className }\n\t\t\t\t\n\t\t\t} for col in column_names\n\t\t}\n\t\tdata.append(row_dict)\n\n\treturn data\n",
"type": "script"
}
],
"type": "query"
}
},
"props.editingCell": {
"onChange": {
"enabled": null,
"script": "\tall_alarms \u003d system.alarm.queryStatus(includeShelved\u003dTrue)\n\tshelved_alarms \u003d [alarm for alarm in all_alarms if alarm.isShelved()]\n\t\n\t# Build dataset for table\n\theaders \u003d [\u0027ID\u0027, \u0027StartTimestamp\u0027, \u0027EndTimestamp\u0027, \u0027Duration\u0027, \u0027Description\u0027, \u0027Priority\u0027, \u0027Tag\u0027, \u0027MCM\u0027]\n\tdata \u003d []\n\t\n\tfor alarm in shelved_alarms:\n\t # Calculate duration (time since shelved)\n\t if alarm.activeTime:\n\t duration_ms \u003d system.date.now().getTime() - alarm.activeTime.getTime()\n\t duration_seconds \u003d duration_ms / 1000\n\t hours \u003d int(duration_seconds / 3600)\n\t minutes \u003d int((duration_seconds % 3600) / 60)\n\t seconds \u003d int(duration_seconds % 60)\n\t duration \u003d \"%02d:%02d:%02d\" % (hours, minutes, seconds)\n\t else:\n\t duration \u003d \"00:00:00\"\n\t \n\t # Extract tag name from source\n\t tag_name \u003d alarm.source.split(\u0027/\u0027)[-1] if \u0027/\u0027 in alarm.source else alarm.source\n\t \n\t row \u003d [\n\t str(alarm.id) if hasattr(alarm, \u0027id\u0027) else \u0027\u0027,\n\t alarm.activeTime if alarm.activeTime else system.date.now(),\n\t None, # End timestamp (shelved alarms don\u0027t have end time yet)\n\t duration,\n\t alarm.displayPath if alarm.displayPath else alarm.source,\n\t alarm.priority.name if alarm.priority else \u0027Unknown\u0027,\n\t tag_name,\n\t \u0027System\u0027 # Adjust based on your source format\n\t ]\n\t data.append(row)\n\t\n\t# Create dataset and update the custom property\n\tdataset \u003d system.dataset.toDataSet(headers, data)\n\tself.custom.shelvedAlarmsData \u003d dataset"
}
},
"props.selection": {
"persistent": true
}
},
"props": {
"columns": [
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY HH:mm:ss",
"editable": false,
"field": "FirstTimestamp",
"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": {
"backgroundColor": "#FFFEFE",
"classes": ""
},
"title": "First Timestamp"
},
"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": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": ""
},
{
"align": "center",
"boolean": "value",
"dateFormat": "MM-DD-YYYY HH:mm:ss",
"editable": false,
"field": "LastTimestamp",
"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": "Last Timestamp"
},
"justify": "center",
"nullFormat": {
"includeNullStrings": false,
"nullFormatValue": "",
"strict": false
},
"number": "value",
"numberFormat": "none",
"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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM-DD-YYYY HH:mm:ss",
"editable": false,
"field": "Count",
"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": "Count"
},
"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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "none",
"editable": false,
"field": "Duration",
"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": "Duration"
},
"justify": "center",
"nullFormat": {
"includeNullStrings": false,
"nullFormatValue": "",
"strict": false
},
"number": "value",
"numberFormat": "none",
"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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Priority",
"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": ""
},
{
"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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Description",
"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": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"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": "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": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "FullTag",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Device",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": ""
}
],
"emptyMessage": {
"noData": {
"text": "No Alarms"
},
"noFilterResults": {
"text": "No Alarms"
}
},
"filter": {
"enabled": true,
"results": {
"enabled": true
}
},
"pager": {
"activeOption": 100
}
},
"type": "ia.display.table"
}
],
"meta": {
"name": "FlexContainer_0"
},
"position": {
"basis": "500px",
"grow": 1
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "Hit_List"
},
"position": {
"tabIndex": 1
},
"props": {
"direction": "column",
"justify": "space-evenly"
},
"type": "ia.container.flex"
},
{
"children": [
{
"children": [
{
"children": [
{
"custom": {
"SetFilter": true
},
"events": {
"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\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"
}
}
},
"meta": {
"name": "Button",
"tooltip": {
"enabled": true,
"style": {
"background-color": "white",
"borderColor": "#000000",
"borderStyle": "solid",
"borderWidth": "1px",
"box-shadow": "5px 5px 5px grey",
"color": "#000000",
"fontFamily": "Arial",
"fontWeight": "normal"
},
"text": "Show Filters"
}
},
"position": {
"basis": "120px"
},
"props": {
"image": {
"icon": {
"path": "material/filter_alt"
},
"position": "center"
},
"primary": false,
"style": {
"margin": 15,
"marginLeft": 20
},
"text": ""
},
"type": "ia.input.button"
},
{
"meta": {
"name": "Label"
},
"position": {
"basis": "281px"
},
"props": {
"style": {
"color": "#FF0000",
"margin-left": "20px"
},
"text": "ALL TIMESTAMPS ARE IN UTC"
},
"type": "ia.display.label"
}
],
"meta": {
"name": "Show filters"
},
"position": {
"basis": "70px",
"shrink": 0
},
"type": "ia.container.flex"
},
{
"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,
1760443389071
],
"$ts": 1760443389070
},
"startDate": {
"$": [
"ts",
192,
1760443389071
],
"$ts": 1760441589070
}
},
"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:3007: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:3013: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:00now (if before 13:00, use 13:00 yesterdaynow)\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:3023: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": {
"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": "\tmessaging.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"
},
"props.value": {
"binding": {
"config": {
"path": "../Dropdown.custom.startDate"
},
"type": "property"
},
"onChange": {
"enabled": null,
"script": "\tmessaging.message_handler.set_time_from_filters(self)\n\t\t\n\tif system.date.secondsBetween(self.props.value,self.getSibling(\"DateTimeInput_0\").props.value) \u003e 604800:\n\t\tself.getSibling(\"DateTimeInput_0\").props.value \u003d system.date.addSeconds(self.props.value,604800)"
}
}
},
"props": {
"formattedValue": "Oct 13, 2025 8:38 PM",
"minDate": {
"$": [
"ts",
192,
1759755629641
],
"$ts": 1728219629641
},
"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": "if(dateDiff({../DateTimeInput.props.value},now(),\"day\") \u003c 7, now(),dateArithmetic({../DateTimeInput.props.value}, 7, \"days\"))"
},
"type": "expr"
}
},
"props.minDate": {
"binding": {
"config": {
"expression": "{../DateTimeInput.props.value}"
},
"type": "expr"
}
},
"props.value": {
"binding": {
"config": {
"path": "../Dropdown.custom.endDate"
},
"type": "property"
},
"onChange": {
"enabled": null,
"script": "\tmessaging.message_handler.set_time_to_filters(self)"
},
"persistent": true
}
},
"props": {
"formattedValue": "Oct 13, 2025 9:08 PM",
"style": {
"margin": 15
},
"value": {
"$": [
"ts",
192,
1760443389071
],
"$ts": 1760443389070
}
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "reset-historical-filters",
"pageScope": true,
"script": "#\tsystem.perspective.print(payload)\n#\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": "70px",
"shrink": 0
},
"type": "ia.container.flex"
},
{
"children": [
{
"meta": {
"name": "Label"
},
"position": {
"basis": "100px"
},
"props": {
"style": {
"fontFamily": "Arial",
"fontWeight": "bold",
"textAlign": "center"
},
"text": "Priority"
},
"type": "ia.display.label"
},
{
"events": {
"component": {
"onActionPerformed": {
"config": {
"script": "\tmessaging.message_handler.set_priority_filters(self)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Dropdown"
},
"position": {
"basis": "490px"
},
"propConfig": {
"props.value": {
"persistent": false
}
},
"props": {
"options": [
{
"label": "All",
"value": ""
},
{
"label": "Diagnostic",
"value": "diagnostic"
},
{
"label": "Low",
"value": "low"
},
{
"label": "Medium",
"value": "medium"
},
{
"label": "High",
"value": "high"
}
],
"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_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": "All",
"value": ""
},
{
"label": "MCM01",
"value": "MCM01"
},
{
"label": "MCM02",
"value": "MCM02"
},
{
"label": "MCM03",
"value": "MCM03"
},
{
"label": "MCM04",
"value": "MCM04"
},
{
"label": "MCM05",
"value": "MCM05"
},
{
"label": "SMC",
"value": "SMC"
}
],
"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"
}
],
"meta": {
"name": "Priority"
},
"position": {
"basis": "70px",
"shrink": 0
},
"type": "ia.container.flex"
}
],
"custom": {
"ShowFilters": true
},
"meta": {
"name": "Filters"
},
"position": {
"basis": "180px",
"grow": 1,
"shrink": 0
},
"propConfig": {
"position.display": {
"binding": {
"config": {
"path": "this.custom.ShowFilters"
},
"type": "property"
},
"persistent": true
}
},
"props": {
"direction": "column",
"style": {
"borderStyle": "solid",
"borderWidth": "1px",
"box-shadow": "0 4px 20px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)",
"marginBottom": 10,
"marginLeft": 20,
"marginRight": 20,
"marginTop": 10
}
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "show-historical-filters",
"pageScope": true,
"script": "\tshow \u003d payload[\"data\"]\n\tself.custom.ShowFilters \u003d show",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.container.flex"
},
{
"children": [
{
"custom": {
"amount": 0,
"device_filters": null,
"duration_filter": null,
"hasNext": true,
"hit_limit": false,
"loading": false,
"max_duration": {
"$": [
"ts",
192,
1748426336635
],
"$ts": 1747562336635
},
"page_size": 100,
"record_count": 0,
"source_id_filters": null,
"type_filters": null
},
"events": {
"component": {
"onRowDoubleClick": {
"config": {
"script": "\t\n\tmyData \u003d self.props.selection.data\n\n\talarms.alarm_click.handleClick(myData)"
},
"scope": "G",
"type": "script"
}
}
},
"meta": {
"name": "Table"
},
"position": {
"basis": "1920px",
"grow": 1
},
"propConfig": {
"custom.priority_filters": {
"binding": {
"config": {
"path": ".../Filters/Priority/Dropdown.props.value"
},
"transforms": [
{
"expression": "coalesce({value},\u0027\u0027)",
"type": "expression"
}
],
"type": "property"
}
},
"custom.time_from_filter": {
"binding": {
"config": {
"path": ".../Filters/Time/DateTimeInput.props.value"
},
"type": "property"
}
},
"custom.time_to_filter": {
"binding": {
"config": {
"path": ".../Filters/Time/DateTimeInput_0.props.value"
},
"type": "property"
}
},
"props.columns[1].filter.date.value": {
"binding": {
"config": {
"path": "this.custom.time_from_filter"
},
"transforms": [
{
"expression": "coalesce({value}, dateArithmetic(now(), -30, \"minute\"))",
"type": "expression"
}
],
"type": "property"
}
},
"props.columns[2].filter.date.value": {
"binding": {
"config": {
"path": "this.custom.time_to_filter"
},
"transforms": [
{
"expression": "coalesce({value},NOW())",
"type": "expression"
}
],
"type": "property"
}
},
"props.columns[2].filter.number.value": {
"binding": {
"config": {
"path": "this.custom.time_to_filter"
},
"enabled": false,
"type": "property"
}
},
"props.columns[5].filter.string.value": {
"binding": {
"config": {
"path": "this.custom.priority_filters"
},
"transforms": [
{
"expression": "coalesce({value},\"\")",
"type": "expression"
}
],
"type": "property"
}
},
"props.columns[6].filter.string.value": {
"binding": {
"config": {
"path": ".../Filters/Priority/Dropdown_0.props.value"
},
"type": "property"
}
},
"props.data": {
"binding": {
"config": {
"parameters": {
"TabIndex": "{....../TabContainer.props.currentTabIndex}",
"endtime": "{this.custom.time_to_filter}",
"starttime": "{this.custom.time_from_filter}"
},
"polling": {
"enabled": true,
"rate": "10"
},
"queryPath": "GetAlarms"
},
"transforms": [
{
"code": "\t# Transform (script)\n\tfrom system.dataset import toPyDataSet\n\t\n\t# Handle null/empty input\n\tds \u003d toPyDataSet(value) if value is not None else None\n#\tif not ds:\n#\t self.custom.loading \u003d False\n#\t self.custom.record_count \u003d 0\n#\t self.custom.hit_limit \u003d False\n#\t return []\n\t\n\t# Priority to style class mapping\n\tPRIORITY_STYLES \u003d {\n\t \"High\": \"Alarms-Styles/High\",\n\t \"Medium\": \"Alarms-Styles/Medium\",\n\t \"Low\": \"Alarms-Styles/Low\",\n\t \"Diagnostic\": \"Alarms-Styles/Diagnostic\",\n\t \"Critical\": \"Alarms-Styles/Critical\"\n\t}\n\tDEFAULT_STYLE \u003d \"Alarms-Styles/NoAlarm\"\n\t\n\t\n\tcols \u003d list(ds.columnNames)\n\tdata \u003d []\n\t\n\tfor row in ds:\n\t # Get priority and map to style class\n\t priority \u003d row.get(\"Priority\", None) if hasattr(row, \"get\") else row[\"Priority\"]\n\t className \u003d PRIORITY_STYLES.get(priority, DEFAULT_STYLE)\n\t \n\t # Build row with transformations\n\t row_dict \u003d {}\n\t for col in cols:\n\t cell_value \u003d row[col]\n\t \n\t # Transform Location: Chute -\u003e SMC\n\t if col \u003d\u003d \"Location\" and cell_value \u003d\u003d \"Chute\":\n\t cell_value \u003d \"SMC\"\n\t \n\t row_dict[col] \u003d {\n\t \"value\": cell_value,\n\t \"style\": {\"classes\": className}\n\t }\n\t \n\t data.append(row_dict)\n\t\n\t# Update component state\n\tself.custom.loading \u003d False\n\tself.custom.record_count \u003d len(data)\n\tself.custom.hit_limit \u003d False\n\t\n\treturn data",
"type": "script"
}
],
"type": "query"
}
}
},
"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": [
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "none",
"editable": false,
"field": "ID",
"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": "",
"paddingLeft": 12
},
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY HH:mm:ss",
"editable": false,
"field": "StartTimestamp",
"filter": {
"boolean": {
"condition": ""
},
"date": {
"condition": "later than date time"
},
"enabled": true,
"number": {
"condition": "",
"value": ""
},
"string": {
"condition": "",
"value": ""
},
"visible": "never"
},
"footer": {
"align": "center",
"justify": "left",
"style": {
"classes": ""
},
"title": ""
},
"header": {
"align": "center",
"justify": "center",
"style": {
"classes": ""
},
"title": "Start Timestamp"
},
"justify": "center",
"nullFormat": {
"includeNullStrings": false,
"nullFormatValue": "",
"strict": false
},
"number": "value",
"numberFormat": "none",
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY HH:mm:ss",
"editable": false,
"field": "EndTimestamp",
"filter": {
"boolean": {
"condition": ""
},
"date": {
"condition": "earlier than date time"
},
"enabled": true,
"number": {
"condition": "",
"value": ""
},
"string": {
"condition": "",
"value": ""
},
"visible": "never"
},
"footer": {
"align": "center",
"justify": "left",
"style": {
"classes": ""
},
"title": ""
},
"header": {
"align": "center",
"justify": "center",
"style": {
"classes": ""
},
"title": "End Timestamp"
},
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "none",
"editable": false,
"field": "Duration",
"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": "",
"paddingLeft": 12
},
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "none",
"editable": false,
"field": "Description",
"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": "none",
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Priority",
"filter": {
"boolean": {
"condition": ""
},
"date": {
"condition": "",
"value": ""
},
"enabled": true,
"number": {
"condition": "",
"value": ""
},
"string": {
"condition": "contains"
},
"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": 50
},
{
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Tag",
"filter": {
"boolean": {
"condition": ""
},
"date": {
"condition": "",
"value": ""
},
"enabled": true,
"number": {
"condition": "",
"value": ""
},
"string": {
"condition": "contains",
"value": ""
},
"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": 50
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "FullTag",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": ""
},
{
"align": "center",
"boolean": "checkbox",
"dateFormat": "MM/DD/YYYY",
"editable": false,
"field": "Device",
"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": "",
"display": "none"
},
"toggleSwitch": {
"color": {
"selected": "",
"unselected": ""
}
},
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 300
}
],
"emptyMessage": {
"noData": {
"text": "No Alarms"
},
"noFilterResults": {
"text": "No Alarms"
}
},
"enabled": true,
"filter": {
"enabled": true,
"results": {
"enabled": true
}
},
"pager": {
"activeOption": 100
},
"style": {
"margin": 20
},
"total": "value"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "update-first-request",
"pageScope": true,
"script": "\tdata \u003d payload[\"data\"]\n\tinitial_data \u003d payload[\"initial_data\"]\n\tself.props.data \u003d data\n\tself.custom.initial_data \u003d initial_data",
"sessionScope": false,
"viewScope": false
},
{
"messageType": "update-historical-data",
"pageScope": true,
"script": "\thistorical_data \u003d payload[\"data\"]\n\tself.props.data \u003d historical_data",
"sessionScope": false,
"viewScope": false
},
{
"messageType": "load_initial_data",
"pageScope": true,
"script": "\trequest \u003d payload[\"data\"]\n\tsystem.perspective.print(\"initial message received\")\n\tif request \u003d\u003d True:\n\t\tself.props.data \u003d self.custom.initial_data",
"sessionScope": false,
"viewScope": false
},
{
"messageType": "reset-historical-filters",
"pageScope": true,
"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
},
{
"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-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": "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
},
{
"messageType": "refreshHistoricalTable",
"pageScope": true,
"script": "\tself.refreshBinding(\"props.data\")",
"sessionScope": false,
"viewScope": true
}
]
},
"type": "ia.display.table"
}
],
"meta": {
"name": "Table"
},
"position": {
"basis": "980px",
"grow": 1
},
"props": {
"direction": "column"
},
"scripts": {
"customMethods": [],
"extensionFunctions": null,
"messageHandlers": [
{
"messageType": "update-historical-data",
"pageScope": true,
"script": "#\tdata \u003d payload[\"data\"]\n#\tself.getChild(\"Table\").props.data \u003d data\n\tpass",
"sessionScope": false,
"viewScope": false
}
]
},
"type": "ia.container.flex"
},
{
"children": [
{
"children": [
{
"custom": {
"download_in_progress": true,
"enable_timeout": false,
"priority_filters": "medium",
"time_from_filter": {
"$": [
"ts",
192,
1759316536954
],
"$ts": 1756755000000
},
"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\tfrom datetime import datetime\n\t\n\ttry:\n\t # Get the table data - try filtered first, then fall back to all data\n\t root \u003d self.parent.parent.parent\n\t table \u003d root.getChild(\"Table\").getChild(\"Table\")\n\t \n\t # Try to get filtered data first, otherwise use all data\n\t data \u003d None\n\t try:\n\t # Check if filtered data exists and has content\n\t filtered_data \u003d table.props.filter.results.data\n\t if filtered_data and len(filtered_data) \u003e 0:\n\t data \u003d filtered_data\n\t system.perspective.print(\"Using filtered data: %d records\" % len(data))\n\t except:\n\t pass\n\t \n\t # Fall back to all data if no filtered data\n\t if not data:\n\t data \u003d table.props.data\n\t system.perspective.print(\"Using all data: %d records\" % len(data))\n\t \n\t # Apply sorting if sortOrder exists\n\t try:\n\t sort_order \u003d table.props.sortOrder\n\t if sort_order and len(sort_order) \u003e 0:\n\t system.perspective.print(\"Applying sort: \" + str(sort_order))\n\t \n\t # Ignition table sortOrder is typically a list of objects with \u0027field\u0027 and \u0027direction\u0027\n\t for sort_item in reversed(sort_order): # Apply in reverse for multiple sorts\n\t field \u003d None\n\t direction \u003d \u0027asc\u0027\n\t \n\t # Try different ways to access the sort configuration\n\t if hasattr(sort_item, \u0027field\u0027):\n\t field \u003d sort_item.field\n\t direction \u003d getattr(sort_item, \u0027direction\u0027, \u0027asc\u0027)\n\t elif hasattr(sort_item, \u0027column\u0027):\n\t field \u003d sort_item.column \n\t direction \u003d getattr(sort_item, \u0027direction\u0027, \u0027asc\u0027)\n\t elif isinstance(sort_item, dict):\n\t field \u003d sort_item.get(\u0027field\u0027) or sort_item.get(\u0027column\u0027)\n\t direction \u003d sort_item.get(\u0027direction\u0027, \u0027asc\u0027)\n\t \n\t if field:\n\t def get_sort_value(item):\n\t if field in item:\n\t cell \u003d item[field]\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t val \u003d cell[\"value\"]\n\t else:\n\t val \u003d cell\n\t \n\t # Handle None values\n\t if val is None:\n\t return \"\"\n\t elif hasattr(val, \u0027value\u0027):\n\t return val.value\n\t else:\n\t return val\n\t return \"\"\n\t \n\t reverse_sort \u003d (str(direction).lower() \u003d\u003d \u0027desc\u0027)\n\t data \u003d sorted(data, key\u003dget_sort_value, reverse\u003dreverse_sort)\n\t system.perspective.print(\"Sorted by %s (%s)\" % (field, direction))\n\t except Exception as e:\n\t system.perspective.print(\"Sort error: \" + str(e))\n\t\n\t column_order \u003d [\n\t \"ID\",\n\t \"StartTimestamp\",\n\t \"EndTimestamp\", \n\t \"Duration\",\n\t \"Description\",\n\t \"Priority\",\n\t \"Location\",\n\t \"Tag\",\n\t \"FullTag\",\n\t \"Device\"\n\t ]\n\t\n\t csv_content \u003d \",\".join(column_order) + \"\\n\"\n\t \t\n\t def unwrap(v):\n\t if hasattr(v, \u0027value\u0027):\n\t return str(v.value)\n\t return str(v) if v is not None else \"\"\n\t \t\n\t if data and len(data) \u003e 0:\n\t for item in data:\n\t row_data \u003d []\n\t \n\t for col in column_order:\n\t # Look for the column in the current item\n\t if col in item:\n\t cell \u003d item[col]\n\t # Extract the value from the nested structure\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t raw_value \u003d cell[\"value\"]\n\t else:\n\t raw_value \u003d cell\n\t else:\n\t raw_value \u003d \"\"\n\t \n\t # Process and clean the value\n\t processed_value \u003d unwrap(raw_value).replace(\",\", \";\").replace(\"\\r\", \" \").replace(\"\\n\", \" \")\n\t row_data.append(processed_value)\n\t \n\t csv_content +\u003d \",\".join(row_data) + \"\\n\"\n\t else:\n\t csv_content +\u003d \"No alarms in current view\\n\"\n\t\n\t csv_bytes \u003d csv_content.encode(\"utf-8\")\n\t system.perspective.download(\"historical_alarms.csv\", csv_bytes)\n\t system.perspective.print(\"Historical export: CSV download started\")\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"
}
],
"meta": {
"name": "FlexContainer"
},
"position": {
"basis": "960px"
},
"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"
}
}
},
"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"
}
},
"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"
}
}
},
"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"
}
},
"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"
}
},
"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
},
"primary": false,
"text": "Next"
},
"type": "ia.input.button"
}
],
"meta": {
"name": "FlexContainer_0"
},
"position": {
"basis": 960
},
"props": {
"justify": "space-evenly"
},
"type": "ia.container.flex"
},
{
"meta": {
"name": "FlexContainer_1"
},
"position": {
"basis": 960
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "Paginate"
},
"position": {
"basis": "70px",
"shrink": 0
},
"props": {
"justify": "space-evenly",
"style": {
"display": "none"
}
},
"type": "ia.container.flex"
},
{
"children": [
{
"custom": {
"download_in_progress": true,
"enable_timeout": false,
"priority_filters": "medium",
"time_from_filter": {
"$": [
"ts",
192,
1759316536954
],
"$ts": 1756755000000
},
"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\tfrom datetime import datetime\n\t\n\ttry:\n\t # Get the table data - try filtered first, then fall back to all data\n\t # Navigate up the component hierarchy to find the table\n\t current \u003d self\n\t table \u003d None\n\t \n\t # Try different navigation paths to find the table\n\t try:\n\t # Method 1: Try the original path\n\t root \u003d self.parent.parent.parent\n\t table \u003d root.getChild(\"Table\").getChild(\"Table\")\n\t except:\n\t try:\n\t # Method 2: Try going up more levels\n\t root \u003d self.parent.parent.parent.parent\n\t table \u003d root.getChild(\"Table\").getChild(\"Table\")\n\t except:\n\t try:\n\t # Method 3: Try finding by component name search\n\t current \u003d self.parent\n\t while current and not hasattr(current, \u0027meta\u0027) or current.meta.name !\u003d \u0027Historical_tab\u0027:\n\t current \u003d current.parent\n\t if current:\n\t table \u003d current.getChild(\"root\").getChild(\"Table\").getChild(\"Table\")\n\t except:\n\t pass\n\t \n\t if not table:\n\t raise Exception(\"Could not find table component\")\n\t \n\t # Try to get filtered data first, otherwise use all data\n\t data \u003d None\n\t try:\n\t # Check if filtered data exists and has content\n\t filtered_data \u003d table.props.filter.results.data\n\t if filtered_data and len(filtered_data) \u003e 0:\n\t data \u003d filtered_data\n\t system.perspective.print(\"Using filtered data: %d records\" % len(data))\n\t except:\n\t pass\n\t \n\t # Fall back to all data if no filtered data\n\t if not data:\n\t data \u003d table.props.data\n\t system.perspective.print(\"Using all data: %d records\" % len(data))\n\t \n\t # Apply sorting if sortOrder exists\n\t try:\n\t sort_order \u003d table.props.sortOrder\n\t if sort_order and len(sort_order) \u003e 0:\n\t system.perspective.print(\"Applying sort: \" + str(sort_order))\n\t \n\t # Sort the data based on the sort order\n\t for sort_config in reversed(sort_order): # Apply in reverse for multiple sorts\n\t field \u003d None\n\t direction \u003d \u0027asc\u0027\n\t \n\t # Try different ways to get field and direction\n\t if isinstance(sort_config, dict):\n\t field \u003d sort_config.get(\u0027field\u0027) or sort_config.get(\u0027column\u0027)\n\t direction \u003d sort_config.get(\u0027direction\u0027, \u0027asc\u0027)\n\t elif hasattr(sort_config, \u0027field\u0027):\n\t field \u003d sort_config.field\n\t direction \u003d getattr(sort_config, \u0027direction\u0027, \u0027asc\u0027)\n\t elif hasattr(sort_config, \u0027column\u0027):\n\t field \u003d sort_config.column\n\t direction \u003d getattr(sort_config, \u0027direction\u0027, \u0027asc\u0027)\n\t \n\t if field:\n\t def get_sort_value(item):\n\t if field in item:\n\t cell \u003d item[field]\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t val \u003d cell[\"value\"]\n\t else:\n\t val \u003d cell\n\t \n\t # Handle None values\n\t if val is None:\n\t return \"\"\n\t elif hasattr(val, \u0027value\u0027):\n\t return val.value\n\t else:\n\t return val\n\t return \"\"\n\t \n\t reverse_sort \u003d (str(direction).lower() \u003d\u003d \u0027desc\u0027)\n\t data \u003d sorted(data, key\u003dget_sort_value, reverse\u003dreverse_sort)\n\t system.perspective.print(\"Sorted by %s (%s)\" % (field, direction))\n\t except Exception as e:\n\t system.perspective.print(\"Sort error: \" + str(e))\n\t\n\t column_order \u003d [\n\t \"ID\",\n\t \"StartTimestamp\",\n\t \"EndTimestamp\", \n\t \"Duration\",\n\t \"Description\",\n\t \"Priority\",\n\t \"Location\",\n\t \"Tag\",\n\t \"FullTag\",\n\t \"Device\"\n\t ]\n\t\n\t csv_content \u003d \",\".join(column_order) + \"\\n\"\n\t \t\n\t def unwrap(v):\n\t if hasattr(v, \u0027value\u0027):\n\t return str(v.value)\n\t return str(v) if v is not None else \"\"\n\t \t\n\t if data and len(data) \u003e 0:\n\t for item in data:\n\t row_data \u003d []\n\t \n\t for col in column_order:\n\t # Look for the column in the current item\n\t if col in item:\n\t cell \u003d item[col]\n\t # Extract the value from the nested structure\n\t if isinstance(cell, dict) and \"value\" in cell:\n\t raw_value \u003d cell[\"value\"]\n\t else:\n\t raw_value \u003d cell\n\t else:\n\t raw_value \u003d \"\"\n\t \n\t # Process and clean the value\n\t processed_value \u003d unwrap(raw_value).replace(\",\", \";\").replace(\"\\r\", \" \").replace(\"\\n\", \" \")\n\t row_data.append(processed_value)\n\t \n\t csv_content +\u003d \",\".join(row_data) + \"\\n\"\n\t else:\n\t csv_content +\u003d \"No alarms in current view\\n\"\n\t\n\t csv_bytes \u003d csv_content.encode(\"utf-8\")\n\t system.perspective.download(\"historical_alarms.csv\", csv_bytes)\n\t system.perspective.print(\"Historical export: CSV download started\")\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": "FlexContainer"
},
"position": {
"basis": 100
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "root"
},
"props": {
"direction": "column",
"style": {
"classes": "Background-Styles/Grey-Background"
}
},
"type": "ia.container.flex"
}
],
"meta": {
"name": "Historical_tab"
},
"position": {
"tabIndex": 2
},
"props": {
"direction": "column",
"justify": "space-evenly"
},
"type": "ia.container.flex"
}
],
"custom": {
"shelvedAlarms": []
},
"meta": {
"name": "TabContainer"
},
"position": {
"basis": "300px",
"grow": 1
},
"propConfig": {
"props.currentTabIndex": {
"onChange": {
"enabled": null,
"script": "\tlogger \u003d system.util.getLogger(\"DropdownTimeChange\")\n\n\ttry:\n\t\tif currentValue is None or currentValue.value is None:\n\t\t\tlogger.info(\"No currentValue, exiting.\")\n\t\t\treturn\n\n\t\tval_num \u003d int(currentValue.value)\n\t\tlogger.info(\"Tab index changed to: %d\" % val_num)\n\n\t\t# Get dropdown for each tab\n\t\tif val_num \u003d\u003d 1:\n\t\t\tdd \u003d self.getChild(\"Hit_List\").getChild(\"FlexContainer\").getChild(\"Time\").getChild(\"Dropdown\")\n\t\t\tlogger.info(\"Selected Hit_List Dropdown.\")\n\t\telif val_num \u003d\u003d 2:\n\t\t\tdd \u003d self.getChild(\"Historical_tab\").getChild(\"root\").getChild(\"Filters\").getChild(\"Time\").getChild(\"Dropdown\")\n\t\t\tlogger.info(\"Selected Historical_tab Dropdown.\")\n\t\telse:\n\t\t\tlogger.info(\"Unhandled tab value: %s\" % str(val_num))\n\t\t\treturn\n\n\t\tnow \u003d system.date.now()\n\t\ttoday0 \u003d system.date.setTime(now, 0, 0, 0)\n\t\tyday0 \u003d system.date.addDays(today0, -1)\n\n\t\tval \u003d str(dd.props.value or \u0027\u0027).strip()\n\t\tlogger.info(\"Dropdown value: %s\" % val)\n\n\t\tif val \u003d\u003d \"custom\":\n\t\t\tdd.custom.customTime \u003d True\n\t\t\tlogger.info(\"Custom mode selected — skipping time overwrite.\")\n\t\t\treturn\n\t\tdd.custom.customTime \u003d False\n\n\t\tdef t(day, h, m, s):\n\t\t\treturn system.date.setTime(day, h, m, s)\n\n\t\tif val \u003d\u003d \"currentDay\":\n\t\t\tstart, end \u003d today0, now\n\t\telif val \u003d\u003d \"morning\":\n\t\t\tstart, end \u003d t(today0, 2, 30, 0), t(today0, 7, 30, 0)\n\t\telif val \u003d\u003d \"daylight\":\n\t\t\tstart, end \u003d t(today0, 7, 30, 0), t(today0, 13, 0, 0)\n\t\telif val \u003d\u003d \"twilight\":\n\t\t\tif now \u003e\u003d t(today0, 13, 0, 0):\n\t\t\t\tstart, end \u003d t(today0, 13, 0, 0), now\n\t\t\telse:\n\t\t\t\tstart, end \u003d t(yday0, 13, 0, 0), now\n\t\telif val \u003d\u003d \"night\":\n\t\t\tstart, end \u003d t(yday0, 18, 30, 0), t(yday0, 23, 30, 0)\n\t\telif val \u003d\u003d \"wrapDown\":\n\t\t\tstart, end \u003d t(yday0, 23, 30, 0), t(today0, 2, 30, 0)\n\t\telif val \u003d\u003d \"currentShot\":\n\t\t\tif now \u003e\u003d t(today0, 13, 0, 0):\n\t\t\t\tstart, end \u003d t(today0, 13, 0, 0), now\n\t\t\telse:\n\t\t\t\tstart, end \u003d t(yday0, 13, 0, 0), now\n\t\telse:\n\t\t\ttry:\n\t\t\t\tmins \u003d int(val)\n\t\t\texcept:\n\t\t\t\tmins \u003d 60\n\t\t\t\tlogger.warn(\"Invalid numeric value \u0027%s\u0027, defaulting to 60 min.\" % val)\n\t\t\tend \u003d now\n\t\t\tstart \u003d system.date.addMinutes(end, -mins)\n\n\t\t# Apply to dropdown\n\t\tdd.custom.startDate \u003d start\n\t\tdd.custom.endDate \u003d end\n\n\t\tlogger.info(\"Time range applied successfully: start\u003d%s | end\u003d%s\" %\n\t\t (system.date.format(start, \"yyyy-MM-dd HH:mm:ss\"),\n\t\t system.date.format(end, \"yyyy-MM-dd HH:mm:ss\")))\n\n\texcept Exception as e:\n\t\tlogger.error(\"Error in valueChanged: %s\" % str(e))"
}
}
},
"props": {
"contentStyle": {
"classes": "Background-Styles/Grey-Background"
},
"menuType": "modern",
"style": {
"classes": "Background-Styles/Grey-Background"
},
"tabSize": {
"width": 140
},
"tabStyle": {
"active": {
"backgroundColor": "#EEEEEE",
"borderLeftColor": "#7FFF00",
"borderLeftStyle": "solid",
"borderLeftWidth": 5,
"borderTopLeftRadius": 5,
"borderTopRightRadius": 5,
"color": "#000000",
"fontFamily": "Arial",
"fontWeight": "bold",
"outlineStyle": "none",
"textDecoration": "underline"
},
"inactive": {
"backgroundColor": "#D7D7D7",
"borderLeftColor": "#FFFFFF",
"borderTopLeftRadius": 5,
"borderTopRightRadius": 5,
"color": "#969696",
"fontFamily": "Arial"
}
},
"tabs": [
"Active Alarms",
"Alarm Hit List",
"Historical"
]
},
"type": "ia.container.tab"
}
],
"meta": {
"name": "root"
},
"props": {
"style": {
"classes": "Background-Styles/Main-Background"
}
},
"type": "ia.container.flex"
}
}