diff --git a/application/src/main/data/json/system/widget_bundles/gateway_widgets.json b/application/src/main/data/json/system/widget_bundles/gateway_widgets.json index ce78185c29..669f706d15 100644 --- a/application/src/main/data/json/system/widget_bundles/gateway_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/gateway_widgets.json @@ -22,23 +22,19 @@ } }, { - "alias": "new_config_form", - "name": "Config form", + "alias": "gateway_configuration", + "name": "Gateway Configuration", "descriptor": { "type": "static", - "sizeX": 7.5, - "sizeY": 10.5, - "resources": [ - { - "url": "" - } - ], + "sizeX": 8, + "sizeY": 6.5, + "resources": [], "templateHtml": "\n\n", - "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/*}*/", + "templateCss": "", "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", - "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", + "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}", "dataKeySettingsSchema": "{}\n", - "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\":{}}" + "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\":{}}" } } ] diff --git a/ui/src/app/components/gateWay/gateway-config.directive.js b/ui/src/app/components/gateWay/gateway-config.directive.js deleted file mode 100644 index 66ba36620c..0000000000 --- a/ui/src/app/components/gateWay/gateway-config.directive.js +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import './gateway-config.scss'; - -/* eslint-disable import/no-unresolved, import/default */ - -import gatewayTemplate from './gateway-config.tpl.html'; -import gatewayDialogTemplate from './gateway-config-dialog.tpl.html'; -import beautify from "js-beautify"; - -/* eslint-enable import/no-unresolved, import/default */ -const js_beautify = beautify.js; - -export default angular.module('thingsboard.directives.gatewayConfig', []) - .directive('tbGatewayConfig', GatewayConfig) - .name; - -/*@ngInject*/ -function GatewayConfig() { - return { - restrict: "E", - scope: true, - bindToController: { - disabled: '=ngDisabled', - titleText: '@?', - keyPlaceholderText: '@?', - valuePlaceholderText: '@?', - noDataText: '@?', - gatewayConfig: '=', - changeAlignment: '=' - }, - controller: GatewayConfigController, - controllerAs: 'vm', - templateUrl: gatewayTemplate - }; -} - -/*@ngInject*/ -function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window, types, toast, $timeout, $compile, $translate) { //eslint-disable-line - - let vm = this; - - vm.kvList = []; - vm.types = types; - $scope.$watch('vm.gatewayConfig', () => { - vm.stopWatchKvList(); - vm.kvList.length = 0; - if (vm.gatewayConfig) { - for (var property in vm.gatewayConfig) { - if (Object.prototype.hasOwnProperty.call(vm.gatewayConfig, property)) { - vm.kvList.push( - { - enabled: vm.gatewayConfig[property].enabled, - key: property + '', - value: vm.gatewayConfig[property].connector + '', - config: js_beautify(vm.gatewayConfig[property].config + '', {indent_size: 4}) - } - ); - } - } - } - $mdUtil.nextTick(() => { - vm.watchKvList(); - }); - }); - - vm.watchKvList = () => { - $scope.kvListWatcher = $scope.$watch('vm.kvList', () => { - if (!vm.gatewayConfig) { - return; - } - for (let property in vm.gatewayConfig) { - if (Object.prototype.hasOwnProperty.call(vm.gatewayConfig, property)) { - delete vm.gatewayConfig[property]; - } - } - for (let i = 0; i < vm.kvList.length; i++) { - let entry = vm.kvList[i]; - if (entry.key && entry.value) { - let connectorJSON = angular.toJson({ - enabled: entry.enabled, - connector: entry.value, - config: angular.fromJson(entry.config) - }); - vm.gatewayConfig [entry.key] = angular.fromJson(connectorJSON); - } - } - }, true); - }; - - vm.stopWatchKvList = () => { - if ($scope.kvListWatcher) { - $scope.kvListWatcher(); - $scope.kvListWatcher = null; - } - }; - - vm.removeKeyVal = (index) => { - if (index > -1) { - vm.kvList.splice(index, 1); - } - }; - - vm.addKeyVal = () => { - if (!vm.kvList) { - vm.kvList = []; - } - vm.kvList.push( - { - enabled: false, - key: '', - value: '', - config: '{}' - } - ); - } - - vm.openConfigDialog = ($event, index, config, typeName) => { - if ($event) { - $event.stopPropagation(); - } - $mdDialog.show({ - controller: GatewayDialogController, - controllerAs: 'vm', - templateUrl: gatewayDialogTemplate, - parent: angular.element($document[0].body), - locals: { - config: config, - typeName: typeName - }, - targetEvent: $event, - fullscreen: true, - multiple: true, - }).then(function (config) { - if (config) { - if (index > -1) { - vm.kvList[index].config = config; - } - } - }, function () { - }); - - }; - - vm.configTypeChange = (keyVal) => { - for (let prop in types.gatewayConfigType) { - if (types.gatewayConfigType[prop].value === keyVal.value) { - if (!keyVal.key) { - keyVal.key = vm.configTypeChangeValid(types.gatewayConfigType[prop].name, 0); - } - } - } - vm.checkboxValid(keyVal); - }; - - vm.keyValChange = (keyVal, indexKey) => { - keyVal.key = vm.keyValChangeValid(keyVal.key, 0, indexKey); - vm.checkboxValid(keyVal); - }; - - vm.configTypeChangeValid = (name, index) => { - let newKeyName = index ? name + index : name; - let indexRes = vm.kvList.findIndex((element) => element.key === newKeyName); - return indexRes === -1 ? newKeyName : vm.configTypeChangeValid(name, ++index); - }; - - vm.keyValChangeValid = (name, index, indexKey) => { - angular.forEach(vm.kvList, function (value, key) { - let nameEq = (index === 0) ? name : name + index; - if (key !== indexKey && value.key && value.key === nameEq) { - index++; - vm.keyValChangeValid(name, index, indexKey); - } - - }); - return (index === 0) ? name : name + index; - }; - - vm.buttonValid = (config) => { - return (angular.equals("{}", config)) ? "md-warn" : "md-primary"; - }; - - vm.checkboxValid = (keyVal) => { - if (!keyVal.key || angular.equals("", keyVal.key) - || !keyVal.value || angular.equals("", keyVal.value) - || angular.equals("{}", keyVal.config)) { - return keyVal.enabled = false; - } - return true; - }; - vm.checkboxValidMouseover = ($event, keyVal) => { - console.log($event, keyVal); //eslint-disable-line - vm.checkboxValidClick ($event, keyVal); - }; - - vm.checkboxValidClick = ($event, keyVal) => { - if (!vm.checkboxValid(keyVal)) { - let errTxt = ""; - if (!keyVal.key || angular.equals("", keyVal.key)) { - errTxt = $translate.instant('gateway.keyval-name-err'); - } - - if (!keyVal.value || angular.equals("", keyVal.value)) { - errTxt += '
' + $translate.instant('gateway.keyval-type-err') + '
'; - } - - if (angular.equals("{}", keyVal.config)) { - errTxt += '
' + $translate.instant('gateway.keyval-config-err') + '
'; - } - if (!angular.equals("", errTxt)) { - displayTooltip($event, '
' + - '
' + - '
' + $translate.instant('gateway.keyval-save-err') + '
' + - '
' + errTxt + '
' + - '
' + - '
'); - } - } - else { - destroyTooltips(); - } - }; - - - function displayTooltip(event, content) { - destroyTooltips(); - vm.tooltipTimeout = $timeout(() => { - var element = angular.element(event.target); - element.tooltipster( - { - theme: 'tooltipster-shadow', - delay: 10, - animation: 'grow', - side: 'right' - } - ); - var contentElement = angular.element(content); - $compile(contentElement)($scope); - var tooltip = element.tooltipster('instance'); - tooltip.content(contentElement); - tooltip.open(); - }, 500); - } - - function destroyTooltips() { - if (vm.tooltipTimeout) { - $timeout.cancel(vm.tooltipTimeout); - vm.tooltipTimeout = null; - } - var instances = angular.element.tooltipster.instances(); - instances.forEach((instance) => { - if (!instance.isErrorTooltip) { - instance.destroy(); - } - }); - } -} - -/*@ngInject*/ -function GatewayDialogController($scope, $mdDialog, $document, $window, config, typeName) { - let vm = this; - vm.doc = $document[0]; - vm.config = angular.copy(config); - vm.typeName = "" + typeName; - vm.configAreaOptions = { - useWrapMode: false, - mode: 'json', - showGutter: true, - showPrintMargin: true, - theme: 'github', - advanced: { - enableSnippets: true, - enableBasicAutocompletion: true, - enableLiveAutocompletion: true - }, - onLoad: function (_ace) { - _ace.$blockScrolling = 1; - } - }; - - vm.validateConfig = (model, editorName) => { - if (model && model.length) { - try { - angular.fromJson(model); - $scope.theForm[editorName].$setValidity('configJSON', true); - } catch (e) { - $scope.theForm[editorName].$setValidity('configJSON', false); - } - } - }; - - vm.save = () => { - $mdDialog.hide(vm.config); - }; - - vm.cancel = () => { - $mdDialog.hide(); - }; - - vm.beautifyJson = () => { - vm.config = js_beautify(vm.config, {indent_size: 4}); - }; -} - diff --git a/ui/src/app/components/gateWay/gateway-config.tpl.html b/ui/src/app/components/gateWay/gateway-config.tpl.html deleted file mode 100644 index 565c771099..0000000000 --- a/ui/src/app/components/gateWay/gateway-config.tpl.html +++ /dev/null @@ -1,94 +0,0 @@ - -
-
-
- - - - - {{ 'gateway.enabled' | translate }} - - -
-
- - - - - {{configType.value}} - - - - {{ 'gateway.connector-type' | translate }} - - - - -
-
extension.field-required
-
- - {{ 'gateway.name' | translate }} - -
-
-
- - settings_ethernet - - {{ 'gateway.update-config' | translate }} - - - - close - - {{ 'gateway.delete' | translate }} - - -
-
- {{vm.noDataText ? vm.noDataText : 'gateway.no-connectors'}} -
- - - {{ 'gateway.add-connectors' | translate }} - - action.add - -
-
diff --git a/ui/src/app/components/gateWay/gateway-form.directive.js b/ui/src/app/components/gateWay/gateway-form.directive.js deleted file mode 100644 index 2aa05ce004..0000000000 --- a/ui/src/app/components/gateWay/gateway-form.directive.js +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import './gateway-form.scss'; -/* eslint-disable import/no-unresolved, import/default */ - -import gatewayFormTemplate from './gateway-form.tpl.html'; - -/* eslint-enable import/no-unresolved, import/default */ - -export default angular.module('thingsboard.directives.gatewayForm', []) - .directive('tbGatewayForm', GatewayForm) - .name; - -/*@ngInject*/ -function GatewayForm() { - return { - restrict: "E", - scope: true, - bindToController: { - disabled: '=ngDisabled', - keyPlaceholderText: '@?', - valuePlaceholderText: '@?', - noDataText: '@?', - formId: '=', - ctx: '=', - gatewayFormConfig: '=', - theForm: '=' - }, - controller: GatewayFormController, - controllerAs: 'vm', - templateUrl: gatewayFormTemplate - }; -} - -/*@ngInject*/ -function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, toast, importExport, attributeService, deviceService, userService, $mdDialog, $mdUtil, types, $window, $q) { - $scope.$mdExpansionPanel = $mdExpansionPanel; - let vm = this; - const attributeNameClinet = "current_configuration"; - const attributeNameServer = "configuration_drafts"; - const attributeNameShared = "configuration"; - const attributeNameLogShared = "RemoteLoggingLevel"; - 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"'; - vm.types = types; - - vm.configurations = { - singleSelect: '', - host: $document[0].domain, - port: 1883, - remoteConfiguration: true, - accessToken: '', - entityType: '', - entityId: '', - storageType: "memoryStorage", // "memoryStorage"; fileStorage - readRecordsCount: 100, - maxRecordsCount: 10000, - dataFolderPath: './data/', - maxFilesCount: 5, - securityType: "accessToken", // "accessToken", "tls" - caCertPath: '/etc/thingsboard-gateway/ca.pem', - privateKeyPath: '/etc/thingsboard-gateway/privateKey.pem', - certPath: '/etc/thingsboard-gateway/certificate.pem', - connectors: {}, - remoteLoggingLevel: "DEBUG", // level login - remoteLoggingPathToLogs: './logs/' - }; - getGatewaysListByUser(true); - - vm.securityTypes = [{ - name: 'Access Token', - value: 'accessToken' - }, { - name: 'TLS', - value: 'tls' - }]; - - vm.storageTypes = [{ - name: 'Memory storage', - value: 'memoryStorage' - }, { - name: 'File storage', - value: 'fileStorage' - }]; - - $scope.$on('gateway-form-resize', function (event, formId) { - if (vm.formId == formId) { - updateWidgetDisplaying(); - } - }); - - function updateWidgetDisplaying() { - if (vm.ctx && vm.ctx.$container) { - vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); - } - } - - updateWidgetDisplaying(); - - vm.getAccessToken = (deviceObj) => { - if (deviceObj.name) { - deviceService.findByName(deviceObj.name, {ignoreErrors: true}) - .then( - function (device) { - getDeviceCredential(device.id.id); - } - ) - } - }; - - function getDeviceCredential(deviceId) { - return deviceService.getDeviceCredentials(deviceId).then( - (deviceCredentials) => { - vm.configurations.accessToken = deviceCredentials.credentialsId; - vm.configurations.entityType = deviceCredentials.deviceId.entityType; - vm.configurations.entityId = deviceCredentials.deviceId.id; - vm.getAttributeStart(); - } - ); - } - - vm.createDevice = (deviceObj) => { - deviceService.findByName(deviceObj.name, {ignoreErrors: true}) - .then( - function (device) { - getDeviceCredential(device.id.id).then(() => { - getGatewaysListByUser(); - }); - }, - function () { - deviceService.saveDevice(deviceObj).then( - (device) => { - deviceService.getDeviceCredentials(device.id.id).then( - (data) => { - vm.configurations.accessToken = data.credentialsId; - vm.configurations.entityType = device.id.entityType; - vm.configurations.entityId = device.id.id; - vm.getAttributeStart(); - getGatewaysListByUser(); - } - ); - } - ); - }); - }; - - vm.saveAttributeConfig = () => { - vm.setAttribute(attributeNameShared, $window.btoa(angular.toJson(vm.getConfigAllByAttributeJSON())), types.attributesScope.shared.value); - vm.setAttribute(attributeNameServer, $window.btoa(angular.toJson(vm.getConfigByAttributeTmpJSON())), types.attributesScope.server.value); - vm.setAttribute(attributeNameLogShared, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); - }; - - vm.getAttributeStart = () => { - let initResps = []; - vm.configurations.connectors = {}; - initResps.push(vm.getAttributeConfig(attributeNameClinet, types.attributesScope.client.value)); - initResps.push(vm.getAttributeConfig(attributeNameServer, types.attributesScope.server.value)); - initResps.push(vm.getAttributeConfig(attributeNameLogShared, types.attributesScope.shared.value)); - $q.all(initResps).then((resp) => { - vm.getAttributeInitFromClient(resp[0]); - vm.getAttributeInitFromServer(resp[1]); - vm.getAttributeInitFromShared(resp[2]); - }, (err) => { - console.log("getAttribute_error", err); //eslint-disable-line - }); - }; - - vm.getAttributeConfig = (attributeName, typeValue) => { - let keys = [attributeName]; - return attributeService.getEntityAttributesValues(vm.configurations.entityType, vm.configurations.entityId, typeValue, keys); - }; - - vm.setAttribute = (attributeName, attributeConfig, typeValue) => { - let attributes = [ - { - key: attributeName, - value: attributeConfig - } - ]; - attributeService.saveEntityAttributes(vm.configurations.entityType, vm.configurations.entityId, typeValue, attributes).then(() => { - }, (err) => { - console.log("setAttribute_", err); //eslint-disable-line - }); - }; - - vm.exportConfig = () => { - let fileZip = {}; - fileZip["tb_gateway.yaml"] = vm.getConfig(); - vm.createConfigByExport(fileZip); - vm.getLogsConfigByExport(fileZip); - importExport.exportJSZip(fileZip, 'config'); - vm.setAttribute(attributeNameLogShared, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); - }; - - vm.getConfig = () => { - let config; - config = 'thingsboard:\n'; - config += ' host: ' + vm.configurations.host + '\n'; - config += ' remoteConfiguration: ' + vm.configurations.remoteConfiguration + '\n'; - config += ' port: ' + vm.configurations.port + '\n'; - config += ' security:\n'; - if (vm.configurations.securityType === 'accessToken') { - config += ' access-token: ' + vm.configurations.accessToken + '\n'; - } else if (vm.configurations.securityType === 'tls') { - config += ' ca_cert: ' + vm.configurations.caCertPath + '\n'; - config += ' privateKey: ' + vm.configurations.privateKeyPath + '\n'; - config += ' cert: ' + vm.configurations.certPath + '\n'; - } - config += 'storage:\n'; - if (vm.configurations.storageType === 'memoryStorage') { - config += ' type: memory\n'; - config += ' read_records_count: ' + vm.configurations.readRecordsCount + '\n'; - config += ' max_records_count: ' + vm.configurations.maxRecordsCount + '\n'; - } else if (vm.configurations.storageType === 'fileStorage') { - config += ' type: file\n'; - config += ' data_folder_path: ' + vm.configurations.dataFolderPath + '\n'; - config += ' max_file_count: ' + vm.configurations.maxFilesCount + '\n'; - config += ' max_read_records_count: ' + vm.configurations.readRecordsCount + '\n'; - config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; - } - config += 'connectors:\n'; - for (let connector in vm.configurations.connectors) { - if (vm.configurations.connectors[connector].enabled) { - config += ' -\n'; - config += ' name: ' + connector + ' Connector\n'; - config += ' type: ' + vm.configurations.connectors[connector].connector + '\n'; - config += ' configuration: ' + vm.validFileName(connector) + ".json" + '\n'; - } - } - return config; - }; - - vm.createConfigByExport = (fileZipAdd) => { - for (let connector in vm.configurations.connectors) { - if (vm.configurations.connectors[connector].enabled) { - fileZipAdd[vm.validFileName(connector) + ".json"] = angular.toJson(vm.configurations.connectors[connector].config); - } - } - }; - - vm.getLogsConfigByExport = (fileZipAdd) => { - fileZipAdd["logs.conf"] = vm.getLogsConfig(); - }; - - vm.getLogsConfig = () => { - return vm.remoteLoggingConfig - .replace(/{ERROR}/g, vm.configurations.remoteLoggingLevel) - .replace(/{.\/logs\/}/g, vm.configurations.remoteLoggingPathToLogs); - }; - - vm.getConfigAllByAttributeJSON = () => { - let thingsBoardAll = {}; - thingsBoardAll["thingsboard"] = vm.getConfigMainByAttributeJSON(); - vm.getConfigByAttributeJSON(thingsBoardAll); - return thingsBoardAll; - }; - - vm.getConfigMainByAttributeJSON = () => { - let configMain = {}; - let thingsBoard = {}; - thingsBoard.host = vm.configurations.host; - thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; - thingsBoard.port = vm.configurations.port; - let security = {}; - if (vm.configurations.securityType === 'accessToken') { - security.accessToken = (vm.configurations.accessToken) ? vm.configurations.accessToken : "" - } else { - security.caCert = vm.configurations.caCertPath; - security.privateKey = vm.configurations.privateKeyPath; - security.cert = vm.configurations.certPath; - } - thingsBoard.security = security; - configMain.thingsboard = thingsBoard; - - let storage = {}; - if (vm.configurations.storageType === 'memoryStorage') { - storage.type = "memory"; - storage.read_records_count = vm.configurations.readRecordsCount; - storage.max_records_count = vm.configurations.maxRecordsCount; - } else if (vm.configurations.storageType === 'fileStorage') { - storage.type = "file"; - storage.data_folder_path = vm.configurations.dataFolderPath; - storage.max_file_count = vm.configurations.maxFilesCount; - storage.max_read_records_count = vm.configurations.readRecordsCount; - storage.max_records_per_file = vm.configurations.maxRecordsCount; - } - configMain.storage = storage; - - let conn = []; - for (let connector in vm.configurations.connectors) { - if (vm.configurations.connectors[connector].enabled) { - let connect = {}; - connect.configuration = vm.validFileName(connector) + ".json"; - connect.name = connector; - connect.type = vm.configurations.connectors[connector].connector; - conn.push(connect); - } - } - configMain.connectors = conn; - - configMain.logs = $window.btoa(vm.getLogsConfig()); - - return configMain; - }; - - vm.getConfigByAttributeJSON = (thingsBoardBy) => { - for (let connector in vm.configurations.connectors) { - if (vm.configurations.connectors[connector].enabled) { - let typeAr = vm.configurations.connectors[connector].connector; - let objTypeAll = []; - for (let conn in vm.configurations.connectors) { - if (typeAr === vm.configurations.connectors[conn].connector && vm.configurations.connectors[conn].enabled) { - let objType = {}; - objType["name"] = conn; - objType["config"] = vm.configurations.connectors[conn].config; - objTypeAll.push(objType); - } - } - if (objTypeAll.length > 0) { - thingsBoardBy[typeAr] = objTypeAll; - } - } - } - }; - - vm.getConfigByAttributeTmpJSON = () => { - let connects = {}; - for (let connector in vm.configurations.connectors) { - if (!vm.configurations.connectors[connector].enabled && Object.keys(vm.configurations.connectors[connector].config).length !== 0) { - let conn = {}; - conn["connector"] = vm.configurations.connectors[connector].connector; - conn["config"] = vm.configurations.connectors[connector].config; - connects[connector] = conn; - } - } - return connects; - }; - - function getGatewaysListByUser(firstInit) { - vm.gateways = []; - vm.currentUser = userService.getCurrentUser(); - if (vm.currentUser.authority === 'TENANT_ADMIN') { - deviceService.getTenantDevices({limit: 500}).then( - (devices) => { - if (devices.data.length > 0) { - devices.data.forEach((device) => { - if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { - vm.gateways.push(device.name); - if (firstInit && vm.gateways.length && device.name === vm.gateways[0]) { - vm.configurations.singleSelect = vm.gateways[0]; - let deviceObj = { - "name": vm.configurations.singleSelect, - "type": "Gateway", - "additionalInfo": { - "gateway": true - } - }; - vm.getAccessToken(deviceObj); - } - } - }); - } - } - ); - } else if (vm.currentUser.authority === 'CUSTOMER_USER') { - deviceService.getCustomerDevices(vm.currentUser.customerId, {limit: 500}).then( - (devices) => { - if (devices.data.length > 0) { - devices.data.forEach((device) => { - if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { - vm.gateways.push(device.name); - if (firstInit && vm.gateways.length) { - vm.configurations.singleSelect = vm.gateways[0]; - let deviceObj = { - "name": vm.configurations.singleSelect, - "type": "Gateway", - "additionalInfo": { - "gateway": true - } - }; - vm.getAccessToken(deviceObj); - } - } - }); - } - } - ); - } - } - - vm.getAttributeInitFromClient = (resp) => { - if (resp.length > 0) { - vm.configurations.connectors = {}; - let attribute = angular.fromJson($window.atob(resp[0].value)); - for (var type in attribute) { - let keyVal = attribute[type]; - if (type === "thingsboard") { - if (keyVal !== null && Object.keys(keyVal).length > 0) { - vm.setConfigMain(keyVal); - } - } else { - for (let typeVal in keyVal) { - let typeName = ''; - if (Object.prototype.hasOwnProperty.call(keyVal[typeVal], 'name')) { - typeName = 'name'; - } - let key = ""; - key = (typeName === "") ? "No name" : ((typeName === 'name') ? keyVal[typeVal].name : keyVal[typeVal][typeName].name); - let conn = {}; - conn["enabled"] = true; - conn["connector"] = type; - conn["config"] = angular.toJson(keyVal[typeVal].config); - vm.configurations.connectors[key] = conn; - } - } - } - } - }; - - vm.getAttributeInitFromServer = (resp) => { - if (resp.length > 0) { - let attribute = angular.fromJson($window.atob(resp[0].value)); - for (let key in attribute) { - let conn = {}; - conn["enabled"] = false; - conn["connector"] = attribute[key].connector; - conn["config"] = angular.toJson(attribute[key].config); - vm.configurations.connectors[key] = conn; - } - } - }; - - vm.getAttributeInitFromShared = (resp) => { - if (resp.length > 0) { - if (vm.types.gatewayLogLevel[resp[0].value.toLowerCase()]) { - vm.configurations.remoteLoggingLevel = resp[0].value.toUpperCase(); - } - } else { - vm.configurations.remoteLoggingLevel = vm.types.gatewayLogLevel.debug; - } - }; - - vm.setConfigMain = (keyVal) => { - if (Object.prototype.hasOwnProperty.call(keyVal, 'thingsboard')) { - vm.configurations.host = keyVal.thingsboard.host; - vm.configurations.port = keyVal.thingsboard.port; - vm.configurations.remoteConfiguration = keyVal.thingsboard.remoteConfiguration; - if (Object.prototype.hasOwnProperty.call(keyVal.thingsboard.security, 'accessToken')) { - vm.configurations.securityType = 'accessToken'; - vm.configurations.accessToken = keyVal.thingsboard.security.accessToken; - } else { - vm.configurations.securityType = 'tls'; - vm.configurations.caCertPath = keyVal.thingsboard.security.caCert; - vm.configurations.privateKeyPath = keyVal.thingsboard.security.private_key; - vm.configurations.certPath = keyVal.thingsboard.security.cert; - } - } - if (Object.prototype.hasOwnProperty.call(keyVal, 'storage') && Object.prototype.hasOwnProperty.call(keyVal.storage, 'type')) { - if (keyVal.storage.type === 'memory') { - vm.configurations.storageType = 'memoryStorage'; - vm.configurations.readRecordsCount = keyVal.storage.read_records_count; - vm.configurations.maxRecordsCount = keyVal.storage.max_records_count; - } else if (keyVal.storage.type === 'file') { - vm.configurations.storageType = 'fileStorage'; - vm.configurations.dataFolderPath = keyVal.storage.data_folder_path; - vm.configurations.maxFilesCount = keyVal.storage.max_file_count; - vm.configurations.readRecordsCount = keyVal.storage.read_records_count; - vm.configurations.maxRecordsCount = keyVal.storage.max_records_count; - } - } - }; - - vm.setSaveTypeConfig = (itemVal) => { - vm.configurations.remoteConfiguration = itemVal.item; - }; - - vm.validFileName = (fileName) => { - let fileName1 = fileName.replace("_", ""); - let fileName2 = fileName1.replace("-", ""); - let fileName3 = fileName2.replace(/^\s+|\s+$/g, ''); - let fileName4 = fileName3.toLowerCase(); - return fileName4; - }; -} - - diff --git a/ui/src/app/components/gateWay/gateway-form.tpl.html b/ui/src/app/components/gateWay/gateway-form.tpl.html deleted file mode 100644 index 8ea0cfcc07..0000000000 --- a/ui/src/app/components/gateWay/gateway-form.tpl.html +++ /dev/null @@ -1,219 +0,0 @@ - -
- - - -
{{ 'gateway.thingsboard' | translate | uppercase }}
- - -
- - -
{{ 'gateway.thingsboard' | translate | uppercase }}
- - -
- - - - - - - - {{securityType.name}} - - - -
- - - -
-
extension.field-required
-
-
- - - -
-
extension.field-required
-
max
-
min
-
-
-
-
- - - - - - - - - - - - -
- - {{ 'gateway.remote' | translate }} - {{'gateway.remote-tip' | translate }} - -
- - - - - {{loggingLevel}} - - - - - - -
-
extension.field-required
-
-
-
-
-
-
- - -
{{ 'gateway.storage' | translate | uppercase }}
- - -
- - -
{{ 'gateway.storage' | translate | uppercase }}
- - -
- - - - - - {{storageType.name}} - - - - -
- - - -
-
extension.field-required
-
-
- - - - -
-
extension.field-required
-
-
-
- -
- - - -
-
extension.field-required
-
-
- - - - -
-
extension.field-required
-
-
-
-
-
-
- - -
{{ 'gateway.connectors' | translate | uppercase }}
- - -
- - -
{{ 'gateway.connectors' | translate | uppercase }}
- - -
- - - - -
-
-
-
- - {{'action.download' | translate }} - {{'gateway.download-tip' | translate }} - - - - {{'action.save' | translate }} - {{'gateway.save-tip' | translate }} - -
-
diff --git a/ui/src/app/components/gateWay/gateway-config-dialog.tpl.html b/ui/src/app/components/gateway/gateway-config-dialog.tpl.html similarity index 92% rename from ui/src/app/components/gateWay/gateway-config-dialog.tpl.html rename to ui/src/app/components/gateway/gateway-config-dialog.tpl.html index ce55d15f48..87195ac584 100644 --- a/ui/src/app/components/gateWay/gateway-config-dialog.tpl.html +++ b/ui/src/app/components/gateway/gateway-config-dialog.tpl.html @@ -55,15 +55,15 @@ required> - - {{'action.save'|translate}} diff --git a/ui/src/app/components/gateWay/gateway-config-select.directive.js b/ui/src/app/components/gateway/gateway-config-select.directive.js similarity index 74% rename from ui/src/app/components/gateWay/gateway-config-select.directive.js rename to ui/src/app/components/gateway/gateway-config-select.directive.js index 5178fed6d6..79ff454475 100644 --- a/ui/src/app/components/gateWay/gateway-config-select.directive.js +++ b/ui/src/app/components/gateway/gateway-config-select.directive.js @@ -17,7 +17,7 @@ import './gateway-config-select.scss'; /* eslint-disable import/no-unresolved, import/default */ -import gatewayAliasSelectTemplate from './gateway-config-select.tpl.html'; +import gatewaySelectTemplate from './gateway-config-select.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -32,23 +32,26 @@ export default angular.module('thingsboard.directives.gatewayConfigSelect', []) function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, $mdDialog) { var linker = function (scope, element, attrs, ngModelCtrl) { - var template = $templateCache.get(gatewayAliasSelectTemplate); + const template = $templateCache.get(gatewaySelectTemplate); element.html(template); scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; - - scope.ngModelCtrl = ngModelCtrl; - scope.singleSelect = null; + scope.gateway = null; + scope.gatewaySearchText = ''; scope.updateValidity = function () { var value = ngModelCtrl.$viewValue; var valid = angular.isDefined(value) && value != null || !scope.tbRequired; - ngModelCtrl.$setValidity('singleSelect', valid); + ngModelCtrl.$setValidity('gateway', valid); }; - scope.$watch('singleSelect', function () { - scope.updateView(); - }); + function startWatchers() { + scope.$watch('gateway', function (newVal, prevVal) { + if (!angular.equals(newVal, prevVal) && newVal !== null) { + scope.updateView(); + } + }); + } scope.gatewayNameSearch = function (gatewaySearchText) { return gatewaySearchText ? scope.gatewayList.filter( @@ -58,22 +61,20 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, scope.createFilterForGatewayName = function (query) { var lowercaseQuery = query.toLowerCase(); return function filterFn(device) { - return (device.toLowerCase().indexOf(lowercaseQuery) === 0); + return (device.name.toLowerCase().indexOf(lowercaseQuery) === 0); }; }; scope.updateView = function () { - ngModelCtrl.$setViewValue(scope.singleSelect); + ngModelCtrl.$setViewValue(scope.gateway); scope.updateValidity(); - let deviceObj = {"name": scope.singleSelect, "type": "Gateway", "additionalInfo": { - "gateway": true - }}; - scope.getAccessToken(deviceObj); + scope.getAccessToken(scope.gateway.id); }; ngModelCtrl.$render = function () { if (ngModelCtrl.$viewValue) { - scope.singleSelect = ngModelCtrl.$viewValue; + scope.gateway = ngModelCtrl.$viewValue; + startWatchers(); } }; @@ -85,9 +86,9 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) { $event.preventDefault(); let indexRes = scope.gatewayList.findIndex((element) => element.key === scope.gatewaySearchText); - if (indexRes === -1) { - scope.createNewGatewayDialog($event, {name: scope.gatewaySearchText}); - } + if (indexRes === -1) { + scope.createNewGatewayDialog($event, scope.gatewaySearchText); + } } }; @@ -96,7 +97,7 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, $event.stopPropagation(); } var title = $translate.instant('gateway.create-new-gateway'); - var content = $translate.instant('gateway.create-new-gateway-text', {gatewayName: deviceName.name}); + var content = $translate.instant('gateway.create-new-gateway-text', {gatewayName: deviceName}); var confirm = $mdDialog.confirm() .targetEvent($event) .title(title) @@ -106,9 +107,13 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, .ok($translate.instant('action.yes')); $mdDialog.show(confirm).then( () => { - let deviceObj = {"name": deviceName.name, "type": "Gateway", "additionalInfo": { - "gateway": true - }}; + let deviceObj = { + name: deviceName, + type: "Gateway", + additionalInfo: { + gateway: true + } + }; scope.createDevice(deviceObj); }, () => { @@ -125,7 +130,6 @@ function GatewayConfigSelect($compile, $templateCache, $mdConstant, $translate, link: linker, scope: { tbRequired: '=?', - allowedEntityTypes: '=?', gatewayList: '=?', getAccessToken: '=', createDevice: '=', diff --git a/ui/src/app/components/gateWay/gateway-config-select.scss b/ui/src/app/components/gateway/gateway-config-select.scss similarity index 100% rename from ui/src/app/components/gateWay/gateway-config-select.scss rename to ui/src/app/components/gateway/gateway-config-select.scss diff --git a/ui/src/app/components/gateWay/gateway-config-select.tpl.html b/ui/src/app/components/gateway/gateway-config-select.tpl.html similarity index 76% rename from ui/src/app/components/gateWay/gateway-config-select.tpl.html rename to ui/src/app/components/gateway/gateway-config-select.tpl.html index 57c89e5e4a..9a7f6ed655 100644 --- a/ui/src/app/components/gateWay/gateway-config-select.tpl.html +++ b/ui/src/app/components/gateway/gateway-config-select.tpl.html @@ -16,14 +16,14 @@ -->
- - {{item}} + {{item.name}}
@@ -41,14 +41,13 @@ gateway.no-gateway-found
- gateway.no-gateway-matching - gateway.create-new-gateway + gateway.no-gateway-matching + gateway.create-new-gateway
-
-
Test
+
+
gateway.gateway-name-required
diff --git a/ui/src/app/components/gateway/gateway-config.directive.js b/ui/src/app/components/gateway/gateway-config.directive.js new file mode 100644 index 0000000000..120a6d3e15 --- /dev/null +++ b/ui/src/app/components/gateway/gateway-config.directive.js @@ -0,0 +1,170 @@ +/* + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './gateway-config.scss'; + +/* eslint-disable import/no-unresolved, import/default */ + +import gatewayConfigTemplate from './gateway-config.tpl.html'; +import gatewayConfigDialogTemplate from './gateway-config-dialog.tpl.html'; +import beautify from "js-beautify"; + +/* eslint-enable import/no-unresolved, import/default */ +const js_beautify = beautify.js; + +export default angular.module('thingsboard.directives.gatewayConfig', []) + .directive('tbGatewayConfig', GatewayConfig) + .name; + +/*@ngInject*/ +function GatewayConfig() { + return { + restrict: "E", + scope: true, + bindToController: { + disabled: '=ngDisabled', + gatewayConfig: '=', + changeAlignment: '=', + theForm: '=' + }, + controller: GatewayConfigController, + controllerAs: 'vm', + templateUrl: gatewayConfigTemplate + }; +} + +/*@ngInject*/ +function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window, types) { + let vm = this; + vm.types = types; + + vm.removeConnector = (index) => { + if (index > -1) { + vm.gatewayConfig.splice(index, 1); + } + }; + + vm.addNewConnector = () => { + vm.gatewayConfig.push({ + enabled: false, + configType: '', + config: {}, + name: '' + }); + }; + + vm.openConfigDialog = ($event, index, config, typeName) => { + if ($event) { + $event.stopPropagation(); + } + $mdDialog.show({ + controller: GatewayDialogController, + controllerAs: 'vm', + templateUrl: gatewayConfigDialogTemplate, + parent: angular.element($document[0].body), + locals: { + config: config, + typeName: typeName + }, + targetEvent: $event, + fullscreen: true, + multiple: true, + }).then(function (config) { + if (config && index > -1) { + vm.gatewayConfig[index].config = config; + } + }); + + }; + + vm.changeConnectorType = (connector) => { + for (let gatewayConfigTypeKey in types.gatewayConfigType) { + if (types.gatewayConfigType[gatewayConfigTypeKey].value === connector.configType) { + if (!connector.name) { + connector.name = generateConnectorName(types.gatewayConfigType[gatewayConfigTypeKey].name, 0); + break; + } + } + } + }; + + vm.changeConnectorName = (connector, currentConnectorIndex) => { + connector.name = validateConnectorName(connector.name, 0, currentConnectorIndex); + }; + + function generateConnectorName(name, index) { + let newKeyName = index ? name + index : name; + let indexRes = vm.gatewayConfig.findIndex((element) => element.name === newKeyName); + return indexRes === -1 ? newKeyName : generateConnectorName(name, ++index); + } + + function validateConnectorName(name, index, currentConnectorIndex) { + for (let i = 0; i < vm.gatewayConfig.length; i++) { + let nameEq = (index === 0) ? name : name + index; + if (i !== currentConnectorIndex && vm.gatewayConfig[i].name === nameEq) { + index++; + validateConnectorName(name, index, currentConnectorIndex); + } + } + return (index === 0) ? name : name + index; + } + + vm.validateJSON = (config) => { + return angular.equals({}, config); + }; +} + +/*@ngInject*/ +function GatewayDialogController($scope, $mdDialog, $document, $window, config, typeName) { + let vm = this; + vm.config = js_beautify(angular.toJson(config), {indent_size: 4}); + vm.typeName = typeName; + vm.configAreaOptions = { + useWrapMode: true, + mode: 'json', + advanced: { + enableSnippets: true, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true + }, + onLoad: function (_ace) { + _ace.$blockScrolling = 1; + } + }; + + vm.validateConfig = (model, editorName) => { + if (model && model.length) { + try { + angular.fromJson(model); + $scope.theForm[editorName].$setValidity('config', true); + } catch (e) { + $scope.theForm[editorName].$setValidity('config', false); + } + } + }; + + vm.save = () => { + $mdDialog.hide(angular.fromJson(vm.config)); + }; + + vm.cancel = () => { + $mdDialog.hide(); + }; + + vm.beautifyJson = () => { + vm.config = js_beautify(vm.config, {indent_size: 4}); + }; +} + diff --git a/ui/src/app/components/gateWay/gateway-config.scss b/ui/src/app/components/gateway/gateway-config.scss similarity index 85% rename from ui/src/app/components/gateWay/gateway-config.scss rename to ui/src/app/components/gateway/gateway-config.scss index f128db8f21..45d9532927 100644 --- a/ui/src/app/components/gateWay/gateway-config.scss +++ b/ui/src/app/components/gateway/gateway-config.scss @@ -56,20 +56,20 @@ .tb-json-toolbar{ height: 40px; } +} - .tb-json-panel { - height: calc(100% - 80px); - margin-left: 15px; - border: 1px solid #c0c0c0; +.tb-json-panel { + height: calc(100% - 80px); + margin-left: 15px; + border: 1px solid #c0c0c0; - .tb-json-input { - width: 100%; - min-width: 400px; - height: 100%; + .tb-json-input { + width: 100%; + min-width: 400px; + height: 100%; - &:not(.fill-height) { - min-height: 200px; - } + &:not(.fill-height) { + min-height: 200px; } } } diff --git a/ui/src/app/components/gateway/gateway-config.tpl.html b/ui/src/app/components/gateway/gateway-config.tpl.html new file mode 100644 index 0000000000..eef7c737e4 --- /dev/null +++ b/ui/src/app/components/gateway/gateway-config.tpl.html @@ -0,0 +1,81 @@ + +
+
+
+ + +
+
+ + + + + {{configType.value}} + + +
+
gateway.connector-type-required
+
+
+ + +
+
gateway.connector-name-required
+
+
+
+
+ + more_horiz + + {{ 'gateway.update-config' | translate }} + + + + close + + {{ 'gateway.delete' | translate }} + + +
+
+ {{'gateway.no-connectors'}} +
+ + + {{ 'gateway.connector-add' | translate }} + + action.add + +
+
diff --git a/ui/src/app/components/gateway/gateway-form.directive.js b/ui/src/app/components/gateway/gateway-form.directive.js new file mode 100644 index 0000000000..1e2e02ce24 --- /dev/null +++ b/ui/src/app/components/gateway/gateway-form.directive.js @@ -0,0 +1,467 @@ +/* + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './gateway-form.scss'; +/* eslint-disable import/no-unresolved, import/default */ + +import gatewayFormTemplate from './gateway-form.tpl.html'; + +/* eslint-enable import/no-unresolved, import/default */ + +export default angular.module('thingsboard.directives.gatewayForm', []) + .directive('tbGatewayForm', GatewayForm) + .name; + +/*@ngInject*/ +function GatewayForm() { + return { + restrict: "E", + scope: true, + bindToController: { + formId: '=', + ctx: '=' + }, + controller: GatewayFormController, + controllerAs: 'vm', + templateUrl: gatewayFormTemplate + }; +} + +/*@ngInject*/ +function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, toast, importExport, attributeService, deviceService, userService, $mdDialog, $mdUtil, types, $window, $q, entityService, utils, $translate) { + let vm = this; + const currentConfigurationAttribute = "current_configuration"; + const configurationDraftsAttribute = "configuration_drafts"; + const configurationAttribute = "configuration"; + const remoteLoggingLevelAttribute = "RemoteLoggingLevel"; + + 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"'; + + vm.types = types; + + vm.configurations = { + gateway: '', + host: $document[0].domain, + port: 1883, + remoteConfiguration: true, + accessToken: '', + storageType: "memoryStorage", + readRecordsCount: 100, + maxRecordsCount: 10000, + dataFolderPath: './data/', + maxFilesCount: 5, + securityType: "accessToken", + caCertPath: '/etc/thingsboard-gateway/ca.pem', + privateKeyPath: '/etc/thingsboard-gateway/privateKey.pem', + certPath: '/etc/thingsboard-gateway/certificate.pem', + connectors: [], + remoteLoggingLevel: "DEBUG", + remoteLoggingPathToLogs: './logs/' + }; + + let archiveFileName = ''; + let gatewayNameExists = ''; + let successfulSaved = ''; + + vm.securityTypes = [{ + name: 'gateway.security-types.access-token', + value: 'accessToken' + }, { + name: 'gateway.security-types.tls', + value: 'tls' + }]; + + vm.storageTypes = [{ + name: 'gateway.storage-types.memory-storage', + value: 'memoryStorage' + }, { + name: 'gateway.storage-types.file-storage', + value: 'fileStorage' + }]; + + $scope.$watch('vm.ctx', function () { + if (vm.ctx ) { + vm.settings = vm.ctx.settings; + vm.widgetConfig = vm.ctx.widgetConfig; + initializeConfig(); + } + }); + + $scope.$on('gateway-form-resize', function (event, formId) { + if (vm.formId == formId) { + updateWidgetDisplaying(); + } + }); + + function updateWidgetDisplaying() { + vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); + } + + function initWidgetSettings() { + let widgetTitle; + if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) { + widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle); + } else { + widgetTitle = $translate.instant('gateway.gateway'); + } + vm.ctx.widgetTitle = widgetTitle; + + archiveFileName = vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration'; + gatewayNameExists = utils.customTranslation(vm.settings.deviceNameExist, vm.settings.deviceNameExist) || $translate.instant('gateway.gateway-exists'); + successfulSaved = utils.customTranslation(vm.settings.successfulSave, vm.settings.successfulSave) || $translate.instant('gateway.gateway-saved'); + } + + function initializeConfig() { + updateWidgetDisplaying(); + initWidgetSettings(); + getGatewaysList(true); + } + + vm.getAccessToken = (deviceId) => { + if (deviceId.id) { + getDeviceCredentials(deviceId.id); + } + }; + + vm.collapsePanel = function (panelId) { + $mdExpansionPanel(panelId).collapse(); + }; + + function getDeviceCredentials(deviceId) { + return deviceService.getDeviceCredentials(deviceId).then( + (deviceCredentials) => { + vm.configurations.accessToken = deviceCredentials.credentialsId; + getAttributes(); + } + ); + } + + vm.createDevice = (deviceObj) => { + deviceService.findByName(deviceObj.name, {ignoreErrors: true}) + .then( + function () { + toast.showError(gatewayNameExists, angular.element('.gateway-form'),'top left'); + }, + function () { + if(vm.settings.gatewayType && vm.settings.gatewayType.length){ + deviceObj.type = vm.settings.gatewayType; + } + deviceService.saveDevice(deviceObj).then( + (device) => { + getDeviceCredentials(device.id.id).then(() =>{ + getGatewaysList(); + }); + } + ); + }); + }; + + vm.saveAttributeConfig = () => { + $q.all([ + saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value), + saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value), + saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value) + ]).then(() =>{ + toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'),'top left'); + }) + }; + + function getAttributes() { + let promises = []; + promises.push(getAttribute(currentConfigurationAttribute, types.attributesScope.client.value)); + promises.push(getAttribute(configurationDraftsAttribute, types.attributesScope.server.value)); + promises.push(getAttribute(remoteLoggingLevelAttribute, types.attributesScope.shared.value)); + $q.all(promises).then((response) => { + processCurrentConfiguration(response[0]); + processConfigurationDrafts(response[1]); + processLoggingLevel(response[2]); + }); + } + + function getAttribute(attributeName, attributeScope) { + return attributeService.getEntityAttributesValues(vm.configurations.gateway.id.entityType, vm.configurations.gateway.id.id, attributeScope, attributeName); + } + + function saveAttribute(attributeName, attributeValue, attributeScope) { + let attributes = [{ + key: attributeName, + value: attributeValue + }]; + return attributeService.saveEntityAttributes(vm.configurations.gateway.id.entityType, vm.configurations.gateway.id.id, attributeScope, attributes); + } + + vm.exportConfig = () => { + let filesZip = {}; + filesZip["tb_gateway.yaml"] = generateYAMLConfigurationFile(); + generateConfigConnectorFiles(filesZip); + generateLogConfigFile(filesZip); + importExport.exportJSZip(filesZip, archiveFileName); + saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value); + }; + + function generateYAMLConfigurationFile() { + let config; + config = 'thingsboard:\n'; + config += ' host: ' + vm.configurations.host + '\n'; + config += ' remoteConfiguration: ' + vm.configurations.remoteConfiguration + '\n'; + config += ' port: ' + vm.configurations.port + '\n'; + config += ' security:\n'; + if (vm.configurations.securityType === 'accessToken') { + config += ' access-token: ' + vm.configurations.accessToken + '\n'; + } else if (vm.configurations.securityType === 'tls') { + config += ' ca_cert: ' + vm.configurations.caCertPath + '\n'; + config += ' privateKey: ' + vm.configurations.privateKeyPath + '\n'; + config += ' cert: ' + vm.configurations.certPath + '\n'; + } + config += 'storage:\n'; + if (vm.configurations.storageType === 'memoryStorage') { + config += ' type: memory\n'; + config += ' read_records_count: ' + vm.configurations.readRecordsCount + '\n'; + config += ' max_records_count: ' + vm.configurations.maxRecordsCount + '\n'; + } else if (vm.configurations.storageType === 'fileStorage') { + config += ' type: file\n'; + config += ' data_folder_path: ' + vm.configurations.dataFolderPath + '\n'; + config += ' max_file_count: ' + vm.configurations.maxFilesCount + '\n'; + config += ' max_read_records_count: ' + vm.configurations.readRecordsCount + '\n'; + config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; + } + config += 'connectors:\n'; + for(let i = 0; i < vm.configurations.connectors.length; i++){ + if (vm.configurations.connectors[i].enabled) { + config += ' -\n'; + config += ' name: ' + vm.configurations.connectors[i].name + '\n'; + config += ' type: ' + vm.configurations.connectors[i].configType + '\n'; + config += ' configuration: ' + generateFileName(vm.configurations.connectors[i].name) + '\n'; + } + } + return config; + } + + function generateConfigConnectorFiles(fileZipAdd) { + for(let i = 0; i < vm.configurations.connectors.length; i++){ + if (vm.configurations.connectors[i].enabled) { + fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config); + } + } + } + + function generateLogConfigFile(fileZipAdd) { + fileZipAdd["logs.conf"] = getLogsConfig(); + } + + function getLogsConfig() { + return templateLogsConfig + .replace(/{ERROR}/g, vm.configurations.remoteLoggingLevel) + .replace(/{.\/logs\/}/g, vm.configurations.remoteLoggingPathToLogs); + } + + function getGatewayConfigJSON() { + let gatewayConfig = {}; + gatewayConfig["thingsboard"] = gatewayMainConfigJSON(); + gatewayConnectorConfigJSON(gatewayConfig); + return gatewayConfig; + } + + function gatewayMainConfigJSON() { + let configuration = {}; + + let thingsBoard = {}; + thingsBoard.host = vm.configurations.host; + thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; + thingsBoard.port = vm.configurations.port; + let security = {}; + if (vm.configurations.securityType === 'accessToken') { + security.accessToken = (vm.configurations.accessToken) ? vm.configurations.accessToken : "" + } else { + security.caCert = vm.configurations.caCertPath; + security.privateKey = vm.configurations.privateKeyPath; + security.cert = vm.configurations.certPath; + } + thingsBoard.security = security; + configuration.thingsboard = thingsBoard; + + let storage = {}; + if (vm.configurations.storageType === 'memoryStorage') { + storage.type = "memory"; + storage.read_records_count = vm.configurations.readRecordsCount; + storage.max_records_count = vm.configurations.maxRecordsCount; + } else if (vm.configurations.storageType === 'fileStorage') { + storage.type = "file"; + storage.data_folder_path = vm.configurations.dataFolderPath; + storage.max_file_count = vm.configurations.maxFilesCount; + storage.max_read_records_count = vm.configurations.readRecordsCount; + storage.max_records_per_file = vm.configurations.maxRecordsCount; + } + configuration.storage = storage; + + let connectors = []; + for (let i = 0; i < vm.configurations.connectors.length; i++) { + if (vm.configurations.connectors[i].enabled) { + let connector = { + configuration: generateFileName(vm.configurations.connectors[i].name), + name: vm.configurations.connectors[i].name, + type: vm.configurations.connectors[i].configType + }; + connectors.push(connector); + } + } + configuration.connectors = connectors; + + configuration.logs = $window.btoa(getLogsConfig()); + + return configuration; + } + + function gatewayConnectorConfigJSON(gatewayConfiguration) { + for(let i = 0; i < vm.configurations.connectors.length; i++){ + if (vm.configurations.connectors[i].enabled) { + let typeConnector = vm.configurations.connectors[i].configType; + if(!angular.isArray(gatewayConfiguration[typeConnector])){ + gatewayConfiguration[typeConnector] = []; + } + + let connectorConfig = { + name: vm.configurations.connectors[i].name, + config: vm.configurations.connectors[i].config + }; + gatewayConfiguration[typeConnector].push(connectorConfig); + } + } + } + + function getDraftConnectorJSON() { + let draftConnector = {}; + for(let i = 0; i < vm.configurations.connectors.length; i++){ + if (!vm.configurations.connectors[i].enabled) { + let connector = { + connector: vm.configurations.connectors[i].configType, + config: vm.configurations.connectors[i].config + }; + draftConnector[vm.configurations.connectors[i].name] = connector; + } + } + return draftConnector; + } + + function getGatewaysList(firstInit) { + vm.gateways = []; + entityService.getEntitiesByNameFilter(types.entityType.device, "", -1).then((devices) => { + for (let i = 0; i < devices.length; i++) { + const device = devices[i]; + if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { + vm.gateways.push(device); + if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) { + vm.configurations.gateway = device; + vm.getAccessToken(device.id); + } + } + } + }); + } + + function processCurrentConfiguration(response) { + if (response.length > 0) { + vm.configurations.connectors = []; + let attribute = angular.fromJson($window.atob(response[0].value)); + for (var attributeKey in attribute) { + let keyValue = attribute[attributeKey]; + if (attributeKey === "thingsboard") { + if (keyValue !== null && Object.keys(keyValue).length > 0) { + setConfigGateway(keyValue); + } + } else { + for (let connectorType in keyValue) { + let name = "No name"; + if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) { + name = keyValue[connectorType].name ; + } + let connector = { + enabled: true, + configType: attributeKey, + config: keyValue[connectorType].config, + name: name + }; + vm.configurations.connectors.push(connector); + } + } + } + } + } + + function processConfigurationDrafts(response) { + if (response.length > 0) { + let attribute = angular.fromJson($window.atob(response[0].value)); + for (let key in attribute) { + let connector = { + enabled: false, + configType: attribute[key].connector, + config: attribute[key].config, + name: key + }; + vm.configurations.connectors.push(connector); + } + } + } + + function processLoggingLevel(response) { + if (response.length > 0) { + if (vm.types.gatewayLogLevel[response[0].value.toLowerCase()]) { + vm.configurations.remoteLoggingLevel = response[0].value.toUpperCase(); + } + } else { + vm.configurations.remoteLoggingLevel = vm.types.gatewayLogLevel.debug; + } + } + + function setConfigGateway(keyValue) { + if (Object.prototype.hasOwnProperty.call(keyValue, 'thingsboard')) { + vm.configurations.host = keyValue.thingsboard.host; + vm.configurations.port = keyValue.thingsboard.port; + vm.configurations.remoteConfiguration = keyValue.thingsboard.remoteConfiguration; + if (Object.prototype.hasOwnProperty.call(keyValue.thingsboard.security, 'accessToken')) { + vm.configurations.securityType = 'accessToken'; + vm.configurations.accessToken = keyValue.thingsboard.security.accessToken; + } else { + vm.configurations.securityType = 'tls'; + vm.configurations.caCertPath = keyValue.thingsboard.security.caCert; + vm.configurations.privateKeyPath = keyValue.thingsboard.security.private_key; + vm.configurations.certPath = keyValue.thingsboard.security.cert; + } + } + + if (Object.prototype.hasOwnProperty.call(keyValue, 'storage') && Object.prototype.hasOwnProperty.call(keyValue.storage, 'type')) { + if (keyValue.storage.type === 'memory') { + vm.configurations.storageType = 'memoryStorage'; + vm.configurations.readRecordsCount = keyValue.storage.read_records_count; + vm.configurations.maxRecordsCount = keyValue.storage.max_records_count; + } else if (keyValue.storage.type === 'file') { + vm.configurations.storageType = 'fileStorage'; + vm.configurations.dataFolderPath = keyValue.storage.data_folder_path; + vm.configurations.maxFilesCount = keyValue.storage.max_file_count; + vm.configurations.readRecordsCount = keyValue.storage.read_records_count; + vm.configurations.maxRecordsCount = keyValue.storage.max_records_count; + } + } + } + + function generateFileName(fileName) { + return fileName.replace("_", "") + .replace("-", "") + .replace(/^\s+|\s+/g, '') + .toLowerCase() + '.json'; + } +} + + diff --git a/ui/src/app/components/gateWay/gateway-form.scss b/ui/src/app/components/gateway/gateway-form.scss similarity index 90% rename from ui/src/app/components/gateWay/gateway-form.scss rename to ui/src/app/components/gateway/gateway-form.scss index a5e7bc8b44..f6851c7688 100644 --- a/ui/src/app/components/gateWay/gateway-form.scss +++ b/ui/src/app/components/gateway/gateway-form.scss @@ -14,7 +14,9 @@ * limitations under the License. */ .gateway-form{ + height: 100%; padding: 5px 5px 0; + background-color: transparent; .gateway-form-row{ md-input-container{ @@ -30,11 +32,11 @@ } } + .security-type { + margin-top: 18px; + } + .form-action-buttons{ padding-top: 8px; } } - -.security-type { - margin-top: 38px; -} diff --git a/ui/src/app/components/gateway/gateway-form.tpl.html b/ui/src/app/components/gateway/gateway-form.tpl.html new file mode 100644 index 0000000000..abe030d543 --- /dev/null +++ b/ui/src/app/components/gateway/gateway-form.tpl.html @@ -0,0 +1,227 @@ + + +
+ + + +
{{ 'gateway.thingsboard' | translate | uppercase }}
+ + +
+ + +
{{ 'gateway.thingsboard' | translate | uppercase }}
+ + +
+ + + + + + + + {{securityType.name | translate}} + + + +
+ + + +
+
gateway.thingsboard-host-required
+
+
+ + + +
+
gateway.thingsboard-port-required
+
gateway.thingsboard-port-max
+
gateway.thingsboard-port-min
+
gateway.thingsboard-port-pattern
+
+
+
+
+ + + + + + + + + + + + +
+ + {{ 'gateway.remote' | translate }} + +
+ + + + + {{logLevel}} + + + + + + +
+
gateway.path-logs-required
+
+
+
+
+
+
+ + +
{{ 'gateway.storage' | translate | uppercase }}
+ + +
+ + +
{{ 'gateway.storage' | translate | uppercase }}
+ + +
+ + + + + + {{storageType.name | translate}} + + + + +
+ + + +
+
gateway.storage-pack-size-required
+
gateway.storage-pack-size-min
+
gateway.storage-pack-size-pattern
+
+
+ + + + +
+
gateway.storage-max-records-required
+
gateway.storage-max-records-min
+
gateway.storage-max-records-pattern
+
+
+
+ +
+ + + +
+
gateway.storage-max-files-required
+
gateway.storage-max-files-min
+
gateway.storage-max-files-pattern
+
+
+ + + + +
+
gateway.storage-path-required
+
+
+
+
+
+
+ + +
{{ 'gateway.connectors' | translate | uppercase }}
+ + +
+ + +
{{ 'gateway.connectors' | translate | uppercase }}
+ + +
+ + + + +
+
+
+
+ + {{'action.download' | translate }} + {{'gateway.download-tip' | translate }} + + + + {{'action.save' | translate }} + {{'gateway.save-tip' | translate }} + +
+
+
diff --git a/ui/src/app/import-export/import-export.service.js b/ui/src/app/import-export/import-export.service.js index 6220fc3c6a..b5dbfa6ef3 100644 --- a/ui/src/app/import-export/import-export.service.js +++ b/ui/src/app/import-export/import-export.service.js @@ -29,7 +29,7 @@ import * as JSZip from 'jszip'; export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, $rootScope, dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) { - const JSZIP_TYPE = { + const ZIP_TYPE = { mimeType: 'application/zip', extension: 'zip' }; @@ -989,29 +989,19 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, dialogElement[0].style.width = dialogElement[0].offsetWidth + 2 + "px"; } - /** - * - * @param data - * @param filename - * Warn data !!! Not object, if object, then object convert from object to format txt - * Example: data = {keyNameFile1: valueFile1, - * keyNameFile2: valueFile2...} - * fileName - name file of the arhiv - */ function exportJSZip(data, filename) { let jsZip = new JSZip(); for (let keyName in data) { let valueData = data[keyName]; jsZip.file(keyName, valueData); } - jsZip.generateAsync({type: "Blob"}).then(function (content) { - downloadFile(content, filename, JSZIP_TYPE); + jsZip.generateAsync({type: "blob"}).then(function (content) { + downloadFile(content, filename, ZIP_TYPE); }); } function downloadFile(data, filename, fileType) { - console.log("downloadFile", data, filename, fileType); // eslint-disable-line if (!filename) { filename = 'download'; } diff --git a/ui/src/app/layout/index.js b/ui/src/app/layout/index.js index d674a1fdd3..a00baa5199 100644 --- a/ui/src/app/layout/index.js +++ b/ui/src/app/layout/index.js @@ -30,9 +30,9 @@ import thingsboardSideMenu from '../components/side-menu.directive'; import thingsboardNavTree from '../components/nav-tree.directive'; import thingsboardDashboardAutocomplete from '../components/dashboard-autocomplete.directive'; import thingsboardKvMap from '../components/kv-map.directive'; -import thingsboardGatewayConfig from '../components/gateWay/gateway-config.directive'; -import thingsboardGatewayConfigSelect from '../components/gateWay/gateway-config-select.directive'; -import thingsboardGatewayForm from '../components/gateWay/gateway-form.directive'; +import thingsboardGatewayConfig from '../components/gateway/gateway-config.directive'; +import thingsboardGatewayConfigSelect from '../components/gateway/gateway-config-select.directive'; +import thingsboardGatewayForm from '../components/gateway/gateway-form.directive'; import thingsboardJsonObjectEdit from '../components/json-object-edit.directive'; import thingsboardJsonContent from '../components/json-content.directive'; diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 5acd0f81e5..48bff7d6cd 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -1126,56 +1126,78 @@ "function": "Function" }, "gateway": { - "key": "Key configuration", - "value": "Value configuration", - "remove-entry": "Remove configuration", "add-entry": "Add configuration", - "no-data": "No configurations", - "gateway-required": "Gateway is required.", - "gateway-name": "Gateway name", + "connector-add": "Add new connector", + "connector-enabled": "Enable connector", + "connector-name": "Connector name", + "connector-name-required": "Connector name is required.", + "connector-type": "Connector type", + "connector-type-required": "Connector type is required.", + "connectors": "Connectors configuration", "create-new-gateway": "Create a new gateway", "create-new-gateway-text": "Are you sure you want create a new gateway with name: '{{gatewayName}}'?", + "delete": "Delete configuration", + "download-tip": "Download configuration file", + "gateway": "Gateway", + "gateway-exists": "Device with same name is already exists.", + "gateway-name": "Gateway name", + "gateway-name-required": "Gateway name is required.", + "gateway-saved": "Gateway configuration successfully saved.", + "json-parse": "Not valid JSON.", + "json-required": "Field cannot be empty.", + "no-connectors": "No connectors", + "no-data": "No configurations", + "no-gateway-found": "No gateway found.", "no-gateway-matching": " '{{item}}' not found.", - "thingsboard": "ThingsBoard", - "connectors": "Connectors configuration", - "thingsboard-host": "ThingsBoard Host", - "thingsboard-port": "ThingsBoard Port", + "path-logs": "Path to log files", + "path-logs-required": "Path is required.", + "remote": "Remote configuration", + "remote-logging-level": "Logging level", + "remove-entry": "Remove configuration", + "save-tip": "Save configuration file", "security-type": "Security type", - "tls-path-ca-certificate": "Path to CA certificate on gateway:", - "tls-path-private-key": "Path to private key on gateway:", - "tls-path-client-certificate": "Path to client certificate on gateway:", + "security-types": { + "access-token": "Access Token", + "tls": "TLS" + }, "storage": "Storage", + "storage-max-file-records": "Maximum records in file", + "storage-max-files": "Maximum number of files", + "storage-max-files-min": "Minimum number is 1.", + "storage-max-files-pattern": "Number is not valid.", + "storage-max-files-required": "Number is required.", + "storage-max-records": "Maximum records in storage", + "storage-max-records-min": "Minimum number of records is 1.", + "storage-max-records-pattern": "Number is not valid.", + "storage-max-records-required": "Maximum records is required.", + "storage-pack-size": "Maximum event pack size", + "storage-pack-size-min": "Minimum number is 1.", + "storage-pack-size-pattern": "Number is not valid.", + "storage-pack-size-required": "Maximum event pack size is required.", + "storage-path": "Storage path", + "storage-path-required": "Storage path is required.", "storage-type": "Storage type", - "storage-read-time": "Read records per time:", - "storage-max-time": "Maximum records per time:", - "storage-max-files": "Maximum files:", - "storage-data-path": "Data folder path:", - "download-tip": "Download configuration file", - "save-tip": "Save configuration file", - "remote-tip": "Allow remote configuration", - "remote": "Remote configuration", - "remote-logging-level": "Logging level", - "remote-logging-path-logs": "Path to logs", - "connector-type": "Connector type", - "update-config": "Add/update config JSON", - "delete": "Delete configuration", - "title-connectors-json": "Connector {{typeName}} configuration", - "json-required": "Config json is required for gateway config.", - "json-parse": "Unable to parse config json for gateway config.", + "storage-types": { + "file-storage": "File storage", + "memory-storage": "Memory storage" + }, + "thingsboard": "ThingsBoard", + "thingsboard-host": "ThingsBoard host", + "thingsboard-host-required": "Host is required.", + "thingsboard-port": "ThingsBoard port", + "thingsboard-port-max": "Maximum port number is 65535.", + "thingsboard-port-min": "Minimum port number is 1.", + "thingsboard-port-pattern": "Port is not valid.", + "thingsboard-port-required": "Port is required.", "tidy": "Tidy", "tidy-tip": "Tidy config JSON", - "transformer-json-config": "JSON for the config*", + "title-connectors-json": "Connector {{typeName}} configuration", + "tls-path-ca-certificate": "Path to CA certificate on gateway", + "tls-path-client-certificate": "Path to client certificate on gateway", + "tls-path-private-key": "Path to private key on gateway", "toggle-fullscreen": "Toggle fullscreen", - "add-connectors": "Add new connectors", - "no-connectors": "No connectors", - "enabled": "Enabled", - "name": "Name", - "no-gateway-found": "No gateway found.", - "gateway": "Gateway", - "keyval-save-err": "Save config error", - "keyval-name-err": "Please add Name", - "keyval-type-err": "Please add Connector type", - "keyval-config-err": "Please add configuration JSON" + "transformer-json-config": "Configuration JSON*", + "update-config": "Add/update configuration JSON" }, "grid": { "delete-item-title": "Are you sure you want to delete this item?",