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,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 | "descriptor": { | 27 | "descriptor": { |
28 | "type": "static", | 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 | "templateHtml": "<tb-gateway-form\n form-id=\"formId\"\n ctx=\"ctx\">\n</tb-gateway-form>\n", | 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 | "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", | 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 | "dataKeySettingsSchema": "{}\n", | 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,15 +55,15 @@ | ||
55 | required> | 55 | required> |
56 | </div> | 56 | </div> |
57 | </div> | 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 | <div ng-message="required" flex class="tb-error-message" translate>gateway.json-required</div> | 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 | </div> | 61 | </div> |
62 | </div> | 62 | </div> |
63 | </div> | 63 | </div> |
64 | </md-dialog-content> | 64 | </md-dialog-content> |
65 | <md-dialog-actions layout="row" layout-align="end center" class="action-buttons"> | 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 | class="md-raised md-primary"> | 67 | class="md-raised md-primary"> |
68 | {{'action.save'|translate}} | 68 | {{'action.save'|translate}} |
69 | </md-button> | 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,7 +17,7 @@ import './gateway-config-select.scss'; | ||
17 | 17 | ||
18 | /* eslint-disable import/no-unresolved, import/default */ | 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 | /* eslint-enable import/no-unresolved, import/default */ | 22 | /* eslint-enable import/no-unresolved, import/default */ |
23 | 23 | ||
@@ -32,23 +32,26 @@ export default angular.module('thingsboard.directives.gatewayConfigSelect', []) | @@ -32,23 +32,26 @@ export default angular.module('thingsboard.directives.gatewayConfigSelect', []) | ||
32 | function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, $mdDialog) { | 32 | function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, $mdDialog) { |
33 | 33 | ||
34 | var linker = function (scope, element, attrs, ngModelCtrl) { | 34 | var linker = function (scope, element, attrs, ngModelCtrl) { |
35 | - var template = $templateCache.get(gatewayAliasSelectTemplate); | 35 | + const template = $templateCache.get(gatewaySelectTemplate); |
36 | element.html(template); | 36 | element.html(template); |
37 | 37 | ||
38 | scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; | 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 | scope.updateValidity = function () { | 42 | scope.updateValidity = function () { |
44 | var value = ngModelCtrl.$viewValue; | 43 | var value = ngModelCtrl.$viewValue; |
45 | var valid = angular.isDefined(value) && value != null || !scope.tbRequired; | 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 | scope.gatewayNameSearch = function (gatewaySearchText) { | 56 | scope.gatewayNameSearch = function (gatewaySearchText) { |
54 | return gatewaySearchText ? scope.gatewayList.filter( | 57 | return gatewaySearchText ? scope.gatewayList.filter( |
@@ -58,22 +61,20 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | @@ -58,22 +61,20 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | ||
58 | scope.createFilterForGatewayName = function (query) { | 61 | scope.createFilterForGatewayName = function (query) { |
59 | var lowercaseQuery = query.toLowerCase(); | 62 | var lowercaseQuery = query.toLowerCase(); |
60 | return function filterFn(device) { | 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 | scope.updateView = function () { | 68 | scope.updateView = function () { |
66 | - ngModelCtrl.$setViewValue(scope.singleSelect); | 69 | + ngModelCtrl.$setViewValue(scope.gateway); |
67 | scope.updateValidity(); | 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 | ngModelCtrl.$render = function () { | 74 | ngModelCtrl.$render = function () { |
75 | if (ngModelCtrl.$viewValue) { | 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,9 +86,9 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | ||
85 | if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) { | 86 | if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) { |
86 | $event.preventDefault(); | 87 | $event.preventDefault(); |
87 | let indexRes = scope.gatewayList.findIndex((element) => element.key === scope.gatewaySearchText); | 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,7 +97,7 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | ||
96 | $event.stopPropagation(); | 97 | $event.stopPropagation(); |
97 | } | 98 | } |
98 | var title = $translate.instant('gateway.create-new-gateway'); | 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 | var confirm = $mdDialog.confirm() | 101 | var confirm = $mdDialog.confirm() |
101 | .targetEvent($event) | 102 | .targetEvent($event) |
102 | .title(title) | 103 | .title(title) |
@@ -106,9 +107,13 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | @@ -106,9 +107,13 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | ||
106 | .ok($translate.instant('action.yes')); | 107 | .ok($translate.instant('action.yes')); |
107 | $mdDialog.show(confirm).then( | 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 | scope.createDevice(deviceObj); | 117 | scope.createDevice(deviceObj); |
113 | }, | 118 | }, |
114 | () => { | 119 | () => { |
@@ -125,7 +130,6 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | @@ -125,7 +130,6 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, | ||
125 | link: linker, | 130 | link: linker, |
126 | scope: { | 131 | scope: { |
127 | tbRequired: '=?', | 132 | tbRequired: '=?', |
128 | - allowedEntityTypes: '=?', | ||
129 | gatewayList: '=?', | 133 | gatewayList: '=?', |
130 | getAccessToken: '=', | 134 | getAccessToken: '=', |
131 | createDevice: '=', | 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,14 +16,14 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | <section layout='column'> | 18 | <section layout='column'> |
19 | - <md-autocomplete md-input-name="singleSelect" flex | 19 | + <md-autocomplete md-input-name="gateway" flex |
20 | ng-required="tbRequired" | 20 | ng-required="tbRequired" |
21 | md-no-cache="true" | 21 | md-no-cache="true" |
22 | - ng-model="singleSelect" | ||
23 | - md-selected-item="singleSelect" | 22 | + ng-model="gateway" |
23 | + md-selected-item="gateway" | ||
24 | md-search-text="gatewaySearchText" | 24 | md-search-text="gatewaySearchText" |
25 | md-items="item in gatewayNameSearch(gatewaySearchText)" | 25 | md-items="item in gatewayNameSearch(gatewaySearchText)" |
26 | - md-item-text="item" | 26 | + md-item-text="item.name" |
27 | tb-keydown="gatewayNameEnter($event)" | 27 | tb-keydown="gatewayNameEnter($event)" |
28 | tb-keypress="gatewayNameEnter($event)" | 28 | tb-keypress="gatewayNameEnter($event)" |
29 | md-min-length="0" | 29 | md-min-length="0" |
@@ -33,7 +33,7 @@ | @@ -33,7 +33,7 @@ | ||
33 | md-input-class="tb-test" | 33 | md-input-class="tb-test" |
34 | md-menu-container-class="tb-gateway-autocomplete-container"> | 34 | md-menu-container-class="tb-gateway-autocomplete-container"> |
35 | <md-item-template> | 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 | </md-item-template> | 37 | </md-item-template> |
38 | <md-not-found> | 38 | <md-not-found> |
39 | <div class="tb-not-found"> | 39 | <div class="tb-not-found"> |
@@ -41,14 +41,13 @@ | @@ -41,14 +41,13 @@ | ||
41 | <span translate>gateway.no-gateway-found</span> | 41 | <span translate>gateway.no-gateway-found</span> |
42 | </div> | 42 | </div> |
43 | <div ng-if="!textIsEmpty(gatewaySearchText)"> | 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 | </div> | 46 | </div> |
48 | </div> | 47 | </div> |
49 | </md-not-found> | 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 | </div> | 51 | </div> |
53 | </md-autocomplete> | 52 | </md-autocomplete> |
54 | </section> | 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,20 +56,20 @@ | ||
56 | .tb-json-toolbar{ | 56 | .tb-json-toolbar{ |
57 | height: 40px; | 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,61 +15,49 @@ | ||
15 | limitations under the License. | 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 | </div> | 24 | </div> |
33 | <div layout="row" flex class="gateway-config-row" | 25 | <div layout="row" flex class="gateway-config-row" |
34 | ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | 26 | ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> |
35 | <md-input-container class="md-block" flex> | 27 | <md-input-container class="md-block" flex> |
36 | <label>{{'gateway.connector-type' | translate }}</label> | 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 | <md-option ng-repeat="configType in vm.types.gatewayConfigType" ng-value="configType.value"> | 33 | <md-option ng-repeat="configType in vm.types.gatewayConfigType" ng-value="configType.value"> |
39 | {{configType.value}} | 34 | {{configType.value}} |
40 | </md-option> | 35 | </md-option> |
41 | </md-select> | 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 | </md-input-container> | 40 | </md-input-container> |
46 | <md-input-container class="md-block" flex> | 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 | ng-model-options="{ updateOn: 'blur' }" | 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 | </div> | 47 | </div> |
53 | - <md-tooltip md-direction="top"> | ||
54 | - {{ 'gateway.name' | translate }} | ||
55 | - </md-tooltip> | ||
56 | </md-input-container> | 48 | </md-input-container> |
57 | </div> | 49 | </div> |
58 | <div layout="row" layout-align="end center" class="action-buttons" | 50 | <div layout="row" layout-align="end center" class="action-buttons" |
59 | ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> | 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 | aria-label="{{ 'gateway.update-config' | translate }}" | 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 | <md-tooltip md-direction="top"> | 56 | <md-tooltip md-direction="top"> |
67 | {{ 'gateway.update-config' | translate }} | 57 | {{ 'gateway.update-config' | translate }} |
68 | </md-tooltip> | 58 | </md-tooltip> |
69 | </md-button> | 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 | aria-label="{{ 'gateway.delete' | translate }}"> | 61 | aria-label="{{ 'gateway.delete' | translate }}"> |
74 | <md-icon class="material-icons">close</md-icon> | 62 | <md-icon class="material-icons">close</md-icon> |
75 | <md-tooltip md-direction="top"> | 63 | <md-tooltip md-direction="top"> |
@@ -77,18 +65,17 @@ | @@ -77,18 +65,17 @@ | ||
77 | </md-tooltip> | 65 | </md-tooltip> |
78 | </md-button> | 66 | </md-button> |
79 | </div> | 67 | </div> |
80 | - </div> | ||
81 | - <span ng-show="!vm.kvList.length" | 68 | + </section> |
69 | + <span ng-show="!vm.gatewayConfig.length" | ||
82 | layout-align="center center" ng-class="{'disabled': vm.disabled}" | 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 | <div> | 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 | <md-tooltip md-direction="top"> | 75 | <md-tooltip md-direction="top"> |
89 | - {{ 'gateway.add-connectors' | translate }} | 76 | + {{ 'gateway.connector-add' | translate }} |
90 | </md-tooltip> | 77 | </md-tooltip> |
91 | <span translate>action.add</span> | 78 | <span translate>action.add</span> |
92 | </md-button> | 79 | </md-button> |
93 | </div> | 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,7 +14,9 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | .gateway-form{ | 16 | .gateway-form{ |
17 | + height: 100%; | ||
17 | padding: 5px 5px 0; | 18 | padding: 5px 5px 0; |
19 | + background-color: transparent; | ||
18 | 20 | ||
19 | .gateway-form-row{ | 21 | .gateway-form-row{ |
20 | md-input-container{ | 22 | md-input-container{ |
@@ -30,11 +32,11 @@ | @@ -30,11 +32,11 @@ | ||
30 | } | 32 | } |
31 | } | 33 | } |
32 | 34 | ||
35 | + .security-type { | ||
36 | + margin-top: 18px; | ||
37 | + } | ||
38 | + | ||
33 | .form-action-buttons{ | 39 | .form-action-buttons{ |
34 | padding-top: 8px; | 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,205 +15,213 @@ | ||
15 | limitations under the License. | 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 | <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> | 23 | <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> |
29 | <span flex></span> | 24 | <span flex></span> |
30 | <md-expansion-panel-icon></md-expansion-panel-icon> | 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 | <md-input-container class="md-block"> | 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 | </md-option> | 46 | </md-option> |
98 | </md-select> | 47 | </md-select> |
99 | </md-input-container> | 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 | <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> | 114 | <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> |
121 | <span flex></span> | 115 | <span flex></span> |
122 | <md-expansion-panel-icon></md-expansion-panel-icon> | 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 | <md-input-container class="md-block" flex> | 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 | </md-input-container> | 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 | <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> | 187 | <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> |
188 | <span flex></span> | 188 | <span flex></span> |
189 | <md-expansion-panel-icon></md-expansion-panel-icon> | 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,7 +29,7 @@ import * as JSZip from 'jszip'; | ||
29 | export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, $rootScope, | 29 | export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, $rootScope, |
30 | dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) { | 30 | dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) { |
31 | 31 | ||
32 | - const JSZIP_TYPE = { | 32 | + const ZIP_TYPE = { |
33 | mimeType: 'application/zip', | 33 | mimeType: 'application/zip', |
34 | extension: 'zip' | 34 | extension: 'zip' |
35 | }; | 35 | }; |
@@ -989,29 +989,19 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -989,29 +989,19 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
989 | dialogElement[0].style.width = dialogElement[0].offsetWidth + 2 + "px"; | 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 | function exportJSZip(data, filename) { | 992 | function exportJSZip(data, filename) { |
1002 | let jsZip = new JSZip(); | 993 | let jsZip = new JSZip(); |
1003 | for (let keyName in data) { | 994 | for (let keyName in data) { |
1004 | let valueData = data[keyName]; | 995 | let valueData = data[keyName]; |
1005 | jsZip.file(keyName, valueData); | 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 | function downloadFile(data, filename, fileType) { | 1004 | function downloadFile(data, filename, fileType) { |
1014 | - console.log("downloadFile", data, filename, fileType); // eslint-disable-line | ||
1015 | if (!filename) { | 1005 | if (!filename) { |
1016 | filename = 'download'; | 1006 | filename = 'download'; |
1017 | } | 1007 | } |
@@ -30,9 +30,9 @@ import thingsboardSideMenu from '../components/side-menu.directive'; | @@ -30,9 +30,9 @@ import thingsboardSideMenu from '../components/side-menu.directive'; | ||
30 | import thingsboardNavTree from '../components/nav-tree.directive'; | 30 | import thingsboardNavTree from '../components/nav-tree.directive'; |
31 | import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive'; | 31 | import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive'; |
32 | import thingsboardKvMap from '../components/kv-map.directive'; | 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 | import thingsboardJsonObjectEdit from '../components/json-object-edit.directive'; | 36 | import thingsboardJsonObjectEdit from '../components/json-object-edit.directive'; |
37 | import thingsboardJsonContent from '../components/json-content.directive'; | 37 | import thingsboardJsonContent from '../components/json-content.directive'; |
38 | 38 |
@@ -1126,56 +1126,78 @@ | @@ -1126,56 +1126,78 @@ | ||
1126 | "function": "Function" | 1126 | "function": "Function" |
1127 | }, | 1127 | }, |
1128 | "gateway": { | 1128 | "gateway": { |
1129 | - "key": "Key configuration", | ||
1130 | - "value": "Value configuration", | ||
1131 | - "remove-entry": "Remove configuration", | ||
1132 | "add-entry": "Add configuration", | 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 | "create-new-gateway": "Create a new gateway", | 1137 | "create-new-gateway": "Create a new gateway", |
1137 | "create-new-gateway-text": "Are you sure you want create a new gateway with name: '{{gatewayName}}'?", | 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 | "no-gateway-matching": " '{{item}}' not found.", | 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 | "security-type": "Security type", | 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 | "storage": "Storage", | 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 | "storage-type": "Storage type", | 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 | "tidy": "Tidy", | 1192 | "tidy": "Tidy", |
1166 | "tidy-tip": "Tidy config JSON", | 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 | "toggle-fullscreen": "Toggle fullscreen", | 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 | "grid": { | 1202 | "grid": { |
1181 | "delete-item-title": "Are you sure you want to delete this item?", | 1203 | "delete-item-title": "Are you sure you want to delete this item?", |