Files
Stream_PHX_A7/Gateways/FE/projects/.resources/1d3296fbc279efe86dc5f5de57d6facdc871a08acf39f9a7a7561a1fcdcc4c9d

6078 lines
263 KiB
Plaintext

{
"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"
}
}