Commit b3abfd38666a0b2cc6900a7791d34ee692514786

Authored by Vladyslav
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
@@ -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 ]
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 -  
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:&apos;...&apos;}}" }'>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:&apos;...&apos;}}" }'>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?",