Commit 106ba882936d62f028e8de623967d23d63f9e5dc
1 parent
3e798d13
Add rest of the widget functions help resources. Improved map widgets settings schema.
Showing
25 changed files
with
876 additions
and
64 deletions
... | ... | @@ -163,7 +163,7 @@ |
163 | 163 | "templateHtml": "<tb-qrcode-widget \n [ctx]=\"ctx\">\n</tb-qrcode-widget>", |
164 | 164 | "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}", |
165 | 165 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", |
166 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n", | |
166 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n", | |
167 | 167 | "dataKeySettingsSchema": "{}\n", |
168 | 168 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data[0] ? data[0]['entityName'] : '';\"},\"title\":\"QR Code\"}" |
169 | 169 | } |
... | ... | @@ -181,7 +181,7 @@ |
181 | 181 | "templateHtml": "<tb-markdown-widget \n [ctx]=\"ctx\">\n</tb-markdown-widget>", |
182 | 182 | "templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n", |
183 | 183 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n", |
184 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n }\n ]\n}\n", | |
184 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n }\n ]\n}\n", | |
185 | 185 | "dataKeySettingsSchema": "{}\n", |
186 | 186 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\",\"useMarkdownTextFunction\":false},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" |
187 | 187 | } | ... | ... |
... | ... | @@ -73,7 +73,7 @@ |
73 | 73 | "templateHtml": "<tb-switch [ctx]='ctx'></tb-switch>", |
74 | 74 | "templateCss": "", |
75 | 75 | "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", |
76 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
76 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/convert_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
77 | 77 | "dataKeySettingsSchema": "{}\n", |
78 | 78 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
79 | 79 | } |
... | ... | @@ -91,7 +91,7 @@ |
91 | 91 | "templateHtml": "<tb-round-switch [ctx]='ctx'></tb-round-switch>", |
92 | 92 | "templateCss": "", |
93 | 93 | "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", |
94 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
94 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/convert_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
95 | 95 | "dataKeySettingsSchema": "{}\n", |
96 | 96 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
97 | 97 | } |
... | ... | @@ -109,7 +109,7 @@ |
109 | 109 | "templateHtml": "<tb-led-indicator [ctx]='ctx'></tb-led-indicator>", |
110 | 110 | "templateCss": "", |
111 | 111 | "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", |
112 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
112 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_value_fn\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}", | |
113 | 113 | "dataKeySettingsSchema": "{}\n", |
114 | 114 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
115 | 115 | } |
... | ... | @@ -151,4 +151,4 @@ |
151 | 151 | } |
152 | 152 | } |
153 | 153 | ] |
154 | -} | |
154 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -19,8 +19,8 @@ |
19 | 19 | "templateHtml": "<tb-entities-table-widget \n [ctx]=\"ctx\">\n</tb-entities-table-widget>", |
20 | 20 | "templateCss": "", |
21 | 21 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", |
22 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", | |
23 | - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", | |
22 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", | |
23 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", | |
24 | 24 | "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Device admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Device admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add device\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"addDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"addDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addDeviceForm.invalid || !addDeviceForm.dirty\\\">\\n Create\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddDeviceDialog();\\n\\nfunction openAddDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();\\n}\\n\\nfunction AddDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.addDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addDeviceFormGroup.markAsPristine();\\n let device = {\\n name: vm.addDeviceFormGroup.get('deviceName').value,\\n type: vm.addDeviceFormGroup.get('deviceType').value,\\n label: vm.addDeviceFormGroup.get('deviceLabel').value\\n };\\n deviceService.saveDevice(device).subscribe(\\n function (device) {\\n saveAttributes(device.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit device\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editDeviceForm=\\\"ngForm\\\" [formGroup]=\\\"editDeviceFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit device</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Device name</mat-label>\\n <input matInput formControlName=\\\"deviceName\\\" required>\\n <mat-error *ngIf=\\\"editDeviceFormGroup.get('deviceName').hasError('required')\\\">\\n Device name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"deviceType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'DEVICE'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"deviceLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || editDeviceForm.invalid || !editDeviceForm.dirty\\\">\\n Update\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditDeviceDialog();\\n\\nfunction openEditDeviceDialog() {\\n customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();\\n}\\n\\nfunction EditDeviceDialogController(instance) {\\n let vm = instance;\\n \\n vm.device = null;\\n vm.attributes = {};\\n \\n vm.editDeviceFormGroup = vm.fb.group({\\n deviceName: ['', [vm.validators.required]],\\n deviceType: ['', [vm.validators.required]],\\n deviceLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editDeviceFormGroup.markAsPristine();\\n vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,\\n vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,\\n vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value\\n deviceService.saveDevice(vm.device).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n deviceService.getDevice(entityId.id).subscribe(\\n function (device) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.device = device;\\n vm.editDeviceFormGroup.patchValue(\\n {\\n deviceName: vm.device.name,\\n deviceType: vm.device.type,\\n deviceLabel: vm.device.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editDeviceFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete device\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\\n\\nopenDeleteDeviceDialog();\\n\\nfunction openDeleteDeviceDialog() {\\n let title = \\\"Are you sure you want to delete the device \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the device and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteDevice();\\n }\\n }\\n );\\n}\\n\\nfunction deleteDevice() {\\n deviceService.deleteDevice(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" |
25 | 25 | } |
26 | 26 | }, |
... | ... | @@ -37,8 +37,8 @@ |
37 | 37 | "templateHtml": "<tb-entities-table-widget \n [ctx]=\"ctx\">\n</tb-entities-table-widget>", |
38 | 38 | "templateCss": "", |
39 | 39 | "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", |
40 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", | |
41 | - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", | |
40 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"reserveSpaceForHiddenAction\": {\n \"title\": \"Hidden cell button actions display mode\",\n \"type\": \"string\",\n \"default\": \"true\"\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n {\n \"key\": \"reserveSpaceForHiddenAction\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"true\",\n \"label\": \"Show empty space instead of hidden cell button action\"\n },\n {\n \"value\": \"false\",\n \"label\": \"Don't reserve space for hidden action buttons\"\n }\n ]\n },\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/row_style_fn\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}", | |
41 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_style_fn\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/entity/cell_content_fn\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}", | |
42 | 42 | "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"entitiesTitle\":\"Asset admin table\",\"enableSelectColumnDisplay\":true},\"title\":\"Asset admin table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{\"headerButton\":[{\"name\":\"Add asset\",\"icon\":\"add\",\"type\":\"customPretty\",\"customHtml\":\"<form #addAssetForm=\\\"ngForm\\\" [formGroup]=\\\"addAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Add asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"addAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n style=\\\"margin-right: 20px;\\\"\\n type=\\\"submit\\\"\\n [disabled]=\\\"(isLoading$ | async) || addAssetForm.invalid || !addAssetForm.dirty\\\">\\n Create\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenAddAssetDialog();\\n\\nfunction openAddAssetDialog() {\\n customDialog.customDialog(htmlTemplate, AddAssetDialogController).subscribe();\\n}\\n\\nfunction AddAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.addAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.addAssetFormGroup.markAsPristine();\\n let asset = {\\n name: vm.addAssetFormGroup.get('assetName').value,\\n type: vm.addAssetFormGroup.get('assetType').value,\\n label: vm.addAssetFormGroup.get('assetLabel').value\\n };\\n assetService.saveAsset(asset).subscribe(\\n function (asset) {\\n saveAttributes(asset.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n function saveAttributes(entityId) {\\n let attributes = vm.addAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, \\\"SERVER_SCOPE\\\", attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"70837a9d-c3de-a9a7-03c5-dccd14998758\"}],\"actionCellButton\":[{\"name\":\"Edit asset\",\"icon\":\"edit\",\"type\":\"customPretty\",\"customHtml\":\"<form #editAssetForm=\\\"ngForm\\\" [formGroup]=\\\"editAssetFormGroup\\\"\\n (ngSubmit)=\\\"save()\\\" style=\\\"width: 480px;\\\">\\n <mat-toolbar fxLayout=\\\"row\\\" color=\\\"primary\\\">\\n <h2>Edit asset</h2>\\n <span fxFlex></span>\\n <button mat-button mat-icon-button\\n (click)=\\\"cancel()\\\"\\n type=\\\"button\\\">\\n <mat-icon class=\\\"material-icons\\\">close</mat-icon>\\n </button>\\n </mat-toolbar>\\n <mat-progress-bar color=\\\"warn\\\" mode=\\\"indeterminate\\\" *ngIf=\\\"isLoading$ | async\\\">\\n </mat-progress-bar>\\n <div style=\\\"height: 4px;\\\" *ngIf=\\\"!(isLoading$ | async)\\\"></div>\\n <div mat-dialog-content>\\n <div class=\\\"mat-padding\\\" fxLayout=\\\"column\\\">\\n <mat-form-field class=\\\"mat-block\\\">\\n <mat-label>Asset name</mat-label>\\n <input matInput formControlName=\\\"assetName\\\" required>\\n <mat-error *ngIf=\\\"editAssetFormGroup.get('assetName').hasError('required')\\\">\\n Asset name is required.\\n </mat-error>\\n </mat-form-field>\\n <div fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <tb-entity-subtype-autocomplete\\n fxFlex=\\\"50\\\"\\n formControlName=\\\"assetType\\\"\\n [required]=\\\"true\\\"\\n [entityType]=\\\"'ASSET'\\\"\\n ></tb-entity-subtype-autocomplete>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Label</mat-label>\\n <input matInput formControlName=\\\"assetLabel\\\">\\n </mat-form-field>\\n </div>\\n <div formGroupName=\\\"attributes\\\" fxLayout=\\\"row\\\" fxLayoutGap=\\\"8px\\\">\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Latitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"latitude\\\">\\n </mat-form-field>\\n <mat-form-field fxFlex=\\\"50\\\" class=\\\"mat-block\\\">\\n <mat-label>Longitude</mat-label>\\n <input type=\\\"number\\\" step=\\\"any\\\" matInput formControlName=\\\"longitude\\\">\\n </mat-form-field>\\n </div>\\n </div> \\n </div>\\n <div mat-dialog-actions fxLayout=\\\"row\\\">\\n <span fxFlex></span>\\n <button mat-button color=\\\"primary\\\"\\n type=\\\"button\\\"\\n [disabled]=\\\"(isLoading$ | async)\\\"\\n (click)=\\\"cancel()\\\" cdkFocusInitial>\\n Cancel\\n </button>\\n <button mat-button mat-raised-button color=\\\"primary\\\"\\n type=\\\"submit\\\"\\n style=\\\"margin-right: 20px;\\\"\\n [disabled]=\\\"(isLoading$ | async) || editAssetForm.invalid || !editAssetForm.dirty\\\">\\n Update\\n </button>\\n </div>\\n</form>\\n\",\"customCss\":\"\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\nlet attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));\\n\\nopenEditAssetDialog();\\n\\nfunction openEditAssetDialog() {\\n customDialog.customDialog(htmlTemplate, EditAssetDialogController).subscribe();\\n}\\n\\nfunction EditAssetDialogController(instance) {\\n let vm = instance;\\n \\n vm.asset = null;\\n vm.attributes = {};\\n \\n vm.editAssetFormGroup = vm.fb.group({\\n assetName: ['', [vm.validators.required]],\\n assetType: ['', [vm.validators.required]],\\n assetLabel: [''],\\n attributes: vm.fb.group({\\n latitude: [null],\\n longitude: [null]\\n }) \\n });\\n \\n vm.cancel = function() {\\n vm.dialogRef.close(null);\\n };\\n \\n vm.save = function() {\\n vm.editAssetFormGroup.markAsPristine();\\n vm.asset.name = vm.editAssetFormGroup.get('assetName').value,\\n vm.asset.type = vm.editAssetFormGroup.get('assetType').value,\\n vm.asset.label = vm.editAssetFormGroup.get('assetLabel').value\\n assetService.saveAsset(vm.asset).subscribe(\\n function () {\\n saveAttributes().subscribe(\\n function () {\\n widgetContext.updateAliases();\\n vm.dialogRef.close(null);\\n }\\n );\\n }\\n );\\n };\\n \\n getEntityInfo();\\n \\n function getEntityInfo() {\\n assetService.getAsset(entityId.id).subscribe(\\n function (asset) {\\n attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',\\n ['latitude', 'longitude']).subscribe(\\n function (attributes) {\\n for (let i = 0; i < attributes.length; i++) {\\n vm.attributes[attributes[i].key] = attributes[i].value; \\n }\\n vm.asset = asset;\\n vm.editAssetFormGroup.patchValue(\\n {\\n assetName: vm.asset.name,\\n assetType: vm.asset.type,\\n assetLabel: vm.asset.label,\\n attributes: {\\n latitude: vm.attributes.latitude,\\n longitude: vm.attributes.longitude\\n }\\n }, {emitEvent: false}\\n );\\n } \\n );\\n }\\n ); \\n }\\n \\n function saveAttributes() {\\n let attributes = vm.editAssetFormGroup.get('attributes').value;\\n let attributesArray = [];\\n for (let key in attributes) {\\n attributesArray.push({key: key, value: attributes[key]});\\n }\\n if (attributesArray.length > 0) {\\n return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);\\n } else {\\n return widgetContext.rxjs.of([]);\\n }\\n }\\n}\",\"customResources\":[],\"id\":\"93931e52-5d7c-903e-67aa-b9435df44ff4\"},{\"name\":\"Delete asset\",\"icon\":\"delete\",\"type\":\"custom\",\"customFunction\":\"let $injector = widgetContext.$scope.$injector;\\nlet dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));\\nlet assetService = $injector.get(widgetContext.servicesMap.get('assetService'));\\n\\nopenDeleteAssetDialog();\\n\\nfunction openDeleteAssetDialog() {\\n let title = \\\"Are you sure you want to delete the asset \\\" + entityName + \\\"?\\\";\\n let content = \\\"Be careful, after the confirmation, the asset and all related data will become unrecoverable!\\\";\\n dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(\\n function (result) {\\n if (result) {\\n deleteAsset();\\n }\\n }\\n );\\n}\\n\\nfunction deleteAsset() {\\n assetService.deleteAsset(entityId.id).subscribe(\\n function () {\\n widgetContext.updateAliases();\\n }\\n );\\n}\\n\",\"id\":\"ec2708f6-9ff0-186b-e4fc-7635ebfa3074\"}]}}" |
43 | 43 | } |
44 | 44 | } | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | "templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\n</fieldset>", |
20 | 20 | "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", |
21 | 21 | "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", |
22 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
22 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\n }\n ]\n}", | |
23 | 23 | "dataKeySettingsSchema": "{}\n", |
24 | 24 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"Basic GPIO Control\"}" |
25 | 25 | } |
... | ... | @@ -73,7 +73,7 @@ |
73 | 73 | "templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\n</fieldset>", |
74 | 74 | "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", |
75 | 75 | "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", |
76 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
76 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/rpc/parse_gpio_status_fn\"\n }\n ]\n}", | |
77 | 77 | "dataKeySettingsSchema": "{}\n", |
78 | 78 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#008a00\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0,\"_uniqueKey\":0},{\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0,\"_uniqueKey\":1},{\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1,\"_uniqueKey\":2},{\"_uniqueKey\":3,\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"_uniqueKey\":4,\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"_uniqueKey\":5,\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"_uniqueKey\":6,\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"_uniqueKey\":7,\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"_uniqueKey\":8,\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"_uniqueKey\":9,\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"_uniqueKey\":10,\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"_uniqueKey\":11,\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"_uniqueKey\":12,\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"_uniqueKey\":13,\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"_uniqueKey\":14,\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"_uniqueKey\":15,\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"_uniqueKey\":16,\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}]},\"title\":\"Raspberry Pi GPIO Control\"}" |
79 | 79 | } | ... | ... |
... | ... | @@ -431,11 +431,19 @@ export const commonMapSettingsSchema = |
431 | 431 | condition: 'model.provider === "image-map"' |
432 | 432 | }, |
433 | 433 | 'showLabel', |
434 | - 'label', | |
435 | - 'useLabelFunction', | |
434 | + { | |
435 | + key: 'useLabelFunction', | |
436 | + condition: 'model.showLabel === true' | |
437 | + }, | |
438 | + { | |
439 | + key: 'label', | |
440 | + condition: 'model.showLabel === true && model.useLabelFunction !== true' | |
441 | + }, | |
436 | 442 | { |
437 | 443 | key: 'labelFunction', |
438 | - type: 'javascript' | |
444 | + type: 'javascript', | |
445 | + helpId: 'widget/lib/map/label_fn', | |
446 | + condition: 'model.showLabel === true && model.useLabelFunction === true' | |
439 | 447 | }, |
440 | 448 | 'showTooltip', |
441 | 449 | { |
... | ... | @@ -451,17 +459,27 @@ export const commonMapSettingsSchema = |
451 | 459 | value: 'hover', |
452 | 460 | label: 'Show tooltip on hover' |
453 | 461 | } |
454 | - ] | |
462 | + ], | |
463 | + condition: 'model.showTooltip === true' | |
464 | + }, | |
465 | + { | |
466 | + key: 'autocloseTooltip', | |
467 | + condition: 'model.showTooltip === true' | |
468 | + }, | |
469 | + { | |
470 | + key: 'useTooltipFunction', | |
471 | + condition: 'model.showTooltip === true' | |
455 | 472 | }, |
456 | - 'autocloseTooltip', | |
457 | 473 | { |
458 | 474 | key: 'tooltipPattern', |
459 | - type: 'textarea' | |
475 | + type: 'textarea', | |
476 | + condition: 'model.showTooltip === true && model.useTooltipFunction !== true' | |
460 | 477 | }, |
461 | - 'useTooltipFunction', | |
462 | 478 | { |
463 | 479 | key: 'tooltipFunction', |
464 | - type: 'javascript' | |
480 | + type: 'javascript', | |
481 | + helpId: 'widget/lib/map/tooltip_fn', | |
482 | + condition: 'model.showTooltip === true && model.useTooltipFunction === true' | |
465 | 483 | }, |
466 | 484 | { |
467 | 485 | key: 'markerOffsetX', |
... | ... | @@ -474,6 +492,7 @@ export const commonMapSettingsSchema = |
474 | 492 | { |
475 | 493 | key: 'posFunction', |
476 | 494 | type: 'javascript', |
495 | + helpId: 'widget/lib/map/position_fn', | |
477 | 496 | condition: 'model.provider === "image-map"' |
478 | 497 | }, |
479 | 498 | { |
... | ... | @@ -483,17 +502,25 @@ export const commonMapSettingsSchema = |
483 | 502 | 'useColorFunction', |
484 | 503 | { |
485 | 504 | key: 'colorFunction', |
486 | - type: 'javascript' | |
505 | + type: 'javascript', | |
506 | + helpId: 'widget/lib/map/color_fn', | |
507 | + condition: 'model.useColorFunction === true' | |
487 | 508 | }, |
509 | + 'useMarkerImageFunction', | |
488 | 510 | { |
489 | 511 | key: 'markerImage', |
490 | - type: 'image' | |
512 | + type: 'image', | |
513 | + condition: 'model.useMarkerImageFunction !== true' | |
514 | + }, | |
515 | + { | |
516 | + key: 'markerImageSize', | |
517 | + condition: 'model.useMarkerImageFunction !== true' | |
491 | 518 | }, |
492 | - 'markerImageSize', | |
493 | - 'useMarkerImageFunction', | |
494 | 519 | { |
495 | 520 | key: 'markerImageFunction', |
496 | - type: 'javascript' | |
521 | + type: 'javascript', | |
522 | + helpId: 'widget/lib/map/marker_image_fn', | |
523 | + condition: 'model.useMarkerImageFunction === true' | |
497 | 524 | }, |
498 | 525 | { |
499 | 526 | key: 'markerImages', |
... | ... | @@ -502,7 +529,8 @@ export const commonMapSettingsSchema = |
502 | 529 | key: 'markerImages[]', |
503 | 530 | type: 'image' |
504 | 531 | } |
505 | - ] | |
532 | + ], | |
533 | + condition: 'model.useMarkerImageFunction === true' | |
506 | 534 | } |
507 | 535 | ] |
508 | 536 | }; |
... | ... | @@ -590,24 +618,36 @@ export const mapPolygonSchema = |
590 | 618 | key: 'polygonColor', |
591 | 619 | type: 'color' |
592 | 620 | }, |
621 | + 'usePolygonColorFunction', | |
622 | + { | |
623 | + key: 'polygonColorFunction', | |
624 | + helpId: 'widget/lib/map/polygon_color_fn', | |
625 | + type: 'javascript', | |
626 | + condition: 'model.usePolygonColorFunction === true' | |
627 | + }, | |
593 | 628 | 'polygonOpacity', |
594 | 629 | { |
595 | 630 | key: 'polygonStrokeColor', |
596 | 631 | type: 'color' |
597 | 632 | }, |
598 | - 'polygonStrokeOpacity', 'polygonStrokeWeight', 'showPolygonTooltip', | |
633 | + 'polygonStrokeOpacity', | |
634 | + 'polygonStrokeWeight', | |
635 | + 'showPolygonTooltip', | |
599 | 636 | { |
600 | - key: 'polygonTooltipPattern', | |
601 | - type: 'textarea' | |
602 | - }, 'usePolygonTooltipFunction', { | |
603 | - key: 'polygonTooltipFunction', | |
604 | - type: 'javascript' | |
637 | + key: 'usePolygonTooltipFunction', | |
638 | + condition: 'model.showPolygonTooltip === true' | |
605 | 639 | }, |
606 | - 'usePolygonColorFunction', | |
607 | 640 | { |
608 | - key: 'polygonColorFunction', | |
609 | - type: 'javascript' | |
641 | + key: 'polygonTooltipPattern', | |
642 | + type: 'textarea', | |
643 | + condition: 'model.showPolygonTooltip === true && model.usePolygonTooltipFunction !== true' | |
610 | 644 | }, |
645 | + { | |
646 | + key: 'polygonTooltipFunction', | |
647 | + helpId: 'widget/lib/map/polygon_tooltip_fn', | |
648 | + type: 'javascript', | |
649 | + condition: 'model.showPolygonTooltip === true && model.usePolygonTooltipFunction === true' | |
650 | + } | |
611 | 651 | ] |
612 | 652 | }; |
613 | 653 | |
... | ... | @@ -822,11 +862,18 @@ export const pathSchema = |
822 | 862 | { |
823 | 863 | key: 'color', |
824 | 864 | type: 'color' |
825 | - }, 'useColorFunction', { | |
865 | + }, | |
866 | + 'useColorFunction', | |
867 | + { | |
826 | 868 | key: 'colorFunction', |
827 | - type: 'javascript' | |
828 | - }, 'strokeWeight', 'strokeOpacity', | |
829 | - 'usePolylineDecorator', { | |
869 | + helpId: 'widget/lib/map/trip_path_color_fn', | |
870 | + type: 'javascript', | |
871 | + condition: 'model.useColorFunction === true' | |
872 | + }, | |
873 | + 'strokeWeight', | |
874 | + 'strokeOpacity', | |
875 | + 'usePolylineDecorator', | |
876 | + { | |
830 | 877 | key: 'decoratorSymbol', |
831 | 878 | type: 'rc-select', |
832 | 879 | multiple: false, |
... | ... | @@ -837,16 +884,22 @@ export const pathSchema = |
837 | 884 | value: 'dash', |
838 | 885 | label: 'Dash' |
839 | 886 | }] |
840 | - }, 'decoratorSymbolSize', 'useDecoratorCustomColor', { | |
887 | + }, | |
888 | + 'decoratorSymbolSize', | |
889 | + 'useDecoratorCustomColor', | |
890 | + { | |
841 | 891 | key: 'decoratorCustomColor', |
842 | 892 | type: 'color' |
843 | - }, { | |
893 | + }, | |
894 | + { | |
844 | 895 | key: 'decoratorOffset', |
845 | 896 | type: 'textarea' |
846 | - }, { | |
897 | + }, | |
898 | + { | |
847 | 899 | key: 'endDecoratorOffset', |
848 | 900 | type: 'textarea' |
849 | - }, { | |
901 | + }, | |
902 | + { | |
850 | 903 | key: 'decoratorRepeat', |
851 | 904 | type: 'textarea' |
852 | 905 | } |
... | ... | @@ -856,7 +909,7 @@ export const pathSchema = |
856 | 909 | export const pointSchema = |
857 | 910 | { |
858 | 911 | schema: { |
859 | - title: 'Trip Animation Path Configuration', | |
912 | + title: 'Trip Animation Points Configuration', | |
860 | 913 | type: 'object', |
861 | 914 | properties: { |
862 | 915 | showPoints: { |
... | ... | @@ -908,13 +961,17 @@ export const pointSchema = |
908 | 961 | 'useColorPointFunction', |
909 | 962 | { |
910 | 963 | key: 'colorPointFunction', |
911 | - type: 'javascript' | |
964 | + helpId: 'widget/lib/map/trip_path_point_color_fn', | |
965 | + type: 'javascript', | |
966 | + condition: 'model.useColorPointFunction === true' | |
912 | 967 | }, |
913 | 968 | 'pointSize', |
914 | 969 | 'usePointAsAnchor', |
915 | 970 | { |
916 | 971 | key: 'pointAsAnchorFunction', |
917 | - type: 'javascript' | |
972 | + helpId: 'widget/lib/map/trip_point_as_anchor_fn', | |
973 | + type: 'javascript', | |
974 | + condition: 'model.usePointAsAnchor === true' | |
918 | 975 | }, |
919 | 976 | 'pointTooltipOnRightPanel', |
920 | 977 | ] |
... | ... | @@ -1077,36 +1134,85 @@ export const tripAnimationSchema = { |
1077 | 1134 | }, |
1078 | 1135 | required: [] |
1079 | 1136 | }, |
1080 | - form: ['normalizationStep', 'latKeyName', 'lngKeyName', 'showLabel', 'label', 'useLabelFunction', { | |
1137 | + form: [ | |
1138 | + 'normalizationStep', | |
1139 | + 'latKeyName', | |
1140 | + 'lngKeyName', | |
1141 | + 'showLabel', | |
1142 | + { | |
1143 | + key: 'useLabelFunction', | |
1144 | + condition: 'model.showLabel === true' | |
1145 | + }, | |
1146 | + { | |
1147 | + key: 'label', | |
1148 | + condition: 'model.showLabel === true && model.useLabelFunction !== true' | |
1149 | + }, | |
1150 | + { | |
1081 | 1151 | key: 'labelFunction', |
1082 | - type: 'javascript' | |
1083 | - }, 'showTooltip', { | |
1152 | + type: 'javascript', | |
1153 | + helpId: 'widget/lib/map/trip_label_fn', | |
1154 | + condition: 'model.showLabel === true && model.useLabelFunction === true' | |
1155 | + }, | |
1156 | + 'showTooltip', | |
1157 | + { | |
1084 | 1158 | key: 'tooltipColor', |
1085 | - type: 'color' | |
1086 | - }, { | |
1159 | + type: 'color', | |
1160 | + condition: 'model.showTooltip === true' | |
1161 | + }, | |
1162 | + { | |
1087 | 1163 | key: 'tooltipFontColor', |
1088 | - type: 'color' | |
1089 | - }, 'tooltipOpacity', { | |
1164 | + type: 'color', | |
1165 | + condition: 'model.showTooltip === true' | |
1166 | + }, | |
1167 | + { | |
1168 | + key: 'tooltipOpacity', | |
1169 | + condition: 'model.showTooltip === true' | |
1170 | + }, | |
1171 | + { | |
1172 | + key: 'autocloseTooltip', | |
1173 | + condition: 'model.showTooltip === true' | |
1174 | + }, | |
1175 | + { | |
1176 | + key: 'useTooltipFunction', | |
1177 | + condition: 'model.showTooltip === true', | |
1178 | + }, | |
1179 | + { | |
1090 | 1180 | key: 'tooltipPattern', |
1091 | - type: 'textarea' | |
1092 | - }, 'useTooltipFunction', { | |
1181 | + type: 'textarea', | |
1182 | + condition: 'model.showTooltip === true && model.useTooltipFunction !== true' | |
1183 | + }, | |
1184 | + { | |
1093 | 1185 | key: 'tooltipFunction', |
1094 | - type: 'javascript' | |
1095 | - }, 'autocloseTooltip', { | |
1186 | + type: 'javascript', | |
1187 | + helpId: 'widget/lib/map/trip_tooltip_fn', | |
1188 | + condition: 'model.showTooltip === true && model.useTooltipFunction === true' | |
1189 | + }, | |
1190 | + 'rotationAngle', | |
1191 | + 'useMarkerImageFunction', | |
1192 | + { | |
1096 | 1193 | key: 'markerImage', |
1097 | - type: 'image' | |
1098 | - }, 'markerImageSize', 'rotationAngle', 'useMarkerImageFunction', | |
1099 | - { | |
1194 | + type: 'image', | |
1195 | + condition: 'model.useMarkerImageFunction !== true' | |
1196 | + }, | |
1197 | + { | |
1198 | + key: 'markerImageSize', | |
1199 | + condition: 'model.useMarkerImageFunction !== true' | |
1200 | + }, | |
1201 | + { | |
1100 | 1202 | key: 'markerImageFunction', |
1101 | - type: 'javascript' | |
1102 | - }, { | |
1203 | + type: 'javascript', | |
1204 | + helpId: 'widget/lib/map/trip_marker_image_fn', | |
1205 | + condition: 'model.useMarkerImageFunction === true' | |
1206 | + }, | |
1207 | + { | |
1103 | 1208 | key: 'markerImages', |
1104 | 1209 | items: [ |
1105 | 1210 | { |
1106 | 1211 | key: 'markerImages[]', |
1107 | 1212 | type: 'image' |
1108 | 1213 | } |
1109 | - ] | |
1214 | + ], | |
1215 | + condition: 'model.useMarkerImageFunction === true' | |
1110 | 1216 | }] |
1111 | 1217 | }; |
1112 | 1218 | ... | ... |
... | ... | @@ -205,9 +205,9 @@ class ThingsboardAceEditor extends React.Component<ThingsboardAceEditorProps, Th |
205 | 205 | </div> |
206 | 206 | <React.Suspense fallback={<div>Loading...</div>}> |
207 | 207 | <ReactAce mode={this.props.mode} |
208 | + theme={'textmate'} | |
208 | 209 | height={this.state.isFull ? '100%' : '150px'} |
209 | 210 | width={this.state.isFull ? '100%' : '300px'} |
210 | - theme='github' | |
211 | 211 | onChange={this.onValueChanged} |
212 | 212 | onFocus={this.onFocus} |
213 | 213 | onBlur={this.onBlur} | ... | ... |
... | ... | @@ -43,6 +43,7 @@ export function loadAceDependencies(): Observable<any> { |
43 | 43 | aceObservables.push(from(import('ace-builds/src-noconflict/snippets/text'))); |
44 | 44 | aceObservables.push(from(import('ace-builds/src-noconflict/snippets/markdown'))); |
45 | 45 | aceObservables.push(from(import('ace-builds/src-noconflict/snippets/html'))); |
46 | + aceObservables.push(from(import('ace-builds/src-noconflict/theme-textmate'))); | |
46 | 47 | aceObservables.push(from(import('ace-builds/src-noconflict/theme-github'))); |
47 | 48 | return forkJoin(aceObservables).pipe( |
48 | 49 | tap(() => { | ... | ... |
1 | +#### Marker color function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute color of the marker. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting color of the marker. | |
19 | + | |
20 | +In case no data is returned, color value from **Color** settings field will be used. | |
21 | + | |
22 | +<div class="divider"></div> | |
23 | + | |
24 | +##### Examples | |
25 | + | |
26 | +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: | |
27 | + | |
28 | +```javascript | |
29 | +var type = data['Type']; | |
30 | +if (type == 'colorpin') { | |
31 | + var temperature = data['temperature']; | |
32 | + if (typeof temperature !== undefined) { | |
33 | + var percent = (temperature + 60)/120 * 100; | |
34 | + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); | |
35 | + } | |
36 | + return 'blue'; | |
37 | +} | |
38 | +{:copy-code} | |
39 | +``` | |
40 | + | |
41 | +<br> | |
42 | +<br> | ... | ... |
1 | +#### Marker label function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute text or HTML code of the marker label. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting text or HTML of the marker label. | |
19 | + | |
20 | +<div class="divider"></div> | |
21 | + | |
22 | +##### Examples | |
23 | + | |
24 | +* Display styled label with corresponding latest telemetry data for `energy meter` or `thermometer` device types: | |
25 | + | |
26 | +```javascript | |
27 | +var deviceType = data['Type']; | |
28 | +if (typeof deviceType !== undefined) { | |
29 | + if (deviceType == "energy meter") { | |
30 | + return '<span style="color:orange;">${entityName}, ${energy:2} kWt</span>'; | |
31 | + } else if (deviceType == "thermometer") { | |
32 | + return '<span style="color:blue;">${entityName}, ${temperature:2} °C</span>'; | |
33 | + } | |
34 | +} | |
35 | +return data.entityName; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | + <li><b>data:</b> <code><a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a></code> - A <a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a> object associated with marker.<br/> | |
2 | + Represents basic entity properties (ex. <code>entityId</code>, <code>entityName</code>)<br/>and provides access to other entity attributes/timeseries declared in widget datasource configuration. | |
3 | + </li> | |
4 | + <li><b>dsData:</b> <code><a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData[]</a></code> - All available widget data (entities) as array of <a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a> objects<br/> | |
5 | + resolved from configured datasources. Each object represents basic entity properties (ex. <code>entityId</code>, <code>entityName</code>)<br/> | |
6 | + and provides access to other entity attributes/timeseries declared in widget datasource configuration. | |
7 | + </li> | |
8 | + <li><b>dsIndex</b> <code>number</code> - index of the current marker data in <code>dsData</code> array.<br> | |
9 | + <strong>Note: </strong> The <code>data</code> argument is equivalent to <code>dsData[dsIndex]</code> expression. | |
10 | + </li> | ... | ... |
1 | +#### Marker image function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, images, dsData, dsIndex): {url: string, size: number}* | |
7 | + | |
8 | +A JavaScript function used to compute marker image. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return marker image data having the following structure: | |
19 | + | |
20 | +```typescript | |
21 | +{ | |
22 | + url: string, | |
23 | + size: number | |
24 | +} | |
25 | +``` | |
26 | + | |
27 | +- *url* - marker image url; | |
28 | +- *size* - marker image size; | |
29 | + | |
30 | +In case no data is returned, default marker image will be used. | |
31 | + | |
32 | +<div class="divider"></div> | |
33 | + | |
34 | +##### Examples | |
35 | + | |
36 | +<ul> | |
37 | +<li> | |
38 | +Calculate image url depending on <code>temperature</code> telemetry value for <code>thermometer</code> device type.<br> | |
39 | +Let's assume 4 images are defined in <b>Marker images</b> section. Each image corresponds to particular temperature level: | |
40 | +</li> | |
41 | +</ul> | |
42 | + | |
43 | +```javascript | |
44 | +var type = data['Type']; | |
45 | +if (type == 'thermometer') { | |
46 | + var res = { | |
47 | + url: images[0], | |
48 | + size: 40 | |
49 | + } | |
50 | + var temperature = data['temperature']; | |
51 | + if (typeof temperature !== undefined) { | |
52 | + var percent = (temperature + 60)/120; | |
53 | + var index = Math.min(3, Math.floor(4 * percent)); | |
54 | + res.url = images[index]; | |
55 | + } | |
56 | + return res; | |
57 | +} | |
58 | +{:copy-code} | |
59 | +``` | |
60 | + | |
61 | +<br> | |
62 | +<br> | ... | ... |
1 | +#### Polygon color function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute color of the polygon. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting color of the polygon. | |
19 | + | |
20 | +In case no data is returned, color value from **Polygon color** settings field will be used. | |
21 | + | |
22 | +<div class="divider"></div> | |
23 | + | |
24 | +##### Examples | |
25 | + | |
26 | +* Calculate color depending on `temperature` telemetry value for `thermostat` device type: | |
27 | + | |
28 | +```javascript | |
29 | +var type = data['Type']; | |
30 | +if (type == 'thermostat') { | |
31 | + var temperature = data['temperature']; | |
32 | + if (typeof temperature !== undefined) { | |
33 | + var percent = (temperature + 60)/120 * 100; | |
34 | + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); | |
35 | + } | |
36 | + return 'blue'; | |
37 | +} | |
38 | +{:copy-code} | |
39 | +``` | |
40 | + | |
41 | +<br> | |
42 | +<br> | ... | ... |
1 | +#### Polygon tooltip function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute text or HTML code to be displayed in the polygon tooltip. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting text or HTML for the polygon tooltip. | |
19 | + | |
20 | +<div class="divider"></div> | |
21 | + | |
22 | +##### Examples | |
23 | + | |
24 | +* Display details with corresponding telemetry data for `energy meter` or `thermostat` device types: | |
25 | + | |
26 | +```javascript | |
27 | +var deviceType = data['Type']; | |
28 | +if (typeof deviceType !== undefined) { | |
29 | + if (deviceType == "energy meter") { | |
30 | + return '<b>${entityName}</b><br/><b>Energy:</b> ${energy:2} kWt<br/>'; | |
31 | + } else if (deviceType == "thermostat") { | |
32 | + return '<b>${entityName}</b><br/><b>Temperature:</b> ${temperature:2} °C<br/>'; | |
33 | + } | |
34 | +} | |
35 | +return data.entityName; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | +#### Position conversion function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (origXPos, origYPos): {x: number, y: number}* | |
7 | + | |
8 | +A JavaScript function used to convert original relative x, y coordinates of the marker. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +- **origXPos:** <code>number</code> - original relative x coordinate as double from 0 to 1; | |
13 | +- **origYPos:** <code>number</code> - original relative y coordinate as double from 0 to 1; | |
14 | + | |
15 | +**Returns:** | |
16 | + | |
17 | +Should return position data having the following structure: | |
18 | + | |
19 | +```typescript | |
20 | +{ | |
21 | + x: number, | |
22 | + y: number | |
23 | +} | |
24 | +``` | |
25 | + | |
26 | +- *x* - new relative x coordinate as double from 0 to 1; | |
27 | +- *y* - new relative y coordinate as double from 0 to 1; | |
28 | + | |
29 | +<div class="divider"></div> | |
30 | + | |
31 | +##### Examples | |
32 | + | |
33 | +* Scale the coordinates to half the original: | |
34 | + | |
35 | +```javascript | |
36 | +return {x: origXPos / 2, y: origYPos / 2}; | |
37 | +{:copy-code} | |
38 | +``` | |
39 | + | |
40 | +<br> | |
41 | +<br> | ... | ... |
1 | +#### Marker tooltip function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/map_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting text or HTML for the marker tooltip. | |
19 | + | |
20 | +<div class="divider"></div> | |
21 | + | |
22 | +##### Examples | |
23 | + | |
24 | +* Display details with corresponding telemetry data for `thermostat` device type: | |
25 | + | |
26 | +```javascript | |
27 | +var deviceType = data['Type']; | |
28 | +if (typeof deviceType !== undefined) { | |
29 | + if (deviceType == "energy meter") { | |
30 | + return '<b>${entityName}</b><br/><b>Energy:</b> ${energy:2} kWt<br/>'; | |
31 | + } else if (deviceType == "thermometer") { | |
32 | + return '<b>${entityName}</b><br/><b>Temperature:</b> ${temperature:2} °C<br/>'; | |
33 | + } | |
34 | +} | |
35 | +return data.entityName; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | + <li><b>data:</b> <code><a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a></code> - A <a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a> object associated with the point of the trip.<br/> | |
2 | + Represents basic entity properties (ex. <code>entityId</code>, <code>entityName</code>)<br/>and provides access to other entity attributes/timeseries declared in widget datasource configuration. | |
3 | + </li> | |
4 | + <li><b>dsData:</b> <code><a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData[][]</a></code> - two-dimensional array of <a href="https://github.com/thingsboard/thingsboard/blob/5bb6403407aa4898084832d6698aa9ea6d484889/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts#L108" target="_blank">FormattedData</a> objects presenting<br/> | |
5 | + array of trips (entities with timeseries data) resolved from configured datasources.<br/> | |
6 | + Each element of array is particular entity trip data presented as array of <b>FormattedData</b> object (trip point).<br/> | |
7 | + Each object represents basic entity properties (ex. <code>entityId</code>, <code>entityName</code>)<br/> | |
8 | + and provides access to other entity attributes/timeseries declared in widget datasource configuration. | |
9 | + </li> | |
10 | + <li><b>dsIndex</b> <code>number</code> - index of the current trip data in <code>dsData</code> array. | |
11 | + </li> | ... | ... |
1 | +#### Trip animation widget label function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute text or HTML code of the marker label. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting text or HTML of the marker label. | |
19 | + | |
20 | +<div class="divider"></div> | |
21 | + | |
22 | +##### Examples | |
23 | + | |
24 | +* Display styled label with corresponding latest telemetry data for `energy meter` or `thermometer` device types: | |
25 | + | |
26 | +```javascript | |
27 | +var deviceType = data['Type']; | |
28 | +if (typeof deviceType !== undefined) { | |
29 | + if (deviceType == "energy meter") { | |
30 | + return '<span style="color:orange;">${entityName}, ${energy:2} kWt</span>'; | |
31 | + } else if (deviceType == "thermometer") { | |
32 | + return '<span style="color:blue;">${entityName}, ${temperature:2} °C</span>'; | |
33 | + } | |
34 | +} | |
35 | +return data.entityName; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | +#### Marker image function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, images, dsData, dsIndex): {url: string, size: number}* | |
7 | + | |
8 | +A JavaScript function used to compute marker image. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return marker image data having the following structure: | |
19 | + | |
20 | +```typescript | |
21 | +{ | |
22 | + url: string, | |
23 | + size: number | |
24 | +} | |
25 | +``` | |
26 | + | |
27 | +- *url* - marker image url; | |
28 | +- *size* - marker image size; | |
29 | + | |
30 | +In case no data is returned, default marker image will be used. | |
31 | + | |
32 | +<div class="divider"></div> | |
33 | + | |
34 | +##### Examples | |
35 | + | |
36 | +<ul> | |
37 | +<li> | |
38 | +Calculate image url depending on <code>temperature</code> telemetry value for <code>thermometer</code> device type.<br> | |
39 | +Let's assume 4 images are defined in <b>Marker images</b> section. Each image corresponds to particular temperature level: | |
40 | +</li> | |
41 | +</ul> | |
42 | + | |
43 | +```javascript | |
44 | +var type = data['Type']; | |
45 | +if (type == 'thermometer') { | |
46 | + var res = { | |
47 | + url: images[0], | |
48 | + size: 40 | |
49 | + } | |
50 | + var temperature = data['temperature']; | |
51 | + if (typeof temperature !== undefined) { | |
52 | + var percent = (temperature + 60)/120; | |
53 | + var index = Math.min(3, Math.floor(4 * percent)); | |
54 | + res.url = images[index]; | |
55 | + } | |
56 | + return res; | |
57 | +} | |
58 | +{:copy-code} | |
59 | +``` | |
60 | + | |
61 | +<br> | |
62 | +<br> | ... | ... |
1 | +#### Path color function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute color of the trip path. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting color of the trip path. | |
19 | + | |
20 | +In case no data is returned, color value from **Path color** settings field will be used. | |
21 | + | |
22 | +<div class="divider"></div> | |
23 | + | |
24 | +##### Examples | |
25 | + | |
26 | +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: | |
27 | + | |
28 | +```javascript | |
29 | +var type = data['Type']; | |
30 | +if (type == 'colorpin') { | |
31 | + var temperature = data['temperature']; | |
32 | + if (typeof temperature !== undefined) { | |
33 | + var percent = (temperature + 60)/120 * 100; | |
34 | + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); | |
35 | + } | |
36 | + return 'blue'; | |
37 | +} | |
38 | +{:copy-code} | |
39 | +``` | |
40 | + | |
41 | +<br> | |
42 | +<br> | ... | ... |
1 | +#### Path point color function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute color of the trip path point. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting color of the trip path point. | |
19 | + | |
20 | +In case no data is returned, color value from **Point color** settings field will be used. | |
21 | + | |
22 | +<div class="divider"></div> | |
23 | + | |
24 | +##### Examples | |
25 | + | |
26 | +* Calculate color depending on `temperature` telemetry value for `colorpin` device type: | |
27 | + | |
28 | +```javascript | |
29 | +var type = data['Type']; | |
30 | +if (type == 'colorpin') { | |
31 | + var temperature = data['temperature']; | |
32 | + if (typeof temperature !== undefined) { | |
33 | + var percent = (temperature + 60)/120 * 100; | |
34 | + return tinycolor.mix('blue', 'red', amount = percent).toHexString(); | |
35 | + } | |
36 | + return 'blue'; | |
37 | +} | |
38 | +{:copy-code} | |
39 | +``` | |
40 | + | |
41 | +<br> | |
42 | +<br> | |
43 | + | ... | ... |
1 | +#### Point as anchor function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): boolean* | |
7 | + | |
8 | +A JavaScript function evaluating whether to use trip point as time anchor used in time selector. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +`true` if the point should be decided as anchor, `false` otherwise. | |
19 | + | |
20 | +In case no data is returned, the point is not used as anchor. | |
21 | + | |
22 | +<div class="divider"></div> | |
23 | + | |
24 | +##### Examples | |
25 | + | |
26 | +* Make anchors with 5 seconds step interval: | |
27 | + | |
28 | +```javascript | |
29 | +return data.time % 5000 < 1000; | |
30 | +{:copy-code} | |
31 | +``` | |
32 | + | |
33 | +<br> | |
34 | +<br> | ... | ... |
1 | +#### Trip animation widget tooltip function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data, dsData, dsIndex): string* | |
7 | + | |
8 | +A JavaScript function used to compute text or HTML code to be displayed in the marker tooltip. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + {% include widget/lib/map/trip_fn_args %} | |
14 | +</ul> | |
15 | + | |
16 | +**Returns:** | |
17 | + | |
18 | +Should return string value presenting text or HTML for the marker tooltip. | |
19 | + | |
20 | +<div class="divider"></div> | |
21 | + | |
22 | +##### Examples | |
23 | + | |
24 | +* Display details with corresponding telemetry data for `thermostat` device type: | |
25 | + | |
26 | +```javascript | |
27 | +var deviceType = data['Type']; | |
28 | +if (typeof deviceType !== undefined) { | |
29 | + if (deviceType == "energy meter") { | |
30 | + return '<b>${entityName}</b><br/><b>Energy:</b> ${energy:2} kWt<br/>'; | |
31 | + } else if (deviceType == "thermometer") { | |
32 | + return '<b>${entityName}</b><br/><b>Temperature:</b> ${temperature:2} °C<br/>'; | |
33 | + } | |
34 | +} | |
35 | +return data.entityName; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | +#### Convert value function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (value): any* | |
7 | + | |
8 | +A JavaScript function converting target on/off state of the control widget to payload of the RPC set value command. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + <li><b>value:</b> <code>boolean</code> - value indicating target on/off state of the control widget. | |
14 | + </li> | |
15 | +</ul> | |
16 | + | |
17 | +**Returns:** | |
18 | + | |
19 | +Payload object or primitive to be used by the RPC set value command. | |
20 | + | |
21 | +<div class="divider"></div> | |
22 | + | |
23 | +##### Examples | |
24 | + | |
25 | +* Use original target value as payload: | |
26 | + | |
27 | +```javascript | |
28 | +return value; | |
29 | +{:copy-code} | |
30 | +``` | |
31 | + | |
32 | +* Create json payload with `enabled` boolean property: | |
33 | + | |
34 | +```javascript | |
35 | +return { enabled: value }; | |
36 | +{:copy-code} | |
37 | +``` | |
38 | + | |
39 | +<br> | |
40 | +<br> | ... | ... |
1 | +#### Parse GPIO status function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (body, pin): boolean* | |
7 | + | |
8 | +A JavaScript function evaluating enabled/disable state of GPIO pin from the response of GPIO status request. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + <li><b>body:</b> <code>any</code> - response body of the GPIO status request. | |
14 | + </li> | |
15 | + <li><b>pin:</b> <code>number</code> - number of the GPIO pin. | |
16 | + </li> | |
17 | +</ul> | |
18 | + | |
19 | +**Returns:** | |
20 | + | |
21 | +`true` if GPIO pin should be enabled, `false` otherwise. | |
22 | + | |
23 | +<div class="divider"></div> | |
24 | + | |
25 | +##### Examples | |
26 | + | |
27 | +* Detect status of the pin assuming response body is array of boolean pins states: | |
28 | + | |
29 | +```javascript | |
30 | +return body[pin] === true; | |
31 | +{:copy-code} | |
32 | +``` | |
33 | + | |
34 | +<br> | |
35 | +<br> | ... | ... |
1 | +#### Parse value function | |
2 | + | |
3 | +<div class="divider"></div> | |
4 | +<br/> | |
5 | + | |
6 | +*function (data): boolean* | |
7 | + | |
8 | +A JavaScript function converting attribute/timeseries value or value of the RPC command response to boolean value. | |
9 | + | |
10 | +**Parameters:** | |
11 | + | |
12 | +<ul> | |
13 | + <li><b>data:</b> <code>any</code> - attribute/timeseries value or value of the RPC command response. | |
14 | + </li> | |
15 | +</ul> | |
16 | + | |
17 | +**Returns:** | |
18 | + | |
19 | +`true` if control widget should be switched on, `false` otherwise. | |
20 | + | |
21 | +<div class="divider"></div> | |
22 | + | |
23 | +##### Examples | |
24 | + | |
25 | +* Switch on control widget for any positive value: | |
26 | + | |
27 | +```javascript | |
28 | +return data ? true : false; | |
29 | +{:copy-code} | |
30 | +``` | |
31 | + | |
32 | +* Parse control widget state from json payload having `enabled` boolean property: | |
33 | + | |
34 | +```javascript | |
35 | +var payload = typeof data === 'string' ? JSON.parse(data) : data; | |
36 | +return payload && payload.enabled ? true : false; | |
37 | +{:copy-code} | |
38 | +``` | |
39 | + | |
40 | +<br> | |
41 | +<br> | ... | ... |