Merge branch 'master' into develop/2.3
This commit is contained in:
		
						commit
						ded035b927
					
				@ -63,7 +63,7 @@
 | 
			
		||||
        "resources": [],
 | 
			
		||||
        "templateHtml": "<form class=\"attribute-update-form\"\n      name=\"attrUpdateForm\"\n      ng-submit=\"updateAttribute($event)\"\n>\n    <div style=\"padding: 0 8px; margin: auto 0;\">\n        <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n            <div class=\"grid__element\">\n                <md-checkbox ng-model=\"checkboxValue\"\n                             aria-label=\"Switch entity attribute value\"\n                             ng-change=\"changed()\"\n                             ng-true-value=\"'true'\"\n                             ng-false-value=\"'false'\"\n                >\n                    {{currentValue}}\n                </md-checkbox>\n            </div>\n        </div>\n\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\" ng-bind=\"message\"></div>\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n            No attribute is selected\n        </div>\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n            Timeseries parameter cannot be used in this widget\n        </div>\n    </div>\n</form>",
 | 
			
		||||
        "templateCss": ".attribute-update-form {\n    overflow: hidden;\n    height: 100%;\n    display: flex;\n    flex-direction: column;\n}\n\n.entity-title {\n    font-weight: bold;\n    font-size: 22px;\n    padding-top: 12px;\n    padding-bottom: 6px;\n    color: #666;\n}\n\n.attribute-update-form__grid {\n    display: flex;\n}\n.grid__element:first-child {\n    flex: 1;\n}\n\n.grid__element {\n    display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n    margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n    width: 32px;\n    min-width: 32px;\n    height: 32px;\n    min-height: 32px;\n    padding: 0 !important;\n    margin: 0 !important;\n    line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n    width: 20px;\n    min-width: 20px;\n    height: 20px;\n    min-height: 20px;\n    font-size: 20px;\n}\n\n\nmd-toast{\n    min-width: 0;\n}\nmd-toast .md-toast-content {\n    font-size: 14px!important;\n}",
 | 
			
		||||
        "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n    $scope = self.ctx.$scope;\n    attributeService = $scope.$injector.get('attributeService');\n    toast = $scope.$injector.get('toast');\n    utils = $scope.$injector.get('utils');\n    types = $scope.$injector.get('types');\n    settings = angular.copy(self.ctx.settings) || {};\n    $scope.settings = settings;\n    $scope.isValidParameter = true;\n    $scope.dataKeyDetected = false;\n    $scope.message = 'No entity selected';\n\n    settings.trueValue = settings.trueValue || true;\n    settings.falseValue = settings.falseValue || false;\n    \n    map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n    mapReverse = {[settings.trueValue]:\"true\", [settings.falseValue]:\"false\"};\n    $scope.checkboxValue = \"false\";\n    $scope.currentValue = map[$scope.checkboxValue];\n\n    $scope.changed = function () {\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.updateAttribute();\n    }\n\n    if (self.ctx.datasources && self.ctx.datasources.length) {\n        var datasource = self.ctx.datasources[0];\n        if (datasource.type === 'entity') {\n            if (datasource.entityType && datasource.entityId) {\n                $scope.entityName = datasource.entityName;\n                if (settings.widgetTitle && settings.widgetTitle.length) {\n                    $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n                } else {\n                    $scope.titleTemplate = self.ctx.widgetConfig.title;\n                }\n\n                $scope.entityDetected = true;\n            }\n        }\n        if (datasource.dataKeys.length) {\n            if (datasource.dataKeys[0].type != \"attribute\") {\n                $scope.isValidParameter = false;\n            } else {\n                $scope.currentKey = datasource.dataKeys[0].name;\n                $scope.dataKeyType = datasource.dataKeys[0].type;\n                $scope.dataKeyDetected = true;\n            }\n        }\n    }\n\n    self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n    $scope.updateAttribute = function () {\n        if ($scope.entityDetected) {\n            var datasource = self.ctx.datasources[0];\n\n            attributeService.saveEntityAttributes(\n                datasource.entityType,\n                datasource.entityId,\n                types.attributesScope.server.value,\n                [\n                    {\n                        key: $scope.currentKey,\n                        value: $scope.currentValue\n                    }\n                ]\n            ).then(\n                function success() {\n                    $scope.originalValue = $scope.currentValue;\n                    if (settings.showResultMessage) {\n                        toast.showSuccess('Update successful', 1000, angular.element(self.ctx.$container), 'bottom left');\n                    }\n                },\n                function fail() {\n                    if (settings.showResultMessage) {\n                        toast.showError('Update failed', angular.element(self.ctx.$container), 'bottom left');\n                    }\n                }\n            );\n        }\n    };\n}\n\nself.onDataUpdated = function() {\n\n    try {\n        if ($scope.dataKeyDetected) {\n            $scope.checkboxValue = mapReverse[$scope.originalValue = self.ctx.data[0].data[0][1]] || 'false';\n            $scope.currentValue = map[$scope.checkboxValue];\n            $scope.$digest();\n        }\n    } catch (e) {\n        console.log(e);\n    }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n    return {\n        maxDatasources: 1,\n        maxDataKeys: 1\n    }\n}\n\nself.onDestroy = function() {\n\n}\n",
 | 
			
		||||
        "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n    $scope = self.ctx.$scope;\n    attributeService = $scope.$injector.get('attributeService');\n    toast = $scope.$injector.get('toast');\n    utils = $scope.$injector.get('utils');\n    types = $scope.$injector.get('types');\n    settings = angular.copy(self.ctx.settings) || {};\n    $scope.settings = settings;\n    $scope.isValidParameter = true;\n    $scope.dataKeyDetected = false;\n    $scope.message = 'No entity selected';\n\n    settings.trueValue = settings.trueValue || true;\n    settings.falseValue = settings.falseValue || false;\n\n    map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n    mapReverse = {[settings.trueValue]:true, [settings.falseValue]:false};\n    $scope.checkboxValue = \"false\";\n    $scope.currentValue = map[$scope.checkboxValue];\n\n    $scope.changed = function () {\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.updateAttribute();\n    }\n\n    if (self.ctx.datasources && self.ctx.datasources.length) {\n        var datasource = self.ctx.datasources[0];\n        if (datasource.type === 'entity') {\n            if (datasource.entityType && datasource.entityId) {\n                $scope.entityName = datasource.entityName;\n                if (settings.widgetTitle && settings.widgetTitle.length) {\n                    $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n                } else {\n                    $scope.titleTemplate = self.ctx.widgetConfig.title;\n                }\n\n                $scope.entityDetected = true;\n            }\n        }\n        if (datasource.dataKeys.length) {\n            if (datasource.dataKeys[0].type != \"attribute\") {\n                $scope.isValidParameter = false;\n            } else {\n                $scope.currentKey = datasource.dataKeys[0].name;\n                $scope.dataKeyType = datasource.dataKeys[0].type;\n                $scope.dataKeyDetected = true;\n            }\n        }\n    }\n\n    self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n    $scope.updateAttribute = function () {\n        if ($scope.entityDetected) {\n            var datasource = self.ctx.datasources[0];\n\n            attributeService.saveEntityAttributes(\n                datasource.entityType,\n                datasource.entityId,\n                types.attributesScope.server.value,\n                [\n                    {\n                        key: $scope.currentKey,\n                        value: mapReverse[$scope.currentValue] || false\n                    }\n                ]\n            ).then(\n                function success() {\n                    $scope.originalValue = $scope.currentValue;\n                    if (settings.showResultMessage) {\n                        toast.showSuccess('Update successful', 1000, angular.element(self.ctx.$container), 'bottom left');\n                    }\n                },\n                function fail() {\n                    if (settings.showResultMessage) {\n                        toast.showError('Update failed', angular.element(self.ctx.$container), 'bottom left');\n                    }\n                }\n            );\n        }\n    };\n}\n\nself.onDataUpdated = function() {\n    try {\n        if ($scope.dataKeyDetected) {\n            $scope.checkboxValue = ($scope.originalValue = self.ctx.data[0].data[0][1]) || false;\n            $scope.currentValue = map[$scope.checkboxValue];\n            $scope.$digest();\n        }\n    } catch (e) {\n        console.log(e);\n    }\n}\n\nself.typeParameters = function() {\n    return {\n        maxDatasources: 1,\n        maxDataKeys: 1\n    }\n}\n\nself.onResize = function() {}\nself.onDestroy = function() {}\n",
 | 
			
		||||
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"EntitiesTableSettings\",\n        \"properties\": {\n            \"widgetTitle\": {\n                \"title\": \"Widget title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"trueValue\": {\n                \"title\": \"True value\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"falseValue\": {\n                \"title\": \"False value\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"showResultMessage\":{\n                \"title\":\"Show result message\",\n                \"type\":\"boolean\",\n                \"default\":true\n            }\n        },\n        \"required\": []\n    },\n    \"form\": [\n        \"widgetTitle\",\n        \"showResultMessage\",\n        \"trueValue\",\n        \"falseValue\"\n    ]\n}",
 | 
			
		||||
        "dataKeySettingsSchema": "{}\n",
 | 
			
		||||
        "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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update server boolean attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
 | 
			
		||||
@ -127,7 +127,7 @@
 | 
			
		||||
        "resources": [],
 | 
			
		||||
        "templateHtml": "<form class=\"attribute-update-form\"\n      name=\"attrUpdateForm\"\n      ng-submit=\"updateAttribute($event)\"\n>\n    <div style=\"padding: 0 8px; margin: auto 0;\">\n        <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n            <div class=\"grid__element\">\n                <md-checkbox ng-model=\"checkboxValue\"\n                             aria-label=\"Switch entity attribute value\"\n                             ng-change=\"changed()\"\n                             ng-true-value=\"'true'\"\n                             ng-false-value=\"'false'\"\n                >\n                    {{currentValue}}\n                </md-checkbox>\n            </div>\n        </div>\n\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\" ng-bind=\"message\"></div>\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n            No attribute is selected\n        </div>\n        <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n            Timeseries parameter cannot be used in this widget\n        </div>\n    </div>\n</form>",
 | 
			
		||||
        "templateCss": ".attribute-update-form {\n    overflow: hidden;\n    height: 100%;\n    display: flex;\n    flex-direction: column;\n}\n\n.entity-title {\n    font-weight: bold;\n    font-size: 22px;\n    padding-top: 12px;\n    padding-bottom: 6px;\n    color: #666;\n}\n\n.attribute-update-form__grid {\n    display: flex;\n}\n.grid__element:first-child {\n    flex: 1;\n}\n.grid__element:last-child {\n    margin-top: 19px;\n    margin-left: 7px;\n}\n.grid__element {\n    display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n    margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n    width: 32px;\n    min-width: 32px;\n    height: 32px;\n    min-height: 32px;\n    padding: 0 !important;\n    margin: 0 !important;\n    line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n    width: 20px;\n    min-width: 20px;\n    height: 20px;\n    min-height: 20px;\n    font-size: 20px;\n}\n\n\nmd-toast{\n    min-width: 0;\n}\nmd-toast .md-toast-content {\n    font-size: 14px!important;\n}",
 | 
			
		||||
        "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n    $scope = self.ctx.$scope;\n    attributeService = $scope.$injector.get('attributeService');\n    toast = $scope.$injector.get('toast');\n    utils = $scope.$injector.get('utils');\n    types = $scope.$injector.get('types');\n    settings = angular.copy(self.ctx.settings) || {};\n    $scope.settings = settings;\n    $scope.isValidParameter = true;\n    $scope.dataKeyDetected = false;\n    $scope.message = 'No entity selected';\n\n    settings.trueValue = settings.trueValue || true;\n    settings.falseValue = settings.falseValue || false;\n    \n    map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n    mapReverse = {[settings.trueValue]:\"true\", [settings.falseValue]:\"false\"};\n    $scope.checkboxValue = \"false\";\n    $scope.currentValue = map[$scope.checkboxValue];\n\n    $scope.changed = function () {\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.updateAttribute();\n    }\n    \n    if (self.ctx.datasources && self.ctx.datasources.length) {\n        var datasource = self.ctx.datasources[0];\n        if (datasource.type === 'entity') {\n            if (datasource.entityType === \"DEVICE\") {\n                if (datasource.entityType && datasource.entityId) {\n                    $scope.entityName = datasource.entityName;\n                    if (settings.widgetTitle && settings.widgetTitle.length) {\n                        $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n                    } else {\n                        $scope.titleTemplate = self.ctx.widgetConfig.title;\n                    }\n\n                    $scope.entityDetected = true;\n                }\n            } else {\n                $scope.message = 'Selected entity cannot have shared attributes';\n            }\n        }\n        if (datasource.dataKeys.length) {\n            if (datasource.dataKeys[0].type != \"attribute\") {\n                $scope.isValidParameter = false;\n            } else {\n                $scope.currentKey = datasource.dataKeys[0].name;\n                $scope.dataKeyType = datasource.dataKeys[0].type;\n                $scope.dataKeyDetected = true;\n            }\n        }\n    }\n\n    self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n    $scope.updateAttribute = function () {\n        if ($scope.entityDetected) {\n            var datasource = self.ctx.datasources[0];\n\n            attributeService.saveEntityAttributes(\n                datasource.entityType,\n                datasource.entityId,\n                types.attributesScope.shared.value,\n                [\n                    {\n                        key: $scope.currentKey,\n                        value: $scope.currentValue\n                    }\n                ]\n            ).then(\n                function success() {\n                    $scope.originalValue = $scope.currentValue;\n                    if (settings.showResultMessage) {\n                        toast.showSuccess('Update successful', 1000, angular.element(self.ctx.$container), 'bottom left');\n                    }\n                },\n                function fail() {\n                    if (settings.showResultMessage) {\n                        toast.showError('Update failed', angular.element(self.ctx.$container), 'bottom left');\n                    }\n                }\n            );\n        }\n    };\n}\n\nself.onDataUpdated = function() {\n\n    try {\n        $scope.checkboxValue = mapReverse[$scope.originalValue = self.ctx.data[0].data[0][1]] || 'false';\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.$digest();\n\n    } catch (e) {\n        console.log(e);\n    }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n    return {\n        maxDatasources: 1,\n        maxDataKeys: 1\n    }\n}\n\nself.onDestroy = function() {\n\n}\n",
 | 
			
		||||
        "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n    $scope = self.ctx.$scope;\n    attributeService = $scope.$injector.get('attributeService');\n    toast = $scope.$injector.get('toast');\n    utils = $scope.$injector.get('utils');\n    types = $scope.$injector.get('types');\n    settings = angular.copy(self.ctx.settings) || {};\n    $scope.settings = settings;\n    $scope.isValidParameter = true;\n    $scope.dataKeyDetected = false;\n    $scope.message = 'No entity selected';\n\n    settings.trueValue = settings.trueValue || true;\n    settings.falseValue = settings.falseValue || false;\n\n    map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n    mapReverse = {[settings.trueValue]:true, [settings.falseValue]:false};\n    $scope.checkboxValue = \"false\";\n    $scope.currentValue = map[$scope.checkboxValue];\n\n    $scope.changed = function () {\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.updateAttribute();\n    }\n\n    if (self.ctx.datasources && self.ctx.datasources.length) {\n        var datasource = self.ctx.datasources[0];\n        if (datasource.type === 'entity') {\n            if (datasource.entityType === \"DEVICE\") {\n                if (datasource.entityType && datasource.entityId) {\n                    $scope.entityName = datasource.entityName;\n                    if (settings.widgetTitle && settings.widgetTitle.length) {\n                        $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n                    } else {\n                        $scope.titleTemplate = self.ctx.widgetConfig.title;\n                    }\n\n                    $scope.entityDetected = true;\n                }\n            } else {\n                $scope.message = 'Selected entity cannot have shared attributes';\n            }\n        }\n        if (datasource.dataKeys.length) {\n            if (datasource.dataKeys[0].type != \"attribute\") {\n                $scope.isValidParameter = false;\n            } else {\n                $scope.currentKey = datasource.dataKeys[0].name;\n                $scope.dataKeyType = datasource.dataKeys[0].type;\n                $scope.dataKeyDetected = true;\n            }\n        }\n    }\n\n    self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n    $scope.updateAttribute = function () {\n        if ($scope.entityDetected) {\n            var datasource = self.ctx.datasources[0];\n\n            attributeService.saveEntityAttributes(\n                datasource.entityType,\n                datasource.entityId,\n                types.attributesScope.shared.value,\n                [\n                    {\n                        key: $scope.currentKey,\n                        value: mapReverse[$scope.currentValue] || false\n                    }\n                ]\n            ).then(\n                function success() {\n                    $scope.originalValue = $scope.currentValue;\n                    if (settings.showResultMessage) {\n                        toast.showSuccess('Update successful', 1000, angular.element(self.ctx.$container), 'bottom left');\n                    }\n                },\n                function fail() {\n                    if (settings.showResultMessage) {\n                        toast.showError('Update failed', angular.element(self.ctx.$container), 'bottom left');\n                    }\n                }\n            );\n        }\n    };\n}\n\nself.onDataUpdated = function() {\n    try {\n        $scope.checkboxValue = ($scope.originalValue = self.ctx.data[0].data[0][1]) || 'false';\n        $scope.currentValue = map[$scope.checkboxValue];\n        $scope.$digest();\n\n    } catch (e) {\n        console.log(e);\n    }\n}\n\nself.typeParameters = function() {\n    return {\n        maxDatasources: 1,\n        maxDataKeys: 1\n    }\n}\n\nself.onResize = function() {}\nself.onDestroy = function() {}\n",
 | 
			
		||||
        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"EntitiesTableSettings\",\n        \"properties\": {\n            \"widgetTitle\": {\n                \"title\": \"Widget title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"trueValue\": {\n                \"title\": \"True value\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"falseValue\": {\n                \"title\": \"False value\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            },\n            \"showResultMessage\":{\n                \"title\":\"Show result message\",\n                \"type\":\"boolean\",\n                \"default\":true\n            }\n        },\n        \"required\": []\n    },\n    \"form\": [\n        \"widgetTitle\",\n        \"showResultMessage\",\n        \"trueValue\",\n        \"falseValue\"\n    ]\n}",
 | 
			
		||||
        "dataKeySettingsSchema": "{}\n",
 | 
			
		||||
        "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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"trueValue\":\"active\",\"falseValue\":\"inactive\"},\"title\":\"Update shared boolean attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,134 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2018 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.rule.engine.filter;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.thingsboard.rule.engine.api.RuleNode;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNode;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNodeException;
 | 
			
		||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.plugin.ComponentType;
 | 
			
		||||
import org.thingsboard.server.common.msg.TbMsg;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@RuleNode(
 | 
			
		||||
        type = ComponentType.FILTER,
 | 
			
		||||
        name = "check existence fields",
 | 
			
		||||
        relationTypes = {"True", "False"},
 | 
			
		||||
        configClazz = TbCheckMessageNodeConfiguration.class,
 | 
			
		||||
        nodeDescription = "Checks the existence of the selected keys from message data and metadata.",
 | 
			
		||||
        nodeDetails = "If selected checkbox 'Check that all selected keys are present'\" and all keys in message data and metadata are exist - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.\n" +
 | 
			
		||||
                "Else if the checkbox is not selected, and at least one of the keys from data or metadata of the message exists - send Message via <b>True</b> chain, otherwise, <b>False</b> chain is used. ",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js"},
 | 
			
		||||
        configDirective = "tbFilterNodeCheckMessageConfig")
 | 
			
		||||
public class TbCheckMessageNode implements TbNode {
 | 
			
		||||
 | 
			
		||||
    private static final Gson gson = new Gson();
 | 
			
		||||
 | 
			
		||||
    private TbCheckMessageNodeConfiguration config;
 | 
			
		||||
    private List<String> messageNamesList;
 | 
			
		||||
    private List<String> metadataNamesList;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void init(TbContext tbContext, TbNodeConfiguration configuration) throws TbNodeException {
 | 
			
		||||
        this.config = TbNodeUtils.convert(configuration, TbCheckMessageNodeConfiguration.class);
 | 
			
		||||
        messageNamesList = config.getMessageNames();
 | 
			
		||||
        metadataNamesList = config.getMetadataNames();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMsg(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (config.isCheckAllKeys()) {
 | 
			
		||||
                ctx.tellNext(msg, allKeysData(msg) && allKeysMetadata(msg) ? "True" : "False");
 | 
			
		||||
            } else {
 | 
			
		||||
                ctx.tellNext(msg, atLeastOneData(msg) || atLeastOneMetadata(msg) ? "True" : "False");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            ctx.tellFailure(msg, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void destroy() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean allKeysData(TbMsg msg) {
 | 
			
		||||
        if (!messageNamesList.isEmpty()) {
 | 
			
		||||
            Map<String, String> dataMap = dataToMap(msg);
 | 
			
		||||
            return processAllKeys(messageNamesList, dataMap);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean allKeysMetadata(TbMsg msg) {
 | 
			
		||||
        if (!metadataNamesList.isEmpty()) {
 | 
			
		||||
            Map<String, String> metadataMap = metadataToMap(msg);
 | 
			
		||||
            return processAllKeys(metadataNamesList, metadataMap);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean atLeastOneData(TbMsg msg) {
 | 
			
		||||
        if (!messageNamesList.isEmpty()) {
 | 
			
		||||
            Map<String, String> dataMap = dataToMap(msg);
 | 
			
		||||
            return processAtLeastOne(messageNamesList, dataMap);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean atLeastOneMetadata(TbMsg msg) {
 | 
			
		||||
        if (!metadataNamesList.isEmpty()) {
 | 
			
		||||
            Map<String, String> metadataMap = metadataToMap(msg);
 | 
			
		||||
            return processAtLeastOne(metadataNamesList, metadataMap);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean processAllKeys(List<String> data, Map<String, String> map) {
 | 
			
		||||
        for (String field : data) {
 | 
			
		||||
            if (!map.containsKey(field)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean processAtLeastOne(List<String> data, Map<String, String> map) {
 | 
			
		||||
        for (String field : data) {
 | 
			
		||||
            if (map.containsKey(field)) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Map<String, String> metadataToMap(TbMsg msg) {
 | 
			
		||||
        return msg.getMetaData().getData();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private Map<String, String> dataToMap(TbMsg msg) {
 | 
			
		||||
        return (Map<String, String>) gson.fromJson(msg.getData(), Map.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2018 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.rule.engine.filter;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class TbCheckMessageNodeConfiguration implements NodeConfiguration {
 | 
			
		||||
 | 
			
		||||
    private List<String> messageNames;
 | 
			
		||||
    private List<String> metadataNames;
 | 
			
		||||
 | 
			
		||||
    private boolean checkAllKeys;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public TbCheckMessageNodeConfiguration defaultConfiguration() {
 | 
			
		||||
        TbCheckMessageNodeConfiguration configuration = new TbCheckMessageNodeConfiguration();
 | 
			
		||||
        configuration.setMessageNames(Collections.emptyList());
 | 
			
		||||
        configuration.setMetadataNames(Collections.emptyList());
 | 
			
		||||
        configuration.setCheckAllKeys(true);
 | 
			
		||||
        return configuration;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -53,6 +53,19 @@
 | 
			
		||||
            return result;
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    if (!String.prototype.includes) {
 | 
			
		||||
        String.prototype.includes = function(search, start) {
 | 
			
		||||
            if (angular.isNumber(start)) {
 | 
			
		||||
                start = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (start + search.length > this.length) {
 | 
			
		||||
                return false;
 | 
			
		||||
            } else {
 | 
			
		||||
                return this.indexOf(search, start) !== -1;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (function (arr) {
 | 
			
		||||
        arr.forEach(function (item) {
 | 
			
		||||
 | 
			
		||||
@ -539,10 +539,14 @@ export default class TbMapWidgetV2 {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (locationsChanged && tbMap.initBounds) {
 | 
			
		||||
				tbMap.initBounds = !datasources.every(
 | 
			
		||||
				let dataReceived = datasources.every(
 | 
			
		||||
					function (ds) {
 | 
			
		||||
						return ds.dataReceived === true;
 | 
			
		||||
					});
 | 
			
		||||
				let dataValid = dataReceived && dataMap.dsDataMap.every(function (ds) {
 | 
			
		||||
					return !(!ds[tbMap.locationSettings.latKeyName] && !ds[tbMap.locationSettings.lngKeyName]);
 | 
			
		||||
				});
 | 
			
		||||
				tbMap.initBounds = !dataValid;
 | 
			
		||||
				tbMap.map.fitBounds(bounds);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user