Commit a51c44e5dbc90b4975ded1a9f73a4560d120a507
Committed by
Igor Kulikov
1 parent
1059c21e
Multiple attributes input widget improvement (#2144)
* Extend multiple input widget * Update multiple attributes widget * Change bundle, minor changes * Fix disablefor date input
Showing
4 changed files
with
326 additions
and
217 deletions
... | ... | @@ -319,9 +319,9 @@ |
319 | 319 | "resources": [], |
320 | 320 | "templateHtml": "<tb-multiple-input-widget \n form-id=\"formId\"\n ctx=\"ctx\">\n</tb-multiple-input-widget>", |
321 | 321 | "templateCss": "", |
322 | - "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", | |
323 | - "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}", | |
324 | - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"readOnly\": {\n \"title\": \"Value is read only\",\n \"type\": \"boolean\",\n \"default\": false\n },\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 \"readOnly\",\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", | |
322 | + "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\r\nself.typeParameters = function() {\r\n return {\r\n maxDatasources: 1\r\n }\r\n}\r\n\r\nself.onResize = function() {\r\n self.ctx.$scope.$broadcast('multiple-input-resize', self.ctx.$scope.formId);\r\n}\r\n", | |
323 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"MultipleInput\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showActionButtons\":{\n \"title\":\"Show action buttons\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\": true\n },\n \"fieldsAlignment\": {\n \"title\": \"Fields alignment\",\n \"type\": \"string\",\n \"default\": \"row\"\n },\n \"fieldsInRow\": {\n \"title\": \"Number of fields in the row\",\n \"type\": \"number\",\n \"default\": \"2\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showActionButtons\",\n \"showResultMessage\",\n {\n \"key\": \"fieldsAlignment\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"row\",\n \"label\": \"Row (default)\"\n },\n {\n \"value\": \"column\",\n \"label\": \"Column\"\n }\n ]\n },\n \"fieldsInRow\"\n ]\n}", | |
324 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"dataKeyType\": {\n \"title\": \"Datakey type\",\n \"type\": \"string\",\n \"default\": \"server\"\n },\n \"dataKeyValueType\": {\n \"title\": \"Datakey value type\",\n \"type\": \"string\",\n \"default\": \"string\"\n },\n \"required\": {\n \"title\": \"Value is required\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"isEditable\": {\n \"title\": \"Ability to edit attribute\",\n \"type\": \"string\",\n \"default\": \"editable\"\n },\n \"disabledOnDataKey\": {\n \"title\": \"Disable on false value of another datakey (specify datakey name)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"dataKeyHidden\": {\n \"title\": \"Hide input field\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"step\": {\n \"title\": \"Step interval between values (only for numbers)\",\n \"type\": \"number\",\n \"default\": \"1\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"icon\": {\n \"title\": \"Icon to show before input cell\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"dataKeyType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"server\",\n \"label\": \"Server attribute (default)\"\n },\n {\n \"value\": \"shared\",\n \"label\": \"Shared attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Timeseries\"\n }\n ]\n },\n {\n \"key\": \"dataKeyValueType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"string\",\n \"label\": \"String\"\n },\n {\n \"value\": \"double\",\n \"label\": \"Double\"\n },\n {\n \"value\": \"integer\",\n \"label\": \"Integer\"\n },\n {\n \"value\": \"booleanCheckbox\",\n \"label\": \"Boolean (Checkbox)\"\n },\n {\n \"value\": \"booleanSwitch\",\n \"label\": \"Boolean (Switch)\"\n },\n {\n \"value\": \"dateTime\",\n \"label\": \"Date & Time\"\n },\n {\n \"value\": \"date\",\n \"label\": \"Date\"\n },\n {\n \"value\": \"time\",\n \"label\": \"Time\"\n }\n ]\n },\n \"required\",\n {\n \"key\": \"isEditable\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"editable\",\n \"label\": \"Editable (default)\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n },\n {\n \"value\": \"readonly\",\n \"label\": \"Read-only\"\n }\n ]\n },\n \"disabledOnDataKey\",\n \"dataKeyHidden\",\n \"step\",\n \"requiredErrorMessage\",\n\t\t{\n \t\t\"key\": \"icon\",\n\t\t\t\"type\": \"icon\"\n\t\t}\n ]\n}\n", | |
325 | 325 | "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\":{}}" |
326 | 326 | } |
327 | 327 | }, | ... | ... |
... | ... | @@ -41,25 +41,18 @@ function MultipleInputWidget() { |
41 | 41 | } |
42 | 42 | |
43 | 43 | /*@ngInject*/ |
44 | -function MultipleInputWidgetController($q, $scope, attributeService, toast, types, utils) { | |
44 | +function MultipleInputWidgetController($q, $scope, $translate, attributeService, toast, types, utils) { | |
45 | 45 | var vm = this; |
46 | 46 | |
47 | - vm.dataKeyDetected = false; | |
48 | - vm.hasAnyChange = false; | |
49 | 47 | vm.entityDetected = false; |
50 | - vm.isValidParameter = true; | |
51 | - vm.message = 'No entity selected'; | |
52 | - | |
53 | - vm.rows = []; | |
54 | - vm.rowIndex = 0; | |
48 | + vm.isAllParametersValid = true; | |
55 | 49 | |
50 | + vm.data = []; | |
56 | 51 | vm.datasources = null; |
57 | 52 | |
58 | - vm.cellStyle = cellStyle; | |
59 | - vm.textColor = textColor; | |
60 | 53 | vm.discardAll = discardAll; |
61 | 54 | vm.inputChanged = inputChanged; |
62 | - vm.postData = postData; | |
55 | + vm.save = save; | |
63 | 56 | |
64 | 57 | $scope.$watch('vm.ctx', function() { |
65 | 58 | if (vm.ctx && vm.ctx.defaultSubscription) { |
... | ... | @@ -74,127 +67,109 @@ function MultipleInputWidgetController($q, $scope, attributeService, toast, type |
74 | 67 | |
75 | 68 | $scope.$on('multiple-input-data-updated', function(event, formId) { |
76 | 69 | if (vm.formId == formId) { |
77 | - updateRowData(vm.subscription.data); | |
70 | + updateWidgetData(vm.subscription.data); | |
78 | 71 | $scope.$digest(); |
79 | 72 | } |
80 | 73 | }); |
81 | 74 | |
82 | - function defaultStyle() { | |
83 | - return {}; | |
84 | - } | |
85 | - | |
86 | - function cellStyle(key, rowIndex, firstKey, lastKey) { | |
87 | - var style = {}; | |
88 | - if (key) { | |
89 | - var styleInfo = vm.stylesInfo[key.label]; | |
90 | - var value = key.currentValue; | |
91 | - if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) { | |
92 | - try { | |
93 | - style = styleInfo.cellStyleFunction(value); | |
94 | - } catch (e) { | |
95 | - style = {}; | |
96 | - } | |
97 | - } else { | |
98 | - style = defaultStyle(); | |
99 | - } | |
100 | - } | |
101 | - if (vm.settings.rowMargin) { | |
102 | - if (angular.isUndefined(style.marginTop) && rowIndex != 0) { | |
103 | - style.marginTop = (vm.settings.rowMargin / 2) + 'px'; | |
104 | - } | |
105 | - if (angular.isUndefined(style.marginBottom)) { | |
106 | - style.marginBottom = (vm.settings.rowMargin / 2) + 'px'; | |
107 | - } | |
108 | - } | |
109 | - if (vm.settings.columnMargin) { | |
110 | - if (angular.isUndefined(style.marginLeft) && !firstKey) { | |
111 | - style.marginLeft = (vm.settings.columnMargin / 2) + 'px'; | |
112 | - } | |
113 | - if (angular.isUndefined(style.marginRight) && !lastKey) { | |
114 | - style.marginRight = (vm.settings.columnMargin / 2) + 'px'; | |
115 | - } | |
116 | - } | |
117 | - return style; | |
118 | - } | |
119 | - | |
120 | - function textColor(key) { | |
121 | - var style = {}; | |
122 | - if (key) { | |
123 | - var styleInfo = vm.stylesInfo[key.label]; | |
124 | - if (styleInfo.color) { | |
125 | - style = { color: styleInfo.color }; | |
126 | - } | |
75 | + $scope.$on('multiple-input-resize', function(event, formId) { | |
76 | + if (vm.formId == formId) { | |
77 | + updateWidgetDisplaying(); | |
127 | 78 | } |
128 | - return style; | |
129 | - } | |
79 | + }); | |
130 | 80 | |
131 | 81 | function discardAll() { |
132 | - for (var r = 0; r < vm.rows.length; r++) { | |
133 | - var row = vm.rows[r]; | |
134 | - for (var d = 0; d < row.data.length; d++ ) { | |
135 | - row.data[d].currentValue = row.data[d].originalValue; | |
136 | - } | |
82 | + for (var i = 0; i < vm.data.length; i++) { | |
83 | + vm.data[i].data.currentValue = vm.data[i].data.originalValue; | |
137 | 84 | } |
138 | - vm.hasAnyChange = false; | |
85 | + $scope.multipleInputForm.$setPristine(); | |
139 | 86 | } |
140 | 87 | |
141 | - function inputChanged() { | |
142 | - var newValue = false; | |
143 | - for (var r = 0; r < vm.rows.length; r++) { | |
144 | - var row = vm.rows[r]; | |
145 | - for (var d = 0; d < row.data.length; d++ ) { | |
146 | - if (!row.data[d].currentValue) { | |
147 | - return; | |
148 | - } | |
149 | - if (row.data[d].currentValue !== row.data[d].originalValue) { | |
150 | - newValue = true; | |
151 | - } | |
88 | + function inputChanged(key) { | |
89 | + if (!vm.settings.showActionButtons) { | |
90 | + if (!key.settings.required || (key.settings.required && key.data && angular.isDefined(key.data.currentValue))) { | |
91 | + vm.save(key); | |
152 | 92 | } |
153 | 93 | } |
154 | - vm.hasAnyChange = newValue; | |
155 | 94 | } |
156 | 95 | |
157 | - function postData() { | |
158 | - var promises = []; | |
159 | - for (var r = 0; r < vm.rows.length; r++) { | |
160 | - var row = vm.rows[r]; | |
161 | - var datasource = row.datasource; | |
162 | - var attributes = []; | |
163 | - var newValues = false; | |
164 | - | |
165 | - for (var d = 0; d < row.data.length; d++ ) { | |
166 | - if (row.data[d].currentValue !== row.data[d].originalValue) { | |
167 | - attributes.push({ | |
168 | - key : row.data[d].name, | |
169 | - value : row.data[d].currentValue, | |
170 | - }); | |
171 | - newValues = true; | |
96 | + function save(key) { | |
97 | + var tasks = []; | |
98 | + var serverAttributes = [], sharedAttributes = [], telemetry = []; | |
99 | + var config = { | |
100 | + ignoreLoading: !vm.settings.showActionButtons | |
101 | + }; | |
102 | + var data; | |
103 | + if (key) { | |
104 | + data = [key]; | |
105 | + } else { | |
106 | + data = vm.data; | |
107 | + } | |
108 | + for (let i = 0; i < data.length; i++) { | |
109 | + var item = data[i]; | |
110 | + if (item.data.currentValue !== item.data.originalValue) { | |
111 | + var attribute = { | |
112 | + key: item.name | |
113 | + }; | |
114 | + switch (item.settings.dataKeyValueType) { | |
115 | + case 'dateTime': | |
116 | + case 'date': | |
117 | + attribute.value = item.data.currentValue.getTime(); | |
118 | + break; | |
119 | + case 'time': | |
120 | + attribute.value = item.data.currentValue.getTime() - moment().startOf('day').valueOf();//eslint-disable-line | |
121 | + break; | |
122 | + default: | |
123 | + attribute.value = item.data.currentValue; | |
172 | 124 | } |
173 | - } | |
174 | 125 | |
175 | - if (newValues) { | |
176 | - promises.push(attributeService.saveEntityAttributes( | |
177 | - datasource.entityType, | |
178 | - datasource.entityId, | |
179 | - vm.attributeScope, | |
180 | - attributes)); | |
126 | + switch (item.settings.dataKeyType) { | |
127 | + case 'shared': | |
128 | + sharedAttributes.push(attribute); | |
129 | + break; | |
130 | + case 'timeseries': | |
131 | + telemetry.push(attribute); | |
132 | + break; | |
133 | + default: | |
134 | + serverAttributes.push(attribute); | |
135 | + } | |
181 | 136 | } |
182 | 137 | } |
183 | - | |
184 | - if (promises.length) { | |
185 | - $q.all(promises).then( | |
138 | + for (let i = 0; i < serverAttributes.length; i++) { | |
139 | + tasks.push(attributeService.saveEntityAttributes( | |
140 | + vm.datasources[0].entityType, | |
141 | + vm.datasources[0].entityId, | |
142 | + types.attributesScope.server.value, | |
143 | + serverAttributes, | |
144 | + config)); | |
145 | + } | |
146 | + for (let i = 0; i < sharedAttributes.length; i++) { | |
147 | + tasks.push(attributeService.saveEntityAttributes( | |
148 | + vm.datasources[0].entityType, | |
149 | + vm.datasources[0].entityId, | |
150 | + types.attributesScope.shared.value, | |
151 | + sharedAttributes, | |
152 | + config)); | |
153 | + } | |
154 | + for (let i = 0; i < telemetry.length; i++) { | |
155 | + tasks.push(attributeService.saveEntityTimeseries( | |
156 | + vm.datasources[0].entityType, | |
157 | + vm.datasources[0].entityId, | |
158 | + types.latestTelemetry.value, | |
159 | + telemetry, | |
160 | + config)); | |
161 | + } | |
162 | + if (tasks.length) { | |
163 | + $q.all(tasks).then( | |
186 | 164 | function success() { |
187 | - for (var d = 0; d < row.data.length; d++ ) { | |
188 | - row.data[d].originalValue = row.data[d].currentValue; | |
189 | - } | |
190 | - vm.hasAnyChange = false; | |
165 | + $scope.multipleInputForm.$setPristine(); | |
191 | 166 | if (vm.settings.showResultMessage) { |
192 | - toast.showSuccess('Update successful', 1000, angular.element(vm.ctx.$container), 'bottom left'); | |
167 | + toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(vm.ctx.$container), 'bottom left'); | |
193 | 168 | } |
194 | 169 | }, |
195 | 170 | function fail() { |
196 | 171 | if (vm.settings.showResultMessage) { |
197 | - toast.showError('Update failed', angular.element(vm.ctx.$container), 'bottom left'); | |
172 | + toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(vm.ctx.$container), 'bottom left'); | |
198 | 173 | } |
199 | 174 | } |
200 | 175 | ); |
... | ... | @@ -211,78 +186,75 @@ function MultipleInputWidgetController($q, $scope, attributeService, toast, type |
211 | 186 | |
212 | 187 | vm.ctx.widgetTitle = vm.widgetTitle; |
213 | 188 | |
214 | - vm.attributeScope = vm.settings.attributesShared ? types.attributesScope.shared.value : types.attributesScope.server.value; | |
189 | + vm.isVerticalAlignment = !(vm.settings.fieldsAlignment === 'row'); | |
190 | + | |
191 | + if (!vm.isVerticalAlignment && vm.settings.fieldsInRow) { | |
192 | + vm.inputWidthSettings = 100 / vm.settings.fieldsInRow + '%'; | |
193 | + } | |
215 | 194 | } |
216 | 195 | |
217 | 196 | function updateDatasources() { |
197 | + if (vm.datasources && vm.datasources.length) { | |
198 | + var datasource = vm.datasources[0]; | |
199 | + if (datasource.type === types.datasourceType.entity) { | |
200 | + for (var i = 0; i < datasource.dataKeys.length; i++) { | |
201 | + if ((datasource.entityType !== types.entityType.device) && (datasource.dataKeys[i].settings.dataKeyType !== 'server')) { | |
202 | + vm.isAllParametersValid = false; | |
203 | + } | |
204 | + vm.data.push(datasource.dataKeys[i]); | |
205 | + vm.data[i].data = {}; | |
206 | + } | |
207 | + vm.entityDetected = true; | |
208 | + } | |
209 | + } | |
210 | + } | |
218 | 211 | |
219 | - vm.stylesInfo = {}; | |
220 | - vm.rows = []; | |
221 | - vm.rowIndex = 0; | |
222 | - | |
223 | - if (vm.datasources) { | |
224 | - vm.entityDetected = true; | |
225 | - for (var ds = 0; ds < vm.datasources.length; ds++) { | |
226 | - var row = {}; | |
227 | - var datasource = vm.datasources[ds]; | |
228 | - row.datasource = datasource; | |
229 | - row.data = []; | |
230 | - if (datasource.dataKeys) { | |
231 | - vm.dataKeyDetected = true; | |
232 | - for (var a = 0; a < datasource.dataKeys.length; a++ ) { | |
233 | - var dataKey = datasource.dataKeys[a]; | |
234 | - | |
235 | - if (dataKey.units) { | |
236 | - dataKey.label += ' (' + dataKey.units + ')'; | |
237 | - } | |
238 | - | |
239 | - var keySettings = dataKey.settings; | |
240 | - if (keySettings.inputTypeNumber) { | |
241 | - keySettings.inputType = 'number'; | |
242 | - } else { | |
243 | - keySettings.inputType = 'text'; | |
244 | - } | |
212 | + function updateWidgetData(data) { | |
213 | + for (var i = 0; i < vm.data.length; i++) { | |
214 | + var keyData = data[i].data; | |
215 | + if (keyData && keyData.length) { | |
216 | + var value; | |
217 | + switch (vm.data[i].settings.dataKeyValueType) { | |
218 | + case 'dateTime': | |
219 | + case 'date': | |
220 | + value = moment(keyData[0][1]).toDate(); // eslint-disable-line | |
221 | + break; | |
222 | + case 'time': | |
223 | + value = moment().startOf('day').add(keyData[0][1], 'ms').toDate(); // eslint-disable-line | |
224 | + break; | |
225 | + case 'booleanCheckbox': | |
226 | + case 'booleanSwitch': | |
227 | + value = (keyData[0][1] === 'true'); | |
228 | + break; | |
229 | + default: | |
230 | + value = keyData[0][1]; | |
231 | + } | |
245 | 232 | |
246 | - var cellStyleFunction = null; | |
247 | - var useCellStyleFunction = false; | |
233 | + vm.data[i].data = { | |
234 | + currentValue: value, | |
235 | + originalValue: value | |
236 | + }; | |
248 | 237 | |
249 | - if (keySettings.useCellStyleFunction === true) { | |
250 | - if (angular.isDefined(keySettings.cellStyleFunction) && keySettings.cellStyleFunction.length > 0) { | |
251 | - try { | |
252 | - cellStyleFunction = new Function('value', keySettings.cellStyleFunction); | |
253 | - useCellStyleFunction = true; | |
254 | - } catch (e) { | |
255 | - cellStyleFunction = null; | |
256 | - useCellStyleFunction = false; | |
257 | - } | |
238 | + if (vm.data[i].settings.isEditable === 'editable' && vm.data[i].settings.disabledOnDataKey) { | |
239 | + var conditions = data.filter((item) => { | |
240 | + return item.dataKey.name === vm.data[i].settings.disabledOnDataKey; | |
241 | + }); | |
242 | + if (conditions && conditions.length) { | |
243 | + if (conditions[0].data.length) { | |
244 | + if (conditions[0].data[0][1] === 'false') { | |
245 | + vm.data[i].settings.disabledOnCondition = true; | |
246 | + } else { | |
247 | + vm.data[i].settings.disabledOnCondition = !conditions[0].data[0][1]; | |
258 | 248 | } |
259 | 249 | } |
260 | - | |
261 | - vm.stylesInfo[dataKey.label] = { | |
262 | - useCellStyleFunction: useCellStyleFunction, | |
263 | - cellStyleFunction: cellStyleFunction, | |
264 | - color: keySettings.color | |
265 | - }; | |
266 | - | |
267 | - row.data.push(dataKey); | |
268 | 250 | } |
269 | - vm.rows.push(row); | |
270 | 251 | } |
271 | 252 | } |
272 | 253 | } |
273 | 254 | } |
274 | 255 | |
275 | - function updateRowData(data) { | |
276 | - var dataIndex = 0; | |
277 | - for (var r = 0; r < vm.rows.length; r++) { | |
278 | - var row = vm.rows[r]; | |
279 | - for (var d = 0; d < row.data.length; d++ ) { | |
280 | - var keyData = data[dataIndex++].data; | |
281 | - if (keyData && keyData.length && keyData[0].length > 1) { | |
282 | - row.data[d].currentValue = row.data[d].originalValue = keyData[0][1]; | |
283 | - } | |
284 | - } | |
285 | - } | |
256 | + function updateWidgetDisplaying() { | |
257 | + vm.changeAlignment = (vm.ctx.$container[0].offsetWidth < 620); | |
258 | + vm.smallWidthContainer = (vm.ctx.$container[0].offsetWidth < 420); | |
286 | 259 | } |
287 | - | |
288 | 260 | } | ... | ... |
... | ... | @@ -15,15 +15,25 @@ |
15 | 15 | */ |
16 | 16 | .tb-multiple-input { |
17 | 17 | height: 100%; |
18 | + overflow-x: hidden; | |
19 | + overflow-y: auto; | |
18 | 20 | |
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; | |
21 | + .input-field { | |
22 | + padding-right: 10px; | |
23 | + | |
24 | + md-input-container, | |
25 | + md-checkbox, | |
26 | + md-switch { | |
27 | + margin-bottom: 5px; | |
28 | + } | |
29 | + } | |
30 | + | |
31 | + md-checkbox { | |
32 | + margin-top: 22px; | |
33 | + } | |
34 | + | |
35 | + md-switch { | |
36 | + margin-top: 20px; | |
27 | 37 | } |
28 | 38 | |
29 | 39 | .md-icon-button md-icon { |
... | ... | @@ -32,10 +42,56 @@ |
32 | 42 | height: 20px; |
33 | 43 | min-height: 20px; |
34 | 44 | font-size: 20px; |
45 | + } | |
46 | + | |
47 | + .date-time-input { | |
48 | + &__label { | |
49 | + margin-left: 36px; | |
50 | + font-size: 12px; | |
51 | + color: rgba(0, 0, 0, .54); | |
52 | + } | |
53 | + | |
54 | + mdp-date-picker, | |
55 | + mdp-time-picker { | |
56 | + width: 100%; | |
57 | + | |
58 | + .md-button.md-icon-button { | |
59 | + margin: 5px 0 0; | |
60 | + } | |
35 | 61 | |
36 | - &:not([disabled]) { | |
37 | - color: #f66; | |
62 | + md-input-container { | |
63 | + width: 100%; | |
64 | + margin: 2px 0; | |
65 | + | |
66 | + label { | |
67 | + display: none; | |
68 | + } | |
69 | + } | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + .vertical-alignment { | |
74 | + flex-direction: column; | |
75 | + | |
76 | + md-checkbox, | |
77 | + md-switch { | |
78 | + margin-top: 18px; | |
38 | 79 | } |
80 | + | |
81 | + md-switch { | |
82 | + display: flex; | |
83 | + justify-content: space-between; | |
84 | + } | |
85 | + | |
86 | + .date-time-input { | |
87 | + &__label { | |
88 | + margin-top: 10px; | |
89 | + } | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + .vertically-aligned { | |
94 | + flex-direction: column; | |
39 | 95 | } |
40 | 96 | } |
41 | 97 | ... | ... |
... | ... | @@ -15,53 +15,134 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<form class="tb-multiple-input" name="multipleInputForm" ng-submit="vm.postData($event)" novalidate> | |
18 | +<form class="tb-multiple-input" name="multipleInputForm" ng-submit="vm.save()" novalidate autocomplete="off"> | |
19 | 19 | <div style="padding: 0 8px; margin: auto 0;"> |
20 | - <div ng-show="vm.entityDetected" layout="row" flex ng-repeat="row in vm.rows" ng-init="rowIndex=$index"> | |
21 | - <div layout="column" flex ng-repeat="key in row.data track by $index" ng-init="keyIndex=$index"> | |
22 | - <md-tooltip class="tb-tooltip-multiline" ng-if="key.settings.tooltipMessage && key.settings.tooltipMessage.length" md-direction="left"> | |
23 | - <span ng-bind-html="key.settings.tooltipMessage"></span> | |
24 | - </md-tooltip> | |
25 | - <md-input-container class="md-block" ng-style="vm.cellStyle(key, rowIndex, $first, $last)"> | |
26 | - <label ng-style="vm.textColor(key)">{{key.label}}</label> | |
27 | - <md-icon ng-style="vm.textColor(key)" class="material-icons" ng-if="key.settings.icon"> | |
28 | - {{key.settings.icon}} | |
29 | - </md-icon> | |
30 | - <input name="value{{rowIndex}}{{keyIndex}}" | |
31 | - ng-style="vm.textColor(key)" | |
32 | - ng-disabled="key.settings.readOnly" | |
33 | - ng-model="key.currentValue" | |
34 | - min="{{key.settings.min}}" | |
35 | - max="{{key.settings.max}}" | |
36 | - ng-required="key.settings.required" | |
37 | - type="{{key.settings.inputType}}" | |
38 | - step="{{key.settings.step}}" | |
39 | - md-select-on-focus | |
40 | - ng-change="vm.inputChanged()"> | |
41 | - <div ng-messages="multipleInputForm['value' + rowIndex + keyIndex].$error"> | |
42 | - <div ng-message="min">Value must be greater than {{key.settings.min}}</div> | |
43 | - <div ng-message="max">Value must be lower than {{key.settings.max}}</div> | |
44 | - <div ng-message="required">This field is required</div> | |
20 | + <div ng-show="vm.entityDetected" layout="row" layout-wrap ng-class="{'vertical-alignment': vm.isVerticalAlignment || vm.changeAlignment}"> | |
21 | + <div ng-repeat="key in vm.data" ng-style="{'width': (vm.isVerticalAlignment || vm.changeAlignment) ? '100%' : vm.inputWidthSettings}"> | |
22 | + <div class="input-field" ng-if="(key.settings.dataKeyValueType === 'string') && !key.settings.dataKeyHidden"> | |
23 | + <md-input-container class="md-block"> | |
24 | + <label>{{key.label}}</label> | |
25 | + <md-icon class="material-icons" ng-if="key.settings.icon"> | |
26 | + {{key.settings.icon}} | |
27 | + </md-icon> | |
28 | + <input name="{{key.name}}" | |
29 | + ng-disabled="(key.settings.isEditable === 'disabled') || key.settings.disabledOnCondition" | |
30 | + ng-readonly="key.settings.isEditable === 'readonly'" | |
31 | + ng-model="key.data.currentValue" | |
32 | + ng-required="key.settings.required" | |
33 | + type="text" | |
34 | + md-select-on-focus | |
35 | + ng-blur="vm.inputChanged(key)"> | |
36 | + <div ng-messages="multipleInputForm[key.name].$error"> | |
37 | + <div ng-message="required">{{ key.settings.requiredErrorMessage }}</div> | |
38 | + </div> | |
39 | + </md-input-container> | |
40 | + </div> | |
41 | + <div class="input-field" ng-if="(key.settings.dataKeyValueType === 'double') && !key.settings.dataKeyHidden"> | |
42 | + <md-input-container class="md-block"> | |
43 | + <label>{{key.label}}</label> | |
44 | + <md-icon class="material-icons" ng-if="key.settings.icon"> | |
45 | + {{key.settings.icon}} | |
46 | + </md-icon> | |
47 | + <input name="{{key.name}}" | |
48 | + ng-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
49 | + ng-readonly="key.settings.isEditable === 'readonly'" | |
50 | + ng-model="key.data.currentValue" | |
51 | + ng-required="key.settings.required" | |
52 | + type="number" | |
53 | + step="key.settings.step" | |
54 | + md-select-on-focus | |
55 | + ng-blur="vm.inputChanged(key)"> | |
56 | + <div ng-messages="multipleInputForm[key.name].$error"> | |
57 | + <div ng-message="required">{{ key.settings.requiredErrorMessage }}</div> | |
58 | + </div> | |
59 | + </md-input-container> | |
60 | + </div> | |
61 | + <div class="input-field" ng-if="(key.settings.dataKeyValueType === 'integer') && !key.settings.dataKeyHidden"> | |
62 | + <md-input-container class="md-block"> | |
63 | + <label>{{key.label}}</label> | |
64 | + <md-icon class="material-icons" ng-if="key.settings.icon"> | |
65 | + {{key.settings.icon}} | |
66 | + </md-icon> | |
67 | + <input name="{{key.name}}" | |
68 | + ng-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
69 | + ng-readonly="key.settings.isEditable === 'readonly'" | |
70 | + ng-model="key.data.currentValue" | |
71 | + ng-required="key.settings.required" | |
72 | + type="number" | |
73 | + step="key.settings.step" | |
74 | + md-select-on-focus | |
75 | + ng-pattern="/^-?[0-9]+$/" | |
76 | + ng-blur="vm.inputChanged(key)"> | |
77 | + <div ng-messages="multipleInputForm[key.name].$error"> | |
78 | + <div ng-message="required">{{ key.settings.requiredErrorMessage }}</div> | |
79 | + <div translate ng-message="pattern">value.invalid-integer-value</div> | |
80 | + </div> | |
81 | + </md-input-container> | |
82 | + </div> | |
83 | + <div class="input-field" ng-if="(key.settings.dataKeyValueType === 'booleanCheckbox') && !key.settings.dataKeyHidden" class="md-block"> | |
84 | + <md-checkbox name="{{key.name}}" | |
85 | + ng-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
86 | + ng-model="key.data.currentValue" | |
87 | + ng-change="vm.inputChanged(key)"> | |
88 | + {{key.label}} | |
89 | + </md-checkbox> | |
90 | + </div> | |
91 | + <div class="input-field" ng-if="(key.settings.dataKeyValueType === 'booleanSwitch') && !key.settings.dataKeyHidden" class="md-block"> | |
92 | + <md-switch name="{{key.name}}" | |
93 | + ng-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
94 | + ng-model="key.data.currentValue" | |
95 | + ng-change="vm.inputChanged(key)" | |
96 | + aria-label="{{key.label}}" | |
97 | + md-invert> | |
98 | + {{key.label}} | |
99 | + </md-switch> | |
100 | + </div> | |
101 | + <div ng-if="(key.settings.dataKeyValueType === 'dateTime') || | |
102 | + (key.settings.dataKeyValueType === 'date') || | |
103 | + (key.settings.dataKeyValueType === 'time') && !key.settings.dataKeyHidden" | |
104 | + class="md-block input-field date-time-input" layout="column"> | |
105 | + <label class="date-time-input__label">{{key.label}}</label> | |
106 | + <div layout="row" ng-class="{'vertically-aligned': vm.smallWidthContainer}"> | |
107 | + <mdp-date-picker name="{{key.name + 'Date'}}" | |
108 | + ng-if="key.settings.dataKeyValueType !== 'time'" | |
109 | + mdp-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
110 | + ng-model="key.data.currentValue" | |
111 | + ng-change="vm.inputChanged(key)" | |
112 | + mdp-placeholder="{{ 'widgets.input-widgets.date' | translate }}"> | |
113 | + <div ng-messages="multipleInputForm[key.name].$error"> | |
114 | + <div ng-message="required">{{ key.settings.requiredErrorMessage }}</div> | |
115 | + </div> | |
116 | + </mdp-date-picker> | |
117 | + <mdp-time-picker name="{{key.name + 'Time'}}" | |
118 | + ng-if="key.settings.dataKeyValueType !== 'date'" | |
119 | + mdp-disabled="key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition" | |
120 | + ng-model="key.data.currentValue" | |
121 | + ng-change="vm.inputChanged(key)" | |
122 | + mdp-placeholder="{{ 'widgets.input-widgets.time' | translate }}" | |
123 | + mdp-auto-switch="true"> | |
124 | + <div ng-messages="multipleInputForm[key.name].$error"> | |
125 | + <div ng-message="required">{{ key.settings.requiredErrorMessage }}</div> | |
126 | + </div> | |
127 | + </mdp-time-picker> | |
45 | 128 | </div> |
46 | - </md-input-container> | |
129 | + </div> | |
47 | 130 | </div> |
48 | 131 | </div> |
49 | 132 | |
50 | - <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-hide="vm.entityDetected" ng-bind="vm.message" | |
51 | - ></div> | |
52 | - <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-show="vm.entityDetected && !vm.dataKeyDetected"> | |
53 | - No attribute is selected | |
133 | + <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-hide="vm.entityDetected"> | |
134 | + {{ 'widgets.input-widgets.no-entity-selected' | translate }} | |
54 | 135 | </div> |
55 | - <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-show="vm.entityDetected && !vm.isValidParameter"> | |
56 | - Timeseries parameter cannot be used in this widget | |
136 | + <div style="text-align: center; font-size: 18px; color: #a0a0a0;" ng-show="vm.entityDetected && !vm.isAllParametersValid"> | |
137 | + {{ 'widgets.input-widgets.not-allowed-entity' | translate }} | |
57 | 138 | </div> |
58 | 139 | </div> |
59 | - <div class="md-padding" layout="row" layout-align="end center" ng-show="vm.entityDetected && vm.dataKeyDetected"> | |
60 | - <md-button class="md-primary" ng-click="vm.discardAll()" style="max-height: 50px;margin-right:20px;" ng-disabled="!vm.hasAnyChange"> | |
140 | + <div class="md-padding" layout="row" layout-align="end center" ng-if="vm.entityDetected && vm.settings.showActionButtons"> | |
141 | + <md-button class="md-primary" ng-click="vm.discardAll()" style="max-height: 50px; margin-right:20px;" ng-disabled="!multipleInputForm.$dirty"> | |
61 | 142 | {{ 'action.undo' | translate }} |
62 | 143 | </md-button> |
63 | - <md-button class="md-raised md-primary" type="submit" value="Submit" style="max-height: 50px;margin-right:20px;" | |
64 | - ng-disabled="!vm.hasAnyChange || multipleInputForm.$invalid" ng-click="vm.isFocused = false"> | |
144 | + <md-button class="md-raised md-primary" type="submit" value="Submit" style="max-height: 50px; margin-right:20px;" | |
145 | + ng-disabled="!multipleInputForm.$dirty || multipleInputForm.$invalid" ng-click="vm.isFocused = false"> | |
65 | 146 | {{ 'action.save' | translate }} |
66 | 147 | </md-button> |
67 | 148 | </div> | ... | ... |