-
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 @@
+
+
+
+
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?",