Browse Source

Merge pull request #4651 from vvlladd28/improvement/device-profile/lwm2m

UI: Refactoring device profile transport
pull/4691/head
Igor Kulikov 5 years ago
committed by GitHub
parent
commit
6cd7e3df4b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.scss
  2. 2
      ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.ts
  3. 4
      ui-ngx/src/app/modules/home/components/device/security-config-lwm2m.component.scss
  4. 21
      ui-ngx/src/app/modules/home/components/profile/device/coap-device-profile-transport-configuration.component.ts
  5. 17
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-configuration.component.ts
  6. 209
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html
  7. 153
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  8. 40
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  9. 57
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts
  10. 6
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html
  11. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html
  12. 3
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss
  13. 3
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
  14. 25
      ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts
  15. 28
      ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts
  16. 2
      ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts

20
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.scss

@ -1,20 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host ::ng-deep {
textarea.mat-input-element.cdk-textarea-autosize {
box-sizing: content-box;
}
}

2
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.ts

@ -41,7 +41,7 @@ import { Subject } from 'rxjs';
@Component({
selector: 'tb-security-config-lwm2m-server',
templateUrl: './security-config-lwm2m-server.component.html',
styleUrls: ['./security-config-lwm2m-server.component.scss'],
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,

4
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m.component.scss

@ -27,8 +27,4 @@
.mat-tab-body {
padding: 16px 0;
}
textarea.mat-input-element.cdk-textarea-autosize {
box-sizing: content-box;
}
}

21
ui-ngx/src/app/modules/home/components/profile/device/coap-device-profile-transport-configuration.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
@ -33,6 +33,8 @@ import {
transportPayloadTypeTranslationMap,
} from '@shared/models/device.models';
import { isDefinedAndNotNull } from '@core/utils';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-coap-device-profile-transport-configuration',
@ -44,7 +46,7 @@ import { isDefinedAndNotNull } from '@core/utils';
multi: true
}]
})
export class CoapDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
export class CoapDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
coapTransportDeviceTypes = Object.keys(CoapTransportDeviceType);
@ -56,6 +58,7 @@ export class CoapDeviceProfileTransportConfigurationComponent implements Control
coapDeviceProfileTransportConfigurationFormGroup: FormGroup;
private destroy$ = new Subject();
private requiredValue: boolean;
private transportPayloadTypeConfiguration = this.fb.group({
@ -99,15 +102,23 @@ export class CoapDeviceProfileTransportConfigurationComponent implements Control
})
}
);
this.coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType')
.valueChanges.subscribe(coapDeviceType => {
this.coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(coapDeviceType => {
this.updateCoapDeviceTypeBasedControls(coapDeviceType, true);
});
this.coapDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.coapDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
get coapDeviceTypeDefault(): boolean {
const coapDeviceType = this.coapDeviceProfileTransportConfigurationFormGroup.get('coapDeviceTypeConfiguration.coapDeviceType').value;
return coapDeviceType === CoapTransportDeviceType.DEFAULT;

17
ui-ngx/src/app/modules/home/components/profile/device/device-profile-configuration.component.ts

@ -14,13 +14,15 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models';
import { deepClone } from '@core/utils';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-device-profile-configuration',
@ -32,12 +34,14 @@ import { deepClone } from '@core/utils';
multi: true
}]
})
export class DeviceProfileConfigurationComponent implements ControlValueAccessor, OnInit {
export class DeviceProfileConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
deviceProfileType = DeviceProfileType;
deviceProfileConfigurationFormGroup: FormGroup;
private destroy$ = new Subject();
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
@ -69,11 +73,18 @@ export class DeviceProfileConfigurationComponent implements ControlValueAccessor
this.deviceProfileConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.deviceProfileConfigurationFormGroup.valueChanges.subscribe(() => {
this.deviceProfileConfigurationFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {

209
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html

@ -15,112 +15,107 @@
limitations under the License.
-->
<section [formGroup]="serverFormGroup" style="min-width: 400px;">
<div class="mat-padding">
<div fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.mode' | translate }}</mat-label>
<mat-select formControlName="securityMode">
<mat-option *ngFor="let securityMode of securityConfigLwM2MTypes"
[value]="securityMode">
{{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.server-host' | translate }}</mat-label>
<input matInput type="text" formControlName="host" required
matTooltip="{{'device-profile.lwm2m.server-host-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('host').hasError('required')">
{{ 'device-profile.lwm2m.server-host' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label>
<input matInput type="number" formControlName="port" required
matTooltip="{{'device-profile.lwm2m.server-port-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('port').hasError('required')">
{{ 'device-profile.lwm2m.server-port' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="serverId" required
matTooltip="{{'device-profile.lwm2m.short-id-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div fxLayout="column">
<div fxLayout="row" fxLayoutGap="10px">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label>
<input matInput type="number" formControlName="clientHoldOffTime" required
matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')">
{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}</mat-label>
<input matInput type="number" formControlName="bootstrapServerAccountTimeout" required
matTooltip="{{'device-profile.lwm2m.bootstrap-server-account-timeout-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')">
{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-checkbox formControlName="bootstrapServerIs" color="primary">
{{ 'device-profile.lwm2m.bootstrap-server' | translate }}
</mat-checkbox>
</div>
<div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label>
<textarea matInput
#serverPublicKey
maxlength="{{lenMaxServerPublicKey}}"
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cols="1" required
style="overflow:hidden"
formControlName="serverPublicKey"
matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}"
></textarea>
<mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('required')">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') &&
(serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: 0} }}</strong>
</mat-error>
<mat-error *ngIf="(serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
serverFormGroup.get('serverPublicKey').hasError('minlength')) &&
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: lenMaxServerPublicKey } }}</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<section [formGroup]="serverFormGroup">
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.mode' | translate }}</mat-label>
<mat-select formControlName="securityMode">
<mat-option *ngFor="let securityMode of securityConfigLwM2MTypes"
[value]="securityMode">
{{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.server-host' | translate }}</mat-label>
<input matInput type="text" formControlName="host" required
matTooltip="{{'device-profile.lwm2m.server-host-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('host').hasError('required')">
{{ 'device-profile.lwm2m.server-host' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label>
<input matInput type="number" formControlName="port" required
matTooltip="{{'device-profile.lwm2m.server-port-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('port').hasError('required')">
{{ 'device-profile.lwm2m.server-port' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="serverId" required
matTooltip="{{'device-profile.lwm2m.short-id-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label>
<input matInput type="number" formControlName="clientHoldOffTime" required
matTooltip="{{'device-profile.lwm2m.client-hold-off-time-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')">
{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}</mat-label>
<input matInput type="number" formControlName="bootstrapServerAccountTimeout" required
matTooltip="{{'device-profile.lwm2m.bootstrap-server-account-timeout-tip' | translate}}"
matTooltipPosition="above">
<mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')">
{{ 'device-profile.lwm2m.bootstrap-server-account-timeout' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-checkbox fxFlex formControlName="bootstrapServerIs" color="primary">
{{ 'device-profile.lwm2m.bootstrap-server' | translate }}
</mat-checkbox>
<div fxFlex></div>
</div>
<div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label>
<textarea matInput
#serverPublicKey
maxlength="{{lenMaxServerPublicKey}}"
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cols="1" required
style="overflow:hidden"
formControlName="serverPublicKey"
matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}"
></textarea>
<mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('required')">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') &&
(serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: 0} }}</strong>
</mat-error>
<mat-error *ngIf="(serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
serverFormGroup.get('serverPublicKey').hasError('minlength')) &&
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">
{{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate: {
count: lenMaxServerPublicKey } }}</strong>
</mat-error>
</mat-form-field>
</div>
</section>

153
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<section style="padding-bottom: 16px; margin: 0" mat-dialog-content>
<section style="padding-bottom: 16px; margin: 0">
<mat-tab-group dynamicHeight>
<mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}">
<ng-template matTabContent>
<section [formGroup]="lwm2mDeviceProfileFormGroup">
<div *ngIf="false" class="mat-padding" style="padding-bottom: 0px">
<div *ngIf="false" class="mat-padding" style="padding-bottom: 0">
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.client-only-observe-after-connect-label' | translate }}</mat-label>
<mat-select formControlName="clientOnlyObserveAfterConnect"
@ -34,20 +34,16 @@
</mat-select>
</mat-form-field>
</div>
<div class="mat-padding" style="padding-top: 0">
<tb-profile-lwm2m-object-list
(addList)="addObjectsList($event)"
(removeList)="removeObjectsList($event)"
[required]="required"
formControlName="objectIds">
</tb-profile-lwm2m-object-list>
</div>
<div class="mat-padding">
<tb-profile-lwm2m-observe-attr-telemetry
[required]="required"
formControlName="observeAttrTelemetry">
</tb-profile-lwm2m-observe-attr-telemetry>
</div>
<tb-profile-lwm2m-object-list
(addList)="addObjectsList($event)"
(removeList)="removeObjectsList($event)"
[required]="required"
formControlName="objectIds">
</tb-profile-lwm2m-object-list>
<tb-profile-lwm2m-observe-attr-telemetry
[required]="required"
formControlName="observeAttrTelemetry">
</tb-profile-lwm2m-observe-attr-telemetry>
</section>
</ng-template>
</mat-tab>
@ -58,94 +54,73 @@
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div class="tb-panel-title">{{ 'device-profile.lwm2m.servers' | translate | uppercase }}</div>
</mat-panel-title>
<mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="shortId" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
<input matInput type="number" formControlName="lifetime" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
{{ 'device-profile.lwm2m.lifetime' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
<input matInput type="number" formControlName="defaultMinPeriod" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
{{ 'device-profile.lwm2m.default-min-period' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block" fxFlex="100">
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<mat-select formControlName="binding">
<mat-option *ngFor="let bindingMode of bindingModeTypes"
[value]="bindingMode">
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div>
<mat-checkbox formControlName="notifIfDisabled" color="primary">
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
</mat-checkbox>
</div>
<div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<input matInput type="number" formControlName="shortId" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')">
{{ 'device-profile.lwm2m.short-id' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
<input matInput type="number" formControlName="lifetime" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')">
{{ 'device-profile.lwm2m.lifetime' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
<input matInput type="number" formControlName="defaultMinPeriod" required>
<mat-error
*ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')">
{{ 'device-profile.lwm2m.default-min-period' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<mat-select formControlName="binding">
<mat-option *ngFor="let bindingMode of bindingModeTypes"
[value]="bindingMode">
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox formControlName="notifIfDisabled" color="primary">
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
</mat-checkbox>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div
class="tb-panel-title">{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}</div>
</mat-panel-title>
<mat-panel-title>{{ 'device-profile.lwm2m.bootstrap-server' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="bootstrapServer"
[bootstrapServerIs]=true>
</tb-profile-lwm2m-device-config-server>
</div>
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="bootstrapServer"
[bootstrapServerIs]=true>
</tb-profile-lwm2m-device-config-server>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
<mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<div class="tb-panel-title">{{ 'device-profile.lwm2m.lwm2m-server' | translate | uppercase }}</div>
</mat-panel-title>
<mat-panel-title>{{ 'device-profile.lwm2m.lwm2m-server' | translate }}</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[bootstrapServerIs]=false>
</tb-profile-lwm2m-device-config-server>
</div>
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[bootstrapServerIs]=false>
</tb-profile-lwm2m-device-config-server>
</ng-template>
</mat-expansion-panel>
</mat-accordion>

40
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts

@ -15,7 +15,7 @@
///
import { DeviceProfileTransportConfiguration } from '@shared/models/device.models';
import { Component, forwardRef, Input } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
@ -39,6 +39,8 @@ import { deepClone, isDefinedAndNotNull, isEmpty, isUndefined } from '@core/util
import { JsonArray, JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point';
import { Direction } from '@shared/models/page/sort-order';
import _ from 'lodash';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-profile-lwm2m-device-transport-configuration',
@ -49,11 +51,12 @@ import _ from 'lodash';
multi: true
}]
})
export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators {
export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators, OnDestroy {
private configurationValue: Lwm2mProfileConfigModels;
private requiredValue: boolean;
private disabled = false;
private destroy$ = new Subject();
bindingModeType = BINDING_MODE;
bindingModeTypes = Object.keys(BINDING_MODE);
@ -87,17 +90,21 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
lifetime: [null, Validators.required],
defaultMinPeriod: [null, Validators.required],
notifIfDisabled: [true, []],
binding:[],
binding: [],
bootstrapServer: [null, Validators.required],
lwm2mServer: [null, Validators.required],
});
this.lwm2mDeviceConfigFormGroup = this.fb.group({
configurationJson: [null, Validators.required]
});
this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => {
this.lwm2mDeviceProfileFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
this.updateDeviceProfileValue(value);
});
this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => {
this.lwm2mDeviceConfigFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
this.sortFunction = this.sortObjectKeyPathJson;
@ -110,6 +117,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
registerOnTouched(fn: any): void {
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
@ -122,11 +134,17 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
writeValue(value: Lwm2mProfileConfigModels | null): void {
this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value;
this.lwm2mDeviceConfigFormGroup.patchValue({
configurationJson: this.configurationValue
}, {emitEvent: false});
this.initWriteValue();
if (isDefinedAndNotNull(value)) {
if (Object.keys(value).length !== 0 && (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap)) {
this.configurationValue = value;
} else {
this.configurationValue = getDefaultProfileConfig();
}
this.lwm2mDeviceConfigFormGroup.patchValue({
configurationJson: this.configurationValue
}, {emitEvent: false});
this.initWriteValue();
}
}
private initWriteValue = (): void => {
@ -252,7 +270,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
instanceUpdate.id = instanceId;
instanceUpdate.resources.forEach(resource => {
resource.keyName = _.camelCase(resource.name + instanceUpdate.id);
})
});
return instanceUpdate;
}

57
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts

@ -15,10 +15,19 @@
///
import { Component, ElementRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import {
ControlValueAccessor,
FormBuilder,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Observable } from 'rxjs';
import { filter, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators';
import { distinctUntilChanged, filter, mergeMap, share, tap } from 'rxjs/operators';
import { ModelValue, ObjectLwM2M, PAGE_SIZE_LIMIT } from './lwm2m-profile-config.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { Direction } from '@shared/models/page/sort-order';
@ -33,13 +42,18 @@ import { PageLink } from '@shared/models/page/page-link';
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObjectListComponent),
multi: true
}]
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => Lwm2mObjectListComponent),
multi: true
}
]
})
export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validators {
export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validator {
private requiredValue: boolean;
private dirty = false;
private lw2mModels: Observable<Array<ObjectLwM2M>>;
private modelValue: Array<string> = [];
lwm2mListFormGroup: FormGroup;
@ -78,8 +92,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
private updateValidators = (): void => {
this.lwm2mListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []);
this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity();
this.lwm2mListFormGroup.get('objectsList').setValidators(this.required ? [Validators.required] : []);
this.lwm2mListFormGroup.get('objectsList').updateValueAndValidity();
}
registerOnChange(fn: any): void {
@ -92,6 +106,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
ngOnInit() {
this.filteredObjectsList = this.lwm2mListFormGroup.get('objectLwm2m').valueChanges
.pipe(
distinctUntilChanged(),
tap((value) => {
if (value && typeof value !== 'string') {
this.add(value);
@ -100,7 +115,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
}),
filter(searchText => isString(searchText)),
mergeMap(searchText => this.fetchListObjects(searchText))
mergeMap(searchText => this.fetchListObjects(searchText)),
share()
);
}
@ -131,6 +147,12 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
}
validate(): ValidationErrors | null {
return this.lwm2mListFormGroup.valid ? null : {
lwm2mListObj: false
};
}
private add(object: ObjectLwM2M): void {
if (isDefinedAndNotNull(this.modelValue) && this.modelValue.indexOf(object.keyId) === -1) {
this.modelValue.push(object.keyId);
@ -157,23 +179,13 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
return object ? object.name : undefined;
}
private fetchListObjects = (searchText?: string): Observable<Array<ObjectLwM2M>> => {
private fetchListObjects = (searchText: string): Observable<Array<ObjectLwM2M>> => {
this.searchText = searchText;
return this.getLwM2mModelsPage().pipe(
map(objectLwM2Ms => objectLwM2Ms)
);
}
private getLwM2mModelsPage(): Observable<Array<ObjectLwM2M>> {
const pageLink = new PageLink(PAGE_SIZE_LIMIT, 0, this.searchText, {
property: 'id',
direction: Direction.ASC
});
this.lw2mModels = this.deviceProfileService.getLwm2mObjectsPage(pageLink).pipe(
publishReplay(1),
refCount()
);
return this.lw2mModels;
return this.deviceProfileService.getLwm2mObjectsPage(pageLink);
}
onFocus = (): void => {
@ -183,10 +195,9 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
}
private clear = (value: string = ''): void => {
this.objectInput.nativeElement.value = value;
private clear = (): void => {
this.searchText = '';
this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value);
this.lwm2mListFormGroup.get('objectLwm2m').patchValue(null);
setTimeout(() => {
this.objectInput.nativeElement.blur();
this.objectInput.nativeElement.focus();

6
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<section [formGroup]="resourceFormGroup" class="mat-padding">
<section [formGroup]="resourceFormGroup">
<div fxLayout="row" fxFill formArrayName="resources"
*ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams">
<div class="vertical-padding" fxLayout="column" fxFill [formGroupName]="i">
@ -46,14 +46,14 @@
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="attribute" color="warn"
[checked]="updateObserve(i)"
(change)="updateObserve(i)"
matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="telemetry" color="primary"
[checked]="updateObserve(i)"
(change)="updateObserve(i)"
matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>

2
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html

@ -16,7 +16,7 @@
-->
<section [formGroup]="observeAttrTelemetryFormGroup">
<mat-accordion multi="true" class="mat-body-1" formArrayName="clientLwM2M">
<mat-accordion multi="true" formArrayName="clientLwM2M">
<mat-expansion-panel
*ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;"
[formGroupName]="i">

3
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss

@ -24,6 +24,9 @@
}
:host{
section {
padding: 2px;
}
.instance-list {
mat-expansion-panel-header {
color: inherit;

3
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts

@ -64,7 +64,7 @@ export const BINDING_MODE_NAMES = new Map<BINDING_MODE, string>(
[BINDING_MODE.UQ, 'UQ: UDP connection in queue mode'],
[BINDING_MODE.US, 'US: both UDP and SMS connections active, both in standard mode'],
[BINDING_MODE.UQS, 'UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode'],
[BINDING_MODE.T,'T: TCP connection in standard mode'],
[BINDING_MODE.T, 'T: TCP connection in standard mode'],
[BINDING_MODE.TQ, 'TQ: TCP connection in queue mode'],
[BINDING_MODE.TS, 'TS: both TCP and SMS connections active, both in standard mode'],
[BINDING_MODE.TQS, 'TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode'],
@ -162,7 +162,6 @@ export interface Lwm2mProfileConfigModels {
clientLwM2mSettings: ClientLwM2mSettings;
observeAttr: ObservableAttributes;
bootstrap: BootstrapSecurityConfig;
}
export interface ClientLwM2mSettings {

25
ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import {
ControlValueAccessor,
FormBuilder,
@ -39,6 +39,8 @@ import {
transportPayloadTypeTranslationMap
} from '@shared/models/device.models';
import { isDefinedAndNotNull } from '@core/utils';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-mqtt-device-profile-transport-configuration',
@ -50,7 +52,7 @@ import { isDefinedAndNotNull } from '@core/utils';
multi: true
}]
})
export class MqttDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
export class MqttDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
transportPayloadTypes = Object.keys(TransportPayloadType);
@ -58,6 +60,7 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
mqttDeviceProfileTransportConfigurationFormGroup: FormGroup;
private destroy$ = new Subject();
private requiredValue: boolean;
get required(): boolean {
@ -98,15 +101,23 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
})
}, {validator: this.uniqueDeviceTopicValidator}
);
this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.transportPayloadType')
.valueChanges.subscribe(payloadType => {
this.mqttDeviceProfileTransportConfigurationFormGroup.get('transportPayloadTypeConfiguration.transportPayloadType').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(payloadType => {
this.updateTransportPayloadBasedControls(payloadType, true);
});
this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
@ -192,8 +203,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
}
private uniqueDeviceTopicValidator(control: FormGroup): { [key: string]: boolean } | null {
if (control.value) {
const formValue = control.value as MqttDeviceProfileTransportConfiguration;
if (control.getRawValue()) {
const formValue = control.getRawValue() as MqttDeviceProfileTransportConfiguration;
if (formValue.deviceAttributesTopic === formValue.deviceTelemetryTopic) {
return {unique: true};
}

28
ui-ngx/src/app/modules/home/components/profile/device/snmp-device-profile-transport-configuration.component.ts

@ -14,17 +14,19 @@
/// limitations under the License.
///
import {Component, forwardRef, Input, OnInit} from '@angular/core';
import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceProfileTransportConfiguration,
DeviceTransportType,
SnmpDeviceProfileTransportConfiguration
} from '@shared/models/device.models';
import {isDefinedAndNotNull} from "@core/utils";
import { isDefinedAndNotNull } from '@core/utils';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export interface OidMappingConfiguration {
isAttribute: boolean;
@ -44,8 +46,11 @@ export interface OidMappingConfiguration {
multi: true
}]
})
export class SnmpDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
export class SnmpDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit, OnDestroy {
snmpDeviceProfileTransportConfigurationFormGroup: FormGroup;
private destroy$ = new Subject();
private requiredValue: boolean;
private configuration = [];
@ -71,11 +76,18 @@ export class SnmpDeviceProfileTransportConfigurationComponent implements Control
this.snmpDeviceProfileTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.snmpDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.snmpDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}

2
ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts

@ -32,7 +32,7 @@ import {
})
export class DeviceProfileTabsComponent extends EntityTabsComponent<DeviceProfile> {
deviceTransportTypes = Object.keys(DeviceTransportType);
deviceTransportTypes = Object.values(DeviceTransportType);
deviceTransportTypeTranslations = deviceTransportTypeTranslationMap;

Loading…
Cancel
Save