Commit b3abfd38666a0b2cc6900a7791d34ee692514786
Committed by
GitHub
1 parent
320b9911
Refactoring gateway configuration form (#2389)
* Change translate, layout and clear code * Refactoring code * Refactoring code * Refactoring code * Code refactoring
Showing
16 changed files
with
989 additions
and
1159 deletions
... | ... | @@ -22,23 +22,19 @@ |
22 | 22 | } |
23 | 23 | }, |
24 | 24 | { |
25 | - "alias": "new_config_form", | |
26 | - "name": "Config form", | |
25 | + "alias": "gateway_configuration", | |
26 | + "name": "Gateway Configuration", | |
27 | 27 | "descriptor": { |
28 | 28 | "type": "static", |
29 | - "sizeX": 7.5, | |
30 | - "sizeY": 10.5, | |
31 | - "resources": [ | |
32 | - { | |
33 | - "url": "" | |
34 | - } | |
35 | - ], | |
29 | + "sizeX": 8, | |
30 | + "sizeY": 6.5, | |
31 | + "resources": [], | |
36 | 32 | "templateHtml": "<tb-gateway-form\n form-id=\"formId\"\n ctx=\"ctx\">\n</tb-gateway-form>\n", |
37 | - "templateCss": "#container {\n overflow: auto;\n height: 100%;\n margin: auto;\n}\n\n\n\n/*#configurations {*/\n/* display: flex;*/\n/* flex-direction: column;*/\n/* height: 100%;*/\n/* margin: 0px;*/\n/* padding: 0;*/\n/*}*/\n\n/*.configurationPointParent {*/\n/* display: flex;*/\n/* flex-direction: column;*/\n \n/*}*/\n\n/*.configurationPoint {*/\n/* display: flex;*/\n/* flex-direction: row;*/\n/* justify-content: space-between;*/\n/* margin: 5px;*/\n/*}*/\n\n/*.configurationPoint.select {*/\n/* margin: 0px;*/\n/* padding: 0;*/\n/* border: 0;*/\n/* height: 40px;*/\n\n/*}*/\n\n/*.configurationPoint.select.inputRow {*/\n/* margin: 0px;*/\n/* width: 100%;*/\n/* padding: 0;*/\n/* border: 0;*/\n/* height: 40px;*/\n/*}*/\n\n\n/*.error {*/\n/*color: red;*/\n/*}*/", | |
33 | + "templateCss": "", | |
38 | 34 | "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.formId = \"form-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n self.ctx.$scope.$broadcast('gateway-form-resize', self.ctx.$scope.formId);\n}\n", |
39 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"GatewayConfigForm\",\n \"properties\": {\n \"gatewayTitle\": {\n \"title\": \"Gateway form title\",\n \"type\": \"string\",\n \"default\": \"Gateway Config Form\"\n }\n }\n },\n \"form\": [\n \"gatewayTitle\"\n ]\n}\n", | |
35 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"Gatwey Configuration\"\n },\n \"archiveFileName\": {\n \"title\": \"Default archive file name\",\n \"type\": \"string\",\n \"default\": \"gatewayConfiguration\"\n },\n \"gatewayType\": {\n \"title\": \"Device type for new gateway\",\n \"type\": \"string\",\n \"default\": \"Gateway\"\n },\n \"successfulSave\": {\n \"title\": \"Text message about successfully saved gateway configuration\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"gatewayNameExists\": {\n \"title\": \"Text message when device with entered name is already exists\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n [\n \"widgetTitle\",\n \"archiveFileName\",\n \"gatewayType\"\n ],\n [\n \"successfulSave\",\n \"gatewayNameExists\"\n ]\n ],\n \"groupInfoes\": [{\n \"formIndex\": 0,\n \"GroupTitle\": \"General settings\"\n }, {\n \"formIndex\": 1,\n \"GroupTitle\": \"Messages settings\"\n }]\n}", | |
40 | 36 | "dataKeySettingsSchema": "{}\n", |
41 | - "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"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\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"gatewayTitle\":\"Gateway Config Form\"},\"title\":\"Config form\",\"dropShadow\":true,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
37 | + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"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\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"Gatwey Configuration\",\"archiveFileName\":\"configurationGateway\"},\"title\":\"Gateway Configuration\",\"dropShadow\":true,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
42 | 38 | } |
43 | 39 | } |
44 | 40 | ] | ... | ... |
ui/src/app/components/gateWay/gateway-config.directive.js
deleted
100644 → 0
1 | -/* | |
2 | - * Copyright © 2016-2020 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 './gateway-config.scss'; | |
17 | - | |
18 | -/* eslint-disable import/no-unresolved, import/default */ | |
19 | - | |
20 | -import gatewayTemplate from './gateway-config.tpl.html'; | |
21 | -import gatewayDialogTemplate from './gateway-config-dialog.tpl.html'; | |
22 | -import beautify from "js-beautify"; | |
23 | - | |
24 | -/* eslint-enable import/no-unresolved, import/default */ | |
25 | -const js_beautify = beautify.js; | |
26 | - | |
27 | -export default angular.module('thingsboard.directives.gatewayConfig', []) | |
28 | - .directive('tbGatewayConfig', GatewayConfig) | |
29 | - .name; | |
30 | - | |
31 | -/*@ngInject*/ | |
32 | -function GatewayConfig() { | |
33 | - return { | |
34 | - restrict: "E", | |
35 | - scope: true, | |
36 | - bindToController: { | |
37 | - disabled: '=ngDisabled', | |
38 | - titleText: '@?', | |
39 | - keyPlaceholderText: '@?', | |
40 | - valuePlaceholderText: '@?', | |
41 | - noDataText: '@?', | |
42 | - gatewayConfig: '=', | |
43 | - changeAlignment: '=' | |
44 | - }, | |
45 | - controller: GatewayConfigController, | |
46 | - controllerAs: 'vm', | |
47 | - templateUrl: gatewayTemplate | |
48 | - }; | |
49 | -} | |
50 | - | |
51 | -/*@ngInject*/ | |
52 | -function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window, types, toast, $timeout, $compile, $translate) { //eslint-disable-line | |
53 | - | |
54 | - let vm = this; | |
55 | - | |
56 | - vm.kvList = []; | |
57 | - vm.types = types; | |
58 | - $scope.$watch('vm.gatewayConfig', () => { | |
59 | - vm.stopWatchKvList(); | |
60 | - vm.kvList.length = 0; | |
61 | - if (vm.gatewayConfig) { | |
62 | - for (var property in vm.gatewayConfig) { | |
63 | - if (Object.prototype.hasOwnProperty.call(vm.gatewayConfig, property)) { | |
64 | - vm.kvList.push( | |
65 | - { | |
66 | - enabled: vm.gatewayConfig[property].enabled, | |
67 | - key: property + '', | |
68 | - value: vm.gatewayConfig[property].connector + '', | |
69 | - config: js_beautify(vm.gatewayConfig[property].config + '', {indent_size: 4}) | |
70 | - } | |
71 | - ); | |
72 | - } | |
73 | - } | |
74 | - } | |
75 | - $mdUtil.nextTick(() => { | |
76 | - vm.watchKvList(); | |
77 | - }); | |
78 | - }); | |
79 | - | |
80 | - vm.watchKvList = () => { | |
81 | - $scope.kvListWatcher = $scope.$watch('vm.kvList', () => { | |
82 | - if (!vm.gatewayConfig) { | |
83 | - return; | |
84 | - } | |
85 | - for (let property in vm.gatewayConfig) { | |
86 | - if (Object.prototype.hasOwnProperty.call(vm.gatewayConfig, property)) { | |
87 | - delete vm.gatewayConfig[property]; | |
88 | - } | |
89 | - } | |
90 | - for (let i = 0; i < vm.kvList.length; i++) { | |
91 | - let entry = vm.kvList[i]; | |
92 | - if (entry.key && entry.value) { | |
93 | - let connectorJSON = angular.toJson({ | |
94 | - enabled: entry.enabled, | |
95 | - connector: entry.value, | |
96 | - config: angular.fromJson(entry.config) | |
97 | - }); | |
98 | - vm.gatewayConfig [entry.key] = angular.fromJson(connectorJSON); | |
99 | - } | |
100 | - } | |
101 | - }, true); | |
102 | - }; | |
103 | - | |
104 | - vm.stopWatchKvList = () => { | |
105 | - if ($scope.kvListWatcher) { | |
106 | - $scope.kvListWatcher(); | |
107 | - $scope.kvListWatcher = null; | |
108 | - } | |
109 | - }; | |
110 | - | |
111 | - vm.removeKeyVal = (index) => { | |
112 | - if (index > -1) { | |
113 | - vm.kvList.splice(index, 1); | |
114 | - } | |
115 | - }; | |
116 | - | |
117 | - vm.addKeyVal = () => { | |
118 | - if (!vm.kvList) { | |
119 | - vm.kvList = []; | |
120 | - } | |
121 | - vm.kvList.push( | |
122 | - { | |
123 | - enabled: false, | |
124 | - key: '', | |
125 | - value: '', | |
126 | - config: '{}' | |
127 | - } | |
128 | - ); | |
129 | - } | |
130 | - | |
131 | - vm.openConfigDialog = ($event, index, config, typeName) => { | |
132 | - if ($event) { | |
133 | - $event.stopPropagation(); | |
134 | - } | |
135 | - $mdDialog.show({ | |
136 | - controller: GatewayDialogController, | |
137 | - controllerAs: 'vm', | |
138 | - templateUrl: gatewayDialogTemplate, | |
139 | - parent: angular.element($document[0].body), | |
140 | - locals: { | |
141 | - config: config, | |
142 | - typeName: typeName | |
143 | - }, | |
144 | - targetEvent: $event, | |
145 | - fullscreen: true, | |
146 | - multiple: true, | |
147 | - }).then(function (config) { | |
148 | - if (config) { | |
149 | - if (index > -1) { | |
150 | - vm.kvList[index].config = config; | |
151 | - } | |
152 | - } | |
153 | - }, function () { | |
154 | - }); | |
155 | - | |
156 | - }; | |
157 | - | |
158 | - vm.configTypeChange = (keyVal) => { | |
159 | - for (let prop in types.gatewayConfigType) { | |
160 | - if (types.gatewayConfigType[prop].value === keyVal.value) { | |
161 | - if (!keyVal.key) { | |
162 | - keyVal.key = vm.configTypeChangeValid(types.gatewayConfigType[prop].name, 0); | |
163 | - } | |
164 | - } | |
165 | - } | |
166 | - vm.checkboxValid(keyVal); | |
167 | - }; | |
168 | - | |
169 | - vm.keyValChange = (keyVal, indexKey) => { | |
170 | - keyVal.key = vm.keyValChangeValid(keyVal.key, 0, indexKey); | |
171 | - vm.checkboxValid(keyVal); | |
172 | - }; | |
173 | - | |
174 | - vm.configTypeChangeValid = (name, index) => { | |
175 | - let newKeyName = index ? name + index : name; | |
176 | - let indexRes = vm.kvList.findIndex((element) => element.key === newKeyName); | |
177 | - return indexRes === -1 ? newKeyName : vm.configTypeChangeValid(name, ++index); | |
178 | - }; | |
179 | - | |
180 | - vm.keyValChangeValid = (name, index, indexKey) => { | |
181 | - angular.forEach(vm.kvList, function (value, key) { | |
182 | - let nameEq = (index === 0) ? name : name + index; | |
183 | - if (key !== indexKey && value.key && value.key === nameEq) { | |
184 | - index++; | |
185 | - vm.keyValChangeValid(name, index, indexKey); | |
186 | - } | |
187 | - | |
188 | - }); | |
189 | - return (index === 0) ? name : name + index; | |
190 | - }; | |
191 | - | |
192 | - vm.buttonValid = (config) => { | |
193 | - return (angular.equals("{}", config)) ? "md-warn" : "md-primary"; | |
194 | - }; | |
195 | - | |
196 | - vm.checkboxValid = (keyVal) => { | |
197 | - if (!keyVal.key || angular.equals("", keyVal.key) | |
198 | - || !keyVal.value || angular.equals("", keyVal.value) | |
199 | - || angular.equals("{}", keyVal.config)) { | |
200 | - return keyVal.enabled = false; | |
201 | - } | |
202 | - return true; | |
203 | - }; | |
204 | - vm.checkboxValidMouseover = ($event, keyVal) => { | |
205 | - console.log($event, keyVal); //eslint-disable-line | |
206 | - vm.checkboxValidClick ($event, keyVal); | |
207 | - }; | |
208 | - | |
209 | - vm.checkboxValidClick = ($event, keyVal) => { | |
210 | - if (!vm.checkboxValid(keyVal)) { | |
211 | - let errTxt = ""; | |
212 | - if (!keyVal.key || angular.equals("", keyVal.key)) { | |
213 | - errTxt = $translate.instant('gateway.keyval-name-err'); | |
214 | - } | |
215 | - | |
216 | - if (!keyVal.value || angular.equals("", keyVal.value)) { | |
217 | - errTxt += '<div>' + $translate.instant('gateway.keyval-type-err') + '</div>'; | |
218 | - } | |
219 | - | |
220 | - if (angular.equals("{}", keyVal.config)) { | |
221 | - errTxt += '<div>' + $translate.instant('gateway.keyval-config-err') + '</div>'; | |
222 | - } | |
223 | - if (!angular.equals("", errTxt)) { | |
224 | - displayTooltip($event, '<div class="tb-rule-node-tooltip tb-lib-tooltip">' + | |
225 | - '<div id="tb-node-content" layout="column">' + | |
226 | - '<div class="tb-node-title">' + $translate.instant('gateway.keyval-save-err') + '</div>' + | |
227 | - '<div class="tb-node-details">' + errTxt + '</div>' + | |
228 | - '</div>' + | |
229 | - '</div>'); | |
230 | - } | |
231 | - } | |
232 | - else { | |
233 | - destroyTooltips(); | |
234 | - } | |
235 | - }; | |
236 | - | |
237 | - | |
238 | - function displayTooltip(event, content) { | |
239 | - destroyTooltips(); | |
240 | - vm.tooltipTimeout = $timeout(() => { | |
241 | - var element = angular.element(event.target); | |
242 | - element.tooltipster( | |
243 | - { | |
244 | - theme: 'tooltipster-shadow', | |
245 | - delay: 10, | |
246 | - animation: 'grow', | |
247 | - side: 'right' | |
248 | - } | |
249 | - ); | |
250 | - var contentElement = angular.element(content); | |
251 | - $compile(contentElement)($scope); | |
252 | - var tooltip = element.tooltipster('instance'); | |
253 | - tooltip.content(contentElement); | |
254 | - tooltip.open(); | |
255 | - }, 500); | |
256 | - } | |
257 | - | |
258 | - function destroyTooltips() { | |
259 | - if (vm.tooltipTimeout) { | |
260 | - $timeout.cancel(vm.tooltipTimeout); | |
261 | - vm.tooltipTimeout = null; | |
262 | - } | |
263 | - var instances = angular.element.tooltipster.instances(); | |
264 | - instances.forEach((instance) => { | |
265 | - if (!instance.isErrorTooltip) { | |
266 | - instance.destroy(); | |
267 | - } | |
268 | - }); | |
269 | - } | |
270 | -} | |
271 | - | |
272 | -/*@ngInject*/ | |
273 | -function GatewayDialogController($scope, $mdDialog, $document, $window, config, typeName) { | |
274 | - let vm = this; | |
275 | - vm.doc = $document[0]; | |
276 | - vm.config = angular.copy(config); | |
277 | - vm.typeName = "" + typeName; | |
278 | - vm.configAreaOptions = { | |
279 | - useWrapMode: false, | |
280 | - mode: 'json', | |
281 | - showGutter: true, | |
282 | - showPrintMargin: true, | |
283 | - theme: 'github', | |
284 | - advanced: { | |
285 | - enableSnippets: true, | |
286 | - enableBasicAutocompletion: true, | |
287 | - enableLiveAutocompletion: true | |
288 | - }, | |
289 | - onLoad: function (_ace) { | |
290 | - _ace.$blockScrolling = 1; | |
291 | - } | |
292 | - }; | |
293 | - | |
294 | - vm.validateConfig = (model, editorName) => { | |
295 | - if (model && model.length) { | |
296 | - try { | |
297 | - angular.fromJson(model); | |
298 | - $scope.theForm[editorName].$setValidity('configJSON', true); | |
299 | - } catch (e) { | |
300 | - $scope.theForm[editorName].$setValidity('configJSON', false); | |
301 | - } | |
302 | - } | |
303 | - }; | |
304 | - | |
305 | - vm.save = () => { | |
306 | - $mdDialog.hide(vm.config); | |
307 | - }; | |
308 | - | |
309 | - vm.cancel = () => { | |
310 | - $mdDialog.hide(); | |
311 | - }; | |
312 | - | |
313 | - vm.beautifyJson = () => { | |
314 | - vm.config = js_beautify(vm.config, {indent_size: 4}); | |
315 | - }; | |
316 | -} | |
317 | - |
ui/src/app/components/gateWay/gateway-form.directive.js
deleted
100644 → 0
1 | -/* | |
2 | - * Copyright © 2016-2020 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 './gateway-form.scss'; | |
17 | -/* eslint-disable import/no-unresolved, import/default */ | |
18 | - | |
19 | -import gatewayFormTemplate from './gateway-form.tpl.html'; | |
20 | - | |
21 | -/* eslint-enable import/no-unresolved, import/default */ | |
22 | - | |
23 | -export default angular.module('thingsboard.directives.gatewayForm', []) | |
24 | - .directive('tbGatewayForm', GatewayForm) | |
25 | - .name; | |
26 | - | |
27 | -/*@ngInject*/ | |
28 | -function GatewayForm() { | |
29 | - return { | |
30 | - restrict: "E", | |
31 | - scope: true, | |
32 | - bindToController: { | |
33 | - disabled: '=ngDisabled', | |
34 | - keyPlaceholderText: '@?', | |
35 | - valuePlaceholderText: '@?', | |
36 | - noDataText: '@?', | |
37 | - formId: '=', | |
38 | - ctx: '=', | |
39 | - gatewayFormConfig: '=', | |
40 | - theForm: '=' | |
41 | - }, | |
42 | - controller: GatewayFormController, | |
43 | - controllerAs: 'vm', | |
44 | - templateUrl: gatewayFormTemplate | |
45 | - }; | |
46 | -} | |
47 | - | |
48 | -/*@ngInject*/ | |
49 | -function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, toast, importExport, attributeService, deviceService, userService, $mdDialog, $mdUtil, types, $window, $q) { | |
50 | - $scope.$mdExpansionPanel = $mdExpansionPanel; | |
51 | - let vm = this; | |
52 | - const attributeNameClinet = "current_configuration"; | |
53 | - const attributeNameServer = "configuration_drafts"; | |
54 | - const attributeNameShared = "configuration"; | |
55 | - const attributeNameLogShared = "RemoteLoggingLevel"; | |
56 | - vm.remoteLoggingConfig = '[loggers]}}keys=root, service, connector, converter, tb_connection, storage, extension}}[handlers]}}keys=consoleHandler, serviceHandler, connectorHandler, converterHandler, tb_connectionHandler, storageHandler, extensionHandler}}[formatters]}}keys=LogFormatter}}[logger_root]}}level=ERROR}}handlers=consoleHandler}}[logger_connector]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=connector}}[logger_storage]}}level={ERROR}}}handlers=storageHandler}}formatter=LogFormatter}}qualname=storage}}[logger_tb_connection]}}level={ERROR}}}handlers=tb_connectionHandler}}formatter=LogFormatter}}qualname=tb_connection}}[logger_service]}}level={ERROR}}}handlers=serviceHandler}}formatter=LogFormatter}}qualname=service}}[logger_converter]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=converter}}[logger_extension]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=extension}}[handler_consoleHandler]}}class=StreamHandler}}level={ERROR}}}formatter=LogFormatter}}args=(sys.stdout,)}}[handler_connectorHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}connector.log", "d", 1, 7,)}}[handler_storageHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}storage.log", "d", 1, 7,)}}[handler_serviceHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}service.log", "d", 1, 7,)}}[handler_converterHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}converter.log", "d", 1, 3,)}}[handler_extensionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}extension.log", "d", 1, 3,)}}[handler_tb_connectionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}tb_connection.log", "d", 1, 3,)}}[formatter_LogFormatter]}}format="%(asctime)s - %(levelname)s - [%(filename)s] - %(module)s - %(lineno)d - %(message)s" }}datefmt="%Y-%m-%d %H:%M:%S"'; | |
57 | - vm.types = types; | |
58 | - | |
59 | - vm.configurations = { | |
60 | - singleSelect: '', | |
61 | - host: $document[0].domain, | |
62 | - port: 1883, | |
63 | - remoteConfiguration: true, | |
64 | - accessToken: '', | |
65 | - entityType: '', | |
66 | - entityId: '', | |
67 | - storageType: "memoryStorage", // "memoryStorage"; fileStorage | |
68 | - readRecordsCount: 100, | |
69 | - maxRecordsCount: 10000, | |
70 | - dataFolderPath: './data/', | |
71 | - maxFilesCount: 5, | |
72 | - securityType: "accessToken", // "accessToken", "tls" | |
73 | - caCertPath: '/etc/thingsboard-gateway/ca.pem', | |
74 | - privateKeyPath: '/etc/thingsboard-gateway/privateKey.pem', | |
75 | - certPath: '/etc/thingsboard-gateway/certificate.pem', | |
76 | - connectors: {}, | |
77 | - remoteLoggingLevel: "DEBUG", // level login | |
78 | - remoteLoggingPathToLogs: './logs/' | |
79 | - }; | |
80 | - getGatewaysListByUser(true); | |
81 | - | |
82 | - vm.securityTypes = [{ | |
83 | - name: 'Access Token', | |
84 | - value: 'accessToken' | |
85 | - }, { | |
86 | - name: 'TLS', | |
87 | - value: 'tls' | |
88 | - }]; | |
89 | - | |
90 | - vm.storageTypes = [{ | |
91 | - name: 'Memory storage', | |
92 | - value: 'memoryStorage' | |
93 | - }, { | |
94 | - name: 'File storage', | |
95 | - value: 'fileStorage' | |
96 | - }]; | |
97 | - | |
98 | - $scope.$on('gateway-form-resize', function (event, formId) { | |
99 | - if (vm.formId == formId) { | |
100 | - updateWidgetDisplaying(); | |
101 | - } | |
102 | - }); | |
103 | - | |
104 | - function updateWidgetDisplaying() { | |
105 | - if (vm.ctx && vm.ctx.$container) { | |
106 | - vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); | |
107 | - } | |
108 | - } | |
109 | - | |
110 | - updateWidgetDisplaying(); | |
111 | - | |
112 | - vm.getAccessToken = (deviceObj) => { | |
113 | - if (deviceObj.name) { | |
114 | - deviceService.findByName(deviceObj.name, {ignoreErrors: true}) | |
115 | - .then( | |
116 | - function (device) { | |
117 | - getDeviceCredential(device.id.id); | |
118 | - } | |
119 | - ) | |
120 | - } | |
121 | - }; | |
122 | - | |
123 | - function getDeviceCredential(deviceId) { | |
124 | - return deviceService.getDeviceCredentials(deviceId).then( | |
125 | - (deviceCredentials) => { | |
126 | - vm.configurations.accessToken = deviceCredentials.credentialsId; | |
127 | - vm.configurations.entityType = deviceCredentials.deviceId.entityType; | |
128 | - vm.configurations.entityId = deviceCredentials.deviceId.id; | |
129 | - vm.getAttributeStart(); | |
130 | - } | |
131 | - ); | |
132 | - } | |
133 | - | |
134 | - vm.createDevice = (deviceObj) => { | |
135 | - deviceService.findByName(deviceObj.name, {ignoreErrors: true}) | |
136 | - .then( | |
137 | - function (device) { | |
138 | - getDeviceCredential(device.id.id).then(() => { | |
139 | - getGatewaysListByUser(); | |
140 | - }); | |
141 | - }, | |
142 | - function () { | |
143 | - deviceService.saveDevice(deviceObj).then( | |
144 | - (device) => { | |
145 | - deviceService.getDeviceCredentials(device.id.id).then( | |
146 | - (data) => { | |
147 | - vm.configurations.accessToken = data.credentialsId; | |
148 | - vm.configurations.entityType = device.id.entityType; | |
149 | - vm.configurations.entityId = device.id.id; | |
150 | - vm.getAttributeStart(); | |
151 | - getGatewaysListByUser(); | |
152 | - } | |
153 | - ); | |
154 | - } | |
155 | - ); | |
156 | - }); | |
157 | - }; | |
158 | - | |
159 | - vm.saveAttributeConfig = () => { | |
160 | - vm.setAttribute(attributeNameShared, $window.btoa(angular.toJson(vm.getConfigAllByAttributeJSON())), types.attributesScope.shared.value); | |
161 | - vm.setAttribute(attributeNameServer, $window.btoa(angular.toJson(vm.getConfigByAttributeTmpJSON())), types.attributesScope.server.value); | |
162 | - vm.setAttribute(attributeNameLogShared, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); | |
163 | - }; | |
164 | - | |
165 | - vm.getAttributeStart = () => { | |
166 | - let initResps = []; | |
167 | - vm.configurations.connectors = {}; | |
168 | - initResps.push(vm.getAttributeConfig(attributeNameClinet, types.attributesScope.client.value)); | |
169 | - initResps.push(vm.getAttributeConfig(attributeNameServer, types.attributesScope.server.value)); | |
170 | - initResps.push(vm.getAttributeConfig(attributeNameLogShared, types.attributesScope.shared.value)); | |
171 | - $q.all(initResps).then((resp) => { | |
172 | - vm.getAttributeInitFromClient(resp[0]); | |
173 | - vm.getAttributeInitFromServer(resp[1]); | |
174 | - vm.getAttributeInitFromShared(resp[2]); | |
175 | - }, (err) => { | |
176 | - console.log("getAttribute_error", err); //eslint-disable-line | |
177 | - }); | |
178 | - }; | |
179 | - | |
180 | - vm.getAttributeConfig = (attributeName, typeValue) => { | |
181 | - let keys = [attributeName]; | |
182 | - return attributeService.getEntityAttributesValues(vm.configurations.entityType, vm.configurations.entityId, typeValue, keys); | |
183 | - }; | |
184 | - | |
185 | - vm.setAttribute = (attributeName, attributeConfig, typeValue) => { | |
186 | - let attributes = [ | |
187 | - { | |
188 | - key: attributeName, | |
189 | - value: attributeConfig | |
190 | - } | |
191 | - ]; | |
192 | - attributeService.saveEntityAttributes(vm.configurations.entityType, vm.configurations.entityId, typeValue, attributes).then(() => { | |
193 | - }, (err) => { | |
194 | - console.log("setAttribute_", err); //eslint-disable-line | |
195 | - }); | |
196 | - }; | |
197 | - | |
198 | - vm.exportConfig = () => { | |
199 | - let fileZip = {}; | |
200 | - fileZip["tb_gateway.yaml"] = vm.getConfig(); | |
201 | - vm.createConfigByExport(fileZip); | |
202 | - vm.getLogsConfigByExport(fileZip); | |
203 | - importExport.exportJSZip(fileZip, 'config'); | |
204 | - vm.setAttribute(attributeNameLogShared, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); | |
205 | - }; | |
206 | - | |
207 | - vm.getConfig = () => { | |
208 | - let config; | |
209 | - config = 'thingsboard:\n'; | |
210 | - config += ' host: ' + vm.configurations.host + '\n'; | |
211 | - config += ' remoteConfiguration: ' + vm.configurations.remoteConfiguration + '\n'; | |
212 | - config += ' port: ' + vm.configurations.port + '\n'; | |
213 | - config += ' security:\n'; | |
214 | - if (vm.configurations.securityType === 'accessToken') { | |
215 | - config += ' access-token: ' + vm.configurations.accessToken + '\n'; | |
216 | - } else if (vm.configurations.securityType === 'tls') { | |
217 | - config += ' ca_cert: ' + vm.configurations.caCertPath + '\n'; | |
218 | - config += ' privateKey: ' + vm.configurations.privateKeyPath + '\n'; | |
219 | - config += ' cert: ' + vm.configurations.certPath + '\n'; | |
220 | - } | |
221 | - config += 'storage:\n'; | |
222 | - if (vm.configurations.storageType === 'memoryStorage') { | |
223 | - config += ' type: memory\n'; | |
224 | - config += ' read_records_count: ' + vm.configurations.readRecordsCount + '\n'; | |
225 | - config += ' max_records_count: ' + vm.configurations.maxRecordsCount + '\n'; | |
226 | - } else if (vm.configurations.storageType === 'fileStorage') { | |
227 | - config += ' type: file\n'; | |
228 | - config += ' data_folder_path: ' + vm.configurations.dataFolderPath + '\n'; | |
229 | - config += ' max_file_count: ' + vm.configurations.maxFilesCount + '\n'; | |
230 | - config += ' max_read_records_count: ' + vm.configurations.readRecordsCount + '\n'; | |
231 | - config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; | |
232 | - } | |
233 | - config += 'connectors:\n'; | |
234 | - for (let connector in vm.configurations.connectors) { | |
235 | - if (vm.configurations.connectors[connector].enabled) { | |
236 | - config += ' -\n'; | |
237 | - config += ' name: ' + connector + ' Connector\n'; | |
238 | - config += ' type: ' + vm.configurations.connectors[connector].connector + '\n'; | |
239 | - config += ' configuration: ' + vm.validFileName(connector) + ".json" + '\n'; | |
240 | - } | |
241 | - } | |
242 | - return config; | |
243 | - }; | |
244 | - | |
245 | - vm.createConfigByExport = (fileZipAdd) => { | |
246 | - for (let connector in vm.configurations.connectors) { | |
247 | - if (vm.configurations.connectors[connector].enabled) { | |
248 | - fileZipAdd[vm.validFileName(connector) + ".json"] = angular.toJson(vm.configurations.connectors[connector].config); | |
249 | - } | |
250 | - } | |
251 | - }; | |
252 | - | |
253 | - vm.getLogsConfigByExport = (fileZipAdd) => { | |
254 | - fileZipAdd["logs.conf"] = vm.getLogsConfig(); | |
255 | - }; | |
256 | - | |
257 | - vm.getLogsConfig = () => { | |
258 | - return vm.remoteLoggingConfig | |
259 | - .replace(/{ERROR}/g, vm.configurations.remoteLoggingLevel) | |
260 | - .replace(/{.\/logs\/}/g, vm.configurations.remoteLoggingPathToLogs); | |
261 | - }; | |
262 | - | |
263 | - vm.getConfigAllByAttributeJSON = () => { | |
264 | - let thingsBoardAll = {}; | |
265 | - thingsBoardAll["thingsboard"] = vm.getConfigMainByAttributeJSON(); | |
266 | - vm.getConfigByAttributeJSON(thingsBoardAll); | |
267 | - return thingsBoardAll; | |
268 | - }; | |
269 | - | |
270 | - vm.getConfigMainByAttributeJSON = () => { | |
271 | - let configMain = {}; | |
272 | - let thingsBoard = {}; | |
273 | - thingsBoard.host = vm.configurations.host; | |
274 | - thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; | |
275 | - thingsBoard.port = vm.configurations.port; | |
276 | - let security = {}; | |
277 | - if (vm.configurations.securityType === 'accessToken') { | |
278 | - security.accessToken = (vm.configurations.accessToken) ? vm.configurations.accessToken : "" | |
279 | - } else { | |
280 | - security.caCert = vm.configurations.caCertPath; | |
281 | - security.privateKey = vm.configurations.privateKeyPath; | |
282 | - security.cert = vm.configurations.certPath; | |
283 | - } | |
284 | - thingsBoard.security = security; | |
285 | - configMain.thingsboard = thingsBoard; | |
286 | - | |
287 | - let storage = {}; | |
288 | - if (vm.configurations.storageType === 'memoryStorage') { | |
289 | - storage.type = "memory"; | |
290 | - storage.read_records_count = vm.configurations.readRecordsCount; | |
291 | - storage.max_records_count = vm.configurations.maxRecordsCount; | |
292 | - } else if (vm.configurations.storageType === 'fileStorage') { | |
293 | - storage.type = "file"; | |
294 | - storage.data_folder_path = vm.configurations.dataFolderPath; | |
295 | - storage.max_file_count = vm.configurations.maxFilesCount; | |
296 | - storage.max_read_records_count = vm.configurations.readRecordsCount; | |
297 | - storage.max_records_per_file = vm.configurations.maxRecordsCount; | |
298 | - } | |
299 | - configMain.storage = storage; | |
300 | - | |
301 | - let conn = []; | |
302 | - for (let connector in vm.configurations.connectors) { | |
303 | - if (vm.configurations.connectors[connector].enabled) { | |
304 | - let connect = {}; | |
305 | - connect.configuration = vm.validFileName(connector) + ".json"; | |
306 | - connect.name = connector; | |
307 | - connect.type = vm.configurations.connectors[connector].connector; | |
308 | - conn.push(connect); | |
309 | - } | |
310 | - } | |
311 | - configMain.connectors = conn; | |
312 | - | |
313 | - configMain.logs = $window.btoa(vm.getLogsConfig()); | |
314 | - | |
315 | - return configMain; | |
316 | - }; | |
317 | - | |
318 | - vm.getConfigByAttributeJSON = (thingsBoardBy) => { | |
319 | - for (let connector in vm.configurations.connectors) { | |
320 | - if (vm.configurations.connectors[connector].enabled) { | |
321 | - let typeAr = vm.configurations.connectors[connector].connector; | |
322 | - let objTypeAll = []; | |
323 | - for (let conn in vm.configurations.connectors) { | |
324 | - if (typeAr === vm.configurations.connectors[conn].connector && vm.configurations.connectors[conn].enabled) { | |
325 | - let objType = {}; | |
326 | - objType["name"] = conn; | |
327 | - objType["config"] = vm.configurations.connectors[conn].config; | |
328 | - objTypeAll.push(objType); | |
329 | - } | |
330 | - } | |
331 | - if (objTypeAll.length > 0) { | |
332 | - thingsBoardBy[typeAr] = objTypeAll; | |
333 | - } | |
334 | - } | |
335 | - } | |
336 | - }; | |
337 | - | |
338 | - vm.getConfigByAttributeTmpJSON = () => { | |
339 | - let connects = {}; | |
340 | - for (let connector in vm.configurations.connectors) { | |
341 | - if (!vm.configurations.connectors[connector].enabled && Object.keys(vm.configurations.connectors[connector].config).length !== 0) { | |
342 | - let conn = {}; | |
343 | - conn["connector"] = vm.configurations.connectors[connector].connector; | |
344 | - conn["config"] = vm.configurations.connectors[connector].config; | |
345 | - connects[connector] = conn; | |
346 | - } | |
347 | - } | |
348 | - return connects; | |
349 | - }; | |
350 | - | |
351 | - function getGatewaysListByUser(firstInit) { | |
352 | - vm.gateways = []; | |
353 | - vm.currentUser = userService.getCurrentUser(); | |
354 | - if (vm.currentUser.authority === 'TENANT_ADMIN') { | |
355 | - deviceService.getTenantDevices({limit: 500}).then( | |
356 | - (devices) => { | |
357 | - if (devices.data.length > 0) { | |
358 | - devices.data.forEach((device) => { | |
359 | - if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { | |
360 | - vm.gateways.push(device.name); | |
361 | - if (firstInit && vm.gateways.length && device.name === vm.gateways[0]) { | |
362 | - vm.configurations.singleSelect = vm.gateways[0]; | |
363 | - let deviceObj = { | |
364 | - "name": vm.configurations.singleSelect, | |
365 | - "type": "Gateway", | |
366 | - "additionalInfo": { | |
367 | - "gateway": true | |
368 | - } | |
369 | - }; | |
370 | - vm.getAccessToken(deviceObj); | |
371 | - } | |
372 | - } | |
373 | - }); | |
374 | - } | |
375 | - } | |
376 | - ); | |
377 | - } else if (vm.currentUser.authority === 'CUSTOMER_USER') { | |
378 | - deviceService.getCustomerDevices(vm.currentUser.customerId, {limit: 500}).then( | |
379 | - (devices) => { | |
380 | - if (devices.data.length > 0) { | |
381 | - devices.data.forEach((device) => { | |
382 | - if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { | |
383 | - vm.gateways.push(device.name); | |
384 | - if (firstInit && vm.gateways.length) { | |
385 | - vm.configurations.singleSelect = vm.gateways[0]; | |
386 | - let deviceObj = { | |
387 | - "name": vm.configurations.singleSelect, | |
388 | - "type": "Gateway", | |
389 | - "additionalInfo": { | |
390 | - "gateway": true | |
391 | - } | |
392 | - }; | |
393 | - vm.getAccessToken(deviceObj); | |
394 | - } | |
395 | - } | |
396 | - }); | |
397 | - } | |
398 | - } | |
399 | - ); | |
400 | - } | |
401 | - } | |
402 | - | |
403 | - vm.getAttributeInitFromClient = (resp) => { | |
404 | - if (resp.length > 0) { | |
405 | - vm.configurations.connectors = {}; | |
406 | - let attribute = angular.fromJson($window.atob(resp[0].value)); | |
407 | - for (var type in attribute) { | |
408 | - let keyVal = attribute[type]; | |
409 | - if (type === "thingsboard") { | |
410 | - if (keyVal !== null && Object.keys(keyVal).length > 0) { | |
411 | - vm.setConfigMain(keyVal); | |
412 | - } | |
413 | - } else { | |
414 | - for (let typeVal in keyVal) { | |
415 | - let typeName = ''; | |
416 | - if (Object.prototype.hasOwnProperty.call(keyVal[typeVal], 'name')) { | |
417 | - typeName = 'name'; | |
418 | - } | |
419 | - let key = ""; | |
420 | - key = (typeName === "") ? "No name" : ((typeName === 'name') ? keyVal[typeVal].name : keyVal[typeVal][typeName].name); | |
421 | - let conn = {}; | |
422 | - conn["enabled"] = true; | |
423 | - conn["connector"] = type; | |
424 | - conn["config"] = angular.toJson(keyVal[typeVal].config); | |
425 | - vm.configurations.connectors[key] = conn; | |
426 | - } | |
427 | - } | |
428 | - } | |
429 | - } | |
430 | - }; | |
431 | - | |
432 | - vm.getAttributeInitFromServer = (resp) => { | |
433 | - if (resp.length > 0) { | |
434 | - let attribute = angular.fromJson($window.atob(resp[0].value)); | |
435 | - for (let key in attribute) { | |
436 | - let conn = {}; | |
437 | - conn["enabled"] = false; | |
438 | - conn["connector"] = attribute[key].connector; | |
439 | - conn["config"] = angular.toJson(attribute[key].config); | |
440 | - vm.configurations.connectors[key] = conn; | |
441 | - } | |
442 | - } | |
443 | - }; | |
444 | - | |
445 | - vm.getAttributeInitFromShared = (resp) => { | |
446 | - if (resp.length > 0) { | |
447 | - if (vm.types.gatewayLogLevel[resp[0].value.toLowerCase()]) { | |
448 | - vm.configurations.remoteLoggingLevel = resp[0].value.toUpperCase(); | |
449 | - } | |
450 | - } else { | |
451 | - vm.configurations.remoteLoggingLevel = vm.types.gatewayLogLevel.debug; | |
452 | - } | |
453 | - }; | |
454 | - | |
455 | - vm.setConfigMain = (keyVal) => { | |
456 | - if (Object.prototype.hasOwnProperty.call(keyVal, 'thingsboard')) { | |
457 | - vm.configurations.host = keyVal.thingsboard.host; | |
458 | - vm.configurations.port = keyVal.thingsboard.port; | |
459 | - vm.configurations.remoteConfiguration = keyVal.thingsboard.remoteConfiguration; | |
460 | - if (Object.prototype.hasOwnProperty.call(keyVal.thingsboard.security, 'accessToken')) { | |
461 | - vm.configurations.securityType = 'accessToken'; | |
462 | - vm.configurations.accessToken = keyVal.thingsboard.security.accessToken; | |
463 | - } else { | |
464 | - vm.configurations.securityType = 'tls'; | |
465 | - vm.configurations.caCertPath = keyVal.thingsboard.security.caCert; | |
466 | - vm.configurations.privateKeyPath = keyVal.thingsboard.security.private_key; | |
467 | - vm.configurations.certPath = keyVal.thingsboard.security.cert; | |
468 | - } | |
469 | - } | |
470 | - if (Object.prototype.hasOwnProperty.call(keyVal, 'storage') && Object.prototype.hasOwnProperty.call(keyVal.storage, 'type')) { | |
471 | - if (keyVal.storage.type === 'memory') { | |
472 | - vm.configurations.storageType = 'memoryStorage'; | |
473 | - vm.configurations.readRecordsCount = keyVal.storage.read_records_count; | |
474 | - vm.configurations.maxRecordsCount = keyVal.storage.max_records_count; | |
475 | - } else if (keyVal.storage.type === 'file') { | |
476 | - vm.configurations.storageType = 'fileStorage'; | |
477 | - vm.configurations.dataFolderPath = keyVal.storage.data_folder_path; | |
478 | - vm.configurations.maxFilesCount = keyVal.storage.max_file_count; | |
479 | - vm.configurations.readRecordsCount = keyVal.storage.read_records_count; | |
480 | - vm.configurations.maxRecordsCount = keyVal.storage.max_records_count; | |
481 | - } | |
482 | - } | |
483 | - }; | |
484 | - | |
485 | - vm.setSaveTypeConfig = (itemVal) => { | |
486 | - vm.configurations.remoteConfiguration = itemVal.item; | |
487 | - }; | |
488 | - | |
489 | - vm.validFileName = (fileName) => { | |
490 | - let fileName1 = fileName.replace("_", ""); | |
491 | - let fileName2 = fileName1.replace("-", ""); | |
492 | - let fileName3 = fileName2.replace(/^\s+|\s+$/g, ''); | |
493 | - let fileName4 = fileName3.toLowerCase(); | |
494 | - return fileName4; | |
495 | - }; | |
496 | -} | |
497 | - | |
498 | - |
ui/src/app/components/gateway/gateway-config-dialog.tpl.html
renamed from
ui/src/app/components/gateWay/gateway-config-dialog.tpl.html
... | ... | @@ -55,15 +55,15 @@ |
55 | 55 | required> |
56 | 56 | </div> |
57 | 57 | </div> |
58 | - <div class="tb-error-messages" layout="column" flex ng-messages="theForm.config.$error" role="alert"> | |
58 | + <div class="tb-error-messages" layout="column" ng-messages="theForm.config.$error" role="alert"> | |
59 | 59 | <div ng-message="required" flex class="tb-error-message" translate>gateway.json-required</div> |
60 | - <div ng-message="vm.config" class="tb-error-message" translate>gateway.json-parse</div> | |
60 | + <div ng-message="config" class="tb-error-message" translate>gateway.json-parse</div> | |
61 | 61 | </div> |
62 | 62 | </div> |
63 | 63 | </div> |
64 | 64 | </md-dialog-content> |
65 | 65 | <md-dialog-actions layout="row" layout-align="end center" class="action-buttons"> |
66 | - <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" | |
66 | + <md-button ng-disabled="$root.loading || theForm.config.$invalid || !theForm.config.$dirty" type="submit" | |
67 | 67 | class="md-raised md-primary"> |
68 | 68 | {{'action.save'|translate}} |
69 | 69 | </md-button> | ... | ... |
ui/src/app/components/gateway/gateway-config-select.directive.js
renamed from
ui/src/app/components/gateWay/gateway-config-select.directive.js
... | ... | @@ -17,7 +17,7 @@ import './gateway-config-select.scss'; |
17 | 17 | |
18 | 18 | /* eslint-disable import/no-unresolved, import/default */ |
19 | 19 | |
20 | -import gatewayAliasSelectTemplate from './gateway-config-select.tpl.html'; | |
20 | +import gatewaySelectTemplate from './gateway-config-select.tpl.html'; | |
21 | 21 | |
22 | 22 | /* eslint-enable import/no-unresolved, import/default */ |
23 | 23 | |
... | ... | @@ -32,23 +32,26 @@ export default angular.module('thingsboard.directives.gatewayConfigSelect', []) |
32 | 32 | function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, $mdDialog) { |
33 | 33 | |
34 | 34 | var linker = function (scope, element, attrs, ngModelCtrl) { |
35 | - var template = $templateCache.get(gatewayAliasSelectTemplate); | |
35 | + const template = $templateCache.get(gatewaySelectTemplate); | |
36 | 36 | element.html(template); |
37 | 37 | |
38 | 38 | scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; |
39 | - | |
40 | - scope.ngModelCtrl = ngModelCtrl; | |
41 | - scope.singleSelect = null; | |
39 | + scope.gateway = null; | |
40 | + scope.gatewaySearchText = ''; | |
42 | 41 | |
43 | 42 | scope.updateValidity = function () { |
44 | 43 | var value = ngModelCtrl.$viewValue; |
45 | 44 | var valid = angular.isDefined(value) && value != null || !scope.tbRequired; |
46 | - ngModelCtrl.$setValidity('singleSelect', valid); | |
45 | + ngModelCtrl.$setValidity('gateway', valid); | |
47 | 46 | }; |
48 | 47 | |
49 | - scope.$watch('singleSelect', function () { | |
50 | - scope.updateView(); | |
51 | - }); | |
48 | + function startWatchers() { | |
49 | + scope.$watch('gateway', function (newVal, prevVal) { | |
50 | + if (!angular.equals(newVal, prevVal) && newVal !== null) { | |
51 | + scope.updateView(); | |
52 | + } | |
53 | + }); | |
54 | + } | |
52 | 55 | |
53 | 56 | scope.gatewayNameSearch = function (gatewaySearchText) { |
54 | 57 | return gatewaySearchText ? scope.gatewayList.filter( |
... | ... | @@ -58,22 +61,20 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, |
58 | 61 | scope.createFilterForGatewayName = function (query) { |
59 | 62 | var lowercaseQuery = query.toLowerCase(); |
60 | 63 | return function filterFn(device) { |
61 | - return (device.toLowerCase().indexOf(lowercaseQuery) === 0); | |
64 | + return (device.name.toLowerCase().indexOf(lowercaseQuery) === 0); | |
62 | 65 | }; |
63 | 66 | }; |
64 | 67 | |
65 | 68 | scope.updateView = function () { |
66 | - ngModelCtrl.$setViewValue(scope.singleSelect); | |
69 | + ngModelCtrl.$setViewValue(scope.gateway); | |
67 | 70 | scope.updateValidity(); |
68 | - let deviceObj = {"name": scope.singleSelect, "type": "Gateway", "additionalInfo": { | |
69 | - "gateway": true | |
70 | - }}; | |
71 | - scope.getAccessToken(deviceObj); | |
71 | + scope.getAccessToken(scope.gateway.id); | |
72 | 72 | }; |
73 | 73 | |
74 | 74 | ngModelCtrl.$render = function () { |
75 | 75 | if (ngModelCtrl.$viewValue) { |
76 | - scope.singleSelect = ngModelCtrl.$viewValue; | |
76 | + scope.gateway = ngModelCtrl.$viewValue; | |
77 | + startWatchers(); | |
77 | 78 | } |
78 | 79 | }; |
79 | 80 | |
... | ... | @@ -85,9 +86,9 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, |
85 | 86 | if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) { |
86 | 87 | $event.preventDefault(); |
87 | 88 | let indexRes = scope.gatewayList.findIndex((element) => element.key === scope.gatewaySearchText); |
88 | - if (indexRes === -1) { | |
89 | - scope.createNewGatewayDialog($event, {name: scope.gatewaySearchText}); | |
90 | - } | |
89 | + if (indexRes === -1) { | |
90 | + scope.createNewGatewayDialog($event, scope.gatewaySearchText); | |
91 | + } | |
91 | 92 | } |
92 | 93 | }; |
93 | 94 | |
... | ... | @@ -96,7 +97,7 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, |
96 | 97 | $event.stopPropagation(); |
97 | 98 | } |
98 | 99 | var title = $translate.instant('gateway.create-new-gateway'); |
99 | - var content = $translate.instant('gateway.create-new-gateway-text', {gatewayName: deviceName.name}); | |
100 | + var content = $translate.instant('gateway.create-new-gateway-text', {gatewayName: deviceName}); | |
100 | 101 | var confirm = $mdDialog.confirm() |
101 | 102 | .targetEvent($event) |
102 | 103 | .title(title) |
... | ... | @@ -106,9 +107,13 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, |
106 | 107 | .ok($translate.instant('action.yes')); |
107 | 108 | $mdDialog.show(confirm).then( |
108 | 109 | () => { |
109 | - let deviceObj = {"name": deviceName.name, "type": "Gateway", "additionalInfo": { | |
110 | - "gateway": true | |
111 | - }}; | |
110 | + let deviceObj = { | |
111 | + name: deviceName, | |
112 | + type: "Gateway", | |
113 | + additionalInfo: { | |
114 | + gateway: true | |
115 | + } | |
116 | + }; | |
112 | 117 | scope.createDevice(deviceObj); |
113 | 118 | }, |
114 | 119 | () => { |
... | ... | @@ -125,7 +130,6 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, |
125 | 130 | link: linker, |
126 | 131 | scope: { |
127 | 132 | tbRequired: '=?', |
128 | - allowedEntityTypes: '=?', | |
129 | 133 | gatewayList: '=?', |
130 | 134 | getAccessToken: '=', |
131 | 135 | createDevice: '=', | ... | ... |
ui/src/app/components/gateway/gateway-config-select.scss
renamed from
ui/src/app/components/gateWay/gateway-config-select.scss
ui/src/app/components/gateway/gateway-config-select.tpl.html
renamed from
ui/src/app/components/gateWay/gateway-config-select.tpl.html
... | ... | @@ -16,14 +16,14 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <section layout='column'> |
19 | - <md-autocomplete md-input-name="singleSelect" flex | |
19 | + <md-autocomplete md-input-name="gateway" flex | |
20 | 20 | ng-required="tbRequired" |
21 | 21 | md-no-cache="true" |
22 | - ng-model="singleSelect" | |
23 | - md-selected-item="singleSelect" | |
22 | + ng-model="gateway" | |
23 | + md-selected-item="gateway" | |
24 | 24 | md-search-text="gatewaySearchText" |
25 | 25 | md-items="item in gatewayNameSearch(gatewaySearchText)" |
26 | - md-item-text="item" | |
26 | + md-item-text="item.name" | |
27 | 27 | tb-keydown="gatewayNameEnter($event)" |
28 | 28 | tb-keypress="gatewayNameEnter($event)" |
29 | 29 | md-min-length="0" |
... | ... | @@ -33,7 +33,7 @@ |
33 | 33 | md-input-class="tb-test" |
34 | 34 | md-menu-container-class="tb-gateway-autocomplete-container"> |
35 | 35 | <md-item-template> |
36 | - <span md-highlight-text="gatewaySearchText" md-highlight-flags="^i">{{item}}</span> | |
36 | + <span md-highlight-text="gatewaySearchText" md-highlight-flags="^i">{{item.name}}</span> | |
37 | 37 | </md-item-template> |
38 | 38 | <md-not-found> |
39 | 39 | <div class="tb-not-found"> |
... | ... | @@ -41,14 +41,13 @@ |
41 | 41 | <span translate>gateway.no-gateway-found</span> |
42 | 42 | </div> |
43 | 43 | <div ng-if="!textIsEmpty(gatewaySearchText)"> |
44 | - <span translate | |
45 | - translate-values='{ item: "{{gatewaySearchText | truncate:true:6:'...'}}" }'>gateway.no-gateway-matching</span> | |
46 | - <a translate ng-click="createNewGatewayDialog($event, {name: gatewaySearchText})">gateway.create-new-gateway</a> | |
44 | + <span translate translate-values='{ item: "{{gatewaySearchText | truncate:true:6:'...'}}" }'>gateway.no-gateway-matching</span> | |
45 | + <a translate ng-click="createNewGatewayDialog($event, gatewaySearchText)">gateway.create-new-gateway</a> | |
47 | 46 | </div> |
48 | 47 | </div> |
49 | 48 | </md-not-found> |
50 | - <div ng-messages="theForm.singleSelect.$error"> | |
51 | - <div ng-message="required" translate>Test</div> | |
49 | + <div ng-messages="theForm.gateway.$error"> | |
50 | + <div ng-message="required" translate>gateway.gateway-name-required</div> | |
52 | 51 | </div> |
53 | 52 | </md-autocomplete> |
54 | 53 | </section> | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2020 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 './gateway-config.scss'; | |
17 | + | |
18 | +/* eslint-disable import/no-unresolved, import/default */ | |
19 | + | |
20 | +import gatewayConfigTemplate from './gateway-config.tpl.html'; | |
21 | +import gatewayConfigDialogTemplate from './gateway-config-dialog.tpl.html'; | |
22 | +import beautify from "js-beautify"; | |
23 | + | |
24 | +/* eslint-enable import/no-unresolved, import/default */ | |
25 | +const js_beautify = beautify.js; | |
26 | + | |
27 | +export default angular.module('thingsboard.directives.gatewayConfig', []) | |
28 | + .directive('tbGatewayConfig', GatewayConfig) | |
29 | + .name; | |
30 | + | |
31 | +/*@ngInject*/ | |
32 | +function GatewayConfig() { | |
33 | + return { | |
34 | + restrict: "E", | |
35 | + scope: true, | |
36 | + bindToController: { | |
37 | + disabled: '=ngDisabled', | |
38 | + gatewayConfig: '=', | |
39 | + changeAlignment: '=', | |
40 | + theForm: '=' | |
41 | + }, | |
42 | + controller: GatewayConfigController, | |
43 | + controllerAs: 'vm', | |
44 | + templateUrl: gatewayConfigTemplate | |
45 | + }; | |
46 | +} | |
47 | + | |
48 | +/*@ngInject*/ | |
49 | +function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window, types) { | |
50 | + let vm = this; | |
51 | + vm.types = types; | |
52 | + | |
53 | + vm.removeConnector = (index) => { | |
54 | + if (index > -1) { | |
55 | + vm.gatewayConfig.splice(index, 1); | |
56 | + } | |
57 | + }; | |
58 | + | |
59 | + vm.addNewConnector = () => { | |
60 | + vm.gatewayConfig.push({ | |
61 | + enabled: false, | |
62 | + configType: '', | |
63 | + config: {}, | |
64 | + name: '' | |
65 | + }); | |
66 | + }; | |
67 | + | |
68 | + vm.openConfigDialog = ($event, index, config, typeName) => { | |
69 | + if ($event) { | |
70 | + $event.stopPropagation(); | |
71 | + } | |
72 | + $mdDialog.show({ | |
73 | + controller: GatewayDialogController, | |
74 | + controllerAs: 'vm', | |
75 | + templateUrl: gatewayConfigDialogTemplate, | |
76 | + parent: angular.element($document[0].body), | |
77 | + locals: { | |
78 | + config: config, | |
79 | + typeName: typeName | |
80 | + }, | |
81 | + targetEvent: $event, | |
82 | + fullscreen: true, | |
83 | + multiple: true, | |
84 | + }).then(function (config) { | |
85 | + if (config && index > -1) { | |
86 | + vm.gatewayConfig[index].config = config; | |
87 | + } | |
88 | + }); | |
89 | + | |
90 | + }; | |
91 | + | |
92 | + vm.changeConnectorType = (connector) => { | |
93 | + for (let gatewayConfigTypeKey in types.gatewayConfigType) { | |
94 | + if (types.gatewayConfigType[gatewayConfigTypeKey].value === connector.configType) { | |
95 | + if (!connector.name) { | |
96 | + connector.name = generateConnectorName(types.gatewayConfigType[gatewayConfigTypeKey].name, 0); | |
97 | + break; | |
98 | + } | |
99 | + } | |
100 | + } | |
101 | + }; | |
102 | + | |
103 | + vm.changeConnectorName = (connector, currentConnectorIndex) => { | |
104 | + connector.name = validateConnectorName(connector.name, 0, currentConnectorIndex); | |
105 | + }; | |
106 | + | |
107 | + function generateConnectorName(name, index) { | |
108 | + let newKeyName = index ? name + index : name; | |
109 | + let indexRes = vm.gatewayConfig.findIndex((element) => element.name === newKeyName); | |
110 | + return indexRes === -1 ? newKeyName : generateConnectorName(name, ++index); | |
111 | + } | |
112 | + | |
113 | + function validateConnectorName(name, index, currentConnectorIndex) { | |
114 | + for (let i = 0; i < vm.gatewayConfig.length; i++) { | |
115 | + let nameEq = (index === 0) ? name : name + index; | |
116 | + if (i !== currentConnectorIndex && vm.gatewayConfig[i].name === nameEq) { | |
117 | + index++; | |
118 | + validateConnectorName(name, index, currentConnectorIndex); | |
119 | + } | |
120 | + } | |
121 | + return (index === 0) ? name : name + index; | |
122 | + } | |
123 | + | |
124 | + vm.validateJSON = (config) => { | |
125 | + return angular.equals({}, config); | |
126 | + }; | |
127 | +} | |
128 | + | |
129 | +/*@ngInject*/ | |
130 | +function GatewayDialogController($scope, $mdDialog, $document, $window, config, typeName) { | |
131 | + let vm = this; | |
132 | + vm.config = js_beautify(angular.toJson(config), {indent_size: 4}); | |
133 | + vm.typeName = typeName; | |
134 | + vm.configAreaOptions = { | |
135 | + useWrapMode: true, | |
136 | + mode: 'json', | |
137 | + advanced: { | |
138 | + enableSnippets: true, | |
139 | + enableBasicAutocompletion: true, | |
140 | + enableLiveAutocompletion: true | |
141 | + }, | |
142 | + onLoad: function (_ace) { | |
143 | + _ace.$blockScrolling = 1; | |
144 | + } | |
145 | + }; | |
146 | + | |
147 | + vm.validateConfig = (model, editorName) => { | |
148 | + if (model && model.length) { | |
149 | + try { | |
150 | + angular.fromJson(model); | |
151 | + $scope.theForm[editorName].$setValidity('config', true); | |
152 | + } catch (e) { | |
153 | + $scope.theForm[editorName].$setValidity('config', false); | |
154 | + } | |
155 | + } | |
156 | + }; | |
157 | + | |
158 | + vm.save = () => { | |
159 | + $mdDialog.hide(angular.fromJson(vm.config)); | |
160 | + }; | |
161 | + | |
162 | + vm.cancel = () => { | |
163 | + $mdDialog.hide(); | |
164 | + }; | |
165 | + | |
166 | + vm.beautifyJson = () => { | |
167 | + vm.config = js_beautify(vm.config, {indent_size: 4}); | |
168 | + }; | |
169 | +} | |
170 | + | ... | ... |
ui/src/app/components/gateway/gateway-config.scss
renamed from
ui/src/app/components/gateWay/gateway-config.scss
... | ... | @@ -56,20 +56,20 @@ |
56 | 56 | .tb-json-toolbar{ |
57 | 57 | height: 40px; |
58 | 58 | } |
59 | +} | |
59 | 60 | |
60 | - .tb-json-panel { | |
61 | - height: calc(100% - 80px); | |
62 | - margin-left: 15px; | |
63 | - border: 1px solid #c0c0c0; | |
61 | +.tb-json-panel { | |
62 | + height: calc(100% - 80px); | |
63 | + margin-left: 15px; | |
64 | + border: 1px solid #c0c0c0; | |
64 | 65 | |
65 | - .tb-json-input { | |
66 | - width: 100%; | |
67 | - min-width: 400px; | |
68 | - height: 100%; | |
66 | + .tb-json-input { | |
67 | + width: 100%; | |
68 | + min-width: 400px; | |
69 | + height: 100%; | |
69 | 70 | |
70 | - &:not(.fill-height) { | |
71 | - min-height: 200px; | |
72 | - } | |
71 | + &:not(.fill-height) { | |
72 | + min-height: 200px; | |
73 | 73 | } |
74 | 74 | } |
75 | 75 | } | ... | ... |
ui/src/app/components/gateway/gateway-config.tpl.html
renamed from
ui/src/app/components/gateWay/gateway-config.tpl.html
... | ... | @@ -15,61 +15,49 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<form name="gatewayConfig" flex layout="column" class="gateway-config"> | |
19 | - <div layout="row" id="section-row" ng-repeat="keyVal in vm.kvList track by $index"> | |
20 | - <div layout="column" layout-align="center center" class="gateway-config-row"> | |
21 | - <md-input-container class="md-block"> | |
22 | - <md-checkbox ng-model="keyVal.enabled" | |
23 | - aria-label="{{ 'gateway.enabled' | translate }}" | |
24 | - ng-change="vm.checkboxValid(keyVal)" | |
25 | - ng-click="vm.checkboxValidClick($event, keyVal)" | |
26 | - ng-mouseover="vm.checkboxValidMouseover($event, keyVal)"> | |
27 | - </md-checkbox> | |
28 | - <md-tooltip md-direction="top"> | |
29 | - {{ 'gateway.enabled' | translate }} | |
30 | - </md-tooltip> | |
31 | - </md-input-container> | |
18 | +<section name="gatewayConfig" layout="column" class="gateway-config"> | |
19 | + <section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index"> | |
20 | + <div layout="column" layout-align="center start" class="gateway-config-row"> | |
21 | + <md-switch ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)" | |
22 | + aria-label="{{ 'gateway.connector-enabled' | translate }}"> | |
23 | + </md-switch> | |
32 | 24 | </div> |
33 | 25 | <div layout="row" flex class="gateway-config-row" |
34 | 26 | ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> |
35 | 27 | <md-input-container class="md-block" flex> |
36 | 28 | <label>{{'gateway.connector-type' | translate }}</label> |
37 | - <md-select name="configType" ng-change="vm.configTypeChange(keyVal)" ng-model="keyVal.value" required> | |
29 | + <md-select name="connectorType" | |
30 | + ng-change="vm.changeConnectorType(connector)" | |
31 | + aria-label="{{ 'gateway.gateway.connector-type' | translate }}" | |
32 | + ng-model="connector.configType" required> | |
38 | 33 | <md-option ng-repeat="configType in vm.types.gatewayConfigType" ng-value="configType.value"> |
39 | 34 | {{configType.value}} |
40 | 35 | </md-option> |
41 | 36 | </md-select> |
42 | - <md-tooltip md-direction="top"> | |
43 | - {{ 'gateway.connector-type' | translate }} | |
44 | - </md-tooltip> | |
37 | + <div ng-messages="vm.theForm.connectorType.$error"> | |
38 | + <div ng-message="required" translate>gateway.connector-type-required</div> | |
39 | + </div> | |
45 | 40 | </md-input-container> |
46 | 41 | <md-input-container class="md-block" flex> |
47 | - <input placeholder="{{ (vm.keyPlaceholderText ? vm.keyPlaceholderText : 'gateway.name') | translate }}" | |
42 | + <input placeholder="{{'gateway.connector-name' | translate }}" | |
48 | 43 | ng-model-options="{ updateOn: 'blur' }" |
49 | - ng-change="vm.keyValChange(keyVal, $index)" name="key" ng-model="keyVal.key" required/> | |
50 | - <div ng-messages="gatewayConfig.key.$error"> | |
51 | - <div ng-message="required" translate>extension.field-required</div> | |
44 | + ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/> | |
45 | + <div ng-messages="vm.theForm.connectorName.$error"> | |
46 | + <div ng-message="required" translate>gateway.connector-name-required</div> | |
52 | 47 | </div> |
53 | - <md-tooltip md-direction="top"> | |
54 | - {{ 'gateway.name' | translate }} | |
55 | - </md-tooltip> | |
56 | 48 | </md-input-container> |
57 | 49 | </div> |
58 | 50 | <div layout="row" layout-align="end center" class="action-buttons" |
59 | 51 | ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> |
60 | - <md-button class="md-icon-button md-fab md-mini" | |
61 | - name="updateconf" | |
62 | - ng-click="vm.openConfigDialog($event, $index, keyVal.config, keyVal.key)" | |
52 | + <md-button class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)" | |
63 | 53 | aria-label="{{ 'gateway.update-config' | translate }}" |
64 | - ng-class="vm.buttonValid(keyVal.config)" required> | |
65 | - <md-icon class="material-icons">settings_ethernet</md-icon> | |
54 | + ng-class="{'md-warn': vm.validateJSON(connector.config)}"> | |
55 | + <md-icon class="material-icons">more_horiz</md-icon> | |
66 | 56 | <md-tooltip md-direction="top"> |
67 | 57 | {{ 'gateway.update-config' | translate }} |
68 | 58 | </md-tooltip> |
69 | 59 | </md-button> |
70 | - <md-button ng-show="!vm.disabled" ng-disabled="$root.loading" | |
71 | - class="md-icon-button md-fab md-mini md-primary" | |
72 | - ng-click="vm.removeKeyVal($index)" | |
60 | + <md-button class="md-icon-button md-mini" ng-click="vm.removeConnector($index)" | |
73 | 61 | aria-label="{{ 'gateway.delete' | translate }}"> |
74 | 62 | <md-icon class="material-icons">close</md-icon> |
75 | 63 | <md-tooltip md-direction="top"> |
... | ... | @@ -77,18 +65,17 @@ |
77 | 65 | </md-tooltip> |
78 | 66 | </md-button> |
79 | 67 | </div> |
80 | - </div> | |
81 | - <span ng-show="!vm.kvList.length" | |
68 | + </section> | |
69 | + <span ng-show="!vm.gatewayConfig.length" | |
82 | 70 | layout-align="center center" ng-class="{'disabled': vm.disabled}" |
83 | - class="no-data-found" translate>{{vm.noDataText ? vm.noDataText : 'gateway.no-connectors'}}</span> | |
71 | + class="no-data-found" translate>{{'gateway.no-connectors'}}</span> | |
84 | 72 | <div> |
85 | - <md-button ng-show="!vm.disabled" ng-disabled="$root.loading" class="md-raised" | |
86 | - ng-click="vm.addKeyVal()" | |
87 | - aria-label="{{ 'gateway.add-connectors' | translate }}"> | |
73 | + <md-button class="md-raised" ng-click="vm.addNewConnector()" | |
74 | + aria-label="{{ 'gateway.connector-add' | translate }}"> | |
88 | 75 | <md-tooltip md-direction="top"> |
89 | - {{ 'gateway.add-connectors' | translate }} | |
76 | + {{ 'gateway.connector-add' | translate }} | |
90 | 77 | </md-tooltip> |
91 | 78 | <span translate>action.add</span> |
92 | 79 | </md-button> |
93 | 80 | </div> |
94 | -</form > | |
81 | +</section > | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2020 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 './gateway-form.scss'; | |
17 | +/* eslint-disable import/no-unresolved, import/default */ | |
18 | + | |
19 | +import gatewayFormTemplate from './gateway-form.tpl.html'; | |
20 | + | |
21 | +/* eslint-enable import/no-unresolved, import/default */ | |
22 | + | |
23 | +export default angular.module('thingsboard.directives.gatewayForm', []) | |
24 | + .directive('tbGatewayForm', GatewayForm) | |
25 | + .name; | |
26 | + | |
27 | +/*@ngInject*/ | |
28 | +function GatewayForm() { | |
29 | + return { | |
30 | + restrict: "E", | |
31 | + scope: true, | |
32 | + bindToController: { | |
33 | + formId: '=', | |
34 | + ctx: '=' | |
35 | + }, | |
36 | + controller: GatewayFormController, | |
37 | + controllerAs: 'vm', | |
38 | + templateUrl: gatewayFormTemplate | |
39 | + }; | |
40 | +} | |
41 | + | |
42 | +/*@ngInject*/ | |
43 | +function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, toast, importExport, attributeService, deviceService, userService, $mdDialog, $mdUtil, types, $window, $q, entityService, utils, $translate) { | |
44 | + let vm = this; | |
45 | + const currentConfigurationAttribute = "current_configuration"; | |
46 | + const configurationDraftsAttribute = "configuration_drafts"; | |
47 | + const configurationAttribute = "configuration"; | |
48 | + const remoteLoggingLevelAttribute = "RemoteLoggingLevel"; | |
49 | + | |
50 | + const templateLogsConfig = '[loggers]}}keys=root, service, connector, converter, tb_connection, storage, extension}}[handlers]}}keys=consoleHandler, serviceHandler, connectorHandler, converterHandler, tb_connectionHandler, storageHandler, extensionHandler}}[formatters]}}keys=LogFormatter}}[logger_root]}}level=ERROR}}handlers=consoleHandler}}[logger_connector]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=connector}}[logger_storage]}}level={ERROR}}}handlers=storageHandler}}formatter=LogFormatter}}qualname=storage}}[logger_tb_connection]}}level={ERROR}}}handlers=tb_connectionHandler}}formatter=LogFormatter}}qualname=tb_connection}}[logger_service]}}level={ERROR}}}handlers=serviceHandler}}formatter=LogFormatter}}qualname=service}}[logger_converter]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=converter}}[logger_extension]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=extension}}[handler_consoleHandler]}}class=StreamHandler}}level={ERROR}}}formatter=LogFormatter}}args=(sys.stdout,)}}[handler_connectorHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}connector.log", "d", 1, 7,)}}[handler_storageHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}storage.log", "d", 1, 7,)}}[handler_serviceHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}service.log", "d", 1, 7,)}}[handler_converterHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}converter.log", "d", 1, 3,)}}[handler_extensionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}extension.log", "d", 1, 3,)}}[handler_tb_connectionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}tb_connection.log", "d", 1, 3,)}}[formatter_LogFormatter]}}format="%(asctime)s - %(levelname)s - [%(filename)s] - %(module)s - %(lineno)d - %(message)s" }}datefmt="%Y-%m-%d %H:%M:%S"'; | |
51 | + | |
52 | + vm.types = types; | |
53 | + | |
54 | + vm.configurations = { | |
55 | + gateway: '', | |
56 | + host: $document[0].domain, | |
57 | + port: 1883, | |
58 | + remoteConfiguration: true, | |
59 | + accessToken: '', | |
60 | + storageType: "memoryStorage", | |
61 | + readRecordsCount: 100, | |
62 | + maxRecordsCount: 10000, | |
63 | + dataFolderPath: './data/', | |
64 | + maxFilesCount: 5, | |
65 | + securityType: "accessToken", | |
66 | + caCertPath: '/etc/thingsboard-gateway/ca.pem', | |
67 | + privateKeyPath: '/etc/thingsboard-gateway/privateKey.pem', | |
68 | + certPath: '/etc/thingsboard-gateway/certificate.pem', | |
69 | + connectors: [], | |
70 | + remoteLoggingLevel: "DEBUG", | |
71 | + remoteLoggingPathToLogs: './logs/' | |
72 | + }; | |
73 | + | |
74 | + let archiveFileName = ''; | |
75 | + let gatewayNameExists = ''; | |
76 | + let successfulSaved = ''; | |
77 | + | |
78 | + vm.securityTypes = [{ | |
79 | + name: 'gateway.security-types.access-token', | |
80 | + value: 'accessToken' | |
81 | + }, { | |
82 | + name: 'gateway.security-types.tls', | |
83 | + value: 'tls' | |
84 | + }]; | |
85 | + | |
86 | + vm.storageTypes = [{ | |
87 | + name: 'gateway.storage-types.memory-storage', | |
88 | + value: 'memoryStorage' | |
89 | + }, { | |
90 | + name: 'gateway.storage-types.file-storage', | |
91 | + value: 'fileStorage' | |
92 | + }]; | |
93 | + | |
94 | + $scope.$watch('vm.ctx', function () { | |
95 | + if (vm.ctx ) { | |
96 | + vm.settings = vm.ctx.settings; | |
97 | + vm.widgetConfig = vm.ctx.widgetConfig; | |
98 | + initializeConfig(); | |
99 | + } | |
100 | + }); | |
101 | + | |
102 | + $scope.$on('gateway-form-resize', function (event, formId) { | |
103 | + if (vm.formId == formId) { | |
104 | + updateWidgetDisplaying(); | |
105 | + } | |
106 | + }); | |
107 | + | |
108 | + function updateWidgetDisplaying() { | |
109 | + vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); | |
110 | + } | |
111 | + | |
112 | + function initWidgetSettings() { | |
113 | + let widgetTitle; | |
114 | + if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) { | |
115 | + widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle); | |
116 | + } else { | |
117 | + widgetTitle = $translate.instant('gateway.gateway'); | |
118 | + } | |
119 | + vm.ctx.widgetTitle = widgetTitle; | |
120 | + | |
121 | + archiveFileName = vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration'; | |
122 | + gatewayNameExists = utils.customTranslation(vm.settings.deviceNameExist, vm.settings.deviceNameExist) || $translate.instant('gateway.gateway-exists'); | |
123 | + successfulSaved = utils.customTranslation(vm.settings.successfulSave, vm.settings.successfulSave) || $translate.instant('gateway.gateway-saved'); | |
124 | + } | |
125 | + | |
126 | + function initializeConfig() { | |
127 | + updateWidgetDisplaying(); | |
128 | + initWidgetSettings(); | |
129 | + getGatewaysList(true); | |
130 | + } | |
131 | + | |
132 | + vm.getAccessToken = (deviceId) => { | |
133 | + if (deviceId.id) { | |
134 | + getDeviceCredentials(deviceId.id); | |
135 | + } | |
136 | + }; | |
137 | + | |
138 | + vm.collapsePanel = function (panelId) { | |
139 | + $mdExpansionPanel(panelId).collapse(); | |
140 | + }; | |
141 | + | |
142 | + function getDeviceCredentials(deviceId) { | |
143 | + return deviceService.getDeviceCredentials(deviceId).then( | |
144 | + (deviceCredentials) => { | |
145 | + vm.configurations.accessToken = deviceCredentials.credentialsId; | |
146 | + getAttributes(); | |
147 | + } | |
148 | + ); | |
149 | + } | |
150 | + | |
151 | + vm.createDevice = (deviceObj) => { | |
152 | + deviceService.findByName(deviceObj.name, {ignoreErrors: true}) | |
153 | + .then( | |
154 | + function () { | |
155 | + toast.showError(gatewayNameExists, angular.element('.gateway-form'),'top left'); | |
156 | + }, | |
157 | + function () { | |
158 | + if(vm.settings.gatewayType && vm.settings.gatewayType.length){ | |
159 | + deviceObj.type = vm.settings.gatewayType; | |
160 | + } | |
161 | + deviceService.saveDevice(deviceObj).then( | |
162 | + (device) => { | |
163 | + getDeviceCredentials(device.id.id).then(() =>{ | |
164 | + getGatewaysList(); | |
165 | + }); | |
166 | + } | |
167 | + ); | |
168 | + }); | |
169 | + }; | |
170 | + | |
171 | + vm.saveAttributeConfig = () => { | |
172 | + $q.all([ | |
173 | + saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value), | |
174 | + saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value), | |
175 | + saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value) | |
176 | + ]).then(() =>{ | |
177 | + toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'),'top left'); | |
178 | + }) | |
179 | + }; | |
180 | + | |
181 | + function getAttributes() { | |
182 | + let promises = []; | |
183 | + promises.push(getAttribute(currentConfigurationAttribute, types.attributesScope.client.value)); | |
184 | + promises.push(getAttribute(configurationDraftsAttribute, types.attributesScope.server.value)); | |
185 | + promises.push(getAttribute(remoteLoggingLevelAttribute, types.attributesScope.shared.value)); | |
186 | + $q.all(promises).then((response) => { | |
187 | + processCurrentConfiguration(response[0]); | |
188 | + processConfigurationDrafts(response[1]); | |
189 | + processLoggingLevel(response[2]); | |
190 | + }); | |
191 | + } | |
192 | + | |
193 | + function getAttribute(attributeName, attributeScope) { | |
194 | + return attributeService.getEntityAttributesValues(vm.configurations.gateway.id.entityType, vm.configurations.gateway.id.id, attributeScope, attributeName); | |
195 | + } | |
196 | + | |
197 | + function saveAttribute(attributeName, attributeValue, attributeScope) { | |
198 | + let attributes = [{ | |
199 | + key: attributeName, | |
200 | + value: attributeValue | |
201 | + }]; | |
202 | + return attributeService.saveEntityAttributes(vm.configurations.gateway.id.entityType, vm.configurations.gateway.id.id, attributeScope, attributes); | |
203 | + } | |
204 | + | |
205 | + vm.exportConfig = () => { | |
206 | + let filesZip = {}; | |
207 | + filesZip["tb_gateway.yaml"] = generateYAMLConfigurationFile(); | |
208 | + generateConfigConnectorFiles(filesZip); | |
209 | + generateLogConfigFile(filesZip); | |
210 | + importExport.exportJSZip(filesZip, archiveFileName); | |
211 | + saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); | |
212 | + }; | |
213 | + | |
214 | + function generateYAMLConfigurationFile() { | |
215 | + let config; | |
216 | + config = 'thingsboard:\n'; | |
217 | + config += ' host: ' + vm.configurations.host + '\n'; | |
218 | + config += ' remoteConfiguration: ' + vm.configurations.remoteConfiguration + '\n'; | |
219 | + config += ' port: ' + vm.configurations.port + '\n'; | |
220 | + config += ' security:\n'; | |
221 | + if (vm.configurations.securityType === 'accessToken') { | |
222 | + config += ' access-token: ' + vm.configurations.accessToken + '\n'; | |
223 | + } else if (vm.configurations.securityType === 'tls') { | |
224 | + config += ' ca_cert: ' + vm.configurations.caCertPath + '\n'; | |
225 | + config += ' privateKey: ' + vm.configurations.privateKeyPath + '\n'; | |
226 | + config += ' cert: ' + vm.configurations.certPath + '\n'; | |
227 | + } | |
228 | + config += 'storage:\n'; | |
229 | + if (vm.configurations.storageType === 'memoryStorage') { | |
230 | + config += ' type: memory\n'; | |
231 | + config += ' read_records_count: ' + vm.configurations.readRecordsCount + '\n'; | |
232 | + config += ' max_records_count: ' + vm.configurations.maxRecordsCount + '\n'; | |
233 | + } else if (vm.configurations.storageType === 'fileStorage') { | |
234 | + config += ' type: file\n'; | |
235 | + config += ' data_folder_path: ' + vm.configurations.dataFolderPath + '\n'; | |
236 | + config += ' max_file_count: ' + vm.configurations.maxFilesCount + '\n'; | |
237 | + config += ' max_read_records_count: ' + vm.configurations.readRecordsCount + '\n'; | |
238 | + config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; | |
239 | + } | |
240 | + config += 'connectors:\n'; | |
241 | + for(let i = 0; i < vm.configurations.connectors.length; i++){ | |
242 | + if (vm.configurations.connectors[i].enabled) { | |
243 | + config += ' -\n'; | |
244 | + config += ' name: ' + vm.configurations.connectors[i].name + '\n'; | |
245 | + config += ' type: ' + vm.configurations.connectors[i].configType + '\n'; | |
246 | + config += ' configuration: ' + generateFileName(vm.configurations.connectors[i].name) + '\n'; | |
247 | + } | |
248 | + } | |
249 | + return config; | |
250 | + } | |
251 | + | |
252 | + function generateConfigConnectorFiles(fileZipAdd) { | |
253 | + for(let i = 0; i < vm.configurations.connectors.length; i++){ | |
254 | + if (vm.configurations.connectors[i].enabled) { | |
255 | + fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config); | |
256 | + } | |
257 | + } | |
258 | + } | |
259 | + | |
260 | + function generateLogConfigFile(fileZipAdd) { | |
261 | + fileZipAdd["logs.conf"] = getLogsConfig(); | |
262 | + } | |
263 | + | |
264 | + function getLogsConfig() { | |
265 | + return templateLogsConfig | |
266 | + .replace(/{ERROR}/g, vm.configurations.remoteLoggingLevel) | |
267 | + .replace(/{.\/logs\/}/g, vm.configurations.remoteLoggingPathToLogs); | |
268 | + } | |
269 | + | |
270 | + function getGatewayConfigJSON() { | |
271 | + let gatewayConfig = {}; | |
272 | + gatewayConfig["thingsboard"] = gatewayMainConfigJSON(); | |
273 | + gatewayConnectorConfigJSON(gatewayConfig); | |
274 | + return gatewayConfig; | |
275 | + } | |
276 | + | |
277 | + function gatewayMainConfigJSON() { | |
278 | + let configuration = {}; | |
279 | + | |
280 | + let thingsBoard = {}; | |
281 | + thingsBoard.host = vm.configurations.host; | |
282 | + thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; | |
283 | + thingsBoard.port = vm.configurations.port; | |
284 | + let security = {}; | |
285 | + if (vm.configurations.securityType === 'accessToken') { | |
286 | + security.accessToken = (vm.configurations.accessToken) ? vm.configurations.accessToken : "" | |
287 | + } else { | |
288 | + security.caCert = vm.configurations.caCertPath; | |
289 | + security.privateKey = vm.configurations.privateKeyPath; | |
290 | + security.cert = vm.configurations.certPath; | |
291 | + } | |
292 | + thingsBoard.security = security; | |
293 | + configuration.thingsboard = thingsBoard; | |
294 | + | |
295 | + let storage = {}; | |
296 | + if (vm.configurations.storageType === 'memoryStorage') { | |
297 | + storage.type = "memory"; | |
298 | + storage.read_records_count = vm.configurations.readRecordsCount; | |
299 | + storage.max_records_count = vm.configurations.maxRecordsCount; | |
300 | + } else if (vm.configurations.storageType === 'fileStorage') { | |
301 | + storage.type = "file"; | |
302 | + storage.data_folder_path = vm.configurations.dataFolderPath; | |
303 | + storage.max_file_count = vm.configurations.maxFilesCount; | |
304 | + storage.max_read_records_count = vm.configurations.readRecordsCount; | |
305 | + storage.max_records_per_file = vm.configurations.maxRecordsCount; | |
306 | + } | |
307 | + configuration.storage = storage; | |
308 | + | |
309 | + let connectors = []; | |
310 | + for (let i = 0; i < vm.configurations.connectors.length; i++) { | |
311 | + if (vm.configurations.connectors[i].enabled) { | |
312 | + let connector = { | |
313 | + configuration: generateFileName(vm.configurations.connectors[i].name), | |
314 | + name: vm.configurations.connectors[i].name, | |
315 | + type: vm.configurations.connectors[i].configType | |
316 | + }; | |
317 | + connectors.push(connector); | |
318 | + } | |
319 | + } | |
320 | + configuration.connectors = connectors; | |
321 | + | |
322 | + configuration.logs = $window.btoa(getLogsConfig()); | |
323 | + | |
324 | + return configuration; | |
325 | + } | |
326 | + | |
327 | + function gatewayConnectorConfigJSON(gatewayConfiguration) { | |
328 | + for(let i = 0; i < vm.configurations.connectors.length; i++){ | |
329 | + if (vm.configurations.connectors[i].enabled) { | |
330 | + let typeConnector = vm.configurations.connectors[i].configType; | |
331 | + if(!angular.isArray(gatewayConfiguration[typeConnector])){ | |
332 | + gatewayConfiguration[typeConnector] = []; | |
333 | + } | |
334 | + | |
335 | + let connectorConfig = { | |
336 | + name: vm.configurations.connectors[i].name, | |
337 | + config: vm.configurations.connectors[i].config | |
338 | + }; | |
339 | + gatewayConfiguration[typeConnector].push(connectorConfig); | |
340 | + } | |
341 | + } | |
342 | + } | |
343 | + | |
344 | + function getDraftConnectorJSON() { | |
345 | + let draftConnector = {}; | |
346 | + for(let i = 0; i < vm.configurations.connectors.length; i++){ | |
347 | + if (!vm.configurations.connectors[i].enabled) { | |
348 | + let connector = { | |
349 | + connector: vm.configurations.connectors[i].configType, | |
350 | + config: vm.configurations.connectors[i].config | |
351 | + }; | |
352 | + draftConnector[vm.configurations.connectors[i].name] = connector; | |
353 | + } | |
354 | + } | |
355 | + return draftConnector; | |
356 | + } | |
357 | + | |
358 | + function getGatewaysList(firstInit) { | |
359 | + vm.gateways = []; | |
360 | + entityService.getEntitiesByNameFilter(types.entityType.device, "", -1).then((devices) => { | |
361 | + for (let i = 0; i < devices.length; i++) { | |
362 | + const device = devices[i]; | |
363 | + if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { | |
364 | + vm.gateways.push(device); | |
365 | + if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) { | |
366 | + vm.configurations.gateway = device; | |
367 | + vm.getAccessToken(device.id); | |
368 | + } | |
369 | + } | |
370 | + } | |
371 | + }); | |
372 | + } | |
373 | + | |
374 | + function processCurrentConfiguration(response) { | |
375 | + if (response.length > 0) { | |
376 | + vm.configurations.connectors = []; | |
377 | + let attribute = angular.fromJson($window.atob(response[0].value)); | |
378 | + for (var attributeKey in attribute) { | |
379 | + let keyValue = attribute[attributeKey]; | |
380 | + if (attributeKey === "thingsboard") { | |
381 | + if (keyValue !== null && Object.keys(keyValue).length > 0) { | |
382 | + setConfigGateway(keyValue); | |
383 | + } | |
384 | + } else { | |
385 | + for (let connectorType in keyValue) { | |
386 | + let name = "No name"; | |
387 | + if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) { | |
388 | + name = keyValue[connectorType].name ; | |
389 | + } | |
390 | + let connector = { | |
391 | + enabled: true, | |
392 | + configType: attributeKey, | |
393 | + config: keyValue[connectorType].config, | |
394 | + name: name | |
395 | + }; | |
396 | + vm.configurations.connectors.push(connector); | |
397 | + } | |
398 | + } | |
399 | + } | |
400 | + } | |
401 | + } | |
402 | + | |
403 | + function processConfigurationDrafts(response) { | |
404 | + if (response.length > 0) { | |
405 | + let attribute = angular.fromJson($window.atob(response[0].value)); | |
406 | + for (let key in attribute) { | |
407 | + let connector = { | |
408 | + enabled: false, | |
409 | + configType: attribute[key].connector, | |
410 | + config: attribute[key].config, | |
411 | + name: key | |
412 | + }; | |
413 | + vm.configurations.connectors.push(connector); | |
414 | + } | |
415 | + } | |
416 | + } | |
417 | + | |
418 | + function processLoggingLevel(response) { | |
419 | + if (response.length > 0) { | |
420 | + if (vm.types.gatewayLogLevel[response[0].value.toLowerCase()]) { | |
421 | + vm.configurations.remoteLoggingLevel = response[0].value.toUpperCase(); | |
422 | + } | |
423 | + } else { | |
424 | + vm.configurations.remoteLoggingLevel = vm.types.gatewayLogLevel.debug; | |
425 | + } | |
426 | + } | |
427 | + | |
428 | + function setConfigGateway(keyValue) { | |
429 | + if (Object.prototype.hasOwnProperty.call(keyValue, 'thingsboard')) { | |
430 | + vm.configurations.host = keyValue.thingsboard.host; | |
431 | + vm.configurations.port = keyValue.thingsboard.port; | |
432 | + vm.configurations.remoteConfiguration = keyValue.thingsboard.remoteConfiguration; | |
433 | + if (Object.prototype.hasOwnProperty.call(keyValue.thingsboard.security, 'accessToken')) { | |
434 | + vm.configurations.securityType = 'accessToken'; | |
435 | + vm.configurations.accessToken = keyValue.thingsboard.security.accessToken; | |
436 | + } else { | |
437 | + vm.configurations.securityType = 'tls'; | |
438 | + vm.configurations.caCertPath = keyValue.thingsboard.security.caCert; | |
439 | + vm.configurations.privateKeyPath = keyValue.thingsboard.security.private_key; | |
440 | + vm.configurations.certPath = keyValue.thingsboard.security.cert; | |
441 | + } | |
442 | + } | |
443 | + | |
444 | + if (Object.prototype.hasOwnProperty.call(keyValue, 'storage') && Object.prototype.hasOwnProperty.call(keyValue.storage, 'type')) { | |
445 | + if (keyValue.storage.type === 'memory') { | |
446 | + vm.configurations.storageType = 'memoryStorage'; | |
447 | + vm.configurations.readRecordsCount = keyValue.storage.read_records_count; | |
448 | + vm.configurations.maxRecordsCount = keyValue.storage.max_records_count; | |
449 | + } else if (keyValue.storage.type === 'file') { | |
450 | + vm.configurations.storageType = 'fileStorage'; | |
451 | + vm.configurations.dataFolderPath = keyValue.storage.data_folder_path; | |
452 | + vm.configurations.maxFilesCount = keyValue.storage.max_file_count; | |
453 | + vm.configurations.readRecordsCount = keyValue.storage.read_records_count; | |
454 | + vm.configurations.maxRecordsCount = keyValue.storage.max_records_count; | |
455 | + } | |
456 | + } | |
457 | + } | |
458 | + | |
459 | + function generateFileName(fileName) { | |
460 | + return fileName.replace("_", "") | |
461 | + .replace("-", "") | |
462 | + .replace(/^\s+|\s+/g, '') | |
463 | + .toLowerCase() + '.json'; | |
464 | + } | |
465 | +} | |
466 | + | |
467 | + | ... | ... |
ui/src/app/components/gateway/gateway-form.scss
renamed from
ui/src/app/components/gateWay/gateway-form.scss
... | ... | @@ -14,7 +14,9 @@ |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 | .gateway-form{ |
17 | + height: 100%; | |
17 | 18 | padding: 5px 5px 0; |
19 | + background-color: transparent; | |
18 | 20 | |
19 | 21 | .gateway-form-row{ |
20 | 22 | md-input-container{ |
... | ... | @@ -30,11 +32,11 @@ |
30 | 32 | } |
31 | 33 | } |
32 | 34 | |
35 | + .security-type { | |
36 | + margin-top: 18px; | |
37 | + } | |
38 | + | |
33 | 39 | .form-action-buttons{ |
34 | 40 | padding-top: 8px; |
35 | 41 | } |
36 | 42 | } |
37 | - | |
38 | -.security-type { | |
39 | - margin-top: 38px; | |
40 | -} | ... | ... |
ui/src/app/components/gateway/gateway-form.tpl.html
renamed from
ui/src/app/components/gateWay/gateway-form.tpl.html
... | ... | @@ -15,205 +15,213 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<form name="gatewayConfiguration" class="gateway-form"> | |
19 | - <md-expansion-panel-group> | |
20 | - <md-expansion-panel md-component-id="thingsboardPanelId"> | |
21 | - <md-expansion-panel-collapsed> | |
22 | - <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> | |
23 | - <span flex></span> | |
24 | - <md-expansion-panel-icon></md-expansion-panel-icon> | |
25 | - </md-expansion-panel-collapsed> | |
26 | - <md-expansion-panel-expanded> | |
27 | - <md-expansion-panel-header ng-click="$mdExpansionPanel('thingsboardPanelId').collapse()"> | |
18 | +<md-content md-scroll-y layout="column" class="gateway-form"> | |
19 | + <form name="gatewayConfiguration"> | |
20 | + <md-expansion-panel-group> | |
21 | + <md-expansion-panel md-component-id="thingsboardPanelId"> | |
22 | + <md-expansion-panel-collapsed> | |
28 | 23 | <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> |
29 | 24 | <span flex></span> |
30 | 25 | <md-expansion-panel-icon></md-expansion-panel-icon> |
31 | - </md-expansion-panel-header> | |
32 | - <md-expansion-panel-content> | |
33 | - <tb-gateway-config-select tb-required="true" | |
34 | - ng-model="vm.configurations.singleSelect" | |
35 | - the-form="gatewayConfiguration" | |
36 | - gateway-list="vm.gateways" | |
37 | - get_access_token="vm.getAccessToken" | |
38 | - create-device="vm.createDevice"> | |
39 | - </tb-gateway-config-select> | |
40 | - <md-input-container class="md-block"> | |
41 | - <label>{{'gateway.security-type' | translate }}</label> | |
42 | - <md-select name="securityType" ng-model="vm.configurations.securityType"> | |
43 | - <md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value"> | |
44 | - {{securityType.name}} | |
45 | - </md-option> | |
46 | - </md-select> | |
47 | - </md-input-container> | |
48 | - <div layout="row" class="gateway-form-row" | |
49 | - ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
50 | - <md-input-container class="md-block" flex> | |
51 | - <label>{{ 'gateway.thingsboard-host' | translate }}</label> | |
52 | - <input type="text" name="host" ng-model="vm.configurations.host" required> | |
53 | - <div ng-messages="gatewayConfiguration.host.$error"> | |
54 | - <div ng-message="required" translate>extension.field-required</div> | |
55 | - </div> | |
56 | - </md-input-container> | |
57 | - <md-input-container class="md-block" flex> | |
58 | - <label>{{ 'gateway.thingsboard-port' | translate }}</label> | |
59 | - <input type="number" min="1" max="65535" step="1" name="port" | |
60 | - ng-model="vm.configurations.port" required> | |
61 | - <div ng-messages="gatewayConfiguration.port.$error"> | |
62 | - <div ng-message="required" translate>extension.field-required</div> | |
63 | - <div ng-message="max" translate>max</div> | |
64 | - <div ng-message="min" translate>min</div> | |
65 | - </div> | |
66 | - </md-input-container> | |
67 | - </div> | |
68 | - <div ng-if="vm.configurations.securityType=='tls'"> | |
69 | - <md-input-container class="md-block security-type"> | |
70 | - <label>{{'gateway.tls-path-ca-certificate' | translate }}</label> | |
71 | - <input type="text" ng-model="vm.configurations.caCertPath" name="caCertPath"/> | |
72 | - </md-input-container> | |
26 | + </md-expansion-panel-collapsed> | |
27 | + <md-expansion-panel-expanded> | |
28 | + <md-expansion-panel-header ng-click="vm.collapsePanel('thingsboardPanelId')"> | |
29 | + <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> | |
30 | + <span flex></span> | |
31 | + <md-expansion-panel-icon></md-expansion-panel-icon> | |
32 | + </md-expansion-panel-header> | |
33 | + <md-expansion-panel-content> | |
34 | + <tb-gateway-config-select tb-required="true" | |
35 | + ng-model="vm.configurations.gateway" | |
36 | + the-form="gatewayConfiguration" | |
37 | + gateway-list="vm.gateways" | |
38 | + get_access_token="vm.getAccessToken" | |
39 | + create-device="vm.createDevice"> | |
40 | + </tb-gateway-config-select> | |
73 | 41 | <md-input-container class="md-block"> |
74 | - <label>{{'gateway.tls-path-private-key' | translate }}</label> | |
75 | - <input type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath"/> | |
76 | - </md-input-container> | |
77 | - <md-input-container class="md-block"> | |
78 | - <label>{{'gateway.tls-path-client-certificate' | translate }}</label> | |
79 | - <input type="text" ng-model="vm.configurations.certPath" name="certPath"/> | |
80 | - </md-input-container> | |
81 | - </div> | |
82 | - <md-checkbox ng-model="vm.configurations.remoteConfiguration" | |
83 | - name="remoteConfiguration" | |
84 | - ng-click="vm.setSaveTypeConfig({item: vm.configurations.remoteConfiguration})" | |
85 | - aria-label="{{ 'gateway.remote-tip' | translate }}"> | |
86 | - {{ 'gateway.remote' | translate }} | |
87 | - <md-tooltip md-direction="right">{{'gateway.remote-tip' | translate }}</md-tooltip> | |
88 | - </md-checkbox> | |
89 | - <div layout="row" class="gateway-form-row" | |
90 | - ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
91 | - <md-input-container class="md-block md-select-container" flex> | |
92 | - <label>{{'gateway.remote-logging-level' | translate }}</label> | |
93 | - <md-select name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel"> | |
94 | - <md-option ng-repeat="loggingLevel in vm.types.gatewayLogLevel" | |
95 | - ng-value="loggingLevel" ng-selected="$index === 5"> | |
96 | - {{loggingLevel}} | |
42 | + <label>{{'gateway.security-type' | translate }}</label> | |
43 | + <md-select name="securityType" ng-model="vm.configurations.securityType" required> | |
44 | + <md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value"> | |
45 | + {{securityType.name | translate}} | |
97 | 46 | </md-option> |
98 | 47 | </md-select> |
99 | 48 | </md-input-container> |
100 | - <md-input-container class="md-block" flex> | |
101 | - <label>{{'gateway.remote-logging-path-logs' | translate }}</label> | |
102 | - <input type="text" ng-model="vm.configurations.remoteLoggingPathToLogs" | |
103 | - name="remoteLoggingPathToLogs" required> | |
104 | - <div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error"> | |
105 | - <div ng-message="required" translate>extension.field-required</div> | |
106 | - </div> | |
107 | - </md-input-container> | |
108 | - </div> | |
109 | - </md-expansion-panel-content> | |
110 | - </md-expansion-panel-expanded> | |
111 | - </md-expansion-panel> | |
112 | - <md-expansion-panel md-component-id="storagePanelId"> | |
113 | - <md-expansion-panel-collapsed> | |
114 | - <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> | |
115 | - <span flex></span> | |
116 | - <md-expansion-panel-icon></md-expansion-panel-icon> | |
117 | - </md-expansion-panel-collapsed> | |
118 | - <md-expansion-panel-expanded> | |
119 | - <md-expansion-panel-header ng-click="$mdExpansionPanel('storagePanelId').collapse()"> | |
49 | + <div layout="row" class="gateway-form-row" | |
50 | + ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
51 | + <md-input-container class="md-block" flex> | |
52 | + <label>{{ 'gateway.thingsboard-host' | translate }}</label> | |
53 | + <input type="text" name="host" ng-model="vm.configurations.host" required> | |
54 | + <div ng-messages="gatewayConfiguration.host.$error"> | |
55 | + <div ng-message="required" translate>gateway.thingsboard-host-required</div> | |
56 | + </div> | |
57 | + </md-input-container> | |
58 | + <md-input-container class="md-block" flex> | |
59 | + <label>{{ 'gateway.thingsboard-port' | translate }}</label> | |
60 | + <input type="number" min="1" max="65535" ng-pattern="/^-?[0-9]+$/" name="port" | |
61 | + ng-model="vm.configurations.port" required> | |
62 | + <div ng-messages="gatewayConfiguration.port.$error"> | |
63 | + <div ng-message="required" translate>gateway.thingsboard-port-required</div> | |
64 | + <div ng-message="max" translate>gateway.thingsboard-port-max</div> | |
65 | + <div ng-message="min" translate>gateway.thingsboard-port-min</div> | |
66 | + <div ng-message="pattern" translate>gateway.thingsboard-port-pattern</div> | |
67 | + </div> | |
68 | + </md-input-container> | |
69 | + </div> | |
70 | + <div ng-if="vm.configurations.securityType=='tls'"> | |
71 | + <md-input-container class="md-block security-type"> | |
72 | + <label>{{'gateway.tls-path-ca-certificate' | translate }}</label> | |
73 | + <input type="text" ng-model="vm.configurations.caCertPath" name="caCertPath" /> | |
74 | + </md-input-container> | |
75 | + <md-input-container class="md-block"> | |
76 | + <label>{{'gateway.tls-path-private-key' | translate }}</label> | |
77 | + <input type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath" /> | |
78 | + </md-input-container> | |
79 | + <md-input-container class="md-block"> | |
80 | + <label>{{'gateway.tls-path-client-certificate' | translate }}</label> | |
81 | + <input type="text" ng-model="vm.configurations.certPath" name="certPath" /> | |
82 | + </md-input-container> | |
83 | + </div> | |
84 | + <md-checkbox ng-model="vm.configurations.remoteConfiguration" | |
85 | + name="remoteConfiguration" | |
86 | + aria-label="{{ 'gateway.remote-remote' | translate }}"> | |
87 | + {{ 'gateway.remote' | translate }} | |
88 | + </md-checkbox> | |
89 | + <div layout="row" class="gateway-form-row" | |
90 | + ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
91 | + <md-input-container class="md-block md-select-container" flex> | |
92 | + <label>{{'gateway.remote-logging-level' | translate }}</label> | |
93 | + <md-select name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel"> | |
94 | + <md-option ng-repeat="logLevel in vm.types.gatewayLogLevel" | |
95 | + ng-value="logLevel" ng-selected="$index === 5"> | |
96 | + {{logLevel}} | |
97 | + </md-option> | |
98 | + </md-select> | |
99 | + </md-input-container> | |
100 | + <md-input-container class="md-block" flex> | |
101 | + <label>{{'gateway.path-logs' | translate }}</label> | |
102 | + <input type="text" ng-model="vm.configurations.remoteLoggingPathToLogs" | |
103 | + name="remoteLoggingPathToLogs" required> | |
104 | + <div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error"> | |
105 | + <div ng-message="required" translate>gateway.path-logs-required</div> | |
106 | + </div> | |
107 | + </md-input-container> | |
108 | + </div> | |
109 | + </md-expansion-panel-content> | |
110 | + </md-expansion-panel-expanded> | |
111 | + </md-expansion-panel> | |
112 | + <md-expansion-panel md-component-id="storagePanelId"> | |
113 | + <md-expansion-panel-collapsed> | |
120 | 114 | <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> |
121 | 115 | <span flex></span> |
122 | 116 | <md-expansion-panel-icon></md-expansion-panel-icon> |
123 | - </md-expansion-panel-header> | |
124 | - <md-expansion-panel-content> | |
125 | - <md-input-container class="md-block" flex> | |
126 | - <label>{{'gateway.storage-type' | translate }}</label> | |
127 | - <md-select required ng-model="vm.configurations.storageType"> | |
128 | - <md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value"> | |
129 | - {{storageType.name}} | |
130 | - </md-option> | |
131 | - </md-select> | |
132 | - </md-input-container> | |
133 | - | |
134 | - <div layout="row" class="gateway-form-row" | |
135 | - ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
117 | + </md-expansion-panel-collapsed> | |
118 | + <md-expansion-panel-expanded> | |
119 | + <md-expansion-panel-header ng-click="vm.collapsePanel('storagePanelId')"> | |
120 | + <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> | |
121 | + <span flex></span> | |
122 | + <md-expansion-panel-icon></md-expansion-panel-icon> | |
123 | + </md-expansion-panel-header> | |
124 | + <md-expansion-panel-content> | |
136 | 125 | <md-input-container class="md-block" flex> |
137 | - <label>{{'gateway.storage-read-time' | translate }}</label> | |
138 | - <input type="number" min="1" name="readRecordsCount" | |
139 | - ng-model='vm.configurations.readRecordsCount' required/> | |
140 | - <div ng-messages="gatewayConfiguration.readRecordsCount.$error"> | |
141 | - <div ng-message="required" translate>extension.field-required</div> | |
142 | - </div> | |
126 | + <label>{{'gateway.storage-type' | translate }}</label> | |
127 | + <md-select required ng-model="vm.configurations.storageType"> | |
128 | + <md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value"> | |
129 | + {{storageType.name | translate}} | |
130 | + </md-option> | |
131 | + </md-select> | |
143 | 132 | </md-input-container> |
144 | 133 | |
145 | - <md-input-container class="md-block" flex> | |
146 | - <label>{{'gateway.storage-max-time' | translate }}</label> | |
147 | - <input type="number" min="1" name="maxRecordsCount" | |
148 | - ng-model='vm.configurations.maxRecordsCount' required/> | |
149 | - <div ng-messages="gatewayConfiguration.maxRecordsCount.$error"> | |
150 | - <div ng-message="required" translate>extension.field-required</div> | |
151 | - </div> | |
152 | - </md-input-container> | |
153 | - </div> | |
134 | + <div layout="row" class="gateway-form-row" | |
135 | + ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
136 | + <md-input-container class="md-block" flex> | |
137 | + <label>{{'gateway.storage-pack-size' | translate }}</label> | |
138 | + <input type="number" min="1" name="readRecordsCount" ng-pattern="/^-?[0-9]+$/" | |
139 | + ng-model='vm.configurations.readRecordsCount' required/> | |
140 | + <div ng-messages="gatewayConfiguration.readRecordsCount.$error"> | |
141 | + <div ng-message="required" translate>gateway.storage-pack-size-required</div> | |
142 | + <div ng-message="min" translate>gateway.storage-pack-size-min</div> | |
143 | + <div ng-message="pattern" translate>gateway.storage-pack-size-pattern</div> | |
144 | + </div> | |
145 | + </md-input-container> | |
154 | 146 | |
155 | - <div layout="row" class="gateway-form-row" | |
156 | - ng-if="vm.configurations.storageType == 'fileStorage'" | |
157 | - ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
158 | - <md-input-container class="md-block" flex> | |
159 | - <label>{{'gateway.storage-max-files' | translate }}</label> | |
160 | - <input type="number" min="1" name="maxFilesCount" ng-model='vm.configurations.maxFilesCount' | |
161 | - required/> | |
162 | - <div ng-messages="gatewayConfiguration.maxFilesCount.$error"> | |
163 | - <div ng-message="required" translate>extension.field-required</div> | |
164 | - </div> | |
165 | - </md-input-container> | |
147 | + <md-input-container class="md-block" flex> | |
148 | + <label translate>{{ vm.configurations.storageType !== 'fileStorage' ? 'gateway.storage-max-records' : 'gateway.storage-max-file-records' }}</label> | |
149 | + <input type="number" min="1" name="maxRecordsCount" ng-pattern="/^-?[0-9]+$/" | |
150 | + ng-model='vm.configurations.maxRecordsCount' required/> | |
151 | + <div ng-messages="gatewayConfiguration.maxRecordsCount.$error"> | |
152 | + <div ng-message="required" translate>gateway.storage-max-records-required</div> | |
153 | + <div ng-message="min" translate>gateway.storage-max-records-min</div> | |
154 | + <div ng-message="pattern" translate>gateway.storage-max-records-pattern</div> | |
155 | + </div> | |
156 | + </md-input-container> | |
157 | + </div> | |
166 | 158 | |
167 | - <md-input-container class="md-block" flex> | |
168 | - <label>{{'gateway.storage-data-path' | translate }}</label> | |
169 | - <input type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath' | |
170 | - required/> | |
171 | - <div ng-messages="gatewayConfiguration.dataFolderPath.$error"> | |
172 | - <div ng-message="required" translate>extension.field-required</div> | |
173 | - </div> | |
174 | - </md-input-container> | |
175 | - </div> | |
176 | - </md-expansion-panel-content> | |
177 | - </md-expansion-panel-expanded> | |
178 | - </md-expansion-panel> | |
179 | - <md-expansion-panel md-component-id="connectorsPanelId"> | |
180 | - <md-expansion-panel-collapsed> | |
181 | - <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> | |
182 | - <span flex></span> | |
183 | - <md-expansion-panel-icon></md-expansion-panel-icon> | |
184 | - </md-expansion-panel-collapsed> | |
185 | - <md-expansion-panel-expanded> | |
186 | - <md-expansion-panel-header ng-click="$mdExpansionPanel('connectorsPanelId').collapse()"> | |
159 | + <div layout="row" class="gateway-form-row" | |
160 | + ng-if="vm.configurations.storageType == 'fileStorage'" | |
161 | + ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | |
162 | + <md-input-container class="md-block" flex> | |
163 | + <label>{{'gateway.storage-max-files' | translate }}</label> | |
164 | + <input type="number" min="1" name="maxFilesCount" ng-pattern="/^-?[0-9]+$/" | |
165 | + ng-model='vm.configurations.maxFilesCount' required/> | |
166 | + <div ng-messages="gatewayConfiguration.maxFilesCount.$error"> | |
167 | + <div ng-message="required" translate>gateway.storage-max-files-required</div> | |
168 | + <div ng-message="min" translate>gateway.storage-max-files-min</div> | |
169 | + <div ng-message="pattern" translate>gateway.storage-max-files-pattern</div> | |
170 | + </div> | |
171 | + </md-input-container> | |
172 | + | |
173 | + <md-input-container class="md-block" flex> | |
174 | + <label>{{'gateway.storage-path' | translate }}</label> | |
175 | + <input type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath' | |
176 | + required/> | |
177 | + <div ng-messages="gatewayConfiguration.dataFolderPath.$error"> | |
178 | + <div ng-message="required" translate>gateway.storage-path-required</div> | |
179 | + </div> | |
180 | + </md-input-container> | |
181 | + </div> | |
182 | + </md-expansion-panel-content> | |
183 | + </md-expansion-panel-expanded> | |
184 | + </md-expansion-panel> | |
185 | + <md-expansion-panel md-component-id="connectorsPanelId"> | |
186 | + <md-expansion-panel-collapsed> | |
187 | 187 | <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> |
188 | 188 | <span flex></span> |
189 | 189 | <md-expansion-panel-icon></md-expansion-panel-icon> |
190 | - </md-expansion-panel-header> | |
191 | - <md-expansion-panel-content> | |
192 | - <tb-gateway-config | |
193 | - gateway-config="vm.configurations.connectors" | |
194 | - change-alignment="vm.changeAlignment"> | |
195 | - </tb-gateway-config> | |
196 | - </md-expansion-panel-content> | |
197 | - </md-expansion-panel-expanded> | |
198 | - </md-expansion-panel> | |
199 | - </md-expansion-panel-group> | |
200 | - <section layout="row" layout-align="end center" class="form-action-buttons"> | |
201 | - <md-button class="md-primary md-raised" | |
202 | - ng-click="vm.exportConfig()" | |
203 | - ng-if="!vm.configurations.remoteConfiguration" | |
204 | - ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" | |
205 | - aria-label="{{ 'gateway.download-tip' | translate }}"> | |
206 | - {{'action.download' | translate }} | |
207 | - <md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip> | |
208 | - </md-button> | |
190 | + </md-expansion-panel-collapsed> | |
191 | + <md-expansion-panel-expanded> | |
192 | + <md-expansion-panel-header ng-click="vm.collapsePanel('connectorsPanelId')"> | |
193 | + <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> | |
194 | + <span flex></span> | |
195 | + <md-expansion-panel-icon></md-expansion-panel-icon> | |
196 | + </md-expansion-panel-header> | |
197 | + <md-expansion-panel-content> | |
198 | + <tb-gateway-config | |
199 | + gateway-config="vm.configurations.connectors" | |
200 | + the-form="gatewayConfiguration" | |
201 | + change-alignment="vm.changeAlignment"> | |
202 | + </tb-gateway-config> | |
203 | + </md-expansion-panel-content> | |
204 | + </md-expansion-panel-expanded> | |
205 | + </md-expansion-panel> | |
206 | + </md-expansion-panel-group> | |
207 | + <section layout="row" layout-align="end center" class="form-action-buttons"> | |
208 | + <md-button class="md-primary md-raised" | |
209 | + ng-click="vm.exportConfig()" | |
210 | + ng-if="!vm.configurations.remoteConfiguration" | |
211 | + ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" | |
212 | + aria-label="{{ 'gateway.download-tip' | translate }}"> | |
213 | + {{'action.download' | translate }} | |
214 | + <md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip> | |
215 | + </md-button> | |
209 | 216 | |
210 | - <md-button class="md-primary md-raised" | |
211 | - ng-click="vm.saveAttributeConfig()" | |
212 | - ng-if="vm.configurations.remoteConfiguration" | |
213 | - ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" | |
214 | - aria-label="{{ 'gateway.save-tip' | translate }}"> | |
215 | - {{'action.save' | translate }} | |
216 | - <md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}</md-tooltip> | |
217 | - </md-button> | |
218 | - </section> | |
219 | -</form> | |
217 | + <md-button class="md-primary md-raised" | |
218 | + ng-click="vm.saveAttributeConfig()" | |
219 | + ng-if="vm.configurations.remoteConfiguration" | |
220 | + ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" | |
221 | + aria-label="{{ 'gateway.save-tip' | translate }}"> | |
222 | + {{'action.save' | translate }} | |
223 | + <md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}</md-tooltip> | |
224 | + </md-button> | |
225 | + </section> | |
226 | + </form> | |
227 | +</md-content> | ... | ... |
... | ... | @@ -29,7 +29,7 @@ import * as JSZip from 'jszip'; |
29 | 29 | export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, $rootScope, |
30 | 30 | dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) { |
31 | 31 | |
32 | - const JSZIP_TYPE = { | |
32 | + const ZIP_TYPE = { | |
33 | 33 | mimeType: 'application/zip', |
34 | 34 | extension: 'zip' |
35 | 35 | }; |
... | ... | @@ -989,29 +989,19 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
989 | 989 | dialogElement[0].style.width = dialogElement[0].offsetWidth + 2 + "px"; |
990 | 990 | } |
991 | 991 | |
992 | - /** | |
993 | - * | |
994 | - * @param data | |
995 | - * @param filename | |
996 | - * Warn data !!! Not object, if object, then object convert from object to format txt | |
997 | - * Example: data = {keyNameFile1: valueFile1, | |
998 | - * keyNameFile2: valueFile2...} | |
999 | - * fileName - name file of the arhiv | |
1000 | - */ | |
1001 | 992 | function exportJSZip(data, filename) { |
1002 | 993 | let jsZip = new JSZip(); |
1003 | 994 | for (let keyName in data) { |
1004 | 995 | let valueData = data[keyName]; |
1005 | 996 | jsZip.file(keyName, valueData); |
1006 | 997 | } |
1007 | - jsZip.generateAsync({type: "Blob"}).then(function (content) { | |
1008 | - downloadFile(content, filename, JSZIP_TYPE); | |
998 | + jsZip.generateAsync({type: "blob"}).then(function (content) { | |
999 | + downloadFile(content, filename, ZIP_TYPE); | |
1009 | 1000 | }); |
1010 | 1001 | } |
1011 | 1002 | |
1012 | 1003 | |
1013 | 1004 | function downloadFile(data, filename, fileType) { |
1014 | - console.log("downloadFile", data, filename, fileType); // eslint-disable-line | |
1015 | 1005 | if (!filename) { |
1016 | 1006 | filename = 'download'; |
1017 | 1007 | } | ... | ... |
... | ... | @@ -30,9 +30,9 @@ import thingsboardSideMenu from '../components/side-menu.directive'; |
30 | 30 | import thingsboardNavTree from '../components/nav-tree.directive'; |
31 | 31 | import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive'; |
32 | 32 | import thingsboardKvMap from '../components/kv-map.directive'; |
33 | -import thingsboardGatewayConfig from '../components/gateWay/gateway-config.directive'; | |
34 | -import thingsboardGatewayConfigSelect from '../components/gateWay/gateway-config-select.directive'; | |
35 | -import thingsboardGatewayForm from '../components/gateWay/gateway-form.directive'; | |
33 | +import thingsboardGatewayConfig from '../components/gateway/gateway-config.directive'; | |
34 | +import thingsboardGatewayConfigSelect from '../components/gateway/gateway-config-select.directive'; | |
35 | +import thingsboardGatewayForm from '../components/gateway/gateway-form.directive'; | |
36 | 36 | import thingsboardJsonObjectEdit from '../components/json-object-edit.directive'; |
37 | 37 | import thingsboardJsonContent from '../components/json-content.directive'; |
38 | 38 | ... | ... |
... | ... | @@ -1126,56 +1126,78 @@ |
1126 | 1126 | "function": "Function" |
1127 | 1127 | }, |
1128 | 1128 | "gateway": { |
1129 | - "key": "Key configuration", | |
1130 | - "value": "Value configuration", | |
1131 | - "remove-entry": "Remove configuration", | |
1132 | 1129 | "add-entry": "Add configuration", |
1133 | - "no-data": "No configurations", | |
1134 | - "gateway-required": "Gateway is required.", | |
1135 | - "gateway-name": "Gateway name", | |
1130 | + "connector-add": "Add new connector", | |
1131 | + "connector-enabled": "Enable connector", | |
1132 | + "connector-name": "Connector name", | |
1133 | + "connector-name-required": "Connector name is required.", | |
1134 | + "connector-type": "Connector type", | |
1135 | + "connector-type-required": "Connector type is required.", | |
1136 | + "connectors": "Connectors configuration", | |
1136 | 1137 | "create-new-gateway": "Create a new gateway", |
1137 | 1138 | "create-new-gateway-text": "Are you sure you want create a new gateway with name: '{{gatewayName}}'?", |
1139 | + "delete": "Delete configuration", | |
1140 | + "download-tip": "Download configuration file", | |
1141 | + "gateway": "Gateway", | |
1142 | + "gateway-exists": "Device with same name is already exists.", | |
1143 | + "gateway-name": "Gateway name", | |
1144 | + "gateway-name-required": "Gateway name is required.", | |
1145 | + "gateway-saved": "Gateway configuration successfully saved.", | |
1146 | + "json-parse": "Not valid JSON.", | |
1147 | + "json-required": "Field cannot be empty.", | |
1148 | + "no-connectors": "No connectors", | |
1149 | + "no-data": "No configurations", | |
1150 | + "no-gateway-found": "No gateway found.", | |
1138 | 1151 | "no-gateway-matching": " '{{item}}' not found.", |
1139 | - "thingsboard": "ThingsBoard", | |
1140 | - "connectors": "Connectors configuration", | |
1141 | - "thingsboard-host": "ThingsBoard Host", | |
1142 | - "thingsboard-port": "ThingsBoard Port", | |
1152 | + "path-logs": "Path to log files", | |
1153 | + "path-logs-required": "Path is required.", | |
1154 | + "remote": "Remote configuration", | |
1155 | + "remote-logging-level": "Logging level", | |
1156 | + "remove-entry": "Remove configuration", | |
1157 | + "save-tip": "Save configuration file", | |
1143 | 1158 | "security-type": "Security type", |
1144 | - "tls-path-ca-certificate": "Path to CA certificate on gateway:", | |
1145 | - "tls-path-private-key": "Path to private key on gateway:", | |
1146 | - "tls-path-client-certificate": "Path to client certificate on gateway:", | |
1159 | + "security-types": { | |
1160 | + "access-token": "Access Token", | |
1161 | + "tls": "TLS" | |
1162 | + }, | |
1147 | 1163 | "storage": "Storage", |
1164 | + "storage-max-file-records": "Maximum records in file", | |
1165 | + "storage-max-files": "Maximum number of files", | |
1166 | + "storage-max-files-min": "Minimum number is 1.", | |
1167 | + "storage-max-files-pattern": "Number is not valid.", | |
1168 | + "storage-max-files-required": "Number is required.", | |
1169 | + "storage-max-records": "Maximum records in storage", | |
1170 | + "storage-max-records-min": "Minimum number of records is 1.", | |
1171 | + "storage-max-records-pattern": "Number is not valid.", | |
1172 | + "storage-max-records-required": "Maximum records is required.", | |
1173 | + "storage-pack-size": "Maximum event pack size", | |
1174 | + "storage-pack-size-min": "Minimum number is 1.", | |
1175 | + "storage-pack-size-pattern": "Number is not valid.", | |
1176 | + "storage-pack-size-required": "Maximum event pack size is required.", | |
1177 | + "storage-path": "Storage path", | |
1178 | + "storage-path-required": "Storage path is required.", | |
1148 | 1179 | "storage-type": "Storage type", |
1149 | - "storage-read-time": "Read records per time:", | |
1150 | - "storage-max-time": "Maximum records per time:", | |
1151 | - "storage-max-files": "Maximum files:", | |
1152 | - "storage-data-path": "Data folder path:", | |
1153 | - "download-tip": "Download configuration file", | |
1154 | - "save-tip": "Save configuration file", | |
1155 | - "remote-tip": "Allow remote configuration", | |
1156 | - "remote": "Remote configuration", | |
1157 | - "remote-logging-level": "Logging level", | |
1158 | - "remote-logging-path-logs": "Path to logs", | |
1159 | - "connector-type": "Connector type", | |
1160 | - "update-config": "Add/update config JSON", | |
1161 | - "delete": "Delete configuration", | |
1162 | - "title-connectors-json": "Connector {{typeName}} configuration", | |
1163 | - "json-required": "Config json is required for gateway config.", | |
1164 | - "json-parse": "Unable to parse config json for gateway config.", | |
1180 | + "storage-types": { | |
1181 | + "file-storage": "File storage", | |
1182 | + "memory-storage": "Memory storage" | |
1183 | + }, | |
1184 | + "thingsboard": "ThingsBoard", | |
1185 | + "thingsboard-host": "ThingsBoard host", | |
1186 | + "thingsboard-host-required": "Host is required.", | |
1187 | + "thingsboard-port": "ThingsBoard port", | |
1188 | + "thingsboard-port-max": "Maximum port number is 65535.", | |
1189 | + "thingsboard-port-min": "Minimum port number is 1.", | |
1190 | + "thingsboard-port-pattern": "Port is not valid.", | |
1191 | + "thingsboard-port-required": "Port is required.", | |
1165 | 1192 | "tidy": "Tidy", |
1166 | 1193 | "tidy-tip": "Tidy config JSON", |
1167 | - "transformer-json-config": "JSON for the config*", | |
1194 | + "title-connectors-json": "Connector {{typeName}} configuration", | |
1195 | + "tls-path-ca-certificate": "Path to CA certificate on gateway", | |
1196 | + "tls-path-client-certificate": "Path to client certificate on gateway", | |
1197 | + "tls-path-private-key": "Path to private key on gateway", | |
1168 | 1198 | "toggle-fullscreen": "Toggle fullscreen", |
1169 | - "add-connectors": "Add new connectors", | |
1170 | - "no-connectors": "No connectors", | |
1171 | - "enabled": "Enabled", | |
1172 | - "name": "Name", | |
1173 | - "no-gateway-found": "No gateway found.", | |
1174 | - "gateway": "Gateway", | |
1175 | - "keyval-save-err": "Save config error", | |
1176 | - "keyval-name-err": "Please add <b>Name</b>", | |
1177 | - "keyval-type-err": "Please add <b>Connector type</b>", | |
1178 | - "keyval-config-err": "Please add <b>configuration JSON</b>" | |
1199 | + "transformer-json-config": "Configuration JSON*", | |
1200 | + "update-config": "Add/update configuration JSON" | |
1179 | 1201 | }, |
1180 | 1202 | "grid": { |
1181 | 1203 | "delete-item-title": "Are you sure you want to delete this item?", | ... | ... |