Browse Source

UI: refactoring gateway connectors

pull/10482/head
Dmitriymush 2 years ago
parent
commit
9b7b31f97b
  1. 42
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-security.component.html
  2. 31
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-security.component.ts
  3. 8
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table.component.ts
  4. 7
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel.component.ts
  5. 6
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.html
  6. 51
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.scss
  7. 44
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.ts
  8. 4
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.html
  9. 9
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts
  10. 69
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.html
  11. 12
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.scss
  12. 60
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts
  13. 39
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html
  14. 71
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss
  15. 75
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts
  16. 4
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts
  17. 67
      ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts
  18. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

42
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-security.component.html

@ -20,12 +20,12 @@
<div class="fixed-title-width tb-required" translate>gateway.security</div>
<tb-toggle-select formControlName="type" appearance="fill">
<tb-toggle-option *ngFor="let type of securityTypes" [value]="type">
{{ SecurityTypeTranslations.get(type) | translate }}
{{ SecurityTypeTranslationsMap.get(type) | translate }}
</tb-toggle-option>
</tb-toggle-select>
</div>
<ng-container [ngSwitch]="securityFormGroup.get('type').value">
<ng-template [ngSwitchCase]="BrokerSecurityTypes.BASIC">
<ng-template [ngSwitchCase]="BrokerSecurityType.BASIC">
<div class="tb-form-row space-between tb-flex fill-width">
<div class="fixed-title-width" translate>gateway.username</div>
<div class="tb-flex no-gap">
@ -50,36 +50,18 @@
<input matInput type="password" name="value" formControlName="password" placeholder="{{ 'gateway.set' | translate }}"/>
<div class="tb-flex no-gap align-center fill-height" matSuffix>
<tb-toggle-password class="tb-flex align-center fill-height"></tb-toggle-password>
<mat-icon matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.password-required') | translate"
*ngIf="securityFormGroup.get('password').hasError('required')
&& securityFormGroup.get('password').touched;"
style="height: 40px; width: 40px; font-size: 20px; padding: 10px;"
class="tb-error">
warning
</mat-icon>
</div>
</mat-form-field>
</div>
</div>
</ng-template>
<ng-template [ngSwitchCase]="BrokerSecurityTypes.CERTIFICATES">
<ng-template [ngSwitchCase]="BrokerSecurityType.CERTIFICATES">
<div class="tb-form-hint tb-primary-fill">{{ 'gateway.path-hint' | translate }}</div>
<div class="tb-form-row space-between tb-flex fill-width">
<div class="fixed-title-width" translate>gateway.CA-certificate-path</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="pathToCACert" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.path-to-CA-cert-required') | translate"
*ngIf="securityFormGroup.get('pathToCACert').hasError('required')
&& securityFormGroup.get('pathToCACert').touched;"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
</div>
@ -88,15 +70,6 @@
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="pathToPrivateKey" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.path-to-private-key-required') | translate"
*ngIf="securityFormGroup.get('pathToPrivateKey').hasError('required')
&& securityFormGroup.get('pathToPrivateKey').touched;"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
</div>
@ -105,15 +78,6 @@
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="pathToClientCert" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.path-to-client-cert-required') | translate"
*ngIf="securityFormGroup.get('pathToClientCert').hasError('required')
&& securityFormGroup.get('pathToClientCert').touched;"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
</div>

31
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-security.component.ts

@ -40,11 +40,14 @@ import {
FormBuilder,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormGroup, ValidationErrors, Validator, Validators
UntypedFormGroup,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import {
BrokerSecurityTypes,
BrokerSecurityTypeTranslations,
BrokerSecurityType,
BrokerSecurityTypeTranslationsMap,
} from '@home/components/widget/lib/gateway/gateway-widget.models';
import { takeUntil } from 'rxjs/operators';
@ -68,11 +71,11 @@ import { takeUntil } from 'rxjs/operators';
})
export class BrokerSecurityComponent extends PageComponent implements ControlValueAccessor, Validator, AfterViewInit, OnInit, OnDestroy {
BrokerSecurityTypes = BrokerSecurityTypes;
BrokerSecurityType = BrokerSecurityType;
securityTypes = Object.values(BrokerSecurityTypes);
securityTypes = Object.values(BrokerSecurityType);
SecurityTypeTranslations = BrokerSecurityTypeTranslations;
SecurityTypeTranslationsMap = BrokerSecurityTypeTranslationsMap;
securityFormGroup: UntypedFormGroup;
@ -93,12 +96,12 @@ export class BrokerSecurityComponent extends PageComponent implements ControlVal
private fb: FormBuilder) {
super(store);
this.securityFormGroup = this.fb.group({
type: [BrokerSecurityTypes.ANONYMOUS, []],
type: [BrokerSecurityType.ANONYMOUS, []],
username: ['', [Validators.required]],
password: ['', [Validators.required]],
pathToCACert: ['', [Validators.required]],
pathToPrivateKey: ['', [Validators.required]],
pathToClientCert: ['', [Validators.required]]
password: ['', []],
pathToCACert: ['', []],
pathToPrivateKey: ['', []],
pathToClientCert: ['', []]
});
this.securityFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
@ -132,7 +135,7 @@ export class BrokerSecurityComponent extends PageComponent implements ControlVal
writeValue(deviceInfo: any) {
if (!deviceInfo.type) {
deviceInfo.type = BrokerSecurityTypes.ANONYMOUS;
deviceInfo.type = BrokerSecurityType.ANONYMOUS;
}
this.securityFormGroup.reset(deviceInfo);
this.updateView(deviceInfo);
@ -155,10 +158,10 @@ export class BrokerSecurityComponent extends PageComponent implements ControlVal
this.securityFormGroup.get('pathToCACert').disable({emitEvent: false});
this.securityFormGroup.get('pathToPrivateKey').disable({emitEvent: false});
this.securityFormGroup.get('pathToClientCert').disable({emitEvent: false});
if (type === BrokerSecurityTypes.BASIC) {
if (type === BrokerSecurityType.BASIC) {
this.securityFormGroup.get('username').enable({emitEvent: false});
this.securityFormGroup.get('password').enable({emitEvent: false});
} else if (type === BrokerSecurityTypes.CERTIFICATES) {
} else if (type === BrokerSecurityType.CERTIFICATES) {
this.securityFormGroup.get('pathToCACert').enable({emitEvent: false});
this.securityFormGroup.get('pathToPrivateKey').enable({emitEvent: false});
this.securityFormGroup.get('pathToClientCert').enable({emitEvent: false});

8
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table.component.ts

@ -42,9 +42,13 @@ import {
ControlValueAccessor,
FormBuilder, NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormGroup, ValidationErrors, Validator, Validators
UntypedFormGroup,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import {
DeviceInfoType,
SourceTypes,
SourceTypeTranslationsMap
} from '@home/components/widget/lib/gateway/gateway-widget.models';
@ -129,7 +133,7 @@ export class DeviceInfoTableComponent extends PageComponent implements ControlVa
this.mappingFormGroup.addControl('deviceNameExpressionSource',
this.fb.control(SourceTypes.MSG, []));
}
if (this.deviceInfoTypeValue === 'full') {
if (this.deviceInfoType === DeviceInfoType.FULL) {
if (this.useSource) {
this.mappingFormGroup.addControl('deviceProfileExpressionSource',
this.fb.control(SourceTypes.MSG, []));

7
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel.component.ts

@ -35,6 +35,7 @@ import { AppState } from '@core/core.state';
import { PageComponent } from '@shared/components/page.component';
import { isDefinedAndNotNull } from '@core/utils';
import {
MappingDataKey,
MappingKeysType,
MappingValueType,
mappingValueTypesMap
@ -61,7 +62,7 @@ export class MappingDataKeysPanelComponent extends PageComponent implements OnIn
noKeysText: string;
@Input()
keys: string;
keys: Array<MappingDataKey> | {[key: string]: any};
@Input()
keysType: string;
@ -140,7 +141,7 @@ export class MappingDataKeysPanelComponent extends PageComponent implements OnIn
this.keysDataApplied.emit(keys);
}
private prepareKeysFormArray(keys: any): UntypedFormArray {
private prepareKeysFormArray(keys: Array<MappingDataKey> | {[key: string]: any}): UntypedFormArray {
const keysControlGroups: Array<AbstractControl> = [];
if (keys) {
if (this.keysType === MappingKeysType.CUSTOM) {
@ -161,7 +162,7 @@ export class MappingDataKeysPanelComponent extends PageComponent implements OnIn
return this.fb.array(keysControlGroups);
}
valueTitle(value: any): any {
valueTitle(value: any): string {
if (isDefinedAndNotNull(value)) {
if (typeof value === 'object') {
return JSON.stringify(value);

6
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-entity-table tb-absolute-fill">
<div fxFlex fxLayout="column" class="tb-entity-table-content">
<div class="tb-mapping-table tb-absolute-fill">
<div fxFlex fxLayout="column" class="tb-mapping-table-content">
<mat-toolbar class="mat-mdc-table-toolbar" [fxShow]="!textSearchMode">
<div class="mat-toolbar-tools">
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs="center start" class="title-container">
<span class="tb-entity-table-title">{{mappingTypeTranslationsMap.get(mappingType) | translate}}</span>
<span class="tb-mapping-table-title">{{mappingTypeTranslationsMap.get(mappingType) | translate}}</span>
</div>
<span fxFlex></span>
<button mat-icon-button

51
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.scss

@ -19,8 +19,8 @@
width: 100%;
height: 100%;
display: block;
.tb-entity-table {
.tb-entity-table-content {
.tb-mapping-table {
.tb-mapping-table-content {
width: 100%;
height: 100%;
background: #fff;
@ -40,7 +40,7 @@
overflow: hidden;
}
.tb-entity-table-title {
.tb-mapping-table-title {
padding-right: 20px;
white-space: nowrap;
overflow: hidden;
@ -53,55 +53,12 @@
table-layout: fixed;
min-width: 450px;
}
.tb-add-new {
display: flex;
z-index: 1;
pointer-events: none;
button.connector {
height: auto;
padding-right: 12px;
font-size: 20px;
border-style: dashed;
border-width: 2px;
border-radius: 8px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
color: rgba(0, 0, 0, 0.38);
}
}
}
.tb-entity-table-info{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.button-widget-action{
margin-left: auto;
overflow: hidden;
text-overflow: ellipsis;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
}
.attribute-copy {
visibility: hidden;
transition: visibility 0.1s;
}
.attribute:hover {
.attribute-copy {
visibility: visible;
}
}
}
}
@ -110,7 +67,7 @@
height: auto;
min-height: 100px;
.tb-entity-table-title{
.tb-mapping-table-title{
padding-bottom: 5px;
width: 100%;
}

44
ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table.component.ts

@ -36,16 +36,18 @@ import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog';
import { DialogService } from '@core/services/dialog.service';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, take, takeUntil, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
import { Overlay } from '@angular/cdk/overlay';
import { UtilsService } from '@core/services/utils.service';
import { EntityService } from '@core/http/entity.service';
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR, UntypedFormArray } from '@angular/forms';
import {
ConvertorTypeTranslationsMap,
MappingTypes,
MappingInfo,
MappingType,
MappingTypeTranslationsMap,
RequestTypes
RequestType,
RequestTypesTranslationsMap
} from '@home/components/widget/lib/gateway/gateway-widget.models';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { MappingDialogComponent } from '@home/components/widget/lib/gateway/dialog/mapping-dialog.component';
@ -78,14 +80,14 @@ export class MappingTableComponent extends PageComponent implements ControlValue
viewsInited = false;
mappingTypeValue: MappingTypes;
mappingTypeValue: MappingType;
get mappingType(): MappingTypes {
get mappingType(): MappingType {
return this.mappingTypeValue;
}
@Input()
set mappingType(value: MappingTypes) {
set mappingType(value: MappingType) {
if (this.mappingTypeValue !== value) {
this.mappingTypeValue = value;
}
@ -118,7 +120,7 @@ export class MappingTableComponent extends PageComponent implements ControlValue
}
ngOnInit() {
if (this.mappingType === MappingTypes.DATA) {
if (this.mappingType === MappingType.DATA) {
this.mappingColumns.push(
{def: 'topicFilter', title: 'gateway.topic-filter'},
{def: 'QoS', title: 'gateway.mqtt-qos'},
@ -163,10 +165,10 @@ export class MappingTableComponent extends PageComponent implements ControlValue
writeValue(config: any) {
if (isUndefinedOrNull(config)) {
config = this.mappingType === MappingTypes.REQUESTS ? {} : [];
config = this.mappingType === MappingType.REQUESTS ? {} : [];
}
let mappingConfigs = config;
if (this.mappingType === MappingTypes.REQUESTS) {
if (this.mappingType === MappingType.REQUESTS) {
mappingConfigs = [];
Object.keys(config).forEach((configKey) => {
@ -185,9 +187,9 @@ export class MappingTableComponent extends PageComponent implements ControlValue
this.updateTableData(mappingConfigs);
}
updateView(mappingConfigs: Array<any>) {
updateView(mappingConfigs: Array<{[key: string]: any}>) {
let config;
if (this.mappingType === MappingTypes.REQUESTS) {
if (this.mappingType === MappingType.REQUESTS) {
config = {};
for (let mappingConfig of mappingConfigs) {
if (config[mappingConfig.requestType]) {
@ -221,7 +223,7 @@ export class MappingTableComponent extends PageComponent implements ControlValue
$event.stopPropagation();
}
const value = isDefinedAndNotNull(index) ? this.mappingFormGroup.at(index).value : {};
this.dialog.open<MappingDialogComponent, any, boolean>(MappingDialogComponent, {
this.dialog.open<MappingDialogComponent, MappingInfo, boolean>(MappingDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
@ -242,9 +244,9 @@ export class MappingTableComponent extends PageComponent implements ControlValue
);
}
updateTableData(value, textSearch?: string): void {
updateTableData(value: Array<{[key: string]: any}>, textSearch?: string): void {
let tableValue = value;
if (this.mappingType === MappingTypes.DATA) {
if (this.mappingType === MappingType.DATA) {
tableValue = tableValue.map((value) => {
return {
topicFilter: value.topicFilter,
@ -255,15 +257,15 @@ export class MappingTableComponent extends PageComponent implements ControlValue
} else {
tableValue = tableValue.map((value) => {
let details;
if (value.requestType === RequestTypes.ATTRIBUTE_UPDATE) {
if (value.requestType === RequestType.ATTRIBUTE_UPDATE) {
details = value.requestValue.attributeFilter;
} else if (value.requestType === RequestTypes.SERVER_SIDE_RPC) {
} else if (value.requestType === RequestType.SERVER_SIDE_RPC) {
details = value.requestValue.methodFilter;
} else {
details = value.requestValue.topicFilter;
}
return {
type: value.requestType,
type: this.translate.instant(RequestTypesTranslationsMap.get(value.requestType)),
details
};
});
@ -299,13 +301,13 @@ export class MappingTableComponent extends PageComponent implements ControlValue
export class MappingDatasource implements DataSource<any> {
private mappingSubject = new BehaviorSubject<any[]>([]);
private mappingSubject = new BehaviorSubject<Array<{[key: string]: any}>>([]);
private allMappings: Observable<Array<any>>;
private allMappings: Observable<Array<{[key: string]: any}>>;
constructor() {}
connect(collectionViewer: CollectionViewer): Observable<any[] | ReadonlyArray<any>> {
connect(collectionViewer: CollectionViewer): Observable<Array<{[key: string]: any}>> {
return this.mappingSubject.asObservable();
}
@ -313,7 +315,7 @@ export class MappingDatasource implements DataSource<any> {
this.mappingSubject.complete();
}
loadMappings(mappings: any, pageLink?: PageLink, reload: boolean = false): void {
loadMappings(mappings: Array<{[key: string]: any}>, pageLink?: PageLink, reload: boolean = false): void {
if (reload) {
this.allMappings = null;
}

4
ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.html

@ -36,7 +36,7 @@
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="type">
<mat-option *ngFor="let type of gatewayConnectorDefaultTypes | keyvalue" [value]="type.key">
<mat-option *ngFor="let type of gatewayConnectorDefaultTypesTranslatesMap | keyvalue" [value]="type.key">
{{ type.value }}
</mat-option>
</mat-select>
@ -76,7 +76,7 @@
</mat-label>
</mat-slide-toggle>
</div>
<div *ngIf="connectorForm.get('type').value === 'mqtt'" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div *ngIf="connectorForm.get('type').value === connectorType.MQTT" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="sendDataOnlyOnChange">
<mat-label tb-hint-tooltip-icon="{{ 'gateway.send-change-data-hint' | translate }}">
{{ 'gateway.send-change-data' | translate }}

9
ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts

@ -23,7 +23,8 @@ import { BaseData, HasId } from '@shared/models/base-data';
import { DialogComponent } from '@shared/components/dialog.component';
import { Router } from '@angular/router';
import {
GatewayConnectorDefaultTypesTranslates,
ConnectorType,
GatewayConnectorDefaultTypesTranslatesMap,
GatewayLogLevel, getDefaultConfig
} from '@home/components/widget/lib/gateway/gateway-widget.models';
import { Subject } from 'rxjs';
@ -39,7 +40,9 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia
connectorForm: UntypedFormGroup;
gatewayConnectorDefaultTypes = GatewayConnectorDefaultTypesTranslates;
connectorType = ConnectorType;
gatewayConnectorDefaultTypesTranslatesMap = GatewayConnectorDefaultTypesTranslatesMap;
gatewayLogLevel = Object.values(GatewayLogLevel);
submitted = false;
@ -54,7 +57,7 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia
private resourcesService: ResourcesService) {
super(store, router, dialogRef);
this.connectorForm = this.fb.group({
type: ['mqtt', []],
type: [ConnectorType.MQTT, []],
name: ['', [Validators.required, this.uniqNameRequired()]],
logLevel: [GatewayLogLevel.INFO, []],
useDefaults: [true, []],

69
ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.html

@ -35,7 +35,7 @@
{{ MappingHintTranslationsMap.get(this.data?.mappingType) | translate }}
</div>
<ng-container [ngSwitch]="data.mappingType">
<ng-template [ngSwitchCase]="MappingTypes.DATA">
<ng-template [ngSwitchCase]="MappingType.DATA">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" translate>gateway.topic-filter</div>
<div class="tb-flex no-gap">
@ -75,16 +75,17 @@
</tb-toggle-select>
</div>
<ng-container [formGroupName]="converterType" [ngSwitch]="converterType">
<ng-template [ngSwitchCase]="ConvertorTypes.JSON">
<tb-device-info-table formControlName="deviceInfo" deviceInfoType="full">
<ng-template [ngSwitchCase]="ConvertorTypeEnum.JSON">
<tb-device-info-table formControlName="deviceInfo" [deviceInfoType]="DeviceInfoType.FULL" required="true">
</tb-device-info-table>
</ng-template>
<ng-template [ngSwitchCase]="ConvertorTypes.BYTES">
<tb-device-info-table formControlName="deviceInfo" deviceInfoType="full" [sourceTypes]="[sourceTypesEnum.MSG, sourceTypesEnum.CONST]">
<ng-template [ngSwitchCase]="ConvertorTypeEnum.BYTES">
<tb-device-info-table formControlName="deviceInfo" [deviceInfoType]="DeviceInfoType.FULL"
[sourceTypes]="[sourceTypesEnum.MSG, sourceTypesEnum.CONST]" required="true">
</tb-device-info-table>
</ng-template>
<div class="tb-form-panel no-border no-padding"
*ngIf="converterType === ConvertorTypes.BYTES || converterType === ConvertorTypes.JSON">
*ngIf="converterType === ConvertorTypeEnum.BYTES || converterType === ConvertorTypeEnum.JSON">
<div class="tb-form-row space-between tb-flex">
<div class="fixed-title-width" translate>gateway.attributes</div>
<div class="tb-flex">
@ -120,12 +121,21 @@
</div>
</div>
</div>
<div class="tb-form-panel no-border no-padding" *ngIf="converterType === ConvertorTypes.CUSTOM">
<div class="tb-form-panel no-border no-padding" *ngIf="converterType === ConvertorTypeEnum.CUSTOM">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width" translate>gateway.extension</div>
<div class="fixed-title-width tb-required" translate>gateway.extension</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="extension" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.extension-required') | translate"
*ngIf="mappingForm.get('converter.custom.extension').hasError('required') &&
mappingForm.get('converter.topicFilter').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
</div>
@ -155,7 +165,7 @@
</div>
</ng-container>
</ng-template>
<ng-template [ngSwitchCase]="MappingTypes.REQUESTS">
<ng-template [ngSwitchCase]="MappingType.REQUESTS">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width" translate>gateway.request-type</div>
<div class="tb-flex no-gap">
@ -169,12 +179,11 @@
</div>
</div>
<ng-container formGroupName="requestValue">
<ng-container [formGroupName]="requestMappingType" [ngSwitch]="requestMappingType">
<ng-container [formGroup]="mappingForm.get('requestValue').get(requestMappingType)" [ngSwitch]="requestMappingType">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center"
*ngIf="requestMappingType === RequestTypes.ATTRIBUTE_REQUEST ||
requestMappingType === RequestTypes.CONNECT_REQUEST ||
requestMappingType === RequestTypes.DISCONNECT_REQUEST">
<!-- showMappingField('topicFilter')-->
*ngIf="requestMappingType === RequestTypeEnum.ATTRIBUTE_REQUEST ||
requestMappingType === RequestTypeEnum.CONNECT_REQUEST ||
requestMappingType === RequestTypeEnum.DISCONNECT_REQUEST">
<div class="fixed-title-width tb-required" translate>gateway.topic-filter</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
@ -192,18 +201,18 @@
</mat-form-field>
</div>
</div>
<ng-template [ngSwitchCase]="RequestTypes.CONNECT_REQUEST">
<tb-device-info-table formControlName="deviceInfo" deviceInfoType="full">
<ng-template [ngSwitchCase]="RequestTypeEnum.CONNECT_REQUEST">
<tb-device-info-table formControlName="deviceInfo" [deviceInfoType]="DeviceInfoType.FULL" required="true">
</tb-device-info-table>
</ng-template>
<ng-template [ngSwitchCase]="RequestTypes.DISCONNECT_REQUEST">
<tb-device-info-table formControlName="deviceInfo" deviceInfoType="partial">
<ng-template [ngSwitchCase]="RequestTypeEnum.DISCONNECT_REQUEST">
<tb-device-info-table formControlName="deviceInfo" [deviceInfoType]="DeviceInfoType.PARTIAL" required="true">
</tb-device-info-table>
</ng-template>
<ng-template [ngSwitchCase]="RequestTypes.ATTRIBUTE_REQUEST">
<ng-template [ngSwitchCase]="RequestTypeEnum.ATTRIBUTE_REQUEST">
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title tb-required" translate>gateway.from-device-request-settings</div>
<tb-device-info-table formControlName="deviceInfo" deviceInfoType="partial" required="true">
<tb-device-info-table formControlName="deviceInfo" [deviceInfoType]="DeviceInfoType.PARTIAL" required="true">
</tb-device-info-table>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.attribute-name-expression-hint' | translate }}" translate>
@ -254,7 +263,7 @@
</div>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="retain">
<mat-slide-toggle class="mat-slide" formControlName="retain">
<mat-label tb-hint-tooltip-icon="{{ 'gateway.retain-hint' | translate }}">
{{ 'gateway.retain' | translate }}
</mat-label>
@ -281,7 +290,7 @@
</div>
</div>
</ng-template>
<ng-template [ngSwitchCase]="RequestTypes.ATTRIBUTE_UPDATE">
<ng-template [ngSwitchCase]="RequestTypeEnum.ATTRIBUTE_UPDATE">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" translate>gateway.device-name-filter</div>
<div class="tb-flex no-gap">
@ -300,7 +309,6 @@
</div>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<!-- showMappingField('QoS')-->
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.attribute-filter-hint' | translate }}" translate>
gateway.attribute-filter
</div>
@ -320,7 +328,7 @@
</div>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width" translate>gateway.response-topic-expression</div>
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.expression-hint' | translate }}" translate>gateway.response-topic-expression</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="topicExpression" placeholder="{{ 'gateway.set' | translate }}"/>
@ -328,8 +336,8 @@
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.response-topic-expression-required') | translate"
*ngIf="mappingForm.get('requestValue.attributeRequests.topicExpression').hasError('required') &&
mappingForm.get('requestValue.attributeRequests.topicExpression').touched"
*ngIf="mappingForm.get('requestValue.attributeUpdates.topicExpression').hasError('required') &&
mappingForm.get('requestValue.attributeUpdates.topicExpression').touched"
class="tb-error">
warning
</mat-icon>
@ -344,7 +352,7 @@
</mat-slide-toggle>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width" translate>gateway.response-value-expression</div>
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.expression-hint' | translate }}" translate>gateway.response-value-expression</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="valueExpression" placeholder="{{ 'gateway.set' | translate }}"/>
@ -352,8 +360,8 @@
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.response-value-expression-required') | translate"
*ngIf="mappingForm.get('requestValue.attributeRequests.valueExpression').hasError('required') &&
mappingForm.get('requestValue.attributeRequests.valueExpression').touched"
*ngIf="mappingForm.get('requestValue.attributeUpdates.valueExpression').hasError('required') &&
mappingForm.get('requestValue.attributeUpdates.valueExpression').touched"
class="tb-error">
warning
</mat-icon>
@ -361,7 +369,7 @@
</div>
</div>
</ng-template>
<ng-template [ngSwitchCase]="RequestTypes.SERVER_SIDE_RPC">
<ng-template [ngSwitchCase]="RequestTypeEnum.SERVER_SIDE_RPC">
<div class="tb-flex row center align-center no-gap fill-width">
<tb-toggle-select formControlName="type" appearance="fill">
<tb-toggle-option [value]="ServerSideRPCType.TWO_WAY">
@ -373,7 +381,6 @@
</tb-toggle-select>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<!-- showMappingField('QoS')-->
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.device-name-filter-hint' | translate }}" translate>
gateway.device-name-filter
</div>

12
ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.scss

@ -33,4 +33,16 @@
}
}
}
.tb-form-row {
.fixed-title-width {
min-width: 120px;
width: 30%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mat-mdc-form-field {
width: 0;
}
}
}

60
ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts

@ -23,19 +23,19 @@ import { BaseData, HasId } from '@shared/models/base-data';
import { DialogComponent } from '@shared/components/dialog.component';
import { Router } from '@angular/router';
import {
ConvertorTypes,
ConvertorTypeTranslationsMap,
MappingHintTranslationsMap,
ConvertorType,
ConvertorTypeTranslationsMap, DeviceInfoType, MappingDataKey,
MappingHintTranslationsMap, MappingInfo,
MappingKeysAddKeyTranslationsMap,
MappingKeysDeleteKeyTranslationsMap,
MappingKeysNoKeysTextTranslationsMap,
MappingKeysPanelTitleTranslationsMap,
MappingKeysType,
MappingTypes,
MappingType,
MappingTypeTranslationsMap,
QualityTypes,
QualityTypeTranslationsMap,
RequestTypes,
RequestType,
RequestTypesTranslationsMap,
ServerSideRPCType,
SourceTypes,
@ -57,23 +57,25 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
mappingForm: UntypedFormGroup;
MappingTypes = MappingTypes;
MappingType = MappingType;
qualityTypes = QualityTypes;
QualityTranslationsMap = QualityTypeTranslationsMap;
convertorTypes = Object.values(ConvertorTypes);
ConvertorTypes = ConvertorTypes;
convertorTypes = Object.values(ConvertorType);
ConvertorTypeEnum = ConvertorType;
ConvertorTypeTranslationsMap = ConvertorTypeTranslationsMap;
sourceTypes = Object.values(SourceTypes);
sourceTypesEnum = SourceTypes;
SourceTypeTranslationsMap = SourceTypeTranslationsMap;
requestTypes = Object.values(RequestTypes);
RequestTypes = RequestTypes;
requestTypes = Object.values(RequestType);
RequestTypeEnum = RequestType;
RequestTypesTranslationsMap = RequestTypesTranslationsMap;
DeviceInfoType = DeviceInfoType;
ServerSideRPCType = ServerSideRPCType;
MappingKeysType = MappingKeysType;
@ -90,8 +92,8 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
constructor(protected store: Store<AppState>,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: any,
public dialogRef: MatDialogRef<MappingDialogComponent, any>,
@Inject(MAT_DIALOG_DATA) public data: MappingInfo,
public dialogRef: MatDialogRef<MappingDialogComponent, {[key: string]: any}>,
private fb: FormBuilder,
private popoverService: TbPopoverService,
private renderer: Renderer2,
@ -101,27 +103,27 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
this.createMappingForm();
}
get converterAttributes(): Array<any> {
get converterAttributes(): Array<MappingDataKey> {
if (this.converterType) {
return this.mappingForm.get('converter').get(this.converterType).value.attributes;
}
}
get converterTelemetry(): Array<any> {
get converterTelemetry(): Array<MappingDataKey> {
if (this.converterType) {
return this.mappingForm.get('converter').get(this.converterType).value.timeseries;
}
}
get converterType(): ConvertorTypes {
get converterType(): ConvertorType {
return this.mappingForm.get('converter').get('type').value;
}
get customKeys(): any {
get customKeys(): {[key: string]: any} {
return this.mappingForm.get('converter').get('custom').value.extensionConfig;
}
get requestMappingType(): any {
get requestMappingType(): RequestType {
return this.mappingForm.get('requestType').value;
}
@ -136,11 +138,11 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
private createMappingForm(): void {
this.mappingForm = this.fb.group({});
if (this.data.mappingType === MappingTypes.DATA) {
if (this.data.mappingType === MappingType.DATA) {
this.mappingForm.addControl('topicFilter', this.fb.control('', [Validators.required]));
this.mappingForm.addControl('subscriptionQos', this.fb.control(0));
this.mappingForm.addControl('converter', this.fb.group({
type: [ConvertorTypes.JSON, []],
type: [ConvertorType.JSON, []],
json: this.fb.group({
deviceInfo: [{}, []],
attributes: [[], []],
@ -152,7 +154,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
timeseries: [[], []]
}),
custom: this.fb.group({
extension: ['', []],
extension: ['', [Validators.required]],
extensionConfig: [{}, []]
}),
}));
@ -169,8 +171,8 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
})
}
if (this.data.mappingType === MappingTypes.REQUESTS) {
this.mappingForm.addControl('requestType', this.fb.control(RequestTypes.CONNECT_REQUEST, []));
if (this.data.mappingType === MappingType.REQUESTS) {
this.mappingForm.addControl('requestType', this.fb.control(RequestType.CONNECT_REQUEST, []));
this.mappingForm.addControl('requestValue', this.fb.group({
connectRequests: this.fb.group({
topicFilter: ['', [Validators.required]],
@ -197,7 +199,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
retain: [true, []]
}),
serverSideRpc: this.fb.group({
type: [ServerSideRPCType.TWO_WAY, []],
type: [ServerSideRPCType.ONE_WAY, []],
deviceNameFilter: ['', [Validators.required]],
methodFilter: ['', [Validators.required]],
requestTopicExpression: ['', [Validators.required]],
@ -267,7 +269,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
const ctx: any = {
keys: keysControl.value,
keysType: keysType,
rawData: this.mappingForm.get('converter.type').value === ConvertorTypes.BYTES,
rawData: this.mappingForm.get('converter.type').value === ConvertorType.BYTES,
panelTitle: MappingKeysPanelTitleTranslationsMap.get(keysType),
addKeyTitle: MappingKeysAddKeyTranslationsMap.get(keysType),
deleteKeyTitle: MappingKeysDeleteKeyTranslationsMap.get(keysType),
@ -291,9 +293,9 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
}
}
private prepareMappingData(): any {
private prepareMappingData(): {[key: string]: any} {
const formValue = this.mappingForm.value;
if (this.data.mappingType === MappingTypes.DATA) {
if (this.data.mappingType === MappingType.DATA) {
const { converter, topicFilter, subscriptionQos } = formValue;
return {
topicFilter,
@ -311,10 +313,10 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone
}
}
private prepareFormValueData(): any {
private prepareFormValueData(): {[key: string]: any} {
if (this.data.value && Object.keys(this.data.value).length) {
if (this.data.mappingType === MappingTypes.DATA) {
const {converter, topicFilter, subscriptionQos} = this.data.value;
if (this.data.mappingType === MappingType.DATA) {
const { converter, topicFilter, subscriptionQos } = this.data.value;
return {
topicFilter,
subscriptionQos,

39
ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html

@ -155,7 +155,7 @@
{{initialConnector?.type ? gatewayConnectorDefaultTypes.get(initialConnector.type) : ''}}
{{'gateway.configuration' | translate}}
</div>
<tb-toggle-select *ngIf="initialConnector && initialConnector.type === 'mqtt'" formControlName="mode" appearance="fill">
<tb-toggle-select *ngIf="initialConnector && initialConnector.type === connectorType.MQTT" formControlName="mode" appearance="fill">
<tb-toggle-option [value]="connectorConfigurationModes.BASIC">
{{ 'gateway.basic' | translate }}
</tb-toggle-option>
@ -194,8 +194,8 @@
</mat-form-field>
</div>
</div>
<div *ngIf="connectorForm.get('type').value === 'mqtt'" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="sendDataOnlyOnChange">
<div *ngIf="connectorForm.get('type').value === connectorType.MQTT" class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<mat-slide-toggle class="mat-slide" formControlName="sendDataOnlyOnChange">
<mat-label tb-hint-tooltip-icon="{{ 'gateway.send-change-data-hint' | translate }}">
{{ 'gateway.send-change-data' | translate }}
</mat-label>
@ -203,29 +203,12 @@
</div>
</div>
</mat-tab>
<ng-container *ngIf="connectorForm.get('type').value === 'mqtt' &&
<ng-container *ngIf="connectorForm.get('type').value === connectorType.MQTT &&
connectorForm.get('mode').value === connectorConfigurationModes.BASIC; else defaultConfig"
formGroupName="basicConfig">
<mat-tab label="{{ 'gateway.broker.connection' | translate }}*">
<ng-container formGroupName="broker">
<div class="tb-form-panel no-border no-padding padding-top">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" translate>gateway.broker.name</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" formControlName="name" placeholder="{{ 'gateway.set' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="('gateway.broker.name-required') | translate"
*ngIf="connectorForm.get('basicConfig.broker.name').hasError('required')
&& connectorForm.get('basicConfig.broker.name').touched"
class="tb-error">
warning
</mat-icon>
</mat-form-field>
</div>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" translate>gateway.host</div>
<div class="tb-flex no-gap">
@ -308,12 +291,14 @@
<ng-container formGroupName="broker">
<div class="tb-form-panel no-border no-padding padding-top">
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.max-number-of-workers-hint' | translate }}" translate>
<div class="fixed-title-width tb-required" [style.width.%]="50"
tb-hint-tooltip-icon="{{ 'gateway.max-number-of-workers-hint' | translate }}" translate>
gateway.max-number-of-workers
</div>
<div class="tb-flex no-gap" [style.padding-left.px]="66">
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" type="number" min="1" formControlName="maxNumberOfWorkers" placeholder="{{ 'gateway.default' | translate }}"/>
<input matInput name="value" type="number" min="1" formControlName="maxNumberOfWorkers"
placeholder="{{ 'gateway.default' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
@ -328,12 +313,14 @@
</div>
</div>
<div class="tb-form-row column-xs" fxLayoutAlign="space-between center">
<div class="fixed-title-width tb-required" tb-hint-tooltip-icon="{{ 'gateway.max-messages-queue-for-worker-hint' | translate }}" translate>
<div class="fixed-title-width tb-required" [style.width.%]="50"
tb-hint-tooltip-icon="{{ 'gateway.max-messages-queue-for-worker-hint' | translate }}" translate>
gateway.max-messages-queue-for-worker
</div>
<div class="tb-flex no-gap">
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
<input matInput name="value" type="number" min="1" formControlName="maxMessageNumberPerWorker" placeholder="{{ 'gateway.default' | translate }}"/>
<input matInput name="value" type="number" min="1" formControlName="maxMessageNumberPerWorker"
placeholder="{{ 'gateway.default' | translate }}"/>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"

71
ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss

@ -43,26 +43,6 @@
.table-container {
overflow: auto;
.tb-add-new {
display: flex;
z-index: 1;
pointer-events: none;
button.connector {
height: auto;
padding-right: 12px;
font-size: 20px;
border-style: dashed;
border-width: 2px;
border-radius: 8px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
color: rgba(0, 0, 0, 0.38);
}
}
}
}
@ -126,14 +106,51 @@
}
:host ::ng-deep {
.mat-mdc-icon-button.mat-mdc-button-base {
width: 36px;
height: 40px;
padding: 8px 4px;
}
.connector-container {
.mat-mdc-icon-button.mat-mdc-button-base {
width: 36px;
height: 40px;
padding: 8px 4px;
}
.mat-mdc-tab-group, .mat-mdc-tab-body-wrapper {
height: 100%;
.mat-mdc-tab-group, .mat-mdc-tab-body-wrapper {
height: 100%;
}
.mat-mdc-tab-body.mat-mdc-tab-body-active {
position: absolute;
}
.tb-form-row {
.fixed-title-width {
min-width: 120px;
width: 30%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.tb-add-new {
display: flex;
z-index: 999;
pointer-events: none;
background-color: #fff;
button.connector {
height: auto;
padding-right: 12px;
font-size: 20px;
border-style: dashed;
border-width: 2px;
border-radius: 8px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
color: rgba(0, 0, 0, 0.38);
}
}
}
}

75
ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts

@ -52,9 +52,9 @@ import {
ConnectorConfigurationModes,
ConnectorType,
GatewayConnector,
GatewayConnectorDefaultTypesTranslates,
GatewayConnectorDefaultTypesTranslatesMap,
GatewayLogLevel,
MappingTypes,
MappingType,
MqttVersions
} from './gateway-widget.models';
import { MatDialog } from '@angular/material/dialog';
@ -76,27 +76,29 @@ export class ForceErrorStateMatcher implements ErrorStateMatcher {
})
export class GatewayConnectorComponent extends PageComponent implements AfterViewInit {
@Input()
ctx: WidgetContext;
@Input()
device: EntityId;
@ViewChild('nameInput') nameInput: ElementRef;
@ViewChild(MatSort, {static: false}) sort: MatSort;
pageLink: PageLink;
connectorType = ConnectorType;
dataSource: MatTableDataSource<AttributeData>;
displayedColumns = ['enabled', 'key', 'type', 'syncStatus', 'errors', 'actions'];
mqttVersions = MqttVersions;
gatewayConnectorDefaultTypes = GatewayConnectorDefaultTypesTranslates;
gatewayConnectorDefaultTypes = GatewayConnectorDefaultTypesTranslatesMap;
connectorConfigurationModes = ConnectorConfigurationModes;
@Input()
ctx: WidgetContext;
@Input()
device: EntityId;
@ViewChild('nameInput') nameInput: ElementRef;
@ViewChild(MatSort, {static: false}) sort: MatSort;
connectorForm: FormGroup;
textSearchMode: boolean;
@ -105,10 +107,12 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
gatewayLogLevel = Object.values(GatewayLogLevel);
mappingTypes = MappingTypes;
mappingTypes = MappingType;
mode: ConnectorConfigurationModes = this.connectorConfigurationModes.BASIC;
initialConnector: GatewayConnector;
private inactiveConnectors: Array<string>;
private attributeDataSource: AttributeDatasource;
@ -125,8 +129,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
private basicConfigSub: Subscription;
initialConnector: GatewayConnector;
private subscriptionOptions: WidgetSubscriptionOptions = {
callbacks: {
onDataUpdated: () => this.ctx.ngZone.run(() => {
@ -175,7 +177,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
}
ngAfterViewInit() {
this.connectorForm.get('type').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(type => {
@ -193,17 +194,23 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
}
});
this.connectorForm.get('name').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((name) => {
if (this.connectorForm.get('type').value === ConnectorType.MQTT) {
this.connectorForm.get('basicConfig').get('broker.name')?.setValue(name);
}
});
this.connectorForm.get('configurationJson').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((config) => {
const basicConfig = this.connectorForm.get('basicConfig');
const connectorName = this.connectorForm.get('name').value;
const type = this.connectorForm.get('type').value;
const mode = this.connectorForm.get('mode').value;
if (
!isEqual(config, basicConfig?.value) &&
this.initialConnector?.name === connectorName &&
type === 'mqtt' &&
type === ConnectorType.MQTT &&
mode === ConnectorConfigurationModes.ADVANCED
) {
this.connectorForm.get('basicConfig').patchValue(config, {emitEvent: false});
@ -331,7 +338,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
});
}
private updateData(reload: boolean = false) {
private updateData(reload: boolean = false): void {
this.pageLink.sortOrder.property = this.sort.active;
this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()];
this.attributeDataSource.loadAttributes(this.device, AttributeScope.CLIENT_SCOPE, this.pageLink, reload).subscribe(data => {
@ -368,7 +375,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
return sharedIndex !== -1;
}
private combineData() {
private combineData(): void {
this.dataSource.data = [...this.activeData, ...this.inactiveData, ...this.sharedAttributeData].filter((item, index, self) =>
index === self.findIndex((t) => t.key === item.key)
).map(attribute => {
@ -433,7 +440,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
return this.initialConnector.name === connector.name;
}
showToast(message: string) {
showToast(message: string): void {
this.store.dispatch(new ActionNotificationShow(
{
message,
@ -460,9 +467,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
this.dialogService.confirm(title, content, 'Cancel', 'Delete').subscribe(result => {
if (result) {
const tasks: Array<Observable<any>> = [];
const scope = (this.initialConnector && this.activeConnectors.includes(this.initialConnector.name))
? AttributeScope.SHARED_SCOPE
: AttributeScope.SERVER_SCOPE;
const scope = this.activeConnectors.includes(attribute.value?.name) ?
AttributeScope.SHARED_SCOPE :
AttributeScope.SERVER_SCOPE;
tasks.push(this.attributeService.deleteEntityAttributes(this.device, scope, [attribute]));
const activeIndex = this.activeConnectors.indexOf(attribute.key);
const inactiveIndex = this.inactiveConnectors.indexOf(attribute.key);
@ -564,7 +571,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
value.configurationJson = {};
}
value.basicConfig = value.configurationJson;
if (value.type === 'mqtt') {
if (value.type === ConnectorType.MQTT) {
this.addMQTTConfigControls();
} else {
this.connectorForm.setControl('basicConfig', this.fb.group({}), {emitEvent: false});
@ -575,11 +582,11 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
});
}
generate(formControlName: string) {
generate(formControlName: string): void {
this.connectorForm.get(formControlName).patchValue(generateSecret(5));
}
private onDataUpdateError(e: any) {
private onDataUpdateError(e: any): void {
const exceptionData = this.utils.parseException(e);
let errorText = exceptionData.name;
if (exceptionData.message) {
@ -588,11 +595,11 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
console.error(errorText);
}
private onDataUpdated() {
private onDataUpdated(): void {
this.cd.detectChanges();
}
private generateSubscription() {
private generateSubscription(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
@ -614,7 +621,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
}
}
private addMQTTConfigControls() {
private addMQTTConfigControls(): void {
const configControl = this.fb.group({});
const brokerGroup = this.fb.group({
name: ['', [Validators.required]],
@ -637,7 +644,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
this.createBasicConfigWatcher();
}
private createBasicConfigWatcher() {
private createBasicConfigWatcher(): void {
if (this.basicConfigSub) {
this.basicConfigSub.unsubscribe();
}
@ -645,13 +652,11 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie
takeUntil(this.destroy$)
).subscribe((config) => {
const configJson = this.connectorForm.get('configurationJson');
const connectorName = this.connectorForm.get('name').value;
const type = this.connectorForm.get('type').value;
const mode = this.connectorForm.get('mode').value;
if (
!isEqual(config, configJson?.value) &&
this.initialConnector?.name === connectorName &&
type === 'mqtt' &&
type === ConnectorType.MQTT &&
mode === ConnectorConfigurationModes.BASIC
) {
this.connectorForm.get('configurationJson').patchValue(config, {emitEvent: false});

4
ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc-connector.component.ts

@ -33,7 +33,7 @@ import {
BLEMethodsTranslates,
CANByteOrders,
ConnectorType,
GatewayConnectorDefaultTypesTranslates,
GatewayConnectorDefaultTypesTranslatesMap,
HTTPMethods,
ModbusCodesTranslate,
ModbusCommandTypes,
@ -97,7 +97,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValue
bLEMethodsTranslates = BLEMethodsTranslates;
SocketMethodProcessingsTranslates = SocketMethodProcessingsTranslates;
SNMPMethodsTranslations = SNMPMethodsTranslations;
gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslates;
gatewayConnectorDefaultTypesTranslates = GatewayConnectorDefaultTypesTranslatesMap;
modbusCodesTranslate = ModbusCodesTranslate;
urlPattern = /^[-a-zA-Zd_$:{}?~+=\/.0-9-]*$/;

67
ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts

@ -17,6 +17,7 @@
import { ResourcesService } from '@core/services/resources.service';
import { Observable } from 'rxjs';
import { ValueTypeData } from '@shared/models/constants';
import { isUndefinedOrNull } from '@core/utils';
export enum StorageTypes {
MEMORY = 'memory',
@ -130,7 +131,7 @@ export enum ConnectorType {
CUSTOM = 'custom'
}
export const GatewayConnectorDefaultTypesTranslates = new Map<ConnectorType, string>([
export const GatewayConnectorDefaultTypesTranslatesMap = new Map<ConnectorType, string>([
[ConnectorType.MQTT, 'MQTT'],
[ConnectorType.MODBUS, 'MODBUS'],
[ConnectorType.GRPC, 'GRPC'],
@ -311,22 +312,33 @@ export interface AddConnectorConfigData {
dataSourceData: Array<any>
}
export interface MappingDataKey {
key: string,
value: any,
type: MappingValueType
}
export interface MappingInfo {
mappingType: MappingType,
value: {[key: string]: any},
buttonTitle: string
}
export enum ConnectorConfigurationModes {
BASIC = 'basic',
ADVANCED = 'advanced'
}
export enum BrokerSecurityTypes {
export enum BrokerSecurityType {
ANONYMOUS = 'anonymous',
BASIC = 'basic',
CERTIFICATES = 'certificates'
}
export const BrokerSecurityTypeTranslations = new Map<BrokerSecurityTypes, string>(
export const BrokerSecurityTypeTranslationsMap = new Map<BrokerSecurityType, string>(
[
[BrokerSecurityTypes.ANONYMOUS, 'gateway.broker.security-types.anonymous'],
[BrokerSecurityTypes.BASIC, 'gateway.broker.security-types.basic'],
[BrokerSecurityTypes.CERTIFICATES, 'gateway.broker.security-types.certificates']
[BrokerSecurityType.ANONYMOUS, 'gateway.broker.security-types.anonymous'],
[BrokerSecurityType.BASIC, 'gateway.broker.security-types.basic'],
[BrokerSecurityType.CERTIFICATES, 'gateway.broker.security-types.certificates']
]
);
@ -336,22 +348,22 @@ export const MqttVersions = [
{ name: 5, value: 5 }
];
export enum MappingTypes {
export enum MappingType {
DATA = 'data',
REQUESTS = 'requests'
}
export const MappingTypeTranslationsMap = new Map<MappingTypes, string>(
export const MappingTypeTranslationsMap = new Map<MappingType, string>(
[
[MappingTypes.DATA, 'gateway.data-mapping'],
[MappingTypes.REQUESTS, 'gateway.requests-mapping']
[MappingType.DATA, 'gateway.data-mapping'],
[MappingType.REQUESTS, 'gateway.requests-mapping']
]
);
export const MappingHintTranslationsMap = new Map<MappingTypes, string>(
export const MappingHintTranslationsMap = new Map<MappingType, string>(
[
[MappingTypes.DATA, 'gateway.data-mapping-hint'],
[MappingTypes.REQUESTS, 'gateway.requests-mapping-hint']
[MappingType.DATA, 'gateway.data-mapping-hint'],
[MappingType.REQUESTS, 'gateway.requests-mapping-hint']
]
);
@ -365,17 +377,17 @@ export const QualityTypeTranslationsMap = new Map<number, string>(
]
);
export enum ConvertorTypes {
export enum ConvertorType {
JSON = 'json',
BYTES = 'bytes',
CUSTOM = 'custom'
}
export const ConvertorTypeTranslationsMap = new Map<ConvertorTypes, string>(
export const ConvertorTypeTranslationsMap = new Map<ConvertorType, string>(
[
[ConvertorTypes.JSON, 'gateway.JSON'],
[ConvertorTypes.BYTES, 'gateway.bytes'],
[ConvertorTypes.CUSTOM, 'gateway.custom']
[ConvertorType.JSON, 'gateway.JSON'],
[ConvertorType.BYTES, 'gateway.bytes'],
[ConvertorType.CUSTOM, 'gateway.custom']
]
);
@ -385,6 +397,11 @@ export enum SourceTypes {
CONST = 'constant'
}
export enum DeviceInfoType {
FULL = 'full',
PARTIAL = 'partial'
}
export const SourceTypeTranslationsMap = new Map<SourceTypes, string>(
[
[SourceTypes.MSG, 'gateway.source-type.msg'],
@ -393,7 +410,7 @@ export const SourceTypeTranslationsMap = new Map<SourceTypes, string>(
]
);
export enum RequestTypes {
export enum RequestType {
CONNECT_REQUEST = 'connectRequests',
DISCONNECT_REQUEST = 'disconnectRequests',
ATTRIBUTE_REQUEST = 'attributeRequests',
@ -401,13 +418,13 @@ export enum RequestTypes {
SERVER_SIDE_RPC = 'serverSideRpc'
}
export const RequestTypesTranslationsMap = new Map<RequestTypes, string>(
export const RequestTypesTranslationsMap = new Map<RequestType, string>(
[
[RequestTypes.CONNECT_REQUEST, 'gateway.request.connect-request'],
[RequestTypes.DISCONNECT_REQUEST, 'gateway.request.disconnect-request'],
[RequestTypes.ATTRIBUTE_REQUEST, 'gateway.request.attribute-request'],
[RequestTypes.ATTRIBUTE_UPDATE, 'gateway.request.attribute-update'],
[RequestTypes.SERVER_SIDE_RPC, 'gateway.request.rpc-connection'],
[RequestType.CONNECT_REQUEST, 'gateway.request.connect-request'],
[RequestType.DISCONNECT_REQUEST, 'gateway.request.disconnect-request'],
[RequestType.ATTRIBUTE_REQUEST, 'gateway.request.attribute-request'],
[RequestType.ATTRIBUTE_UPDATE, 'gateway.request.attribute-update'],
[RequestType.SERVER_SIDE_RPC, 'gateway.request.rpc-connection'],
]
);

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2803,6 +2803,7 @@
"download-tip": "Download configuration file",
"drop-file": "Drop file here or",
"extension": "Extension",
"extension-required": "Extension is required.",
"extension-configuration": "Extension configuration",
"extension-configuration-hint": "Configuration for convertor",
"fill-connector-defaults": "Fill configuration with default values",

Loading…
Cancel
Save