Feature/gateway remote configuration (#2627)

* new widget for gateway with the last telemetry type

* add isStateForm for the last telemetry type

* add config update save

* update thingboard yaml

* remove update thingboard yaml

* add new widget to gateway_widgets.json

* delete state gateway

* delete state gateway

* Revert "delete state gateway"

This reverts commit d8024ead

* change yml

* edit name isReadOnly

* fix bug  isReadOnly

* [Gateway remote configuration] Changed default logs.conf file

Co-authored-by: nick <nick.@avalr.com.ua>
This commit is contained in:
Ilya Barkov 2020-04-20 16:20:33 +03:00 committed by GitHub
parent 2a2a0f9caf
commit 149ec2804b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 153 additions and 66 deletions

File diff suppressed because one or more lines are too long

View File

@ -606,13 +606,29 @@ export default angular.module('thingsboard.types', [])
value: "modbus", value: "modbus",
name: "Modbus" name: "Modbus"
}, },
opc_ua: { opcua: {
value: "opcua", value: "opcua",
name: "OPC-UA" name: "OPC-UA"
}, },
ble: { ble: {
value: "ble", value: "ble",
name: "BLE" name: "BLE"
},
request: {
value: "request",
name: "Request"
},
can: {
value: "can",
name: "CAN"
},
bacnet: {
value: "bacnet",
name: "BACnet"
},
custom: {
value: "custom",
name: "Custom"
} }
}, },
gatewayLogLevel: { gatewayLogLevel: {

View File

@ -37,7 +37,8 @@ function GatewayConfig() {
disabled: '=ngDisabled', disabled: '=ngDisabled',
gatewayConfig: '=', gatewayConfig: '=',
changeAlignment: '=', changeAlignment: '=',
theForm: '=' theForm: '=',
isReadOnly: '='
}, },
controller: GatewayConfigController, controller: GatewayConfigController,
controllerAs: 'vm', controllerAs: 'vm',
@ -83,6 +84,10 @@ function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window,
multiple: true, multiple: true,
}).then(function (config) { }).then(function (config) {
if (config && index > -1) { if (config && index > -1) {
console.log(config); //eslint-disable-line
if (!angular.equals(vm.gatewayConfig[index].config, config)) {
$scope.gatewayConfiguration.$setDirty();
}
vm.gatewayConfig[index].config = config; vm.gatewayConfig[index].config = config;
} }
}); });

View File

@ -18,7 +18,7 @@
<section name="gatewayConfig" layout="column" class="gateway-config"> <section name="gatewayConfig" layout="column" class="gateway-config">
<section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index"> <section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index">
<div layout="column" layout-align="center start" class="gateway-config-row"> <div layout="column" layout-align="center start" class="gateway-config-row">
<md-switch ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)" <md-switch ng-disabled="vm.isReadOnly" ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)"
aria-label="{{ 'gateway.connector-enabled' | translate }}"> aria-label="{{ 'gateway.connector-enabled' | translate }}">
</md-switch> </md-switch>
</div> </div>
@ -26,7 +26,7 @@
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.connector-type' | translate }}</label> <label>{{'gateway.connector-type' | translate }}</label>
<md-select name="connectorType" <md-select ng-disabled="vm.isReadOnly" name="connectorType"
ng-change="vm.changeConnectorType(connector)" ng-change="vm.changeConnectorType(connector)"
aria-label="{{ 'gateway.gateway.connector-type' | translate }}" aria-label="{{ 'gateway.gateway.connector-type' | translate }}"
ng-model="connector.configType" required> ng-model="connector.configType" required>
@ -39,7 +39,7 @@
</div> </div>
</md-input-container> </md-input-container>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<input placeholder="{{'gateway.connector-name' | translate }}" <input ng-disabled="vm.isReadOnly" placeholder="{{'gateway.connector-name' | translate }}"
ng-model-options="{ updateOn: 'blur' }" ng-model-options="{ updateOn: 'blur' }"
ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/> ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/>
<div ng-messages="vm.theForm.connectorName.$error"> <div ng-messages="vm.theForm.connectorName.$error">
@ -49,7 +49,7 @@
</div> </div>
<div layout="row" layout-align="end center" class="action-buttons" <div layout="row" layout-align="end center" class="action-buttons"
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-button class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)" <md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)"
aria-label="{{ 'gateway.update-config' | translate }}" aria-label="{{ 'gateway.update-config' | translate }}"
ng-class="{'md-warn': vm.validateJSON(connector.config)}"> ng-class="{'md-warn': vm.validateJSON(connector.config)}">
<md-icon class="material-icons">more_horiz</md-icon> <md-icon class="material-icons">more_horiz</md-icon>
@ -57,7 +57,7 @@
{{ 'gateway.update-config' | translate }} {{ 'gateway.update-config' | translate }}
</md-tooltip> </md-tooltip>
</md-button> </md-button>
<md-button class="md-icon-button md-mini" ng-click="vm.removeConnector($index)" <md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.removeConnector($index)"
aria-label="{{ 'gateway.delete' | translate }}"> aria-label="{{ 'gateway.delete' | translate }}">
<md-icon class="material-icons">close</md-icon> <md-icon class="material-icons">close</md-icon>
<md-tooltip md-direction="top"> <md-tooltip md-direction="top">
@ -70,7 +70,7 @@
layout-align="center center" ng-class="{'disabled': vm.disabled}" layout-align="center center" ng-class="{'disabled': vm.disabled}"
class="no-data-found" translate>{{'gateway.no-connectors'}}</span> class="no-data-found" translate>{{'gateway.no-connectors'}}</span>
<div> <div>
<md-button class="md-raised" ng-click="vm.addNewConnector()" <md-button ng-show="!vm.isReadOnly" class="md-raised" ng-click="vm.addNewConnector()"
aria-label="{{ 'gateway.connector-add' | translate }}"> aria-label="{{ 'gateway.connector-add' | translate }}">
<md-tooltip md-direction="top"> <md-tooltip md-direction="top">
{{ 'gateway.connector-add' | translate }} {{ 'gateway.connector-add' | translate }}

View File

@ -31,11 +31,15 @@ function GatewayForm() {
scope: true, scope: true,
bindToController: { bindToController: {
formId: '=', formId: '=',
ctx: '=' ctx: '=',
isStateForm: '=',
deviceName: '=',
isReadOnly: '=',
isState: '='
}, },
controller: GatewayFormController, controller: GatewayFormController,
controllerAs: 'vm', controllerAs: 'vm',
templateUrl: gatewayFormTemplate templateUrl: gatewayFormTemplate,
}; };
} }
@ -47,10 +51,11 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
const configurationAttribute = "configuration"; const configurationAttribute = "configuration";
const remoteLoggingLevelAttribute = "RemoteLoggingLevel"; 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"'; 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=converterHandler}}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.types = types;
vm.deviceNameForm = (vm.deviceName) ? vm.deviceName : null;
vm.idForm = Math.random().toString(36).replace(/^0\.[0-9]*/, '');
vm.configurations = { vm.configurations = {
gateway: '', gateway: '',
host: $document[0].domain, host: $document[0].domain,
@ -74,7 +79,6 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
let archiveFileName = ''; let archiveFileName = '';
let gatewayNameExists = ''; let gatewayNameExists = '';
let successfulSaved = ''; let successfulSaved = '';
vm.securityTypes = [{ vm.securityTypes = [{
name: 'gateway.security-types.access-token', name: 'gateway.security-types.access-token',
value: 'accessToken' value: 'accessToken'
@ -92,13 +96,18 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
}]; }];
$scope.$watch('vm.ctx', function () { $scope.$watch('vm.ctx', function () {
if (vm.ctx ) { if (vm.ctx) {
vm.isStateForm = $scope.isStateForm;
vm.settings = vm.ctx.settings; vm.settings = vm.ctx.settings;
vm.widgetConfig = vm.ctx.widgetConfig; vm.widgetConfig = vm.ctx.widgetConfig;
initializeConfig(); if (vm.ctx.datasources && vm.ctx.datasources.length) {
vm.deviceNameForm = vm.ctx.datasources[0].name;
}
} }
initializeConfig();
}); });
$scope.$on('gateway-form-resize', function (event, formId) { $scope.$on('gateway-form-resize', function (event, formId) {
if (vm.formId == formId) { if (vm.formId == formId) {
updateWidgetDisplaying(); updateWidgetDisplaying();
@ -106,21 +115,34 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
}); });
function updateWidgetDisplaying() { function updateWidgetDisplaying() {
vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); if (vm.ctx) {
vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425);
}
} }
function initWidgetSettings() { function initWidgetSettings() {
let widgetTitle; let widgetTitle;
if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) { if (vm.settings) {
widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle); vm.isReadOnlyForm = (vm.settings.readOnly) ? vm.settings.readOnly : false;
if (vm.settings.gatewayTitle && vm.settings.gatewayTitle.length) {
widgetTitle = utils.customTranslation(vm.settings.gatewayTitle, vm.settings.gatewayTitle);
}
} else { } else {
vm.isReadOnlyForm = false;
widgetTitle = $translate.instant('gateway.gateway'); widgetTitle = $translate.instant('gateway.gateway');
} }
vm.ctx.widgetTitle = widgetTitle; if (vm.ctx) {
vm.ctx.widgetTitle = widgetTitle;
}
archiveFileName = vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration'; archiveFileName = vm.settings && vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration';
gatewayNameExists = utils.customTranslation(vm.settings.gatewayNameExists, vm.settings.gatewayNameExists) || $translate.instant('gateway.gateway-exists'); if (vm.settings) {
successfulSaved = utils.customTranslation(vm.settings.successfulSave, vm.settings.successfulSave) || $translate.instant('gateway.gateway-saved'); 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');
} else {
gatewayNameExists = $translate.instant('gateway.gateway-exists');
successfulSaved = $translate.instant('gateway.gateway-saved');
}
} }
function initializeConfig() { function initializeConfig() {
@ -129,6 +151,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
getGatewaysList(true); getGatewaysList(true);
} }
vm.getAccessToken = (deviceId) => { vm.getAccessToken = (deviceId) => {
if (deviceId.id) { if (deviceId.id) {
getDeviceCredentials(deviceId.id); getDeviceCredentials(deviceId.id);
@ -152,15 +175,15 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
deviceService.findByName(deviceObj.name, {ignoreErrors: true}) deviceService.findByName(deviceObj.name, {ignoreErrors: true})
.then( .then(
function () { function () {
toast.showError(gatewayNameExists, angular.element('.gateway-form'),'top left'); toast.showError(gatewayNameExists, angular.element('.gateway-form'), 'top left');
}, },
function () { function () {
if(vm.settings.gatewayType && vm.settings.gatewayType.length){ if (vm.settings.gatewayType && vm.settings.gatewayType.length) {
deviceObj.type = vm.settings.gatewayType; deviceObj.type = vm.settings.gatewayType;
} }
deviceService.saveDevice(deviceObj).then( deviceService.saveDevice(deviceObj).then(
(device) => { (device) => {
getDeviceCredentials(device.id.id).then(() =>{ getDeviceCredentials(device.id.id).then(() => {
getGatewaysList(); getGatewaysList();
}); });
} }
@ -173,8 +196,8 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value), saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value),
saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value), saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value),
saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value) saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value)
]).then(() =>{ ]).then(() => {
toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'),'top left'); toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'), 'top left');
}) })
}; };
@ -238,7 +261,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n';
} }
config += 'connectors:\n'; config += 'connectors:\n';
for(let i = 0; i < vm.configurations.connectors.length; i++){ for (let i = 0; i < vm.configurations.connectors.length; i++) {
if (vm.configurations.connectors[i].enabled) { if (vm.configurations.connectors[i].enabled) {
config += ' -\n'; config += ' -\n';
config += ' name: ' + vm.configurations.connectors[i].name + '\n'; config += ' name: ' + vm.configurations.connectors[i].name + '\n';
@ -250,7 +273,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
} }
function generateConfigConnectorFiles(fileZipAdd) { function generateConfigConnectorFiles(fileZipAdd) {
for(let i = 0; i < vm.configurations.connectors.length; i++){ for (let i = 0; i < vm.configurations.connectors.length; i++) {
if (vm.configurations.connectors[i].enabled) { if (vm.configurations.connectors[i].enabled) {
fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config); fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config);
} }
@ -276,7 +299,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
function gatewayMainConfigJSON() { function gatewayMainConfigJSON() {
let configuration = {}; let configuration = {};
let thingsBoard = {}; let thingsBoard = {};
thingsBoard.host = vm.configurations.host; thingsBoard.host = vm.configurations.host;
thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration;
@ -325,10 +348,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
} }
function gatewayConnectorConfigJSON(gatewayConfiguration) { function gatewayConnectorConfigJSON(gatewayConfiguration) {
for(let i = 0; i < vm.configurations.connectors.length; i++){ for (let i = 0; i < vm.configurations.connectors.length; i++) {
if (vm.configurations.connectors[i].enabled) { if (vm.configurations.connectors[i].enabled) {
let typeConnector = vm.configurations.connectors[i].configType; let typeConnector = vm.configurations.connectors[i].configType;
if(!angular.isArray(gatewayConfiguration[typeConnector])){ if (!angular.isArray(gatewayConfiguration[typeConnector])) {
gatewayConfiguration[typeConnector] = []; gatewayConfiguration[typeConnector] = [];
} }
@ -343,7 +366,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
function getDraftConnectorJSON() { function getDraftConnectorJSON() {
let draftConnector = {}; let draftConnector = {};
for(let i = 0; i < vm.configurations.connectors.length; i++){ for (let i = 0; i < vm.configurations.connectors.length; i++) {
if (!vm.configurations.connectors[i].enabled) { if (!vm.configurations.connectors[i].enabled) {
let connector = { let connector = {
connector: vm.configurations.connectors[i].configType, connector: vm.configurations.connectors[i].configType,
@ -362,7 +385,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
const device = devices[i]; const device = devices[i];
if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { if (device.additionalInfo !== null && device.additionalInfo.gateway === true) {
vm.gateways.push(device); vm.gateways.push(device);
if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) { if (vm.deviceNameForm && firstInit && vm.gateways.length && device.name === vm.deviceNameForm) {
vm.configurations.gateway = device;
vm.getAccessToken(device.id);
} else if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) {
vm.configurations.gateway = device; vm.configurations.gateway = device;
vm.getAccessToken(device.id); vm.getAccessToken(device.id);
} }
@ -385,7 +411,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
for (let connectorType in keyValue) { for (let connectorType in keyValue) {
let name = "No name"; let name = "No name";
if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) { if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) {
name = keyValue[connectorType].name ; name = keyValue[connectorType].name;
} }
let connector = { let connector = {
enabled: true, enabled: true,

View File

@ -17,30 +17,36 @@
--> -->
<md-content md-scroll-y layout="column" class="gateway-form"> <md-content md-scroll-y layout="column" class="gateway-form">
<form name="gatewayConfiguration"> <form name="gatewayConfiguration">
<md-expansion-panel-group> <md-expansion-panel-group>
<md-expansion-panel md-component-id="thingsboardPanelId"> <md-expansion-panel md-component-id="{{vm.idForm}}thingsboardPanelId">
<md-expansion-panel-collapsed> <md-expansion-panel-collapsed>
<div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-collapsed> </md-expansion-panel-collapsed>
<md-expansion-panel-expanded> <md-expansion-panel-expanded>
<md-expansion-panel-header ng-click="vm.collapsePanel('thingsboardPanelId')"> <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'thingsboardPanelId')">
<div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-header> </md-expansion-panel-header>
<md-expansion-panel-content> <md-expansion-panel-content>
<tb-gateway-config-select tb-required="true" <tb-gateway-config-select ng-if="!vm.isStateForm"
tb-required="true"
ng-model="vm.configurations.gateway" ng-model="vm.configurations.gateway"
the-form="gatewayConfiguration" the-form="gatewayConfiguration"
gateway-list="vm.gateways" gateway-list="vm.gateways"
get_access_token="vm.getAccessToken" get_access_token="vm.getAccessToken"
create-device="vm.createDevice"> create-device="vm.createDevice">
</tb-gateway-config-select> </tb-gateway-config-select>
<md-input-container ng-if="vm.isStateForm"
class="md-block">
<label>{{'gateway.gateway-name' | translate }}</label>
<input ng-disabled="true" type="text" ng-model="vm.configurations.gateway.name" name="gatewayName"/>
</md-input-container>
<md-input-container class="md-block"> <md-input-container class="md-block">
<label>{{'gateway.security-type' | translate }}</label> <label>{{'gateway.security-type' | translate }}</label>
<md-select name="securityType" ng-model="vm.configurations.securityType" required> <md-select ng-disabled="vm.isReadOnlyForm" name="securityType" ng-model="vm.configurations.securityType" required>
<md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value"> <md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value">
{{securityType.name | translate}} {{securityType.name | translate}}
</md-option> </md-option>
@ -50,14 +56,14 @@
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{ 'gateway.thingsboard-host' | translate }}</label> <label>{{ 'gateway.thingsboard-host' | translate }}</label>
<input type="text" name="host" ng-model="vm.configurations.host" required> <input ng-disabled="vm.isReadOnlyForm" type="text" name="host" ng-model="vm.configurations.host" required>
<div ng-messages="gatewayConfiguration.host.$error"> <div ng-messages="gatewayConfiguration.host.$error">
<div ng-message="required" translate>gateway.thingsboard-host-required</div> <div ng-message="required" translate>gateway.thingsboard-host-required</div>
</div> </div>
</md-input-container> </md-input-container>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{ 'gateway.thingsboard-port' | translate }}</label> <label>{{ 'gateway.thingsboard-port' | translate }}</label>
<input type="number" min="1" max="65535" ng-pattern="/^-?[0-9]+$/" name="port" <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" max="65535" ng-pattern="/^-?[0-9]+$/" name="port"
ng-model="vm.configurations.port" required> ng-model="vm.configurations.port" required>
<div ng-messages="gatewayConfiguration.port.$error"> <div ng-messages="gatewayConfiguration.port.$error">
<div ng-message="required" translate>gateway.thingsboard-port-required</div> <div ng-message="required" translate>gateway.thingsboard-port-required</div>
@ -70,18 +76,18 @@
<div ng-if="vm.configurations.securityType=='tls'"> <div ng-if="vm.configurations.securityType=='tls'">
<md-input-container class="md-block security-type"> <md-input-container class="md-block security-type">
<label>{{'gateway.tls-path-ca-certificate' | translate }}</label> <label>{{'gateway.tls-path-ca-certificate' | translate }}</label>
<input type="text" ng-model="vm.configurations.caCertPath" name="caCertPath" /> <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.caCertPath" name="caCertPath"/>
</md-input-container> </md-input-container>
<md-input-container class="md-block"> <md-input-container class="md-block">
<label>{{'gateway.tls-path-private-key' | translate }}</label> <label>{{'gateway.tls-path-private-key' | translate }}</label>
<input type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath" /> <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath"/>
</md-input-container> </md-input-container>
<md-input-container class="md-block"> <md-input-container class="md-block">
<label>{{'gateway.tls-path-client-certificate' | translate }}</label> <label>{{'gateway.tls-path-client-certificate' | translate }}</label>
<input type="text" ng-model="vm.configurations.certPath" name="certPath" /> <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.certPath" name="certPath"/>
</md-input-container> </md-input-container>
</div> </div>
<md-checkbox ng-model="vm.configurations.remoteConfiguration" <md-checkbox ng-show="!vm.isReadOnlyForm" ng-model="vm.configurations.remoteConfiguration"
name="remoteConfiguration" name="remoteConfiguration"
aria-label="{{ 'gateway.remote-remote' | translate }}"> aria-label="{{ 'gateway.remote-remote' | translate }}">
{{ 'gateway.remote' | translate }} {{ 'gateway.remote' | translate }}
@ -90,7 +96,7 @@
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block md-select-container" flex> <md-input-container class="md-block md-select-container" flex>
<label>{{'gateway.remote-logging-level' | translate }}</label> <label>{{'gateway.remote-logging-level' | translate }}</label>
<md-select name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel"> <md-select ng-disabled="vm.isReadOnlyForm" name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel">
<md-option ng-repeat="logLevel in vm.types.gatewayLogLevel" <md-option ng-repeat="logLevel in vm.types.gatewayLogLevel"
ng-value="logLevel" ng-selected="$index === 5"> ng-value="logLevel" ng-selected="$index === 5">
{{logLevel}} {{logLevel}}
@ -99,7 +105,7 @@
</md-input-container> </md-input-container>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.path-logs' | translate }}</label> <label>{{'gateway.path-logs' | translate }}</label>
<input type="text" ng-model="vm.configurations.remoteLoggingPathToLogs" <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.remoteLoggingPathToLogs"
name="remoteLoggingPathToLogs" required> name="remoteLoggingPathToLogs" required>
<div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error"> <div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error">
<div ng-message="required" translate>gateway.path-logs-required</div> <div ng-message="required" translate>gateway.path-logs-required</div>
@ -109,14 +115,14 @@
</md-expansion-panel-content> </md-expansion-panel-content>
</md-expansion-panel-expanded> </md-expansion-panel-expanded>
</md-expansion-panel> </md-expansion-panel>
<md-expansion-panel md-component-id="storagePanelId"> <md-expansion-panel md-component-id="{{vm.idForm}}storagePanelId">
<md-expansion-panel-collapsed> <md-expansion-panel-collapsed>
<div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-collapsed> </md-expansion-panel-collapsed>
<md-expansion-panel-expanded> <md-expansion-panel-expanded>
<md-expansion-panel-header ng-click="vm.collapsePanel('storagePanelId')"> <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'storagePanelId')">
<div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
@ -124,18 +130,17 @@
<md-expansion-panel-content> <md-expansion-panel-content>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.storage-type' | translate }}</label> <label>{{'gateway.storage-type' | translate }}</label>
<md-select required ng-model="vm.configurations.storageType"> <md-select ng-disabled="vm.isReadOnlyForm" required ng-model="vm.configurations.storageType">
<md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value"> <md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value">
{{storageType.name | translate}} {{storageType.name | translate}}
</md-option> </md-option>
</md-select> </md-select>
</md-input-container> </md-input-container>
<div layout="row" class="gateway-form-row" <div layout="row" class="gateway-form-row"
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.storage-pack-size' | translate }}</label> <label>{{'gateway.storage-pack-size' | translate }}</label>
<input type="number" min="1" name="readRecordsCount" ng-pattern="/^-?[0-9]+$/" <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="readRecordsCount" ng-pattern="/^-?[0-9]+$/"
ng-model='vm.configurations.readRecordsCount' required/> ng-model='vm.configurations.readRecordsCount' required/>
<div ng-messages="gatewayConfiguration.readRecordsCount.$error"> <div ng-messages="gatewayConfiguration.readRecordsCount.$error">
<div ng-message="required" translate>gateway.storage-pack-size-required</div> <div ng-message="required" translate>gateway.storage-pack-size-required</div>
@ -143,10 +148,9 @@
<div ng-message="pattern" translate>gateway.storage-pack-size-pattern</div> <div ng-message="pattern" translate>gateway.storage-pack-size-pattern</div>
</div> </div>
</md-input-container> </md-input-container>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label translate>{{ vm.configurations.storageType !== 'fileStorage' ? 'gateway.storage-max-records' : 'gateway.storage-max-file-records' }}</label> <label translate>{{ vm.configurations.storageType !== 'fileStorage' ? 'gateway.storage-max-records' : 'gateway.storage-max-file-records' }}</label>
<input type="number" min="1" name="maxRecordsCount" ng-pattern="/^-?[0-9]+$/" <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="maxRecordsCount" ng-pattern="/^-?[0-9]+$/"
ng-model='vm.configurations.maxRecordsCount' required/> ng-model='vm.configurations.maxRecordsCount' required/>
<div ng-messages="gatewayConfiguration.maxRecordsCount.$error"> <div ng-messages="gatewayConfiguration.maxRecordsCount.$error">
<div ng-message="required" translate>gateway.storage-max-records-required</div> <div ng-message="required" translate>gateway.storage-max-records-required</div>
@ -155,13 +159,12 @@
</div> </div>
</md-input-container> </md-input-container>
</div> </div>
<div layout="row" class="gateway-form-row" <div layout="row" class="gateway-form-row"
ng-if="vm.configurations.storageType == 'fileStorage'" ng-if="vm.configurations.storageType == 'fileStorage'"
ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.storage-max-files' | translate }}</label> <label>{{'gateway.storage-max-files' | translate }}</label>
<input type="number" min="1" name="maxFilesCount" ng-pattern="/^-?[0-9]+$/" <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="maxFilesCount" ng-pattern="/^-?[0-9]+$/"
ng-model='vm.configurations.maxFilesCount' required/> ng-model='vm.configurations.maxFilesCount' required/>
<div ng-messages="gatewayConfiguration.maxFilesCount.$error"> <div ng-messages="gatewayConfiguration.maxFilesCount.$error">
<div ng-message="required" translate>gateway.storage-max-files-required</div> <div ng-message="required" translate>gateway.storage-max-files-required</div>
@ -169,10 +172,9 @@
<div ng-message="pattern" translate>gateway.storage-max-files-pattern</div> <div ng-message="pattern" translate>gateway.storage-max-files-pattern</div>
</div> </div>
</md-input-container> </md-input-container>
<md-input-container class="md-block" flex> <md-input-container class="md-block" flex>
<label>{{'gateway.storage-path' | translate }}</label> <label>{{'gateway.storage-path' | translate }}</label>
<input type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath' <input ng-disabled="vm.isReadOnlyForm" type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath'
required/> required/>
<div ng-messages="gatewayConfiguration.dataFolderPath.$error"> <div ng-messages="gatewayConfiguration.dataFolderPath.$error">
<div ng-message="required" translate>gateway.storage-path-required</div> <div ng-message="required" translate>gateway.storage-path-required</div>
@ -182,14 +184,14 @@
</md-expansion-panel-content> </md-expansion-panel-content>
</md-expansion-panel-expanded> </md-expansion-panel-expanded>
</md-expansion-panel> </md-expansion-panel>
<md-expansion-panel md-component-id="connectorsPanelId"> <md-expansion-panel md-component-id="{{vm.idForm}}connectorsPanelId">
<md-expansion-panel-collapsed> <md-expansion-panel-collapsed>
<div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-collapsed> </md-expansion-panel-collapsed>
<md-expansion-panel-expanded> <md-expansion-panel-expanded>
<md-expansion-panel-header ng-click="vm.collapsePanel('connectorsPanelId')"> <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'connectorsPanelId')">
<div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div>
<span flex></span> <span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon> <md-expansion-panel-icon></md-expansion-panel-icon>
@ -198,13 +200,14 @@
<tb-gateway-config <tb-gateway-config
gateway-config="vm.configurations.connectors" gateway-config="vm.configurations.connectors"
the-form="gatewayConfiguration" the-form="gatewayConfiguration"
change-alignment="vm.changeAlignment"> change-alignment="vm.changeAlignment"
is-read-only="vm.isReadOnlyForm">
</tb-gateway-config> </tb-gateway-config>
</md-expansion-panel-content> </md-expansion-panel-content>
</md-expansion-panel-expanded> </md-expansion-panel-expanded>
</md-expansion-panel> </md-expansion-panel>
</md-expansion-panel-group> </md-expansion-panel-group>
<section layout="row" layout-align="end center" class="form-action-buttons"> <section ng-show="!vm.isReadOnlyForm" layout="row" layout-align="end center" class="form-action-buttons">
<md-button class="md-primary md-raised" <md-button class="md-primary md-raised"
ng-click="vm.exportConfig()" ng-click="vm.exportConfig()"
ng-if="!vm.configurations.remoteConfiguration" ng-if="!vm.configurations.remoteConfiguration"
@ -213,14 +216,14 @@
{{'action.download' | translate }} {{'action.download' | translate }}
<md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip> <md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip>
</md-button> </md-button>
<md-button class="md-primary md-raised" <md-button class="md-primary md-raised"
ng-click="vm.saveAttributeConfig()" ng-click="vm.saveAttributeConfig()"
ng-if="vm.configurations.remoteConfiguration" ng-if="vm.configurations.remoteConfiguration"
ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty"
aria-label="{{ 'gateway.save-tip' | translate }}"> aria-label="{{ 'gateway.save-tip' | translate }}">
{{'action.save' | translate }} {{'action.save' | translate }}
<md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}</md-tooltip> <md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}
</md-tooltip>
</md-button> </md-button>
</section> </section>
</form> </form>

View File

@ -1201,7 +1201,12 @@
"tls-path-private-key": "Path to private key on gateway", "tls-path-private-key": "Path to private key on gateway",
"toggle-fullscreen": "Toggle fullscreen", "toggle-fullscreen": "Toggle fullscreen",
"transformer-json-config": "Configuration JSON*", "transformer-json-config": "Configuration JSON*",
"update-config": "Add/update configuration JSON" "update-config": "Add/update configuration JSON",
"state-title": "Gateway state",
"show-config-tip": "Show gateway configuration",
"title-show-config": "Show gateway configuration",
"read-only": "Read only",
"read-write": ""
}, },
"grid": { "grid": {
"delete-item-title": "Are you sure you want to delete this item?", "delete-item-title": "Are you sure you want to delete this item?",