{ "custom": { "activeControl": "", "configureDatabases": { "sql:Ignition": false, "sql_Ignition": false }, "custom_trends_ref": { "current_config": { "axes": [ { "color": "#757A7F", "dataFormat": "0,0.##", "label": { "font": { "color": "#757A7F", "size": 10 }, "offset": 0, "style": { "classes": "" }, "text": "" }, "name": "Default", "position": "left", "range": { "auto": true, "max": "", "min": "" }, "style": { "classes": "" }, "tick": { "color": "#757A7F", "label": { "font": { "color": "#757A7F", "size": 10 }, "style": { "classes": "" } }, "style": { "classes": "" } }, "width": 60 } ], "config": { "dateFormat": "YYYY/MM/DD", "endDate": {}, "export": { "dateFormat": "None", "timeFormat": "x" }, "measureOfTime": "days", "mode": "realtime", "penNamePathDepth": 3, "pointCount": 300, "rangeEndDate": null, "rangeSelectorPen": "", "rangeStartDate": null, "refreshRate": 1000, "responsiveDesignWidth": 750, "startDate": {}, "tagBrowserStartPath": "histprov:Ignition_Hist", "timeFormat": "h:mm A", "unitOfTime": 1, "visibility": { "buttons": { "showAnnotationButton": true, "showFullscreenButton": true, "showMoreButton": true, "showPanZoomButton": true, "showRangeBrushButton": true, "showSettingsButton": true, "showTagBrowserButton": true, "showXTraceButton": true }, "showDateRangeSelector": true, "showPenControlDisplay": true, "showTagBrowser": true } }, "dataColumns": { "penControl": { "average": true, "axis": true, "currentValue": true, "maximum": true, "minimum": true, "plot": true, "xTrace": true }, "rangeSelection": { "average": true, "delta": true, "first": true, "last": true, "lcl": true, "maximum": true, "median": true, "minimum": true, "standardDeviation": true, "sum": true, "ucl": true } }, "interaction": { "annotation": { "dot": { "color": "#757A7F", "opacity": 1, "radius": 3, "style": { "classes": "" }, "visible": true }, "infoBox": { "dateFormat": "YYYY/MM/DD", "fill": { "color": "#FAFAFB", "opacity": 0.9 }, "font": { "color": "", "size": 11, "style": { "classes": "" } }, "icon": { "fill": { "color": "#929597", "opacity": 1 }, "stroke": { "color": "#929597", "dashArray": 0, "opacity": 0, "width": 0 }, "style": { "classes": "" } }, "showTime": true, "stroke": { "color": "#757A7F", "dashArray": 0, "opacity": 0.9, "width": 1 }, "style": { "classes": "" }, "timeFormat": "h:mm A", "visible": true, "width": "auto" }, "line": { "color": "#757A7F", "dashArray": 0, "opacity": 0.9, "style": { "classes": "" }, "visible": true, "width": 1 } }, "chartZoomLevel": 1, "fullscreen": false, "mode": "panAndZoom", "panAndZoom": { "freeRange": false }, "rangeBrush": { "active": { "color": "#0C7BB3", "opacity": 0.3, "style": { "classes": "" } }, "inactive": { "color": "#757A7F", "opacity": 0.3, "style": { "classes": "" } }, "values": [] }, "rangeZoomLevel": 1, "xTrace": { "infoBox": { "dataFormat": "0,0.##", "dateFormat": "YYYY/MM/DD", "fill": { "color": "#FAFAFB", "opacity": 0.9 }, "font": { "color": "", "size": 11, "style": { "classes": "" } }, "showTime": true, "stroke": { "color": "#757A7F", "dashArray": 0, "opacity": 0.9, "width": 1 }, "style": { "classes": "" }, "timeFormat": "h:mm A", "visible": true, "width": "auto" }, "line": { "color": "#757A7F", "dashArray": 0, "opacity": 0.5, "style": { "classes": "" }, "visible": true, "width": 1 }, "values": [ 1.0013210702341138 ] } }, "legend": { "visible": false }, "pens": [], "plots": [ { "color": "var(--neutral-10)", "markers": [], "relativeWeight": 1, "style": { "classes": "" } } ], "timeAxis": { "color": "#737676", "grid": { "color": "", "dashArray": 0, "opacity": 0.9, "style": { "classes": "" }, "visible": false }, "height": 35, "style": { "classes": "" }, "tick": { "color": "#757A7F", "label": { "angled": false, "font": { "color": "#757A7F", "size": 10 }, "format": "Auto", "style": { "classes": "" } }, "style": { "classes": "" } }, "tickCount": "auto", "visible": true }, "title": { "font": { "color": "", "size": 12 }, "style": { "classes": "" }, "text": "", "visible": false } }, "drv": "", "histprov": "Ignition", "rootTagPath": "" }, "databases": [], "functionTitle": "", "isAdmin": false, "refreshRate": 1000, "viewSaves": false }, "params": {}, "propConfig": { "custom.activeControl": { "persistent": true }, "custom.configureDatabases": { "binding": { "config": { "expression": "true" }, "enabled": false, "transforms": [ { "code": "\t# resets this property when the view is opened\n\treturn {}", "type": "script" } ], "type": "expr" }, "persistent": true }, "custom.custom_trends_ref": { "persistent": true }, "custom.databases": { "binding": { "config": { "expression": "runScript(\u0027system.db.getConnections\u0027, 0)" }, "transforms": [ { "code": "\t# collect the database connection info, check for which ones are enabled for storing ad hoc trend configs\n\ttag_provider \u003d self.session.custom.trends.histprov\n\tbase_path \u003d self.session.custom.trends.rootTagPath\n\t\n\tdatabases \u003d []\n\tfor row in range(value.getRowCount()):\n\t\tif value.getValueAt(row,\u0027Name\u0027) \u003d\u003d self.session.custom.trends.histprov:\n\t\t\tdatabase \u003d {\u0027connector\u0027: \u0027sql\u0027}\n\t\t\tfor column in value.getColumnNames():\n\t\t\t\tdatabase[column] \u003d value.getValueAt(row, column)\n\t\t\tdatabases.append(database)\n\t\n\t# avoid an exception when mongodb module is not installed\n\tif \u0027mongodb\u0027 in system.getDict():\n\t\tfor row in system.mongodb.listConnectorInfo():\n\t\t\tdatabase \u003d row\n\t\t\tdatabase[\u0027connector\u0027] \u003d \u0027mongodb\u0027\n\t\t\tdatabase[\u0027DBType\u0027] \u003d \u0027MongoDB\u0027\n\t\t\t\n\t\t\t# for consistency with system.db.getConnections\n\t\t\tdatabase[\u0027Name\u0027] \u003d database.pop(\u0027name\u0027)\n\t\t\tdatabase[\u0027Status\u0027] \u003d database.pop(\u0027status\u0027)\n\t\t\t\n\t\t\tdatabases.append(database)\n\t\n\tfor database in databases:\n\t\ttry:\n\t\t\tdatabase[\u0027Enabled\u0027] \u003d database[\u0027Status\u0027] \u003d\u003d \u0027Valid\u0027 and self.rootContainer.databaseEnabled(database[\u0027Name\u0027], connector\u003ddatabase[\u0027connector\u0027])\n\t\texcept:\n\t\t\tdatabase[\u0027Enabled\u0027] \u003d False\n\t\n\t\n\treturn databases", "type": "script" } ], "type": "expr" }, "persistent": true }, "custom.functionTitle": { "persistent": true }, "custom.isAdmin": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/roles/Administrator\u0027)" }, "type": "expr" }, "persistent": true }, "custom.refreshRate": { "persistent": true }, "custom.viewSaves": { "binding": { "config": { "expression": "false" }, "type": "expr" }, "persistent": true } }, "props": { "defaultSize": { "height": 951, "width": 1385 } }, "root": { "children": [ { "children": [ { "children": [ { "children": [ { "meta": { "name": "Icon" }, "position": { "basis": "30px", "shrink": 0 }, "props": { "path": "material/trending_up" }, "type": "ia.display.icon" }, { "meta": { "name": "TitleSpacer" }, "position": { "basis": "15px" }, "type": "ia.display.label" }, { "meta": { "name": "AdHocTrends" }, "position": { "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/HeaderTitle" }, "text": "Ad Hoc Trends" }, "type": "ia.display.label" }, { "meta": { "name": "FunctionTitle" }, "position": { "basis": "15px", "grow": 1 }, "propConfig": { "props.text": { "binding": { "config": { "path": "view.custom.functionTitle" }, "type": "property" } } }, "props": { "style": { "classes": "AdHocTrends/FunctionTitle" } }, "type": "ia.display.label" } ], "meta": { "name": "Controls" }, "position": { "basis": "50px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/ControlBar", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "HeaderSmall" }, "props": { "direction": "column", "style": { "classes": "AdHocTrends/Header", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "children": [ { "meta": { "name": "Icon" }, "position": { "basis": "30px", "shrink": 0 }, "props": { "path": "material/trending_up" }, "type": "ia.display.icon" }, { "meta": { "name": "TitleSpacer" }, "position": { "basis": "15px" }, "type": "ia.display.label" }, { "meta": { "name": "AdHocTrends" }, "position": { "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/HeaderTitle" }, "text": "Ad Hoc Trends" }, "type": "ia.display.label" }, { "meta": { "name": "FunctionTitle" }, "position": { "basis": "15px", "grow": 1 }, "propConfig": { "props.text": { "binding": { "config": { "path": "view.custom.functionTitle" }, "type": "property" } } }, "props": { "style": { "classes": "AdHocTrends/FunctionTitle", "textAlign": "right" } }, "type": "ia.display.label" }, { "meta": { "name": "FunctionTitleSpacer" }, "position": { "basis": "5px" }, "type": "ia.display.label" }, { "custom": { "title": "Configure Databases" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "ConfigureDatabases" }, "position": { "basis": "26px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } }, "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/storage" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/FullRadius" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "DbSpacer" }, "position": { "basis": "8px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "type": "ia.display.label" }, { "custom": { "title": "Load from Database" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)\n\tself.parent.parent.getChild(\"LoadFromDb\").getChild(\"Databases\").refreshBinding(\"props.options\")\n\tself.parent.parent.getChild(\"LoadFromDb\").getChild(\"Charts\").refreshBinding(\"props.options\")\n\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "LoadFromDb", "tooltip": { "enabled": true, "location": "center-left", "text": "Load from DB" } }, "position": { "basis": "25px" }, "propConfig": { "position.display": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } }, "props.enabled": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/playlist_play" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/LeftRadius" }, "text": "" }, "type": "ia.input.button" }, { "custom": { "title": "Save to Database" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)\n\tself.parent.parent.getChild(\"SaveToDb\").getChild(\"Charts\").refreshBinding(\"props.options\")\n\tself.parent.parent.getChild(\"SaveToDb\").getChild(\"Databases\").refreshBinding(\"props.options\")" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SaveToDb", "tooltip": { "enabled": true, "location": "center-left", "text": "Save to DB" } }, "position": { "basis": "25px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated\u0027)" }, "type": "expr" } }, "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated\u0027)" }, "type": "expr" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/playlist_add" }, "width": 23 }, "primary": false, "style": { "borderBottomLeftRadius": 3, "borderLeftWidth": "1px", "borderTopLeftRadius": 3, "classes": "AdHocTrends/Control AdHocTrends/RightRadius", "overflow": "visible" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SaveFileSpacer" }, "position": { "basis": "8px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated\u0027)" }, "enabled": false, "type": "expr" } } }, "type": "ia.display.label" }, { "custom": { "title": "Load File" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "LoadFromFile", "tooltip": { "enabled": true, "location": "center-left", "text": "Load From File" } }, "position": { "basis": "25px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/folder_open" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/LeftRadius" }, "text": "" }, "type": "ia.input.button" }, { "custom": { "title": "Save File" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SaveToFile", "tooltip": { "enabled": true, "location": "center-left", "text": "Save To File" } }, "position": { "basis": "25px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/save" }, "width": 23 }, "primary": false, "style": { "borderLeftWidth": "0px", "classes": "AdHocTrends/Control AdHocTrends/RightRadius" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SetRefreshRateSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "title": "Set Real-Time Refresh Rate" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, \u0027root/MainTopControls/HeaderLarge/SetRefreshRate/Rate\u0027, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SetRefreshRate", "tooltip": { "enabled": true, "location": "center-left", "text": "Set Refresh Rate" } }, "position": { "basis": "25px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/access_time" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/LeftRadius" }, "text": "" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.togglePause()" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Pause", "tooltip": { "enabled": true, "location": "center-left", "text": "Play / Pause" } }, "position": { "basis": "25px" }, "propConfig": { "props.image.icon.color": { "binding": { "config": { "expression": "if({this.props.primary}, \u0027var(--neutral-20)\u0027, \u0027var(--neutral-70)\u0027)" }, "type": "expr" } }, "props.primary": { "binding": { "config": { "expression": "{...../Body/PowerChart.props.config.refreshRate} \u003d 0" }, "type": "expr" } } }, "props": { "image": { "icon": { "path": "material/pause_circle_outline" }, "width": 23 }, "style": { "borderLeftWidth": "0px", "classes": "AdHocTrends/Control AdHocTrends/RightRadius" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SetTitleSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "title": "Set Title" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, \u0027root/MainTopControls/HeaderLarge/SetTitle/Title\u0027, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SetTitle", "tooltip": { "enabled": true, "location": "center-left", "text": "Set Title" } }, "position": { "basis": "26px", "shrink": 0 }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/text_fields" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/FullRadius" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "DbSpacer_0" }, "position": { "basis": "8px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "type": "ia.display.label" }, { "custom": { "title": "Configure Databases" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.custom.viewSaves \u003d not self.view.custom.viewSaves" }, "scope": "G", "type": "script" } } }, "meta": { "name": "ViewSaves" }, "position": { "basis": "26px" }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated\u0027)" }, "type": "expr" } }, "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated\u0027)" }, "type": "expr" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/cloud_queue" } }, "primary": false, "style": { "classes": "AdHocTrends/Control AdHocTrends/FullRadius" }, "text": "" }, "type": "ia.input.button" } ], "meta": { "name": "Controls" }, "position": { "basis": "50px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/ControlBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "events": { "dom": { "onKeyPress": { "config": { "script": "\tself.view.rootContainer.setTitle(self.props.text)\n\tif event.key \u003d\u003d \u0027Enter\u0027:\n\t\tself.view.rootContainer.closeFunction()\n\t\t# clearing own text during key press will not work\n\t\t# must be cleared it after this event\n\t\timport threading\n\t\tdef resetText():\n\t\t\tself.props.text \u003d \u0027\u0027\n\t\tthreading.Timer(0.3, resetText).start()\n\t\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Title" }, "position": { "basis": "350px" }, "props": { "deferUpdates": false, "placeholder": "Enter a new title or leave blank to clear...", "rejectUpdatesWhileFocused": false }, "type": "ia.input.text-field" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.getSibling(\u0027Title\u0027).props.text \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tnewTitle \u003d self.getSibling(\u0027Title\u0027).props.text\n\tself.getSibling(\u0027Title\u0027).props.text \u003d \u0027\u0027\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.setTitle(newTitle)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Save" }, "type": "ia.input.button" } ], "meta": { "name": "SetTitle" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "events": { "dom": { "onKeyDown": { "config": { "script": "\tif event.key \u003d\u003d \u0027Enter\u0027:\n\t\tself.view.rootContainer.closeFunction()\n\t\t# the value entered will not yet be availble\n\t\t# must trigger the new rate after this event is done\n\t\timport threading\n\t\tdef setNewRate():\n\t\t\tself.view.rootContainer.setRate(self.props.value)\n\t\tthreading.Timer(0.3, setNewRate).start()\n\t\t\n\t\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Rate" }, "position": { "basis": "150px" }, "props": { "align": "left", "format": "0,0", "inputBounds": { "minimum": 0 }, "placeholder": "Enter a new rate for real-time mode...", "value": 5000 }, "type": "ia.input.numeric-entry-field" }, { "meta": { "name": "Units" }, "position": { "shrink": 0 }, "props": { "text": "(ms)" }, "type": "ia.display.label" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tnewRate \u003d self.getSibling(\u0027Rate\u0027).props.value\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.setRate(newRate)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Save" }, "type": "ia.input.button" } ], "meta": { "name": "SetRefreshRate" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "OptionsSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Display" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.getSibling(\u0027Display\u0027).props.selected\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.saveToFile(includePlots, includeDisplay)\n\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Save" }, "type": "ia.input.button" } ], "meta": { "name": "SaveToFile" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "OptionsSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Display" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "BrowseSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "configJson": "" }, "events": { "component": { "onFileReceived": { "config": { "script": "\tself.custom.configJson \u003d event.file.getString()\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "FileUpload" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "fileUploadIcon": { "path": "material/folder_open", "style": { "cursor": "pointer" } }, "maxUploads": 1, "supportedFileTypes": [ "JSON" ] }, "type": "ia.input.fileupload" }, { "meta": { "name": "BrowseLabel" }, "position": { "shrink": 0 }, "props": { "text": "Browse (10 MB max)" }, "type": "ia.display.label" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.getSibling(\u0027FileUpload\u0027).custom.configJson \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.getSibling(\u0027Display\u0027).props.selected\n\t\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.loadFromFile(self.getSibling(\u0027FileUpload\u0027).custom.configJson, includePlots, includeDisplay)\n\tself.getSibling(\u0027FileUpload\u0027).custom.configJson \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Load" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Load" }, "type": "ia.input.button" } ], "meta": { "name": "LoadFromFile" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "FullSpacer" }, "position": { "basis": "0px", "grow": 1, "shrink": 0 }, "type": "ia.display.label" }, { "meta": { "name": "Databases" }, "position": { "basis": "256px" }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "\tdbList \u003d []\n\tfor db in value:\n\t\tif db[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\telif db[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, \u0027MongoDB\u0027, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\treturn dbList", "type": "script" } ], "type": "property" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": "sql:Ignition" }, "type": "ia.input.dropdown" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.refreshBinding(\u0027custom.databases\u0027)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Refresh" }, "position": { "basis": "26px", "shrink": 0 }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/refresh" } }, "primary": false, "style": { "classes": "AdHocTrends/Control" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "ToggleSwitch" }, "position": { "basis": "140px", "shrink": 0 }, "propConfig": { "props.enabled": { "binding": { "config": { "expression": "!isNull({../Databases.props.value})" }, "type": "expr" } }, "props.label.text": { "binding": { "config": { "expression": "if({this.props.selected}, \u0027Enabled\u0027, \u0027Disabled\u0027)" }, "type": "expr" } }, "props.selected": { "binding": { "config": { "struct": { "databases": "{view.custom.databases}", "selectedDatabase": "{../Databases.props.value}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn next((x.Enabled for x in self.view.custom.databases if \u0027%s:%s\u0027 %(x.connector, x.Name) \u003d\u003d value.selectedDatabase), False)", "type": "script" } ], "type": "expr-struct" }, "onChange": { "enabled": null, "script": "\tselectedDatabase \u003d self.getSibling(\u0027Databases\u0027).props.value\n\tif selectedDatabase:\n\t\tif currentValue:\n\t\t\tif currentValue.value:\n\t\t\t\tself.view.custom.configureDatabases[selectedDatabase] \u003d True\n\t\t\telse:\n\t\t\t\tself.view.custom.configureDatabases[selectedDatabase] \u003d False" } } }, "props": { "color": { "selected": "var(--success)", "unselected": "var(--neutral-60)" }, "label": {} }, "type": "ia.input.toggle-switch" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.view.custom.configureDatabases \u003d {}\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.configureDatabases()\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None\n\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "shrink": 0 }, "propConfig": { "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "props": { "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Save" }, "type": "ia.input.button" } ], "meta": { "name": "ConfigureDatabases" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "OptionsSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Display" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "DatabaseSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Databases" }, "position": { "basis": "256px", "display": false }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "#\treturn [{\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: db.Name} for db in filter(lambda x: x[\u0027Enabled\u0027], value)]\n\t\n\toptions \u003d self.view.rootContainer.populateDatabaseDropdown(value, True)\n\tif len(options) \u003e 0:\n\t\tself.props.value \u003d options[0][\u0027value\u0027]\n\treturn options\t", "type": "script" } ], "type": "property" } }, "props.value": { "binding": { "config": { "expression": "try({this.props.options}[0][\u0027value\u0027],\u0027\u0027)" }, "enabled": false, "type": "expr" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": "sql:Ignition" }, "type": "ia.input.dropdown" }, { "meta": { "name": "ChartSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Charts" }, "position": { "basis": "256px" }, "propConfig": { "props.options": { "binding": { "config": { "path": "../Databases.props.value" }, "transforms": [ { "code": "\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d value), False)\n\tif not dbInfo:\n\t\treturn []\n\tcharts \u003d self.view.rootContainer.getCharts(value)\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027id\u0027], \u0027label\u0027: chart[\u0027config_name\u0027]} for chart in charts]\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027_id\u0027], \u0027label\u0027: chart[\u0027configName\u0027]} for chart in charts]", "type": "script" } ], "type": "property" } } }, "props": { "placeholder": { "text": "Select a chart..." }, "search": { "noResultsText": "No charts found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": null }, "type": "ia.input.dropdown" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.getSibling(\u0027Display\u0027).props.selected\n\tdbName \u003d self.getSibling(\u0027Databases\u0027).props.value\n\tconfigId \u003d self.getSibling(\u0027Charts\u0027).props.value\n\t\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.loadFromDb(dbName, configId, includePlots, includeDisplay)\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Load" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Load" }, "type": "ia.input.button" } ], "meta": { "name": "LoadFromDb" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "OptionsSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Display" }, "position": { "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "PrivateSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Private" }, "position": { "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{session.props.auth.authenticated}" }, "type": "expr" } } }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Store Privately", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "DatabaseSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Databases" }, "position": { "basis": "256px", "display": false }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "#\treturn [{\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: db.Name} for db in filter(lambda x: x[\u0027Enabled\u0027], value)]\n\t\n\toptions \u003d self.view.rootContainer.populateDatabaseDropdown(value, True)\n\tif len(options) \u003e 0:\n\t\tself.props.value \u003d options[0][\u0027value\u0027]\n\treturn options", "type": "script" } ], "type": "property" } }, "props.value": { "binding": { "config": { "expression": "try({this.props.options}[0][\u0027value\u0027],\u0027\u0027)" }, "enabled": false, "type": "expr" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": "sql:Ignition" }, "type": "ia.input.dropdown" }, { "meta": { "name": "Favorite" }, "position": { "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{session.props.auth.authenticated}" }, "type": "expr" } } }, "props": { "checkedIcon": { "style": { "width": "16px" } }, "selected": true, "text": "Set Favorite", "uncheckedIcon": { "style": { "width": "16px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "ChartSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "meta": { "name": "Charts" }, "position": { "basis": "256px" }, "propConfig": { "props.options": { "binding": { "config": { "path": "../Databases.props.value" }, "transforms": [ { "code": "\tself.props.value \u003d \u0027\u0027\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d value), False)\n\tif not dbInfo:\n\t\treturn []\n\tcharts \u003d self.view.rootContainer.getOwnCharts(value)\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027id\u0027], \u0027label\u0027: chart[\u0027config_name\u0027]} for chart in charts]\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\tfrom system.mongodb.types import ObjectId\n\t\treturn [{\u0027value\u0027: chart[\u0027_id\u0027], \u0027label\u0027: chart[\u0027configName\u0027]} for chart in charts]", "type": "script" } ], "type": "property" } } }, "props": { "allowCustomOptions": true, "placeholder": { "text": "Select or create a chart..." }, "search": { "noResultsText": "No charts found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" } }, "type": "ia.input.dropdown" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButton" }, "text": "Cancel" }, "type": "ia.input.button" }, { "custom": { "debug": false, "debug2": "" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.getSibling(\u0027Display\u0027).props.selected\n\tprivate \u003d self.session.props.auth.authenticated and self.getSibling(\u0027Private\u0027).props.selected\n\tfavorite \u003d self.session.props.auth.authenticated and self.getSibling(\u0027Favorite\u0027).props.selected\n\tdbName \u003d self.getSibling(\u0027Databases\u0027).props.value\n\tconfigId \u003d self.getSibling(\u0027Charts\u0027).props.value\n\tnewChart \u003d not any(str(o[\u0027value\u0027]) \u003d\u003d str(configId) for o in self.getSibling(\u0027Charts\u0027).props.options)\n\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.saveToDb(dbName, configId, includePlots, includeDisplay, private, favorite, newChart)\n\tself.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.getSibling(\u0027Charts\u0027).props.value \u003d None\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "shrink": 0 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButton" }, "text": "Save" }, "type": "ia.input.button" } ], "meta": { "name": "SaveToDb" }, "position": { "basis": "40px", "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "justify": "flex-end", "style": { "classes": "AdHocTrends/FunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "HeaderLarge" }, "position": { "size": "large" }, "props": { "direction": "column", "style": { "classes": "AdHocTrends/Header", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "MainTopControls" }, "position": { "shrink": 0 }, "propConfig": { "props.breakpoint": { "binding": { "config": { "expression": "{../Body/PowerChart.props.config.responsiveDesignWidth}+2" }, "type": "expr" } } }, "props": { "style": { "maxHeight": "50px", "zIndex": 1 } }, "type": "ia.container.breakpt" }, { "children": [ { "meta": { "domId": "adhocTrends", "name": "PowerChart", "tooltip": { "text": "tooltip" } }, "position": { "grow": 1 }, "propConfig": { "props.axes": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.axes" }, "type": "property" } }, "props.config.dateFormat": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.dateFormat" }, "type": "property" } }, "props.config.endDate": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.endDate" }, "type": "property" } }, "props.config.export": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.export" }, "type": "property" } }, "props.config.measureOfTime": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.measureOfTime" }, "type": "property" } }, "props.config.mode": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.mode" }, "type": "property" } }, "props.config.penNamePathDepth": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.penNamePathDepth" }, "type": "property" } }, "props.config.pointCount": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.pointCount" }, "type": "property" } }, "props.config.rangeEndDate": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.rangeEndDate" }, "type": "property" } }, "props.config.rangeSelectorPen": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.rangeSelectorPen" }, "type": "property" } }, "props.config.rangeStartDate": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.rangeStartDate" }, "type": "property" } }, "props.config.refreshRate": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.refreshRate" }, "type": "property" } }, "props.config.responsiveDesignWidth": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.responsiveDesignWidth" }, "type": "property" } }, "props.config.startDate": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.startDate" }, "type": "property" } }, "props.config.tagBrowserStartPath": { "binding": { "config": { "path": "session.custom.trends.current_config.config.tagBrowserStartPath" }, "transforms": [ { "code": "\timport time\n\ttime.sleep(0.2)\n\treturn value", "type": "script" } ], "type": "property" }, "persistent": true }, "props.config.timeFormat": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.timeFormat" }, "type": "property" } }, "props.config.unitOfTime": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.unitOfTime" }, "type": "property" } }, "props.config.visibility": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.config.visibility" }, "type": "property" } }, "props.dataColumns": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.dataColumns" }, "type": "property" } }, "props.interaction": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.interaction" }, "type": "property" } }, "props.legend": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.legend" }, "type": "property" } }, "props.pens": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.pens" }, "type": "property" } }, "props.plots": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.plots" }, "type": "property" } }, "props.timeAxis": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.timeAxis" }, "type": "property" } }, "props.title": { "binding": { "config": { "bidirectional": true, "path": "session.custom.trends.current_config.title" }, "type": "property" } } }, "props": { "config": { "tagBrowserStartPath": "histprov:ignition_hist" } }, "type": "ia.chart.powerchart" }, { "children": [ { "children": [ { "meta": { "name": "Label" }, "position": { "grow": 1 }, "props": { "text": "Saved Configs", "textStyle": { "fontSize": "0.8em", "fontWeight": "bold" } }, "type": "ia.display.label" }, { "events": { "dom": { "onClick": { "config": { "script": "\ttable \u003d self.parent.parent.getChild(\"Table\")\n\ttable.refreshBinding(\u0027props.data\u0027)\n\ttable.props.selection.selectedRow \u003d None\n\ttable.props.selection.selectedColumn \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Refresh" }, "position": { "basis": "24px", "shrink": 0 }, "props": { "path": "material/refresh", "style": { "cursor": "pointer" } }, "type": "ia.display.icon" }, { "events": { "dom": { "onClick": { "config": { "script": "\tself.view.custom.viewSaves \u003d False" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Close" }, "position": { "basis": "24px", "shrink": 0 }, "props": { "path": "material/arrow_forward", "style": { "cursor": "pointer" } }, "type": "ia.display.icon" } ], "meta": { "name": "Header" }, "position": { "basis": "40px" }, "props": { "alignItems": "center", "style": { "gap": "10px", "overflow": "hidden", "padding": "0 8px" } }, "type": "ia.container.flex" }, { "meta": { "name": "Table" }, "position": { "basis": "400px", "grow": 1 }, "propConfig": { "props.data": { "binding": { "config": { "expression": "now(0)" }, "transforms": [ { "code": "\tisAdmin \u003d self.view.custom.isAdmin\n\tquery \u003d \"\"\"\n\tSELECT \n\t\tid, config_name, favorite, private, username, t_stamp\n\tFROM ad_hoc_trends_config\n\tWHERE username \u003d ?\n\t\tOR (username IS NULL and ? \u003d 1)\n\tORDER BY t_stamp DESC\n\t\"\"\"\n\treturn system.db.runPrepQuery(query, [self.session.props.auth.user.userName, isAdmin], database\u003d\u0027Ignition\u0027)", "type": "script" } ], "type": "expr" } }, "props.pager.bottom": { "binding": { "config": { "expression": "len({this.props.data}) \u003e {this.props.pager.initialOption}" }, "type": "expr" } }, "props.selection.selectedColumn": { "binding": { "config": { "expression": "null" }, "type": "expr" } }, "props.selection.selectedRow": { "binding": { "config": { "expression": "null" }, "type": "expr" } } }, "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": false, "width": "" }, { "align": "center", "boolean": "checkbox", "dateFormat": "MM/DD/YYYY", "editable": false, "field": "config_name", "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": "Name" }, "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", "editable": false, "field": "favorite", "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": "Favorite" }, "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", "editable": false, "field": "private", "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": "Private" }, "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", "editable": false, "field": "username", "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": "Username" }, "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": "t_stamp", "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": "TStamp" }, "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": "date", "resizable": true, "sort": "none", "sortable": true, "strictWidth": false, "style": { "classes": "" }, "toggleSwitch": { "color": { "selected": "", "unselected": "" } }, "viewParams": {}, "viewPath": "", "visible": true, "width": "" } ], "pager": {}, "selection": {}, "style": { "margin": "0 8px" } }, "type": "ia.display.table" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\ttable \u003d self.parent.parent.getChild(\"Table\")\n\tconfigId \u003d table.props.selection.data[0].id\n\tquery \u003d \"\"\"\n\tDELETE FROM ad_hoc_trends_config\n\tWHERE id \u003d ?\n\t\"\"\"\n\targs \u003d [configId]\n\tsystem.db.runPrepUpdate(query, args, database\u003d\u0027Ignition\u0027)\n\ttable.refreshBinding(\u0027props.data\u0027)\n\tself.props.value \u003d 0" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Delete" }, "position": { "grow": 1 }, "propConfig": { "props.enabled": { "binding": { "config": { "expression": "len({.../Table.props.selection.data}) \u003e 0\r\n\u0026\u0026 {session.props.auth.authenticated}" }, "type": "expr" } } }, "props": { "confirm": { "enabled": true }, "primary": false, "readyState": { "icon": { "style": { "height": "24px", "width": "2rem" } }, "text": "Delete Selected Config" }, "style": { "padding": "0 10px" }, "writingState": { "icon": { "style": { "height": "24px", "width": "2rem" } }, "text": "Delete Selected Config" } }, "type": "ia.input.oneshotbutton" } ], "meta": { "name": "Actions" }, "position": { "basis": "35px", "shrink": 0 }, "props": { "style": { "gap": "10px", "margin": "8px", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "FlexContainer" }, "position": { "basis": "0px", "shrink": 0 }, "propConfig": { "props.style.flex-basis": { "binding": { "config": { "expression": "if(!{view.custom.viewSaves}, 0, 520)" }, "type": "expr" } } }, "props": { "direction": "column", "style": { "border-bottom": "1px solid var(--border)", "border-left": "none", "border-right": "1px solid var(--border)", "border-top": "1px solid var(--border)", "overflow": "hidden", "transition": "all 0.2s ease-in-out" } }, "type": "ia.container.flex" } ], "meta": { "name": "Body", "tooltip": { "enabled": true } }, "position": { "basis": "500px", "grow": 1 }, "type": "ia.container.flex" }, { "children": [ { "children": [ { "children": [ { "events": { "dom": { "onKeyPress": { "config": { "script": "\tself.view.rootContainer.setTitle(self.props.text)\n\tif event.key \u003d\u003d \u0027Enter\u0027:\n\t\tself.view.rootContainer.closeFunction()\n\t\t# clearing own text during key press will not work\n\t\t# must be cleared it after this event\n\t\timport threading\n\t\tdef resetText():\n\t\t\tself.props.text \u003d \u0027\u0027\n\t\tthreading.Timer(0.3, resetText).start()\n\t\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Title" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "deferUpdates": false, "placeholder": "Enter a new title or leave blank to clear...", "rejectUpdatesWhileFocused": false }, "type": "ia.input.text-field" }, { "meta": { "name": "SaveSpacer" }, "position": { "basis": "8px", "shrink": 0 }, "type": "ia.display.label" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.parent.getSibling(\u0027Title\u0027).props.text \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tnewTitle \u003d self.parent.getSibling(\u0027Title\u0027).props.text\n\tself.parent.getSibling(\u0027Title\u0027).props.text \u003d \u0027\u0027\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.setTitle(newTitle)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Save", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelSave" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "SetTitle" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "children": [ { "events": { "dom": { "onKeyDown": { "config": { "script": "\tif event.key \u003d\u003d \u0027Enter\u0027:\n\t\tself.view.rootContainer.closeFunction()\n\t\t# the value entered will not yet be availble\n\t\t# must trigger the new rate after this event is done\n\t\timport threading\n\t\tdef setNewRate():\n\t\t\tself.view.rootContainer.setRate(self.props.value)\n\t\tthreading.Timer(0.3, setNewRate).start()\n\t\t\n\t\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Rate" }, "position": { "basis": "60px", "grow": 1 }, "props": { "align": "left", "format": "0,0", "inputBounds": { "minimum": 0 }, "placeholder": "Enter a new rate for real-time mode...", "style": { "height": "60px" }, "value": 5000 }, "type": "ia.input.numeric-entry-field" }, { "meta": { "name": "Units" }, "position": { "basis": "50px" }, "props": { "text": "(ms)" }, "type": "ia.display.label" } ], "meta": { "name": "RateInput" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tnewRate \u003d self.parent.parent.getChild(\u0027RateInput/Rate\u0027).props.value\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.setRate(newRate)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Save", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelSave" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "SetRefreshRate" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Display" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.parent.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.parent.getSibling(\u0027Display\u0027).props.selected\n\t\n\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.saveToFile(includePlots, includeDisplay)\n\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Save", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelSave" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "SaveToFile" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Display" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "children": [ { "custom": { "configJson": "" }, "events": { "component": { "onFileReceived": { "config": { "script": "\tself.custom.configJson \u003d event.file.getString()\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "FileUpload" }, "position": { "basis": "60px", "grow": 1 }, "props": { "fileUploadIcon": { "path": "material/folder_open", "style": { "cursor": "pointer" } }, "maxUploads": 1, "supportedFileTypes": [ "JSON" ] }, "type": "ia.input.fileupload" }, { "meta": { "name": "BrowseLabel" }, "position": { "shrink": 0 }, "props": { "text": "Browse (10 MB max)" }, "type": "ia.display.label" } ], "meta": { "name": "Browse" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" }, { "meta": { "name": "SaveSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.parent.parent.getChild(\u0027Browse/FileUpload\u0027).custom.configJson \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.parent.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.parent.getSibling(\u0027Display\u0027).props.selected\n\t\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.loadFromFile(self.parent.parent.getChild(\u0027Browse/FileUpload\u0027).custom.configJson, includePlots, includeDisplay)\n\tself.parent.parent.getChild(\u0027Browse/FileUpload\u0027).custom.configJson \u003d \u0027\u0027" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Load" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Load", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelLoad" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "LoadFromFile" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "children": [ { "meta": { "name": "Databases" }, "position": { "basis": "60px", "grow": 1, "shrink": 0 }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "\tdbList \u003d []\n\tfor db in value:\n\t\tif db[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\telif db[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, \u0027MongoDB\u0027, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\treturn dbList", "type": "script" } ], "type": "property" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "enabled": false, "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": null }, "type": "ia.input.dropdown" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.refreshBinding(\u0027custom.databases\u0027)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Refresh" }, "position": { "basis": "60px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/refresh" } }, "primary": false, "style": { "classes": "AdHocTrends/Control" }, "text": "" }, "type": "ia.input.button" } ], "meta": { "name": "DbRefresh" }, "position": { "basis": "60px", "shrink": 0 }, "type": "ia.container.flex" }, { "meta": { "name": "ToggleSwitch" }, "position": { "basis": "60px", "shrink": 0 }, "propConfig": { "props.enabled": { "binding": { "config": { "expression": "!isNull({../DbRefresh/Databases.props.value})" }, "type": "expr" } }, "props.label.text": { "binding": { "config": { "expression": "if({this.props.selected}, \u0027Enabled\u0027, \u0027Disabled\u0027)" }, "type": "expr" } }, "props.selected": { "binding": { "config": { "struct": { "databases": "{view.custom.databases}", "selectedDatabase": "{../DbRefresh/Databases.props.value}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn next((x.Enabled for x in self.view.custom.databases if \u0027%s:%s\u0027 %(x.connector, x.Name) \u003d\u003d value.selectedDatabase), False)", "type": "script" } ], "type": "expr-struct" }, "onChange": { "enabled": null, "script": "\tselectedDatabase \u003d self.parent.getChild(\u0027DbRefresh/Databases\u0027).props.value\n\tif selectedDatabase:\n\t\tif currentValue:\n\t\t\tif currentValue.value:\n\t\t\t\tself.view.custom.configureDatabases[selectedDatabase] \u003d True\n\t\t\telse:\n\t\t\t\tself.view.custom.configureDatabases[selectedDatabase] \u003d False" } } }, "props": { "color": { "selected": "var(--success)", "unselected": "var(--neutral-60)" }, "label": {} }, "type": "ia.input.toggle-switch" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.view.custom.configureDatabases \u003d {}\n\tself.parent.parent.getChild(\u0027DbRefresh/Databases\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.view.rootContainer.configureDatabases()\n\tself.parent.parent.getChild(\u0027DbRefresh/Databases\u0027).props.value \u003d None\n\t" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "grow": 1 }, "propConfig": { "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Save", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelSave" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "ConfigureDatabases" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "enabled": false, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Display" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Databases" }, "position": { "basis": "60px", "display": false, "shrink": 0 }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "#\treturn [{\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: db.Name} for db in filter(lambda x: x[\u0027Enabled\u0027], value)]\n\treturn self.view.rootContainer.populateDatabaseDropdown(value, True)", "type": "script" } ], "type": "property" } }, "props.value": { "binding": { "config": { "expression": "coalesce({this.props.options[0].value},\u0027\u0027)" }, "type": "expr" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "enabled": false, "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" } }, "type": "ia.input.dropdown" }, { "meta": { "name": "ChartSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "key": "value" }, "meta": { "name": "Charts" }, "position": { "basis": "60px", "shrink": 0 }, "propConfig": { "props.options": { "binding": { "config": { "path": "../Databases.props.value" }, "transforms": [ { "code": "\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d value), False)\n\tif not dbInfo:\n\t\treturn []\n\tcharts \u003d self.view.rootContainer.getCharts(value)\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027id\u0027], \u0027label\u0027: chart[\u0027config_name\u0027]} for chart in charts]\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027_id\u0027], \u0027label\u0027: chart[\u0027configName\u0027]} for chart in charts]", "type": "script" } ], "type": "property" } } }, "props": { "placeholder": { "text": "Select a chart..." }, "search": { "noResultsText": "No charts found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" }, "value": null }, "type": "ia.input.dropdown" }, { "meta": { "name": "SaveSpacer" }, "position": { "basis": "8px", "shrink": 0 }, "type": "ia.display.label" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.parent.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.parent.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.parent.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.parent.getSibling(\u0027Display\u0027).props.selected\n\tdbName \u003d self.parent.getSibling(\u0027Databases\u0027).props.value\n\tconfigId \u003d self.parent.getSibling(\u0027Charts\u0027).props.value\n\t\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.loadFromDb(dbName, configId, includePlots, includeDisplay)\n\tself.parent.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.parent.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Load" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Load", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelLoad" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "LoadFromDb" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "meta": { "name": "Plots" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Plots", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Display" }, "position": { "basis": "60px", "shrink": 0 }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "selected": true, "text": "Display Settings", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Private" }, "position": { "basis": "60px", "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{session.props.auth.authenticated}" }, "type": "expr" } } }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "text": "Store Privately", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Favorite" }, "position": { "basis": "60px", "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{session.props.auth.authenticated}" }, "type": "expr" } } }, "props": { "checkedIcon": { "style": { "width": "60px" } }, "text": "Set Favorite", "uncheckedIcon": { "style": { "width": "60px" } } }, "type": "ia.input.checkbox" }, { "meta": { "name": "Databases" }, "position": { "basis": "60px", "display": false, "shrink": 0 }, "propConfig": { "props.options": { "binding": { "config": { "path": "view.custom.databases" }, "transforms": [ { "code": "#\treturn [{\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: db.Name} for db in filter(lambda x: x[\u0027Enabled\u0027], value)]\n\treturn self.view.rootContainer.populateDatabaseDropdown(value, True)", "type": "script" } ], "type": "property" } }, "props.value": { "binding": { "config": { "expression": "coalesce({this.props.options[0].value},\u0027\u0027)" }, "type": "expr" } } }, "props": { "placeholder": { "text": "Select a database..." }, "search": { "enabled": false, "noResultsText": "No databases found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" } }, "type": "ia.input.dropdown" }, { "meta": { "name": "ChartSpacer" }, "position": { "basis": "8px", "shrink": 0 }, "type": "ia.display.label" }, { "custom": { "key": "value" }, "meta": { "name": "Charts" }, "position": { "basis": "60px", "shrink": 0 }, "propConfig": { "props.options": { "binding": { "config": { "path": "../Databases.props.value" }, "transforms": [ { "code": "\tself.props.value \u003d \u0027\u0027\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d value), False)\n\tif not dbInfo:\n\t\treturn []\n\tcharts \u003d self.view.rootContainer.getOwnCharts(value)\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\treturn [{\u0027value\u0027: chart[\u0027id\u0027], \u0027label\u0027: chart[\u0027config_name\u0027]} for chart in charts]\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\tfrom system.mongodb.types import ObjectId\n\t\treturn [{\u0027value\u0027: chart[\u0027_id\u0027], \u0027label\u0027: chart[\u0027configName\u0027]} for chart in charts]", "type": "script" } ], "type": "property" } } }, "props": { "allowCustomOptions": true, "placeholder": { "text": "Select or create a chart..." }, "search": { "noResultsText": "No charts found..." }, "showClearIcon": true, "style": { "classes": "AdHocTrends/DropDown" } }, "type": "ia.input.dropdown" }, { "meta": { "name": "InputSpacer" }, "position": { "basis": "8px", "shrink": 0 }, "type": "ia.display.label" }, { "children": [ { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.closeFunction()\n\tself.parent.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.parent.getSibling(\u0027Charts\u0027).props.value \u003d None" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Cancel" }, "position": { "basis": "80px", "grow": 1 }, "props": { "primary": false, "style": { "classes": "AdHocTrends/CancelButtonMobile" }, "text": "Cancel", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tincludePlots \u003d self.parent.getSibling(\u0027Plots\u0027).props.selected\n\tincludeDisplay \u003d self.parent.getSibling(\u0027Display\u0027).props.selected\n\tprivate \u003d self.session.props.auth.authenticated and self.parent.getSibling(\u0027Private\u0027).props.selected\n\tfavorite \u003d self.session.props.auth.authenticated and self.parent.getSibling(\u0027Favorite\u0027).props.selected\n\tdbName \u003d self.parent.getSibling(\u0027Databases\u0027).props.value\n\tconfigId \u003d self.parent.getSibling(\u0027Charts\u0027).props.value\n\tnewChart \u003d not any(str(o[\u0027value\u0027]) \u003d\u003d str(configId) for o in self.parent.getSibling(\u0027Charts\u0027).props.options)\n\t\n\tself.view.rootContainer.closeFunction()\n\t\n\tself.view.rootContainer.saveToDb(dbName, configId, includePlots, includeDisplay, private, favorite, newChart)\n\tself.parent.getSibling(\u0027Databases\u0027).props.value \u003d None\n\tself.parent.getSibling(\u0027Charts\u0027).props.value \u003d None\n" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Save" }, "position": { "basis": "80px", "grow": 1 }, "props": { "style": { "classes": "AdHocTrends/SaveLoadButtonMobile" }, "text": "Save", "textStyle": { "fontSize": "20px" } }, "type": "ia.input.button" } ], "meta": { "name": "CancelSave" }, "position": { "basis": "60px" }, "props": { "style": { "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "SaveToDb" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "position.display": { "binding": { "config": { "expression": "{view.custom.activeControl} \u003d {this.meta.name}" }, "type": "expr" }, "persistent": true } }, "props": { "direction": "column", "style": { "classes": "AdHocTrends/MobileFunctionBar", "overflow": "visible" } }, "type": "ia.container.flex" }, { "children": [ { "custom": { "title": "Configure Databases" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "ConfigureDatabases" }, "position": { "basis": "36px", "display": false }, "propConfig": { "position.display": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "enabled": false, "type": "expr" } }, "props.enabled": { "binding": { "config": { "expression": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)" }, "type": "expr" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/storage" } }, "primary": false, "style": { "classes": "AdHocTrends/FullRadiusMobile AdHocTrends/MobileControl" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "DatabaseSpacer" }, "position": { "basis": "8px" }, "propConfig": { "position.display": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } } }, "type": "ia.display.label" }, { "custom": { "title": "Load from Database" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)\n\tself.parent.parent.getChild(\"LoadFromDb\").getChild(\"Charts\").refreshBinding(\"props.options\")\n\tself.parent.parent.getChild(\"LoadFromDb\").getChild(\"Databases\").refreshBinding(\"props.options\")" }, "scope": "G", "type": "script" } } }, "meta": { "name": "LoadFromDb" }, "position": { "basis": "35px" }, "propConfig": { "position.display": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } }, "props.enabled": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/playlist_play" } }, "primary": false, "style": { "classes": "AdHocTrends/LeftRadiusMobile AdHocTrends/MobileControl" }, "text": "" }, "type": "ia.input.button" }, { "custom": { "title": "Save to Database" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)\n\tself.parent.parent.getChild(\"SaveToDb\").getChild(\"Charts\").refreshBinding(\"props.options\")\n\tself.parent.parent.getChild(\"SaveToDb\").getChild(\"Databases\").refreshBinding(\"props.options\")" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SaveToDb" }, "position": { "basis": "35px" }, "propConfig": { "position.display": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } }, "props.enabled": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } } }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/playlist_add" }, "width": 23 }, "primary": false, "style": { "borderLeftWidth": "0px", "classes": "AdHocTrends/MobileControl AdHocTrends/RightRadiusMobile" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SaveFileSpacer" }, "position": { "basis": "8px" }, "propConfig": { "position.display": { "binding": { "config": { "struct": { "admin": "isAuthorized(true, \u0027Authenticated/Roles/Administrator\u0027)", "databases": "{view.custom.databases}" }, "waitOnAll": true }, "transforms": [ { "code": "\treturn value.admin or bool(filter(lambda x: x[\u0027Enabled\u0027], value.databases))", "type": "script" } ], "type": "expr-struct" } } }, "type": "ia.display.label" }, { "custom": { "title": "Load File" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "LoadFromFile" }, "position": { "basis": "35px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/folder_open" } }, "primary": false, "style": { "classes": "AdHocTrends/LeftRadiusMobile AdHocTrends/MobileControl" }, "text": "" }, "type": "ia.input.button" }, { "custom": { "title": "Save File" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, None, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SaveToFile" }, "position": { "basis": "35px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/save" }, "width": 23 }, "primary": false, "style": { "borderLeftWidth": "0px", "classes": "AdHocTrends/MobileControl AdHocTrends/RightRadiusMobile" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SetRefreshRateSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "title": "Set Real-Time Refresh Rate" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, \u0027root/MobileBottomControls/FooterSmall/SetRefreshRate/RateInput/Rate\u0027, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SetRefreshRate" }, "position": { "basis": "35px" }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/access_time" } }, "primary": false, "style": { "classes": "AdHocTrends/LeftRadiusMobile AdHocTrends/MobileControl" }, "text": "" }, "type": "ia.input.button" }, { "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.togglePause()" }, "scope": "G", "type": "script" } } }, "meta": { "name": "Pause" }, "position": { "basis": "35px" }, "propConfig": { "props.image.icon.color": { "binding": { "config": { "expression": "if({this.props.primary}, \u0027var(--neutral-20)\u0027, \u0027var(--neutral-70)\u0027)" }, "type": "expr" } }, "props.primary": { "binding": { "config": { "expression": "{...../Body/PowerChart.props.config.refreshRate} \u003d 0" }, "type": "expr" } } }, "props": { "image": { "icon": { "path": "material/pause_circle_outline" }, "width": 23 }, "style": { "borderLeftWidth": "0px", "classes": "AdHocTrends/MobileControl AdHocTrends/RightRadiusMobile" }, "text": "" }, "type": "ia.input.button" }, { "meta": { "name": "SetTitleSpacer" }, "position": { "basis": "8px" }, "type": "ia.display.label" }, { "custom": { "title": "Set Title" }, "events": { "component": { "onActionPerformed": { "config": { "script": "\tself.view.rootContainer.toggleFunction(self.meta.name, \u0027root/MobileBottomControls/FooterSmall/SetTitle/Title\u0027, self.custom.title)" }, "scope": "G", "type": "script" } } }, "meta": { "name": "SetTitle" }, "position": { "basis": "36px", "shrink": 0 }, "props": { "image": { "icon": { "color": "var(--neutral-70)", "path": "material/text_fields" } }, "primary": false, "style": { "classes": "AdHocTrends/FullRadiusMobile AdHocTrends/MobileControl" }, "text": "" }, "type": "ia.input.button" } ], "meta": { "name": "Controls" }, "position": { "basis": "50px", "shrink": 0 }, "props": { "justify": "center", "style": { "classes": "AdHocTrends/MobileControlBar", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "FooterSmall" }, "props": { "direction": "column", "justify": "flex-end", "style": { "classes": "AdHocTrends/Header", "overflow": "visible" } }, "type": "ia.container.flex" } ], "meta": { "name": "MobileBottomControls" }, "position": { "shrink": 0 }, "propConfig": { "props.breakpoint": { "binding": { "config": { "expression": "{../Body/PowerChart.props.config.responsiveDesignWidth}+2" }, "type": "expr" } } }, "props": { "style": { "maxHeight": "50px", "zIndex": 1 } }, "type": "ia.container.breakpt" }, { "meta": { "name": "Debug" }, "position": { "display": false, "shrink": 0 }, "propConfig": { "props.text": { "binding": { "config": { "expression": "{session.custom.site}" }, "type": "expr" } } }, "type": "ia.display.label" } ], "meta": { "name": "root" }, "props": { "direction": "column", "style": { "overflow": "visible" } }, "scripts": { "customMethods": [ { "name": "toggleFunction", "params": [ "name", "focusElement", "title" ], "script": "\t# toggle just forwards to the open/close methods based on what\u0027s currently selected\n\t# visibility of each feature is based on the name that is stored in the activeControl property\n\tif self.view.custom.activeControl \u003d\u003d name:\n\t\tself.view.rootContainer.closeFunction()\n\telse:\n\t\tself.view.rootContainer.openFunction(name, focusElement, title)\n\t\t" }, { "name": "closeFunction", "params": [], "script": "\tself.view.custom.activeControl \u003d None\n\tself.view.custom.functionTitle \u003d \u0027\u0027" }, { "name": "openFunction", "params": [ "name", "focusElement", "title" ], "script": "\tself.view.custom.activeControl \u003d name\n\tself.view.custom.functionTitle \u003d title\n\t\n\t# special case for auto focusing specific elements when opened\n\t# currently used for title and rate \n\t# a delay was necessary in order to allow the input component to become visible first, before focusing\n\tif focusElement:\n\t\timport threading\n\t\tdef focusWorker():\n\t\t\tself.view.getChild(focusElement).focus()\n\t\tthreading.Timer(0.3, focusWorker).start()" }, { "name": "setTitle", "params": [ "title" ], "script": "\t# sets or hides the title of the chart\n\t# if you simply set it to empty,\n\t# it still includes some extra whitespace where the title would be\n\tif title:\n\t\tself.view.getChild(\u0027root/Body/PowerChart\u0027).props.title.text \u003d title\n\t\tself.view.getChild(\u0027root/Body/PowerChart\u0027).props.title.visible \u003d True\n\telse:\n\t\tself.view.getChild(\u0027root/Body/PowerChart\u0027).props.title.text \u003d \u0027\u0027\n\t\tself.view.getChild(\u0027root/Body/PowerChart\u0027).props.title.visible \u003d False" }, { "name": "setRate", "params": [ "rate" ], "script": "\tself.view.getChild(\u0027root/Body/PowerChart\u0027).props.config.refreshRate \u003d rate" }, { "name": "saveToFile", "params": [ "includePlots", "includeDisplay" ], "script": "\tconfig \u003d self.view.rootContainer.getConfigJson(includePlots, includeDisplay)\n\tsystem.perspective.download(\u0027chartsettings.json\u0027, config)\n" }, { "name": "loadFromFile", "params": [ "config", "includePlots", "includeDisplay" ], "script": "\t# save files are split into two sections -\n\t# the configured plots (pens/axes/plots) and the overall display settings (legends/columns)\n\n\tif config:\n\t\tif isinstance(config, str) or isinstance(config, unicode):\n\t\t\tconfig \u003d system.util.jsonDecode(config.decode(\u0027utf-8\u0027))\n\t\tconfig \u003d self.view.rootContainer.propertyTreeRestoreDate(config)\n\t\t\n\t\tpowerChart \u003d self.view.getChild(\u0027root/Body/PowerChart\u0027)\n\t\tif includePlots:\n\t\t\tif \u0027config\u0027 in config:\n\t\t\t\tpowerChart.props.config \u003d config[\u0027config\u0027]\n\t\t\t\t\n\t\t\tif \u0027axes\u0027 in config:\n\t\t\t\tpowerChart.props.axes \u003d config[\u0027axes\u0027]\n\t\t\tif \u0027pens\u0027 in config:\n\t\t\t\tpowerChart.props.pens \u003d config[\u0027pens\u0027]\n\t\t\tif \u0027plots\u0027 in config:\n\t\t\t\tpowerChart.props.plots \u003d config[\u0027plots\u0027]\n\t\t\tif \u0027title\u0027 in config:\n\t\t\t\tpowerChart.props.title \u003d config[\u0027title\u0027]\n\t\t\t\n\t\tif includeDisplay:\n\t\t\tif \u0027timeAxis\u0027 in config:\n\t\t\t\tpowerChart.props.timeAxis \u003d config[\u0027timeAxis\u0027]\n\t\t\tif \u0027interaction\u0027 in config:\n\t\t\t\t# range brushes are not currently writable through the property tree\n\t\t\t\tconfig[\u0027interaction\u0027][\u0027rangeBrush\u0027][\u0027values\u0027] \u003d []\n\t\t\t\tpowerChart.props.interaction \u003d config[\u0027interaction\u0027]\n\t\t\tif \u0027dataColumns\u0027 in config:\n\t\t\t\tpowerChart.props.dataColumns \u003d config[\u0027dataColumns\u0027]\n\t\t\tif \u0027legend\u0027 in config:\n\t\t\t\tpowerChart.props.legend \u003d config[\u0027legend\u0027]\n" }, { "name": "togglePause", "params": [], "script": "\t# this will store the current refresh rate before setting it to 0 so it can be unpaused later\n\tpowerChart \u003d self.view.getChild(\u0027root/Body/PowerChart\u0027)\n\tif powerChart.props.config.refreshRate \u003d\u003d 0:\n\t\tself.view.rootContainer.setRate(self.view.custom.refreshRate)\n\telse:\n\t\tself.view.custom.refreshRate \u003d powerChart.props.config.refreshRate\n\t\tself.view.rootContainer.setRate(0)" }, { "name": "configureDatabases", "params": [], "script": "\t# current functionality allows an admin to toggle the available databases\n\t# the list of databases to enable/disable is store in a property until the admin selects \u0027Save\u0027\n\t# based on that list, this function will attempt to enable/disable each one\n\t# enable means there is a matching configs table and the first row has private\u003d0\n\t# disabled means the first row has private\u003d1, or there is no matching configs table \n\t# for enable: this will check for valid connection, create configs table if necessary, or update the existing matching table with private\u003d0\n\t# for disable: this will check for valid connection, update the existing matching table with private\u003d1\n\t# after doing this, we send out a message to open sessions to update their db listing, so they don\u0027t have to manually refresh anything\n\t\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\tfor dbDetailedName in self.view.custom.configureDatabases:\n\t\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d dbDetailedName), False)\n\t\tif not dbInfo:\n\t\t\tlogger.error(\u0027Unable to create configuration table for database \"%s\" because it was not found in database list (view.custom.databases).\u0027 %dbDetailedName)\n\t\t\tcontinue\n\t\t\n\t\tif dbInfo[\u0027Status\u0027] !\u003d \"Valid\":\n\t\t\tlogger.error(\u0027Unable to create configuration table for database \"%s\" because database does not have a valid connection.\u0027 %dbDetailedName)\n\t\t\tcontinue\n\t\t\n\t\tdbEnable \u003d self.view.custom.configureDatabases[dbDetailedName]\n\t\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\t\tdbType \u003d dbInfo[\u0027DBType\u0027]\n\t\t\tdbName \u003d dbInfo[\u0027Name\u0027]\n\t\t\t\n\t\t\ttableExistsQuery \u003d self.view.rootContainer.getTableExistsQuery(dbType)\n\t\t\ttableFormatMatchesQuery \u003d self.view.rootContainer.getTableFormatMatchesQuery(dbType, dbName)\n\t\t\tcreateTableQuery \u003d self.view.rootContainer.getCreateTableQuery(dbType)\n\t\t\tmakeDatabasePrivateQuery \u003d self.view.rootContainer.getMakeDatabasePrivateQuery(dbType)\n\t\t\t\n\t\t\tif not tableExistsQuery or not tableFormatMatchesQuery or not createTableQuery or not makeDatabasePrivateQuery:\n\t\t\t\tlogger.error(\u0027Unable to create configuration table for sql database \"%s\" because it is an unknown database type \"%s\".\u0027 %(dbInfo[\u0027Name\u0027], dbType))\n\t\t\t\tcontinue\n\t\t\t\n\t\t\ttableExists \u003d system.db.runScalarPrepQuery(tableExistsQuery, None, dbInfo[\u0027Name\u0027])\n\t\t\t\n\t\t\tif dbEnable:\n\t\t\t\tif tableExists:\n\t\t\t\t\ttableFormatMatches \u003d system.db.runScalarPrepQuery(tableFormatMatchesQuery, None, dbInfo[\u0027Name\u0027])\n\t\t\t\t\tif tableFormatMatches:\n\t\t\t\t\t\tsystem.db.runPrepUpdate(makeDatabasePrivateQuery, [False, False], dbInfo[\u0027Name\u0027])\n\t\t\t\t\t\tlogger.info(\u0027Enabled sql database \"%s\"\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\t\t\telse:\n\t\t\t\t\t\tlogger.error(\u0027Unable to create configuration table for sql database \"%s\" because configuration table but does not match expected format [id,user,public,config, config_name,timestamp].\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\t\telse:\n\t\t\t\t\tsystem.db.runPrepUpdate(createTableQuery, None, dbInfo[\u0027Name\u0027])\n\t\t\t\t\tlogger.info(\u0027Created configuration table for sql database \"%s\"\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\t\t\tsystem.db.runPrepUpdate(makeDatabasePrivateQuery, [False, False], dbInfo[\u0027Name\u0027])\n\t\t\t\t\tlogger.info(\u0027Enabled sql database \"%s\"\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\telse:\n\t\t\t\tif tableExists:\n\t\t\t\t\ttableFormatMatches \u003d system.db.runScalarPrepQuery(tableFormatMatchesQuery, None, dbInfo[\u0027Name\u0027])\n\t\t\t\t\tif tableFormatMatches:\n\t\t\t\t\t\tsystem.db.runPrepUpdate(makeDatabasePrivateQuery, [True, True], dbInfo[\u0027Name\u0027])\n\t\t\t\t\t\tlogger.info(\u0027Disabled sql database \"%s\"\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\t\t\telse:\n\t\t\t\t\t\tlogger.error(\u0027Unable to create configuration table for sql database \"%s\" because configuration table but does not match expected format [id,user,public,config, config_name,timestamp].\u0027 %dbInfo[\u0027Name\u0027])\n\t\t\t\telse:\n\t\t\t\t\t# ad hoc trends config table does not exist, so there is no change needed\n\t\t\t\t\tpass\n\t\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\t\t# collection exists\n\t\t\t# upsert\n\t\t\tif dbEnable:\n\t\t\t\tsystem.mongodb.updateOne(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: \u0027config\u0027}, {\u0027$set\u0027: {\u0027Enabled\u0027: True}}, {\u0027upsert\u0027: True})\n\t\t\telse:\n\t\t\t\tsystem.mongodb.updateOne(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: \u0027config\u0027}, {\u0027$set\u0027: {\u0027Enabled\u0027: False}}, {\u0027upsert\u0027: True})\n\t\t\t\n\n\tfor session in filter(lambda x: x.sessionScope !\u003d \u0027designer\u0027, system.perspective.getSessionInfo()):\n\t\tsystem.perspective.sendMessage(\u0027ad_hoc_trends_databaseReconfigured\u0027, {}, \u0027session\u0027, session.id)" }, { "name": "databaseEnabled", "params": [ "dbName", "connector" ], "script": "\t# enable means there is a matching configs table and the first row has private\u003d0\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\tsystem.perspective.print(repr([\u0027dbName\u0027, dbName, \u0027connector\u0027, connector]))\n\tif connector \u003d\u003d \u0027sql\u0027:\n\t\tdbInfo \u003d system.db.getConnectionInfo(dbName)\n\t\tif not dbInfo:\n\t\t\tlogger.error(\u0027Unable to check if database \"%s\" is enabled because it was not found in database connection list (system.db.getConnectionInfo).\u0027 %dbName)\n\t\t\treturn False\n\t\n\t\tdbType \u003d dbInfo.getValueAt(0, \u0027DBType\u0027)\n\t\t\n\t\ttableExistsQuery \u003d self.view.rootContainer.getTableExistsQuery(dbType)\n\t\ttableFormatMatchesQuery \u003d self.view.rootContainer.getTableFormatMatchesQuery(dbType, dbName)\n\t\tdatabaseEnabledQuery \u003d self.view.rootContainer.getDatabaseEnabledQuery(dbType)\n\t\t\n\t\tif not tableExistsQuery or not tableFormatMatchesQuery or not databaseEnabledQuery:\n\t\t\tlogger.debug(\u0027Unable to check if database \"%s\" is enabled because it is an unknown database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\tsystem.perspective.print(\u0027False\u0027)\n\t\t\treturn False\n\t\n\t\tcheck1 \u003d bool(system.db.runScalarPrepQuery(tableExistsQuery, None, dbName))\n\t\tcheck2 \u003d bool(system.db.runScalarPrepQuery(tableFormatMatchesQuery, None, dbName))\n\t\tcheck3 \u003d bool(system.db.runScalarPrepQuery(databaseEnabledQuery, None, dbName))\n\t\tsystem.perspective.print(\"check1: {}, check2: {}, check3: {}\".format(check1, check2, check3))\n\t\treturn check1 and \\\n\t\t\t\tcheck2 and \\\n\t\t\t\tcheck3\n\t\t\n#\t\treturn bool(system.db.runScalarPrepQuery(tableExistsQuery, None, dbName)) and \\\n#\t\t\tbool(system.db.runScalarPrepQuery(tableFormatMatchesQuery, None, dbName)) and \\\n#\t\t\tbool(system.db.runScalarPrepQuery(databaseEnabledQuery, None, dbName))\n\t\t\t\n\telif connector \u003d\u003d \u0027mongodb\u0027:\n\t\tcollections \u003d system.mongodb.listCollectionNames(dbName)\n\t\t\n\t\tif \u0027ad_hoc_trends_config\u0027 in collections:\n\t\t\tdoc \u003d system.mongodb.findOne(dbName, \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: \u0027config\u0027})\n\t\t\tif doc and doc[\u0027Enabled\u0027]:\n\t\t\t\treturn True\n\t\t\n\t\treturn False" }, { "name": "getCharts", "params": [ "dbName" ], "script": "\t# get any chart created by this user or any chart made available publicly (null user or private\u003d0)\n\tif not dbName:\n\t\treturn system.dataset.toPyDataSet(system.dataset.toDataSet([\u0027id\u0027, \u0027username\u0027, \u0027config_name\u0027, \u0027private\u0027, \u0027config\u0027, \u0027t_stamp\u0027], []))\n\t\n\tusername \u003d self.session.props.auth.user.userName\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d dbName), False)\n\tif not dbInfo:\n\t\tlogger.error(\u0027Unable to load charts of database \"%s\" because it was not found in database list (view.custom.databases).\u0027 %dbName)\n\t\treturn\n\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\tdbType \u003d dbInfo[\u0027DBType\u0027]\n\t\t\n\t\tavailableChartsQuery \u003d self.view.rootContainer.getAvailableChartsQuery(dbType)\n\t\t\n\t\tif not availableChartsQuery:\n\t\t\tlogger.debug(\u0027Unable to load charts of database \"%s\" because it is an unknown database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\treturn system.dataset.toPyDataSet(system.dataset.toDataSet([\u0027id\u0027, \u0027username\u0027, \u0027config_name\u0027, \u0027private\u0027, \u0027config\u0027, \u0027t_stamp\u0027], []))\n\t\t\n\t\treturn system.db.runPrepQuery(availableChartsQuery, [username], dbInfo[\u0027Name\u0027])\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\treturn system.mongodb.find(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\n\t\t\t\u0027$and\u0027: [\n\t\t\t\t{\u0027$or\u0027: [{\u0027username\u0027: username}, {\u0027username\u0027: None}, {\u0027private\u0027: False}]},\n\t\t\t\t{\u0027_id\u0027: {\u0027$ne\u0027: \u0027config\u0027}}]\n\t\t})\n" }, { "name": "getOwnCharts", "params": [ "dbName" ], "script": "\t# only returns the list of charts created by this user, or ones created globally (null user)\n\t# used for the saving feature, so that you don\u0027t edit someone else\u0027s charts\n\tif not dbName:\n\t\treturn system.dataset.toPyDataSet(system.dataset.toDataSet([\u0027id\u0027, \u0027username\u0027, \u0027config_name\u0027, \u0027private\u0027, \u0027config\u0027, \u0027t_stamp\u0027], []))\n\t\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d dbName), False)\n\tif not dbInfo:\n\t\tlogger.error(\u0027Unable to load charts of database \"%s\" because it was not found in database list (view.custom.databases).\u0027 %dbName)\n\t\treturn\n\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\tdbType \u003d dbInfo[\u0027DBType\u0027]\n\t\t\n\t\townChartsQuery \u003d self.view.rootContainer.getOwnChartsQuery(dbType)\n\t\t\n\t\tif not ownChartsQuery:\n\t\t\tlogger.debug(\u0027Unable to load charts of database \"%s\" because it is an unknown database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\treturn system.dataset.toPyDataSet(system.dataset.toDataSet([\u0027id\u0027, \u0027username\u0027, \u0027config_name\u0027, \u0027private\u0027, \u0027config\u0027, \u0027t_stamp\u0027], []))\n\t\t\n\t\treturn system.db.runPrepQuery(ownChartsQuery, [self.session.props.auth.user.userName], dbInfo[\u0027Name\u0027])\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\treturn\tsystem.mongodb.find(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\n\t\t\t\u0027$and\u0027: [\n\t\t\t\t{\u0027$or\u0027: [{\u0027username\u0027: self.session.props.auth.user.userName}, {\u0027username\u0027: None}]},\n\t\t\t\t{\u0027_id\u0027: {\u0027$ne\u0027: \u0027config\u0027}}]\n\t\t})\n" }, { "name": "loadFromDb", "params": [ "dbName", "configId", "includePlots", "includeDisplay" ], "script": "\tif not dbName or not configId:\n\t\treturn\n\t\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d dbName), False)\n\tif not dbInfo:\n\t\tlogger.error(\u0027Unable to load chart configuration from database \"%s\" because it was not found in database list (view.custom.databases).\u0027 %dbName)\n\t\treturn\n\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\tdbType \u003d dbInfo[\u0027DBType\u0027]\n\t\t\n\t\tchartConfigQuery \u003d self.view.rootContainer.getChartConfigQuery(dbType)\n\t\tif not chartConfigQuery:\n\t\t\tlogger.debug(\u0027Unable to load chart configuration from database \"%s\" because it is an unknown sql database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\treturn\n\t\t\n\t\tself.view.rootContainer.loadFromFile(system.db.runScalarPrepQuery(chartConfigQuery, [configId], dbInfo[\u0027Name\u0027]), includePlots, includeDisplay)\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\tfrom system.mongodb.types import ObjectId\n\t\tconfigDoc \u003d system.mongodb.findOne(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: ObjectId(configId)})\n\t\tif configDoc:\n\t\t\tself.view.rootContainer.loadFromFile(configDoc[\u0027config\u0027], includePlots, includeDisplay)\n\t\n\t\n\t" }, { "name": "saveToDb", "params": [ "dbName", "configId", "includePlots", "includeDisplay", "private", "favorite", "newChart" ], "script": "\tif not dbName or not configId:\n\t\treturn\n\t\n\t# configId will either be a unique id (newChart \u003d\u003d False) or the name for a new chart (newChart \u003d\u003d True)\n\t\n\tlogger \u003d system.util.getLogger(\u0027Ad Hoc Trends\u0027)\n\t\n\tconfigJson \u003d self.view.rootContainer.getConfigJson(includePlots, includeDisplay)\n\tusername \u003d self.session.props.auth.user.userName\n\tdbInfo \u003d next((d for d in self.view.custom.databases if \u0027%s:%s\u0027 %(d.connector, d.Name) \u003d\u003d dbName), False)\n\tif not dbInfo:\n\t\tlogger.error(\u0027Unable to save chart configuration to database \"%s\" because it was not found in database list (view.custom.databases).\u0027 %dbName)\n\t\treturn\n\n\tif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\tdbType \u003d dbInfo[\u0027DBType\u0027]\n\n\t\tif newChart:\n\t\t\tinsertChartConfigQuery \u003d self.view.rootContainer.getInsertChartConfigQuery(dbType)\n\t\t\tif not insertChartConfigQuery:\n\t\t\t\tlogger.debug(\u0027Unable to save chart configuration to database \"%s\" because it is an unknown database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\t\treturn\n\t\t\t\t\n\t\t\tnewId \u003d system.db.runPrepUpdate(insertChartConfigQuery, [configJson, configId, private, favorite, username], dbInfo[\u0027Name\u0027], getKey\u003d1)\n\t\t\tif favorite:\n\t\t\t\tupdateFavoritesQuery \u003d self.view.rootContainer.getUpdateFavoritesQuery(dbType)\n\t\t\t\tsystem.db.runPrepUpdate(updateFavoritesQuery, [newId, username], dbInfo[\u0027Name\u0027])\n\t\t\t\n\t\t\tlogger.debug(\u0027Saved new chart configuration to database \"%s\"\u0027 %dbName)\n\t\t\t\n\t\telse:\n\t\t\tupdateChartConfigQuery \u003d self.view.rootContainer.getUpdateChartConfigQuery(dbType)\n\t\t\tif not updateChartConfigQuery:\n\t\t\t\tlogger.debug(\u0027Unable to save chart configuration to database \"%s\" because it is an unknown database type \"%s\".\u0027 %(dbName, dbType))\n\t\t\t\treturn\n\t\t\t\t\n\t\t\tsystem.db.runPrepUpdate(updateChartConfigQuery, [configJson, username, private, username, favorite, configId], dbInfo[\u0027Name\u0027])\n\t\t\tif favorite:\n\t\t\t\tupdateFavoritesQuery \u003d self.view.rootContainer.getUpdateFavoritesQuery(dbType)\n\t\t\t\tsystem.db.runPrepUpdate(updateFavoritesQuery, [configId, username], dbInfo[\u0027Name\u0027])\n\t\t\t\n\t\t\tlogger.debug(\u0027Updated chart configuration in database \"%s\"\u0027 %dbName)\n\telif dbInfo[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\tfrom system.mongodb.types import ObjectId\n\t\tif newChart:\n\t\t\tsystem.mongodb.updateOne(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: ObjectId.get()}, {\u0027$set\u0027: {\u0027config\u0027: system.util.jsonDecode(configJson), \u0027configName\u0027: configId, \u0027private\u0027: private, \u0027favorite\u0027: favorite, \u0027username\u0027: username}}, {\u0027upsert\u0027: True})\n\t\telse:\n\t\t\tsystem.mongodb.updateOne(dbInfo[\u0027Name\u0027], \u0027ad_hoc_trends_config\u0027, {\u0027_id\u0027: ObjectId(configId)}, {\u0027$set\u0027: {\u0027config\u0027: system.util.jsonDecode(configJson), \u0027private\u0027: private, \u0027favorite\u0027: favorite, \u0027username\u0027: username}}, {\u0027upsert\u0027: True})\n\t" }, { "name": "getConfigJson", "params": [ "includePlots", "includeDisplay" ], "script": "\tconfig \u003d {}\n\tpowerChart \u003d self.view.getChild(\u0027root/Body/PowerChart\u0027)\n\n\t# added a deepcopy utility that includes an option to convert Date to Instant format string\n\n\tif includePlots:\n\t\tconfig[\u0027config\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.config, True)\n\t\tconfig[\u0027axes\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.axes, True)\n\t\tconfig[\u0027pens\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.pens, True)\n\t\tconfig[\u0027plots\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.plots, True)\n\t\tconfig[\u0027title\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.title, True)\n\t\t\n\tif includeDisplay:\n\t\tconfig[\u0027timeAxis\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.timeAxis, True)\n\n\t\tconfig[\u0027interaction\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.interaction, True)\n\t\t\n\t\tconfig[\u0027dataColumns\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.dataColumns, True)\n\t\tconfig[\u0027legend\u0027] \u003d self.view.rootContainer.propertyDeepcopy(powerChart.props.legend, True)\n\t\n\t# this method easily converts the perspective property trees into json\n\t# using str() of the property itself can include various parts that are not json compatible\n\tif config:\n\t\tfrom com.inductiveautomation.ignition.common import TypeUtilities\n\t\treturn str(TypeUtilities.pyToGson(config))\n\treturn \u0027{}\u0027" }, { "name": "getTableExistsQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT EXISTS(\n\t\t\tSELECT\n\t\t\t\t*\n\t\t\tFROM\n\t\t\t\tinformation_schema.tables\n\t\t\tWHERE\n\t\t\t\ttable_schema NOT IN (\u0027information_schema\u0027, \u0027pg_catalog\u0027) AND\n\t\t\t\ttable_type \u003d \u0027BASE TABLE\u0027 AND\n\t\t\t\ttable_name \u003d \u0027ad_hoc_trends_config\u0027)\u0027\u0027\u0027\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT EXISTS(\n\t\t\tSELECT\n\t\t\t\t*\n\t\t\tFROM\n\t\t\t\tsqlite_master\n\t\t\tWHERE\n\t\t\t\ttype\u003d\u0027table\u0027 AND\n\t\t\t\tname\u003d\u0027ad_hoc_trends_config\u0027)\u0027\u0027\u0027\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT EXISTS(\n\t\t\tSELECT\n\t\t\t\t*\n\t\t\tFROM\n\t\t\t\tinformation_schema.tables\n\t\t\tWHERE\n\t\t\t\ttable_name \u003d \u0027ad_hoc_trends_config\u0027)\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tCASE WHEN EXISTS \n\t\t\t(\n\t\t\t\tSELECT * \n\t\t\t\tFROM INFORMATION_SCHEMA.TABLES\n\t\t\t\tWHERE TABLE_TYPE \u003d \u0027BASE TABLE\u0027\n\t\t\t\tAND TABLE_NAME \u003d \u0027ad_hoc_trends_config\u0027\n\t\t\t)\n\t\t\t\tTHEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tcount(*)\n\t\tFROM\n\t\t\tdba_tables\n\t\tWHERE\n\t\t\ttable_name \u003d \u0027AD_HOC_TRENDS_CONFIG\u0027\n\t\t\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getDatabaseEnabledQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tprivate \u003d false\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d 0\u0027\u0027\u0027\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tprivate \u003d false\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d 0\u0027\u0027\u0027\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\t# by deafult, MySQL will auto increment when you try to set an auto increment column to 0 on INSERT.\n\t\t# using -1 here instead\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tprivate \u003d false\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d -1\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tCOUNT(*)\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\t\u0027\u0027\u0027\n#\t\tSELECT\n#\t\t\tCASE WHEN private \u003d 1\n#\t\t\t\tTHEN 1\n#\t\t\t\tELSE 0\n#\t\t\tEND\n#\t\tFROM\n#\t\t\tad_hoc_trends_config\n#\t\tWHERE\n#\t\t\tid \u003d 0\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tCASE WHEN private \u003d 0\n\t\t\t\tTHEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\n\t\tFROM\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tWHERE\n\t\t\tid \u003d 0\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getTableFormatMatchesQuery", "params": [ "dbType", "dbName" ], "script": "\tsystem.perspective.print(\u0027dbType: {}\u0027.format(dbType))\n\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tcount(*) \u003d 7\n\t\tFROM\n\t\t\tinformation_schema.columns\n\t\tWHERE\n\t\t\ttable_name \u003d \u0027ad_hoc_trends_config\u0027 AND\n\t\t\tcolumn_name IN (\u0027id\u0027,\u0027username\u0027,\u0027config_name\u0027,\u0027private\u0027,\u0027config\u0027,\u0027t_stamp\u0027,\u0027favorite\u0027)\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tcount(*) \u003d 7\n\t\tFROM\n\t\t\tpragma_table_info(\u0027ad_hoc_trends_config\u0027)\n\t\tWHERE\n\t\t\tname IN (\u0027id\u0027,\u0027username\u0027,\u0027config_name\u0027,\u0027private\u0027,\u0027config\u0027,\u0027t_stamp\u0027,\u0027favorite\u0027)\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tcount(*) \u003d 7\n\t\tFROM\n\t\t\tinformation_schema.columns\n\t\tWHERE\n\t\t\ttable_schema \u003d \u0027{}\u0027 AND \n\t\t\ttable_name \u003d \u0027ad_hoc_trends_config\u0027 AND\n\t\t\tcolumn_name IN (\u0027id\u0027,\u0027username\u0027,\u0027config_name\u0027,\u0027private\u0027,\u0027config\u0027,\u0027t_stamp\u0027,\u0027favorite\u0027)\u0027\u0027\u0027.format(dbName)\n\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tCASE WHEN COUNT(*) \u003d 7\n\t\t\t\tTHEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\n\t\tFROM\n\t\t\tinformation_schema.columns\n\t\tWHERE\n\t\t\tTABLE_NAME \u003d \u0027ad_hoc_trends_config\u0027 AND\n\t\t\tCOLUMN_NAME IN (\u0027id\u0027,\u0027username\u0027,\u0027config_name\u0027,\u0027private\u0027,\u0027config\u0027,\u0027t_stamp\u0027,\u0027favorite\u0027)\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tCASE WHEN COUNT(*) \u003d 7\n\t\t\t\tTHEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\n\t\tFROM\n\t\t\tall_tab_cols\n\t\tWHERE\n\t\t\tTABLE_NAME \u003d \u0027AD_HOC_TRENDS_CONFIG\u0027 AND\n\t\t\tCOLUMN_NAME IN (\u0027ID\u0027,\u0027USERNAME\u0027,\u0027CONFIG_NAME\u0027,\u0027PRIVATE\u0027,\u0027CONFIG\u0027,\u0027T_STAMP\u0027,\u0027FAVORITE\u0027)\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getCreateTableQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tCREATE TABLE ad_hoc_trends_config(\n\t\t\tid SERIAL PRIMARY KEY,\n\t\t\tusername text,\n\t\t\tconfig_name text,\n\t\t\tprivate boolean,\n\t\t\tconfig text,\n\t\t\tt_stamp timestamp DEFAULT CURRENT_TIMESTAMP,\n\t\t\tCONSTRAINT name UNIQUE(username, config_name)\n\t\t)\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tCREATE TABLE ad_hoc_trends_config(\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\tusername TEXT,\n\t\t\tconfig_name TEXT,\n\t\t\tprivate INTEGER,\n\t\t\tconfig TEXT,\n\t\t\tt_stamp TEXT DEFAULT CURRENT_TIMESTAMP,\n\t\t\tUNIQUE(username, config_name)\n\t\t)\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tCREATE TABLE ad_hoc_trends_config(\n\t\t\tid INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,\n\t\t\tusername VARCHAR(255),\n\t\t\tconfig_name VARCHAR(255),\n\t\t\tprivate BOOLEAN,\n\t\t\tconfig TEXT,\n\t\t\tt_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n\t\t\tCONSTRAINT name UNIQUE(username, config_name)\n\t\t)\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tCREATE TABLE ad_hoc_trends_config(\n\t\t\tid INT NOT NULL PRIMARY KEY IDENTITY(1, 1),\n\t\t\tusername VARCHAR(255),\n\t\t\tconfig_name VARCHAR(255),\n\t\t\tprivate BIT,\n\t\t\tconfig TEXT,\n\t\t\tt_stamp DATETIME DEFAULT CURRENT_TIMESTAMP,\n\t\t\tCONSTRAINT name UNIQUE(username, config_name)\n\t\t)\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tCREATE TABLE ad_hoc_trends_config(\n\t\t\tid NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,\n\t\t username VARCHAR(255),\n\t\t config_name VARCHAR(255),\n\t\t private NUMBER,\n\t\t config NCLOB,\n\t\t t_stamp DATE DEFAULT CURRENT_TIMESTAMP,\n\t\t CONSTRAINT name UNIQUE(username, config_name)\n\t\t)\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getMakeDatabasePrivateQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO ad_hoc_trends_config\n\t\t\t(id, config, config_name, private, username)\n\t\tVALUES\n\t\t\t(0, null, null, ?, null) \n\t\tON CONFLICT (id) \n\t\tDO UPDATE\n\t\t\tSET\n\t\t\t\tprivate \u003d ?\n\t\t\tWHERE\n\t\t\t\tad_hoc_trends_config.id \u003d 0\n\t\t\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\t# using ? AND ? here to use up to arguments, matching the other SQL queries\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT OR REPLACE INTO ad_hoc_trends_config\n\t\t\t(id, config, config_name, private, username)\n\t\tVALUES\n\t\t\t(0, null, null, ? AND ?, null)\n\t\t\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO ad_hoc_trends_config\n\t\t\t\t\t(id, config, config_name, private, username)\n\t\t\t\tVALUES\n\t\t\t\t\t(-1, null, null, ?, null) \n\t\t\t\tON DUPLICATE KEY UPDATE\n\t\t\t\t\tprivate \u003d ?\n\t\t\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tBEGIN TRAN\n\t\t\tUPDATE ad_hoc_trends_config\n\t\t\tWITH (SERIALIZABLE)\n\t\t\tSET private \u003d ?\n\t\t\tWHERE id \u003d 0\n\t\t\t\n\t\t\tIF @@rowcount \u003d 0\n\t\t\tBEGIN\n\t\t\t\tSET IDENTITY_INSERT ad_hoc_trends_config ON\n\t\t\t\tINSERT INTO ad_hoc_trends_config\n\t\t\t\t(id, config, config_name, private, username)\n\t\t\t\tVALUES\n\t\t\t\t(0, null, null, ?, null)\n\t\t\t\tSET IDENTITY_INSERT ad_hoc_trends_config OFF\n\t\t\tEND\n\t\tCOMMIT TRAN\n\t\t\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tMERGE INTO AD_HOC_TRENDS_CONFIG a\n\t\t\tUSING (SELECT 0 AS ID FROM DUAL d) d\n\t\t\tON (a.ID \u003d d.ID)\n\t\t\tWHEN MATCHED THEN UPDATE SET a.PRIVATE \u003d ?\n\t\t\tWHEN NOT MATCHED THEN INSERT (ID, CONFIG, CONFIG_NAME, PRIVATE, USERNAME) VALUES (0, null, null, ?, null)\n\t\t\u0027\u0027\u0027\n\t\t\n\treturn \u0027\u0027" }, { "name": "getAvailableChartsQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR \n\t\t\t(private \u003d FALSE) OR \n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR \n\t\t\t(private \u003d FALSE) OR \n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR \n\t\t\t(private \u003d FALSE) OR \n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR \n\t\t\t(private \u003d \u0027FALSE\u0027) OR \n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid as \"id\",\n\t\t\tusername as \"username\",\n\t\t\tconfig_name as \"config_name\",\n\t\t\tfavorite as \"favorite\"\n\t\tFROM\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tWHERE\n\t\t\t((USERNAME IS NULL) OR \n\t\t\t(PRIVATE \u003d 0) OR \n\t\t\t(USERNAME \u003d ?)) AND\n\t\t\tID \u003e 0\u0027\u0027\u0027\n\n\t\n\treturn \u0027\u0027" }, { "name": "getOwnChartsQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR\n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR\n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR\n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name,\n\t\t\tfavorite\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\t((username IS NULL) OR\n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid as \"id\",\n\t\t\tusername as \"username\",\n\t\t\tconfig_name as \"config_name\",\n\t\t\tfavorite as \"favorite\"\n\t\tFROM\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tWHERE\n\t\t\t((username IS NULL) OR\n\t\t\t(username \u003d ?)) AND\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getFavoriteChartQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tusername \u003d ? AND\n\t\t\tfavorite \u003d TRUE\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tusername \u003d ? AND\n\t\t\tfavorite \u003d TRUE\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tusername \u003d ? AND\n\t\t\tfavorite \u003d TRUE\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid,\n\t\t\tusername,\n\t\t\tconfig_name\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tusername \u003d ? AND\n\t\t\tfavorite \u003d TRUE\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tid as \"id\",\n\t\t\tusername as \"username\",\n\t\t\tconfig_name as \"config_name\"\n\t\tFROM\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tWHERE\n\t\t\tusername \u003d ? AND\n\t\t\tfavorite \u003d 1\n\t\t\tid \u003e 0\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getChartConfigQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tconfig\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tconfig\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tconfig\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tconfig\n\t\tFROM\n\t\t\tad_hoc_trends_config\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tSELECT\n\t\t\tconfig as \"config\"\n\t\tFROM\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getInsertChartConfigQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO\n\t\t\tad_hoc_trends_config\n\t\t\t(config, config_name, private, favorite, username)\n\t\tVALUES\n\t\t\t(?, ?, ?, ?, ?)\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO\n\t\t\tad_hoc_trends_config\n\t\t\t(config, config_name, private, favorite, username)\n\t\tVALUES\n\t\t\t(?, ?, ?, ?, ?)\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO\n\t\t\tad_hoc_trends_config\n\t\t\t(config, config_name, private, favorite, username)\n\t\tVALUES\n\t\t\t(?, ?, ?, ?, ?)\u0027\u0027\u0027\n\t\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO\n\t\t\tad_hoc_trends_config\n\t\t\t(config, config_name, private, favorite, username)\n\t\tVALUES\n\t\t\t(?, ?, ?, ?, ?)\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tINSERT INTO\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\t\t(config, config_name, private, favorite, username)\n\t\tVALUES\n\t\t\t(?, ?, ?, ?, ?)\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getUpdateChartConfigQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tconfig \u003d ?,\n\t\t\tprivate \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE private\n\t\t\tEND, \n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE favorite\n\t\t\tEND, \n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tconfig \u003d ?,\n\t\t\tprivate \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE private\n\t\t\tEND, \n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE favorite\n\t\t\tEND\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tconfig \u003d ?,\n\t\t\tprivate \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE private\n\t\t\tEND, \n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE favorite\n\t\t\tEND\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tconfig \u003d ?,\n\t\t\tprivate \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE private\n\t\t\tEND, \n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE favorite\n\t\t\tEND\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tSET\n\t\t\tconfig \u003d ?,\n\t\t\tprivate \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE private\n\t\t\tEND, \n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN username \u003d ? THEN ?\n\t\t\t\tELSE favorite\n\t\t\tEND\n\t\tWHERE\n\t\t\tid \u003d ?\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "getUpdateFavoritesQuery", "params": [ "dbType" ], "script": "\tif dbType \u003d\u003d \u0027POSTGRES\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN id \u003d ? THEN TRUE\n\t\t\t\tELSE FALSE\n\t\t\tEND\n\t\tWHERE\n\t\t\tusername \u003d ?\u0027\u0027\u0027\n\n\telif dbType \u003d\u003d \u0027SQLITE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN id \u003d ? THEN TRUE\n\t\t\t\tELSE FALSE\n\t\t\tEND\n\t\tWHERE\n\t\t\tusername \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027MYSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN id \u003d ? THEN TRUE\n\t\t\t\tELSE FALSE\n\t\t\tEND\n\t\tWHERE\n\t\t\tusername \u003d ?\u0027\u0027\u0027\n\t\n\telif dbType \u003d\u003d \u0027MSSQL\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tad_hoc_trends_config\n\t\tSET\n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN id \u003d ? THEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\n\t\tWHERE\n\t\t\tusername \u003d ?\u0027\u0027\u0027\n\t\t\t\n\telif dbType \u003d\u003d \u0027ORACLE\u0027:\n\t\treturn \u0027\u0027\u0027\n\t\tUPDATE\n\t\t\tAD_HOC_TRENDS_CONFIG\n\t\tSET\n\t\t\tfavorite \u003d CASE\n\t\t\t\tWHEN id \u003d ? THEN 1\n\t\t\t\tELSE 0\n\t\t\tEND\n\t\tWHERE\n\t\t\tusername \u003d ?\u0027\u0027\u0027\n\t\n\treturn \u0027\u0027" }, { "name": "dateToInstant", "params": [ "date" ], "script": "\t# using this to convert Date props into string format that can be stored and easily turned back into Date\n\t# using the type ultility converter to string alone does not work well enough as no timezone is included\n\n\treturn str(date.toInstant())" }, { "name": "dateFromInstant", "params": [ "instant" ], "script": "\t# using this to convert a string in Instant form back to java.util.Date for certain props\n\tfrom java.util import Date\n\tfrom java.time import Instant\n\tif isinstance(instant, basestring):\n\t\treturn Date.from(Instant.parse(instant))\n\treturn Date.from(instant)" }, { "name": "propertyDeepcopy", "params": [ "property", "convertDates\u003dFalse" ], "script": "\t# utility for copying the values from a perspective prop tree\n\t# deepcopy() does not appear to work directly on the prop tree wrapper type\n\t# also converting Date object to Instant format string\n\t\n\timport collections\n\tfrom java.util import Date\n\t\n\tdef copyProperties(node):\n\t\t# perspective arrays and python lists (but not strings)\n\t\tif \u0027PropertyTreeScriptWrapper$ArrayWrapper\u0027 in str(type(node)) or \\\n\t\t(isinstance(node, collections.Sequence) and not isinstance(node, basestring)):\n\t\t\tnodeCopy \u003d []\n\t\t\tfor i in node:\n\t\t\t\tnodeCopy.append(copyProperties(i))\n\t\t\treturn nodeCopy\n\t\t# perspective objects and python dictionaries\n\t\telif \u0027PropertyTreeScriptWrapper$ObjectWrapper\u0027 in str(type(node)) or isinstance(node, collections.Mapping):\n\t\t\tnodeCopy \u003d {}\n\t\t\tfor k in node:\n\t\t\t\tnodeCopy[k] \u003d copyProperties(node[k])\n\t\t\treturn nodeCopy\n\t\t# single value, with optional date conversion\n\t\telse:\n\t\t\tif convertDates and isinstance(node, Date):\n\t\t\t\treturn self.view.rootContainer.dateToInstant(node)\n\t\t\treturn node\n\t\t\t\n\treturn copyProperties(property)" }, { "name": "propertyTreeRestoreDate", "params": [ "propertyTree" ], "script": "\t# creates a new copy of the given property tree, replacing Instant formatted strings with java.util.Date\n\timport collections\n\t\n\tdef convertProperties(node):\n\t\t# perspective arrays and python lists (but not strings)\n\t\tif \u0027PropertyTreeScriptWrapper$ArrayWrapper\u0027 in str(type(node)) or \\\n\t\t(isinstance(node, collections.Sequence) and not isinstance(node, basestring)):\n\t\t\tnodeCopy \u003d []\n\t\t\tfor i in node:\n\t\t\t\tnodeCopy.append(convertProperties(i))\n\t\t\treturn nodeCopy\n\t\t# perspective objects and python dictionaries\n\t\telif \u0027PropertyTreeScriptWrapper$ObjectWrapper\u0027 in str(type(node)) or isinstance(node, collections.Mapping):\n\t\t\tnodeCopy \u003d {}\n\t\t\tfor k in node:\n\t\t\t\tnodeCopy[k] \u003d convertProperties(node[k])\n\t\t\treturn nodeCopy\n\t\t# single value\n\t\telse:\n\t\t\t# this will attempt to convert the string back into Date, otherwise just returns the value\n\t\t\tif isinstance(node, basestring):\n\t\t\t\ttry:\n\t\t\t\t\treturn self.view.rootContainer.dateFromInstant(node)\n\t\t\t\texcept:\n\t\t\t\t\treturn node\n\t\t\treturn node\n\t\t\t\n\treturn convertProperties(propertyTree)" }, { "name": "populateDatabaseDropdown", "params": [ "databases", "filterEnabled" ], "script": "\tif filterEnabled:\n\t\tdbList \u003d []\n\t\tfor db in filter(lambda x: x[\u0027Enabled\u0027], databases):\n\t\t\tif db[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\t\telif db[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, \u0027MongoDB\u0027, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\treturn dbList\n\telse:\n\t\tdbList \u003d []\n\t\tfor db in value:\n\t\t\tif db[\u0027connector\u0027] \u003d\u003d \u0027sql\u0027:\n\t\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, db.DBType, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\t\telif db[\u0027connector\u0027] \u003d\u003d \u0027mongodb\u0027:\n\t\t\t\tdbList.append({\u0027label\u0027: \u0027%s (%s)%s\u0027 %(db.Name, \u0027MongoDB\u0027, \u0027\u0027 if db.Status \u003d\u003d \u0027Valid\u0027 else \u0027[OFFLINE]\u0027), \u0027value\u0027: \u0027%s:%s\u0027 %(db.connector, db.Name)})\n\t\treturn dbList" } ], "extensionFunctions": null, "messageHandlers": [ { "messageType": "ad_hoc_trends_databaseReconfigured", "pageScope": false, "script": "\t# called when someone enables/disables a database\n\t# this way, users don\u0027t have to manually refresh their db listing\n\tself.view.custom.configureDatabases \u003d {}\n\tself.view.refreshBinding(\u0027custom.databases\u0027)\n\tif self.view.custom.activeControl in [\u0027LoadFromDb\u0027, \u0027SaveToDb\u0027]:\n\t\tself.view.rootContainer.closeFunction()", "sessionScope": true, "viewScope": false } ] }, "type": "ia.container.flex" } }