diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 52a31314e2..f268c586ba 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -179,10 +179,10 @@
- -
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 80aa438e2d..235658a374 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -366,6 +366,7 @@ export class DeviceWizardDialogComponent extends mergeMap( (deviceCredentials) => { const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential}; + this.deviceCredentials = deviceCredentialsValue; return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe( catchError(e => { this.addDeviceWizardStepper.selectedIndex = 1; @@ -387,7 +388,6 @@ export class DeviceWizardDialogComponent extends }) ); } - return of(device); } allValid(): boolean { diff --git a/ui-ngx/src/app/shared/components/device/gateway-configuration.component.html b/ui-ngx/src/app/shared/components/device/gateway-configuration.component.html index fb38c63a90..445d37d6ee 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-configuration.component.html +++ b/ui-ngx/src/app/shared/components/device/gateway-configuration.component.html @@ -131,9 +131,6 @@ fxFlex="calc(50%-15px)" class="mat-block tb-value-type"> security.password - - {{'security.password-required' | translate}} - info_outlined @@ -466,14 +463,14 @@
-
+
{{ 'gateway.grpc' | translate }} {{ 'gateway.permit-without-calls' | translate }} - + gateway.server-port @@ -489,7 +486,7 @@ {{'gateway.thingsboard-port-pattern' | translate }} - + gateway.grpc-keep-alive-timeout @@ -502,7 +499,7 @@ {{'gateway.grpc-keep-alive-timeout-pattern' | translate }} - + gateway.grpc-keep-alive @@ -515,7 +512,7 @@ {{'gateway.grpc-keep-alive-pattern' | translate }} - + gateway.grpc-min-time-between-pings @@ -528,7 +525,7 @@ {{'gateway.grpc-min-time-between-pings-pattern' | translate }} - + gateway.grpc-max-pings-without-data @@ -541,7 +538,7 @@ {{'gateway.grpc-max-pings-without-data-pattern' | translate }} - + gateway.grpc-min-ping-interval-without-data @@ -592,11 +589,11 @@ {{'gateway.hints.commands' | translate}}
-
- - + + gateway.statistics.attribute-name info_outlined - + gateway.statistics.timeout info_outlined - + gateway.statistics.command ([ [LocalLogsConfigs.tb_connection, 'TB Connection'], [LocalLogsConfigs.storage, 'Storage'], [LocalLogsConfigs.extension, 'Extension'] -]) +]); export const logSavingPeriodTranslations = new Map( [ @@ -213,6 +213,18 @@ export class GatewayConfigurationComponent implements OnInit { }) }); + this.gatewayConfigGroup.get('thingsboard.security').valueChanges.subscribe(security => { + if (security.username) { + this.clientIdUserNameFieldsToggle('clientId'); + } else if (security.clientId) { + this.clientIdUserNameFieldsToggle('username'); + } else if (!security.username && !security.clientId) { + this.clientIdUserNameFieldsToggle(); + } + }); + + this.toggleRpcFields(false); + this.gatewayConfigGroup.get('thingsboard.remoteConfiguration').valueChanges.subscribe(enabled => { if (!enabled) { this.openConfigurationConfirmDialog(); @@ -239,6 +251,10 @@ export class GatewayConfigurationComponent implements OnInit { } }); + this.gatewayConfigGroup.get('grpc.enabled').valueChanges.subscribe(value => { + this.toggleRpcFields(value); + }); + const securityGroup = this.gatewayConfigGroup.get('thingsboard.security') as FormGroup; securityGroup.get('type').valueChanges.subscribe(type => { this.removeAllSecurityValidators(); @@ -262,15 +278,15 @@ export class GatewayConfigurationComponent implements OnInit { securityGroup.get('clientId').updateValueAndValidity(); securityGroup.get('username').addValidators([Validators.required]); securityGroup.get('username').updateValueAndValidity(); - securityGroup.get('password').addValidators([Validators.required]); - securityGroup.get('password').updateValueAndValidity(); + // securityGroup.get('password').addValidators([Validators.required]); + // securityGroup.get('password').updateValueAndValidity(); } securityGroup.updateValueAndValidity(); }); - securityGroup.get('caCert').valueChanges.subscribe(_ => this.cd.detectChanges()) - securityGroup.get('privateKey').valueChanges.subscribe(_ => this.cd.detectChanges()) - securityGroup.get('cert').valueChanges.subscribe(_ => this.cd.detectChanges()) + securityGroup.get('caCert').valueChanges.subscribe(_ => this.cd.detectChanges()); + securityGroup.get('privateKey').valueChanges.subscribe(_ => this.cd.detectChanges()); + securityGroup.get('cert').valueChanges.subscribe(_ => this.cd.detectChanges()); const storageGroup = this.gatewayConfigGroup.get('storage') as FormGroup; storageGroup.get('type').valueChanges.subscribe(type => { @@ -304,7 +320,8 @@ export class GatewayConfigurationComponent implements OnInit { this.attributeService.getEntityAttributes(entityId, AttributeScope.CLIENT_SCOPE, ['general_configuration', 'grpc_configuration', 'logs_configuration', 'storage_configuration', 'RemoteLoggingLevel']).pipe( mergeMap(attributes => attributes.length ? of(attributes) : this.attributeService.getEntityAttributes( - entityId, AttributeScope.SHARED_SCOPE, ['general_configuration', 'grpc_configuration', 'logs_configuration', 'storage_configuration', 'RemoteLoggingLevel'])) + entityId, AttributeScope.SHARED_SCOPE, ['general_configuration', 'grpc_configuration', + 'logs_configuration', 'storage_configuration', 'RemoteLoggingLevel'])) ).subscribe(attributes => { if (attributes.length) { const general_configuration = attributes.find(attribute => attribute.key === 'general_configuration')?.value; @@ -330,6 +347,7 @@ export class GatewayConfigurationComponent implements OnInit { if (grpc_configuration) { const configObj = {grpc: grpc_configuration}; this.gatewayConfigGroup.patchValue(configObj, {emitEvent: false}); + this.toggleRpcFields(grpc_configuration.enabled); } if (logs_configuration) { const configObj = {logs: this.logsToObj(logs_configuration)}; @@ -365,7 +383,7 @@ export class GatewayConfigurationComponent implements OnInit { this.gatewayConfigGroup.get('thingsboard.security.clientId').setValue(parsedValue.clientId); this.gatewayConfigGroup.get('thingsboard.security.username').setValue(parsedValue.userName); this.gatewayConfigGroup.get('thingsboard.security.password').setValue(parsedValue.password); - } else if (credentials.credentialsType === DeviceCredentialsType.X509_CERTIFICATE ) { + } else if (credentials.credentialsType === DeviceCredentialsType.X509_CERTIFICATE) { //if sertificate is present set sertificate as present } }); @@ -375,24 +393,68 @@ export class GatewayConfigurationComponent implements OnInit { logsToObj(logsConfig) { const logsObject = { local: {} - } + }; const logFormat = logsConfig.formatters.LogFormatter.format; const dateFormat = logsConfig.formatters.LogFormatter.datefmt; for (const localLogsConfigsKey of Object.keys(LocalLogsConfigs)) { - const handlerKey = localLogsConfigsKey + "Handler"; + const handlerKey = localLogsConfigsKey + 'Handler'; logsObject[localLogsConfigsKey] = { logLevel: logsConfig.loggers[localLogsConfigsKey].level, - filePath: logsConfig.handlers[handlerKey].filename.split('/'+localLogsConfigsKey)[0], + filePath: logsConfig.handlers[handlerKey].filename.split('/' + localLogsConfigsKey)[0], backupCount: logsConfig.handlers[handlerKey].backupCount, savingTime: logsConfig.handlers[handlerKey].interval, savingPeriod: logsConfig.handlers[handlerKey].when, - } + }; } return {local: logsObject, logFormat, dateFormat}; } + toggleRpcFields(enable: boolean) { + const grpcGroup = this.gatewayConfigGroup.get('grpc') as FormGroup; + if (enable) { + grpcGroup.get('serverPort').enable(); + grpcGroup.get('keepAliveTimeMs').enable(); + grpcGroup.get('keepAliveTimeoutMs').enable(); + grpcGroup.get('maxPingsWithoutData').enable(); + grpcGroup.get('minTimeBetweenPingsMs').enable(); + grpcGroup.get('minPingIntervalWithoutDataMs').enable(); + } else { + grpcGroup.get('serverPort').disable(); + grpcGroup.get('keepAliveTimeMs').disable(); + grpcGroup.get('keepAliveTimeoutMs').disable(); + grpcGroup.get('maxPingsWithoutData').disable(); + grpcGroup.get('minTimeBetweenPingsMs').disable(); + grpcGroup.get('minPingIntervalWithoutDataMs').disable(); + } + } + + clientIdUserNameFieldsToggle(type?: string) { + const clientIdForm = this.gatewayConfigGroup.get('thingsboard.security.clientId'); + const usernameForm = this.gatewayConfigGroup.get('thingsboard.security.username'); + switch (type) { + case 'clientId': + if (clientIdForm.enabled) { + clientIdForm.disable({emitEvent: false}); + } + break; + case 'username': + if (usernameForm.enabled) { + usernameForm.disable({emitEvent: false}); + } + break; + default: + if (clientIdForm.disabled) { + clientIdForm.enable({emitEvent: false}); + } + if (usernameForm.disabled) { + usernameForm.enable({emitEvent: false}); + } + break; + } + } + addCommand(command?): void { const data = command || {}; const commandsFormArray = this.commandFormArray(); @@ -465,42 +527,42 @@ export class GatewayConfigurationComponent implements OnInit { disable_existing_loggers: false, formatters: { LogFormatter: { - class: "logging.Formatter", + class: 'logging.Formatter', format: logsObj.logFormat, datefmt: logsObj.dateFormat, } }, handlers: { consoleHandler: { - class: "logging.StreamHandler", - formatter: "LogFormatter", - level: "DEBUG", - stream: "ext://sys.stdout" + class: 'logging.StreamHandler', + formatter: 'LogFormatter', + level: 'DEBUG', + stream: 'ext://sys.stdout' }, databaseHandler: { - class: "thingsboard_gateway.tb_utility.tb_logger.TimedRotatingFileHandler", - formatter: "LogFormatter", - filename: "./logs/database.log", + class: 'thingsboard_gateway.tb_utility.tb_logger.TimedRotatingFileHandler', + formatter: 'LogFormatter', + filename: './logs/database.log', backupCount: 1, - encoding: "utf-8" + encoding: 'utf-8' } }, loggers: { database: { - handlers: ["databaseHandler", "consoleHandler"], - level: "DEBUG", + handlers: ['databaseHandler', 'consoleHandler'], + level: 'DEBUG', propagate: false } }, root: { - level: "ERROR", + level: 'ERROR', handlers: [ - "consoleHandler" + 'consoleHandler' ] } - } + }; for (const key of Object.keys(logsObj.local)) { - logAttrObj.handlers[key+"Handler"] = this.createHandlerObj(logsObj.local[key], key); + logAttrObj.handlers[key + 'Handler'] = this.createHandlerObj(logsObj.local[key], key); logAttrObj.loggers[key] = this.createLoggerObj(logsObj.local[key], key); } return logAttrObj; @@ -508,22 +570,22 @@ export class GatewayConfigurationComponent implements OnInit { createHandlerObj(logObj, key) { return { - class: "thingsboard_gateway.tb_utility.tb_logger.TimedRotatingFileHandler", - formatter: "LogFormatter", + class: 'thingsboard_gateway.tb_utility.tb_logger.TimedRotatingFileHandler', + formatter: 'LogFormatter', filename: `${logObj.filePath}/${key}.log`, backupCount: logObj.backupCount, interval: logObj.savingTime, when: logObj.savingPeriod, - encoding: "utf-8" - } + encoding: 'utf-8' + }; } createLoggerObj(logObj, key) { return { - handlers: [`${key}Handler`, "consoleHandler"], + handlers: [`${key}Handler`, 'consoleHandler'], level: logObj.logLevel, propagate: false - } + }; } saveConfig(): void { diff --git a/ui-ngx/src/app/shared/components/device/gateway-connectors.component.html b/ui-ngx/src/app/shared/components/device/gateway-connectors.component.html index 387f8707d4..96fd8bcddb 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-connectors.component.html +++ b/ui-ngx/src/app/shared/components/device/gateway-connectors.component.html @@ -16,8 +16,8 @@ -->
-
- +
+

Connectors

@@ -117,7 +117,7 @@
- + Name diff --git a/ui-ngx/src/app/shared/components/device/gateway-connectors.component.ts b/ui-ngx/src/app/shared/components/device/gateway-connectors.component.ts index ae2cf62ef6..086cf55f6d 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-connectors.component.ts +++ b/ui-ngx/src/app/shared/components/device/gateway-connectors.component.ts @@ -84,7 +84,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie inactiveConnectorsDataSource: AttributeDatasource; - dataSource: MatTableDataSource + dataSource: MatTableDataSource; displayedColumns = ['enabled', 'key', 'type', 'actions']; @@ -142,7 +142,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: [''], configuration: [''], configurationJson: [{}, [Validators.required]] - }) + }); this.connectorForm.disable(); } @@ -172,19 +172,19 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.inactiveConnectors = []; this.updateData(true); } - }) + }); } } saveConnector(): void { const value = this.connectorForm.value; - value.configuration = this.camelize(value.name) + ".json"; + value.configuration = this.camelize(value.name) + '.json'; if (value.type !== 'grpc') { delete value.key; } const attributesToSave = [{ key: value.name, - value: value + value }]; const attributesToDelete = []; const scope = (this.activeConnectors.includes(value.name) || !this.initialConnector) ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; @@ -194,8 +194,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie updateActiveConnectors = true; const activeIndex = this.activeConnectors.indexOf(this.initialConnector.name); const inactiveIndex = this.inactiveConnectors.indexOf(this.initialConnector.name); - if (activeIndex !== -1) this.activeConnectors.splice(activeIndex, 1); - if (inactiveIndex !== -1) this.inactiveConnectors.splice(activeIndex, 1); + if (activeIndex !== -1) {this.activeConnectors.splice(activeIndex, 1);} + if (inactiveIndex !== -1) {this.inactiveConnectors.splice(activeIndex, 1);} } if (!this.activeConnectors.includes(value.name) && scope == AttributeScope.SHARED_SCOPE) { this.activeConnectors.push(value.name); @@ -217,9 +217,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie tasks.push(this.attributeService.deleteEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, attributesToDelete)); } forkJoin(tasks).subscribe(_ => { - this.showToast("Update Successful") + this.showToast('Update Successful'); this.updateData(true); - }) + }); } resetSortAndFilter(update: boolean = true) { @@ -240,15 +240,15 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()]; this.attributeDataSource.loadAttributes(this.device, AttributeScope.CLIENT_SCOPE, this.pageLink, reload).subscribe(data => { this.activeData = data.data.filter(value => this.activeConnectors.includes(value.key)); - this.combineData() + this.combineData(); }); this.inactiveConnectorsDataSource.loadAttributes(this.device, AttributeScope.SHARED_SCOPE, this.pageLink, reload).subscribe(data => { this.inactiveData = data.data.filter(value =>this.inactiveConnectors.includes(value.key)); - this.combineData() + this.combineData(); }); } - combineData () { + combineData() { this.dataSource.data = [...this.activeData, ...this.inactiveData]; } @@ -268,7 +268,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: '', configuration: '', configurationJson: {} - }) + }); this.initialConnector = null; this.connectorForm.markAsPristine(); } @@ -279,7 +279,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } const connector = typeof attribute.value === 'string' ? JSON.parse(attribute.value): attribute.value; if (!connector.configuration) { - connector.configuration = ""; + connector.configuration = ''; } if (!connector.key) { connector.key = 'auto'; @@ -303,9 +303,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie })); } - returnType (attribute) { + returnType(attribute) { const value = typeof attribute.value === 'string' ? JSON.parse(attribute.value): attribute.value; - return this.gatewayConnectorDefaultTypes.get(value.type) + return this.gatewayConnectorDefaultTypes.get(value.type); } deleteConnector(attribute: AttributeData, $event: Event): void { @@ -321,8 +321,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie tasks.push(this.attributeService.deleteEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, [attribute])); const activeIndex = this.activeConnectors.indexOf(attribute.key); const inactiveIndex = this.inactiveConnectors.indexOf(attribute.key); - if (activeIndex !== -1) this.activeConnectors.splice(activeIndex, 1); - if (inactiveIndex !== -1) this.inactiveConnectors.splice(activeIndex, 1); + if (activeIndex !== -1) {this.activeConnectors.splice(activeIndex, 1);} + if (inactiveIndex !== -1) {this.inactiveConnectors.splice(activeIndex, 1);} tasks.push(this.attributeService.saveEntityAttributes(this.device, scope, [{ key: scope == AttributeScope.SHARED_SCOPE ? 'active_connectors' : 'inactive_connectors', value: scope == AttributeScope.SHARED_SCOPE ? this.activeConnectors : this.inactiveConnectors @@ -333,10 +333,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.cd.detectChanges(); this.connectorForm.disable(); } - this.updateData() - }) + this.updateData(); + }); } - }) + }); } camelize(str): string { @@ -350,8 +350,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie attribute.value = typeof attribute.value === 'string' ? JSON.parse(attribute.value): attribute.value; const params = deepClone(this.ctx.stateController.getStateParams()); params.connector_logs = attribute; - params.targetEntityParamName = "connector_logs"; - this.ctx.stateController.openState("connector_logs", params); + params.targetEntityParamName = 'connector_logs'; + this.ctx.stateController.openState('connector_logs', params); } connectorRpc(attribute: AttributeData, $event: Event): void { @@ -361,19 +361,19 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie attribute.value = typeof attribute.value === 'string' ? JSON.parse(attribute.value): attribute.value; const params = deepClone(this.ctx.stateController.getStateParams()); params.connector_rpc = attribute; - params.targetEntityParamName = "connector_rpc"; - this.ctx.stateController.openState("connector_rpc", params); + params.targetEntityParamName = 'connector_rpc'; + this.ctx.stateController.openState('connector_rpc', params); } enableConnector(attribute): void { const wasEnabled = this.activeConnectors.includes(attribute.key); if (wasEnabled) { - let index = this.activeConnectors.indexOf(attribute.key); + const index = this.activeConnectors.indexOf(attribute.key); this.activeConnectors.splice(index, 1); this.inactiveConnectors.push(attribute.key); } else { - let index = this.inactiveConnectors.indexOf(attribute.key); + const index = this.inactiveConnectors.indexOf(attribute.key); this.inactiveConnectors.splice(index, 1); this.activeConnectors.push(attribute.key); } @@ -385,7 +385,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value: this.inactiveConnectors }]),]).subscribe(_ => { this.updateData(); - }) + }); } } diff --git a/ui-ngx/src/app/shared/components/device/gateway-logs.component.scss b/ui-ngx/src/app/shared/components/device/gateway-logs.component.scss index a529107a43..34b5f9d249 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-logs.component.scss +++ b/ui-ngx/src/app/shared/components/device/gateway-logs.component.scss @@ -43,8 +43,8 @@ } .status-info { - color: black; - background: rgba(0, 0, 0, 0.1); + color: blue; + background: rgba(0, 0, 128, 0.1); } .msg-status-exception { diff --git a/ui-ngx/src/app/shared/components/device/gateway-statistics.component.html b/ui-ngx/src/app/shared/components/device/gateway-statistics.component.html index b98d481f6d..6233205eaa 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-statistics.component.html +++ b/ui-ngx/src/app/shared/components/device/gateway-statistics.component.html @@ -16,7 +16,7 @@ --> -
+
{{'gateway.statistics.statistic' | translate}} diff --git a/ui-ngx/src/app/shared/components/device/gateway-statistics.component.scss b/ui-ngx/src/app/shared/components/device/gateway-statistics.component.scss index a96dababd5..d14f748547 100644 --- a/ui-ngx/src/app/shared/components/device/gateway-statistics.component.scss +++ b/ui-ngx/src/app/shared/components/device/gateway-statistics.component.scss @@ -21,15 +21,24 @@ .statistics-container { height: 100%; + overflow-y: auto; mat-card { width: 40%; + height: 100%; margin-right: 35px; padding: 15px; } + @media only screen and (max-width: 750px) { + mat-card { + width: 100%; + } + } + .chart-box, .chart-container { height: 100%; + min-height: 300px; flex-grow: 1; }