thingsboard-aplcache

Merge pull request #1447 from jktu2870/input_widgets UI:fix(#1427).

2/1/2019 11:20:17 AM

Details

diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json
index e7f0acf..6dc7f2a 100644
--- a/application/src/main/data/json/system/widget_bundles/input_widgets.json
+++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json
@@ -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\":{}}"