Commit 6091f1a8d8806916b7635035a243c7c799ae52be
1 parent
a568564e
Add new widget 'multiple-widget' to bundle 'input_widgets'
Showing
9 changed files
with
397 additions
and
7 deletions
@@ -196,6 +196,22 @@ | @@ -196,6 +196,22 @@ | ||
196 | "dataKeySettingsSchema": "{}\n", | 196 | "dataKeySettingsSchema": "{}\n", |
197 | "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 integer timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | 197 | "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 integer timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
198 | } | 198 | } |
199 | + }, | ||
200 | + { | ||
201 | + "alias": "update_multiple_attributes", | ||
202 | + "name": "Update Multiple Attributes", | ||
203 | + "descriptor": { | ||
204 | + "type": "latest", | ||
205 | + "sizeX": 7.5, | ||
206 | + "sizeY": 3.5, | ||
207 | + "resources": [], | ||
208 | + "templateHtml": "<tb-multiple-input-widget \n form-id=\"formId\"\n ctx=\"ctx\">\n</tb-multiple-input-widget>", | ||
209 | + "templateCss": "", | ||
210 | + "controllerScript": "let $scope;\r\nlet settings;\r\nlet attributeService;\r\nlet toast;\r\nlet utils;\r\nlet types;\r\n\r\nself.onInit = function() {\r\n var scope = self.ctx.$scope;\r\n var id = self.ctx.$scope.$injector.get('utils').guid();\r\n scope.formId = \"form-\"+id;\r\n scope.ctx = self.ctx;\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n self.ctx.$scope.$broadcast('multiple-input-data-updated', self.ctx.$scope.formId);\r\n}\r\n", | ||
211 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Multiple input title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"attributesShared\": {\n \"title\": \"Attributes are 'shared' (default value is 'server')\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"attributesShared\",\n \"showResultMessage\"\n ]\n}", | ||
212 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"inputTypeNumber\": {\n \"title\": \"Datakey is a number\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"step\": {\n \"title\": \"Step interval between valid values (only for numbers)\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\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)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"inputTypeNumber\",\n \"step\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t},\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n", | ||
213 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update Multiple Attributes\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | ||
214 | + } | ||
199 | } | 215 | } |
200 | ] | 216 | ] |
201 | -} | ||
217 | +} |
@@ -24,6 +24,7 @@ import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget' | @@ -24,6 +24,7 @@ import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget' | ||
24 | import thingsboardEntitiesHierarchyWidget from '../widget/lib/entities-hierarchy-widget'; | 24 | import thingsboardEntitiesHierarchyWidget from '../widget/lib/entities-hierarchy-widget'; |
25 | import thingsboardExtensionsTableWidget from '../widget/lib/extensions-table-widget'; | 25 | import thingsboardExtensionsTableWidget from '../widget/lib/extensions-table-widget'; |
26 | import thingsboardDateRangeNavigatorWidget from '../widget/lib/date-range-navigator/date-range-navigator'; | 26 | import thingsboardDateRangeNavigatorWidget from '../widget/lib/date-range-navigator/date-range-navigator'; |
27 | +import thingsboardMultipleInputWidget from '../widget/lib/multiple-input-widget'; | ||
27 | 28 | ||
28 | import thingsboardRpcWidgets from '../widget/lib/rpc'; | 29 | import thingsboardRpcWidgets from '../widget/lib/rpc'; |
29 | 30 | ||
@@ -49,7 +50,7 @@ import thingsboardUtils from '../common/utils.service'; | @@ -49,7 +50,7 @@ import thingsboardUtils from '../common/utils.service'; | ||
49 | export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, | 50 | export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, |
50 | thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, | 51 | thingsboardTimeseriesTableWidget, thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, |
51 | thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget, | 52 | thingsboardEntitiesHierarchyWidget, thingsboardExtensionsTableWidget, thingsboardDateRangeNavigatorWidget, |
52 | - thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils, TripAnimationWidget]) | 53 | + thingsboardMultipleInputWidget, thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils, TripAnimationWidget]) |
53 | .factory('widgetService', WidgetService) | 54 | .factory('widgetService', WidgetService) |
54 | .name; | 55 | .name; |
55 | 56 |
@@ -49,7 +49,8 @@ | @@ -49,7 +49,8 @@ | ||
49 | "import": "Import", | 49 | "import": "Import", |
50 | "export": "Export", | 50 | "export": "Export", |
51 | "share-via": "Share via {{provider}}", | 51 | "share-via": "Share via {{provider}}", |
52 | - "continue": "Continue" | 52 | + "continue": "Continue", |
53 | + "discard-changes": "Discard Changes" | ||
53 | }, | 54 | }, |
54 | "aggregation": { | 55 | "aggregation": { |
55 | "aggregation": "Aggregation", | 56 | "aggregation": "Aggregation", |
@@ -1694,4 +1695,4 @@ | @@ -1694,4 +1695,4 @@ | ||
1694 | "cs_CZ": "Czech" | 1695 | "cs_CZ": "Czech" |
1695 | } | 1696 | } |
1696 | } | 1697 | } |
1697 | -} | ||
1698 | +} |
@@ -48,7 +48,8 @@ | @@ -48,7 +48,8 @@ | ||
48 | "paste-reference": "Pegar referencia", | 48 | "paste-reference": "Pegar referencia", |
49 | "import": "Importar", | 49 | "import": "Importar", |
50 | "export": "Exportar", | 50 | "export": "Exportar", |
51 | - "share-via": "Compartir via {{provider}}" | 51 | + "share-via": "Compartir via {{provider}}", |
52 | + "discard-changes": "Cancelar los cambios" | ||
52 | }, | 53 | }, |
53 | "aggregation": { | 54 | "aggregation": { |
54 | "aggregation": "Agregación", | 55 | "aggregation": "Agregación", |
@@ -48,7 +48,8 @@ | @@ -48,7 +48,8 @@ | ||
48 | "undo": "Annuler", | 48 | "undo": "Annuler", |
49 | "update": "mise à jour", | 49 | "update": "mise à jour", |
50 | "view": "Afficher", | 50 | "view": "Afficher", |
51 | - "yes": "Oui" | 51 | + "yes": "Oui", |
52 | + "discard-changes": "Annuler les modifications" | ||
52 | }, | 53 | }, |
53 | "admin": { | 54 | "admin": { |
54 | "base-url": "URL de base", | 55 | "base-url": "URL de base", |
@@ -48,7 +48,8 @@ | @@ -48,7 +48,8 @@ | ||
48 | "paste-reference": "Incolla riferimento", | 48 | "paste-reference": "Incolla riferimento", |
49 | "import": "Importa", | 49 | "import": "Importa", |
50 | "export": "Esporta", | 50 | "export": "Esporta", |
51 | - "share-via": "Condividi con {{provider}}" | 51 | + "share-via": "Condividi con {{provider}}", |
52 | + "discard-changes": "Annulla le modifiche" | ||
52 | }, | 53 | }, |
53 | "aggregation": { | 54 | "aggregation": { |
54 | "aggregation": "Aggregazione", | 55 | "aggregation": "Aggregazione", |
1 | +/* | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +import './multiple-input-widget.scss'; | ||
17 | + | ||
18 | +/* eslint-disable import/no-unresolved, import/default */ | ||
19 | + | ||
20 | +import multipleInputWidgetTemplate from './multiple-input-widget.tpl.html'; | ||
21 | + | ||
22 | +/* eslint-enable import/no-unresolved, import/default */ | ||
23 | + | ||
24 | +export default angular.module('thingsboard.widgets.multipleInputWidget', []) | ||
25 | + .directive('tbMultipleInputWidget', MultipleInputWidget) | ||
26 | + .name; | ||
27 | + | ||
28 | +/*@ngInject*/ | ||
29 | +function MultipleInputWidget() { | ||
30 | + return { | ||
31 | + restrict: "E", | ||
32 | + scope: true, | ||
33 | + bindToController: { | ||
34 | + formId: '=', | ||
35 | + ctx: '=' | ||
36 | + }, | ||
37 | + controller: MultipleInputWidgetController, | ||
38 | + controllerAs: 'vm', | ||
39 | + templateUrl: multipleInputWidgetTemplate | ||
40 | + }; | ||
41 | +} | ||
42 | + | ||
43 | +/*@ngInject*/ | ||
44 | +function MultipleInputWidgetController($q, $scope, attributeService, toast, types, utils) { | ||
45 | + var vm = this; | ||
46 | + | ||
47 | + vm.dataKeyDetected = false; | ||
48 | + vm.hasAnyChange = false; | ||
49 | + vm.entityDetected = false; | ||
50 | + vm.isValidParameter = true; | ||
51 | + vm.message = 'No entity selected'; | ||
52 | + | ||
53 | + vm.rows = []; | ||
54 | + vm.rowIndex = 0; | ||
55 | + | ||
56 | + vm.datasources = null; | ||
57 | + | ||
58 | + vm.cellStyle = cellStyle; | ||
59 | + vm.discardAll = discardAll; | ||
60 | + vm.inputChanged = inputChanged; | ||
61 | + vm.postData = postData; | ||
62 | + | ||
63 | + $scope.$watch('vm.ctx', function() { | ||
64 | + if (vm.ctx && vm.ctx.defaultSubscription) { | ||
65 | + vm.settings = vm.ctx.settings; | ||
66 | + vm.widgetConfig = vm.ctx.widgetConfig; | ||
67 | + vm.subscription = vm.ctx.defaultSubscription; | ||
68 | + vm.datasources = vm.subscription.datasources; | ||
69 | + initializeConfig(); | ||
70 | + updateDatasources(); | ||
71 | + } | ||
72 | + }); | ||
73 | + | ||
74 | + $scope.$on('multiple-input-data-updated', function(event, formId) { | ||
75 | + if (vm.formId == formId) { | ||
76 | + updateRowData(vm.subscription.data); | ||
77 | + $scope.$digest(); | ||
78 | + } | ||
79 | + }); | ||
80 | + | ||
81 | + function defaultStyle() { | ||
82 | + return {}; | ||
83 | + } | ||
84 | + | ||
85 | + function cellStyle(key) { | ||
86 | + var style = {}; | ||
87 | + if (key) { | ||
88 | + var styleInfo = vm.stylesInfo[key.label]; | ||
89 | + var value = key.currentValue; | ||
90 | + if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) { | ||
91 | + try { | ||
92 | + style = styleInfo.cellStyleFunction(value); | ||
93 | + } catch (e) { | ||
94 | + style = {}; | ||
95 | + } | ||
96 | + } else { | ||
97 | + style = defaultStyle(); | ||
98 | + } | ||
99 | + } | ||
100 | + return style; | ||
101 | + } | ||
102 | + | ||
103 | + function discardAll() { | ||
104 | + for (var r = 0; r < vm.rows.length; r++) { | ||
105 | + var row = vm.rows[r]; | ||
106 | + for (var d = 0; d < row.data.length; d++ ) { | ||
107 | + row.data[d].currentValue = row.data[d].originalValue; | ||
108 | + } | ||
109 | + } | ||
110 | + vm.hasAnyChange = false; | ||
111 | + } | ||
112 | + | ||
113 | + function inputChanged() { | ||
114 | + var newValue = false; | ||
115 | + for (var r = 0; r < vm.rows.length; r++) { | ||
116 | + var row = vm.rows[r]; | ||
117 | + for (var d = 0; d < row.data.length; d++ ) { | ||
118 | + if (!row.data[d].currentValue) { | ||
119 | + return; | ||
120 | + } | ||
121 | + if (row.data[d].currentValue !== row.data[d].originalValue) { | ||
122 | + newValue = true; | ||
123 | + } | ||
124 | + } | ||
125 | + } | ||
126 | + vm.hasAnyChange = newValue; | ||
127 | + } | ||
128 | + | ||
129 | + function postData() { | ||
130 | + var promises = []; | ||
131 | + for (var r = 0; r < vm.rows.length; r++) { | ||
132 | + var row = vm.rows[r]; | ||
133 | + var datasource = row.datasource; | ||
134 | + var attributes = []; | ||
135 | + var newValues = false; | ||
136 | + | ||
137 | + for (var d = 0; d < row.data.length; d++ ) { | ||
138 | + if (row.data[d].currentValue !== row.data[d].originalValue) { | ||
139 | + attributes.push({ | ||
140 | + key : row.data[d].name, | ||
141 | + value : row.data[d].currentValue, | ||
142 | + }); | ||
143 | + newValues = true; | ||
144 | + } | ||
145 | + } | ||
146 | + | ||
147 | + if (newValues) { | ||
148 | + promises.push(attributeService.saveEntityAttributes( | ||
149 | + datasource.entityType, | ||
150 | + datasource.entityId, | ||
151 | + vm.attributeScope, | ||
152 | + attributes)); | ||
153 | + } | ||
154 | + } | ||
155 | + | ||
156 | + if (promises.length) { | ||
157 | + $q.all(promises).then( | ||
158 | + function success() { | ||
159 | + for (var d = 0; d < row.data.length; d++ ) { | ||
160 | + row.data[d].originalValue = row.data[d].currentValue; | ||
161 | + } | ||
162 | + vm.hasAnyChange = false; | ||
163 | + if (vm.settings.showResultMessage) { | ||
164 | + toast.showSuccess('Update successful', 1000, angular.element(vm.ctx.$container), 'bottom left'); | ||
165 | + } | ||
166 | + }, | ||
167 | + function fail() { | ||
168 | + if (vm.settings.showResultMessage) { | ||
169 | + toast.showError('Update failed', angular.element(vm.ctx.$container), 'bottom left'); | ||
170 | + } | ||
171 | + } | ||
172 | + ); | ||
173 | + } | ||
174 | + } | ||
175 | + | ||
176 | + function initializeConfig() { | ||
177 | + | ||
178 | + if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) { | ||
179 | + vm.widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle); | ||
180 | + } else { | ||
181 | + vm.widgetTitle = vm.ctx.widgetConfig.title; | ||
182 | + } | ||
183 | + | ||
184 | + vm.ctx.widgetTitle = vm.widgetTitle; | ||
185 | + | ||
186 | + vm.attributeScope = vm.settings.attributesShared ? types.attributesScope.shared.value : types.attributesScope.server.value; | ||
187 | + } | ||
188 | + | ||
189 | + function updateDatasources() { | ||
190 | + | ||
191 | + vm.stylesInfo = {}; | ||
192 | + vm.rows = []; | ||
193 | + vm.rowIndex = 0; | ||
194 | + | ||
195 | + if (vm.datasources) { | ||
196 | + vm.entityDetected = true; | ||
197 | + for (var ds = 0; ds < vm.datasources.length; ds++) { | ||
198 | + var row = {}; | ||
199 | + var datasource = vm.datasources[ds]; | ||
200 | + row.datasource = datasource; | ||
201 | + row.data = []; | ||
202 | + if (datasource.dataKeys) { | ||
203 | + vm.dataKeyDetected = true; | ||
204 | + for (var a = 0; a < datasource.dataKeys.length; a++ ) { | ||
205 | + var dataKey = datasource.dataKeys[a]; | ||
206 | + | ||
207 | + if (dataKey.units) { | ||
208 | + dataKey.label += ' (' + dataKey.units + ')'; | ||
209 | + } | ||
210 | + | ||
211 | + var keySettings = dataKey.settings; | ||
212 | + if (keySettings.inputTypeNumber) { | ||
213 | + keySettings.inputType = 'number'; | ||
214 | + } else { | ||
215 | + keySettings.inputType = 'text'; | ||
216 | + } | ||
217 | + | ||
218 | + var cellStyleFunction = null; | ||
219 | + var useCellStyleFunction = false; | ||
220 | + | ||
221 | + if (keySettings.useCellStyleFunction === true) { | ||
222 | + if (angular.isDefined(keySettings.cellStyleFunction) && keySettings.cellStyleFunction.length > 0) { | ||
223 | + try { | ||
224 | + cellStyleFunction = new Function('value', keySettings.cellStyleFunction); | ||
225 | + useCellStyleFunction = true; | ||
226 | + } catch (e) { | ||
227 | + cellStyleFunction = null; | ||
228 | + useCellStyleFunction = false; | ||
229 | + } | ||
230 | + } | ||
231 | + } | ||
232 | + | ||
233 | + vm.stylesInfo[dataKey.label] = { | ||
234 | + useCellStyleFunction: useCellStyleFunction, | ||
235 | + cellStyleFunction: cellStyleFunction | ||
236 | + }; | ||
237 | + | ||
238 | + row.data.push(dataKey); | ||
239 | + } | ||
240 | + vm.rows.push(row); | ||
241 | + } | ||
242 | + } | ||
243 | + } | ||
244 | + } | ||
245 | + | ||
246 | + function updateRowData(data) { | ||
247 | + var dataIndex = 0; | ||
248 | + for (var r = 0; r < vm.rows.length; r++) { | ||
249 | + var row = vm.rows[r]; | ||
250 | + for (var d = 0; d < row.data.length; d++ ) { | ||
251 | + var keyData = data[dataIndex++].data; | ||
252 | + if (keyData && keyData.length && keyData[0].length > 1) { | ||
253 | + row.data[d].currentValue = row.data[d].originalValue = keyData[0][1]; | ||
254 | + } | ||
255 | + } | ||
256 | + } | ||
257 | + } | ||
258 | + | ||
259 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +.tb-multiple-input { | ||
17 | + height: 100%; | ||
18 | + | ||
19 | + .md-button.md-icon-button { | ||
20 | + width: 32px; | ||
21 | + min-width: 32px; | ||
22 | + height: 32px; | ||
23 | + min-height: 32px; | ||
24 | + padding: 0 !important; | ||
25 | + margin: 0; | ||
26 | + line-height: 20px; | ||
27 | + } | ||
28 | + | ||
29 | + .md-icon-button md-icon { | ||
30 | + width: 20px; | ||
31 | + min-width: 20px; | ||
32 | + height: 20px; | ||
33 | + min-height: 20px; | ||
34 | + font-size: 20px; | ||
35 | + | ||
36 | + &:not([disabled]) { | ||
37 | + color: #f66; | ||
38 | + } | ||
39 | + } | ||
40 | +} | ||
41 | + | ||
42 | +md-toast { | ||
43 | + min-width: 0; | ||
44 | + | ||
45 | + .md-toast-content { | ||
46 | + font-size: 14px !important; | ||
47 | + } | ||
48 | +} | ||
49 | + | ||
50 | +.footer { | ||
51 | + position: absolute; | ||
52 | + bottom: 0; | ||
53 | + left: 0; | ||
54 | + width: 100%; | ||
55 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<form class="tb-multiple-input" name="multipleInputForm" ng-submit="vm.postData($event)"> | ||
19 | + <div style="padding: 0 8px; margin: auto 0;"> | ||
20 | + <div ng-show="vm.entityDetected" layout="row" flex ng-repeat="row in vm.rows track by $index"> | ||
21 | + <div layout="column" flex ng-repeat="key in row.data track by $index"> | ||
22 | + <md-input-container class="md-icon-float" ng-style="vm.cellStyle(key)"> | ||
23 | + <label>{{key.label}}</label> | ||
24 | + <md-icon class="material-icons" ng-if="key.settings.icon"> | ||
25 | + {{key.settings.icon}} | ||
26 | + </md-icon> | ||
27 | + <input name="key.name" | ||
28 | + ng-model="key.currentValue" | ||
29 | + type="{{key.settings.inputType}}" | ||
30 | + step="{{key.settings.step}}" | ||
31 | + md-select-on-focus | ||
32 | + ng-change="vm.inputChanged()"> | ||
33 | + </md-input-container> | ||
34 | + </div> | ||
35 | + </div> | ||
36 | + | ||
37 | + <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-hide="vm.entityDetected" ng-bind="vm.message" | ||
38 | + ></div> | ||
39 | + <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-show="vm.entityDetected && !vm.dataKeyDetected"> | ||
40 | + No attribute is selected | ||
41 | + </div> | ||
42 | + <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-show="vm.entityDetected && !vm.isValidParameter"> | ||
43 | + Timeseries parameter cannot be used in this widget | ||
44 | + </div> | ||
45 | + </div> | ||
46 | + <div class="footer md-padding" layout="row" layout-align="end center" ng-show="vm.entityDetected && vm.dataKeyDetected"> | ||
47 | + <md-button class="md-primary" ng-click="vm.discardAll()" style="max-height: 50px;margin-right:20px;" ng-disabled="!vm.hasAnyChange"> | ||
48 | + {{ 'action.discard-changes' | translate }} | ||
49 | + </md-button> | ||
50 | + <md-button class="md-raised md-primary" type="submit" value="Submit" style="max-height: 50px;margin-right:20px;" | ||
51 | + ng-disabled="!vm.hasAnyChange" ng-click="vm.isFocused = false"> | ||
52 | + {{ 'action.save' | translate }} | ||
53 | + </md-button> | ||
54 | + </div> | ||
55 | +</form> |