Browse Source

Lwm2m: front: refactoring

pull/3980/head
nickAS21 6 years ago
parent
commit
cfa9a5778a
  1. 27
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.html
  2. 76
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts
  3. 218
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  4. 132
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  5. 68
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-list.component.ts
  6. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html
  7. 6
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts
  8. 82
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts
  9. 41
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts
  10. 153
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts
  11. 108
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts
  12. 3
      ui-ngx/src/app/modules/home/pages/device/device.module.ts
  13. 57
      ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html
  14. 62
      ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.ts
  15. 206
      ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html
  16. 185
      ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts
  17. 54
      ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts
  18. 6
      ui-ngx/src/app/shared/components/json-object-edit.component.ts
  19. 10
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

@ -90,9 +90,14 @@
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label> <mat-label>{{ 'device-profile.lwm2m.server-public-key' | translate }}</mat-label>
<textarea matInput type="text" rows="3" cols="1" required <textarea matInput
formControlName="serverPublicKey" #serverPublicKey #serverPublicKey
maxlength="{{lenMaxServerPublicKey}}" maxlength="{{lenMaxServerPublicKey}}"
cdkTextareaAutosize
cdkAutosizeMinRows="1"
cols="1" required
style="overflow:hidden"
formControlName="serverPublicKey"
matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}" matTooltip="{{'device-profile.lwm2m.server-public-key-tip' | translate}}"
></textarea> ></textarea>
<mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint> <mat-hint align="end">{{serverPublicKey.value?.length || 0}}/{{lenMaxServerPublicKey}}</mat-hint>
@ -101,14 +106,18 @@
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') && <mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') &&
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK"> (serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
{{ 'device-profile.lwm2m.client-key' | translate }} serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec_182' | translate }}</strong> {{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ translate.get('device-profile.lwm2m.pattern_hex_dec', {
count: 0}) | async }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('serverPublicKey').hasError('pattern') && <mat-error *ngIf="(serverFormGroup.get('serverPublicKey').hasError('maxlength') ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> serverFormGroup.get('serverPublicKey').hasError('minlength')) &&
{{ 'device-profile.lwm2m.client-key' | translate }} serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec' | translate }}</strong> {{ 'device-profile.lwm2m.server-public-key' | translate }}
<strong>{{ translate.get('device-profile.lwm2m.pattern_hex_dec', {
count: lenMaxServerPublicKey }) | async }}</strong>
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</div> </div>

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

@ -14,31 +14,28 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, forwardRef, Inject, Input, OnInit } from "@angular/core"; import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgModel, Validators FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators
} from "@angular/forms"; } from '@angular/forms';
import { import {
SECURITY_CONFIG_MODE, SECURITY_CONFIG_MODE,
SECURITY_CONFIG_MODE_NAMES, SECURITY_CONFIG_MODE_NAMES,
KEY_PUBLIC_REGEXP_PSK,
ServerSecurityConfig, ServerSecurityConfig,
LEN_MAX_PUBLIC_KEY_PSK,
LEN_MAX_PUBLIC_KEY_RPK_X509,
KEY_PUBLIC_REGEXP_X509,
DEFAULT_PORT_BOOTSTRAP_NO_SEC, DEFAULT_PORT_BOOTSTRAP_NO_SEC,
DEFAULT_PORT_SERVER_NO_SEC, DEFAULT_PORT_SERVER_NO_SEC,
DEFAULT_CLIENT_HOLD_OFF_TIME, DEFAULT_CLIENT_HOLD_OFF_TIME,
DEFAULT_ID_SERVER DEFAULT_ID_SERVER, LEN_MAX_PUBLIC_KEY_RPK, LEN_MAX_PUBLIC_KEY_X509, KEY_REGEXP_HEX_DEC
} from "./profile-config.models"; } from './profile-config.models';
import { Store } from "@ngrx/store"; import { Store } from '@ngrx/store';
import { AppState } from "@core/core.state"; import { AppState } from '@core/core.state';
import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { WINDOW } from "@core/services/window.service"; import { WINDOW } from '@core/services/window.service';
import { pairwise, startWith } from 'rxjs/operators'; import { pairwise, startWith } from 'rxjs/operators';
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { TranslateService } from '@ngx-translate/core';
@Component({ @Component({
selector: 'tb-profile-lwm2m-device-config-server', selector: 'tb-profile-lwm2m-device-config-server',
@ -55,12 +52,14 @@ import { DeviceProfileService } from '@core/http/device-profile.service';
export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators { export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validators {
private requiredValue: boolean; private requiredValue: boolean;
valuePrev = null; valuePrev = null;
serverFormGroup: FormGroup; serverFormGroup: FormGroup;
securityConfigLwM2MType = SECURITY_CONFIG_MODE; securityConfigLwM2MType = SECURITY_CONFIG_MODE;
securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE);
credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES;
lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; lenMinServerPublicKey = 0;
lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
currentSecurityMode = null; currentSecurityMode = null;
@ -80,6 +79,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
} }
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
public translate: TranslateService,
public fb: FormBuilder, public fb: FormBuilder,
private deviceProfileService: DeviceProfileService, private deviceProfileService: DeviceProfileService,
@Inject(WINDOW) private window: Window) { @Inject(WINDOW) private window: Window) {
@ -105,7 +105,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
ngOnInit(): void { ngOnInit(): void {
} }
updateValueFields(serverData: ServerSecurityConfig): void { private updateValueFields = (serverData: ServerSecurityConfig): void => {
serverData.bootstrapServerIs = this.bootstrapServerIs; serverData.bootstrapServerIs = this.bootstrapServerIs;
this.serverFormGroup.patchValue(serverData, {emitEvent: false}); this.serverFormGroup.patchValue(serverData, {emitEvent: false});
this.serverFormGroup.get('bootstrapServerIs').disable(); this.serverFormGroup.get('bootstrapServerIs').disable();
@ -113,40 +113,38 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
this.updateValidate(securityMode); this.updateValidate(securityMode);
} }
updateValidate(securityMode: SECURITY_CONFIG_MODE): void { private updateValidate = (securityMode: SECURITY_CONFIG_MODE): void => {
switch (securityMode) { switch (securityMode) {
case SECURITY_CONFIG_MODE.NO_SEC: case SECURITY_CONFIG_MODE.NO_SEC:
this.serverFormGroup.get('serverPublicKey').setValidators([]); this.setValidatorsNoSecPsk();
break; break;
case SECURITY_CONFIG_MODE.PSK: case SECURITY_CONFIG_MODE.PSK:
this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_PSK; this.setValidatorsNoSecPsk();
this.serverFormGroup.get('serverPublicKey').setValidators([]);
break; break;
case SECURITY_CONFIG_MODE.RPK: case SECURITY_CONFIG_MODE.RPK:
this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; this.lenMinServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_PSK)]); this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK;
this.setValidatorsRpkX509();
break; break;
case SECURITY_CONFIG_MODE.X509: case SECURITY_CONFIG_MODE.X509:
this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_RPK_X509; this.lenMinServerPublicKey = 0;
this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); this.lenMaxServerPublicKey = LEN_MAX_PUBLIC_KEY_X509;
this.setValidatorsRpkX509();
break; break;
} }
this.serverFormGroup.updateValueAndValidity(); this.serverFormGroup.updateValueAndValidity();
// this.checkValueWithNewValidate();
} }
// checkValueWithNewValidate(): void { private setValidatorsNoSecPsk = (): void => {
// this.serverFormGroup.patchValue({ this.serverFormGroup.get('serverPublicKey').setValidators([]);
// host: this.serverFormGroup.get('host').value, }
// port: this.serverFormGroup.get('port').value,
// bootstrapServerIs: this.serverFormGroup.get('bootstrapServerIs').value, private setValidatorsRpkX509 = (): void => {
// serverPublicKey: this.serverFormGroup.get('serverPublicKey').value, this.serverFormGroup.get('serverPublicKey').setValidators([Validators.required,
// clientHoldOffTime: this.serverFormGroup.get('clientHoldOffTime').value, Validators.pattern(KEY_REGEXP_HEX_DEC),
// serverId: this.serverFormGroup.get('serverId').value, Validators.minLength(this.lenMinServerPublicKey),
// bootstrapServerAccountTimeout: this.serverFormGroup.get('bootstrapServerAccountTimeout').value, Validators.maxLength(this.lenMaxServerPublicKey)]);
// }, }
// {emitEvent: true});
// }
writeValue(value: any): void { writeValue(value: any): void {
if (value) { if (value) {
@ -160,7 +158,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
this.propagateChange = fn; this.propagateChange = fn;
} }
private propagateChangeState(value: any): void { private propagateChangeState = (value: any): void => {
if (value !== undefined) { if (value !== undefined) {
if (this.valuePrev === null) { if (this.valuePrev === null) {
this.valuePrev = 'init'; this.valuePrev = 'init';
@ -190,7 +188,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
registerOnTouched(fn: any): void { registerOnTouched(fn: any): void {
} }
getServerGroup(): FormGroup { private getServerGroup = (): FormGroup => {
const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC; const port = this.bootstrapServerIs ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC;
return this.fb.group({ return this.fb.group({
host: [this.window.location.hostname, this.required ? [Validators.required] : []], host: [this.window.location.hostname, this.required ? [Validators.required] : []],
@ -204,7 +202,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
}); });
} }
getLwm2mBootstrapSecurityInfo(mode: string) { private getLwm2mBootstrapSecurityInfo = (mode: string): void => {
this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe( this.deviceProfileService.getLwm2mBootstrapSecurityInfo(mode, this.serverFormGroup.get('bootstrapServerIs').value).subscribe(
(serverSecurityConfig) => { (serverSecurityConfig) => {
this.serverFormGroup.patchValue({ this.serverFormGroup.patchValue({

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

@ -19,118 +19,126 @@
<div mat-dialog-content> <div mat-dialog-content>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}"> <mat-tab label="{{ 'device-profile.lwm2m.model-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<tb-profile-lwm2m-object-list <div class="mat-padding">
(addList)="addObjectsList($event)" <tb-profile-lwm2m-object-list
(removeList)="removeObjectsList($event)" (addList)="addObjectsList($event)"
[required]="required" (removeList)="removeObjectsList($event)"
formControlName="objectIds"> [required]="required"
</tb-profile-lwm2m-object-list> formControlName="objectIds">
</div> </tb-profile-lwm2m-object-list>
<div class="mat-padding"> </div>
<tb-profile-lwm2m-observe-attr-telemetry <div class="mat-padding">
[required]="required" <tb-profile-lwm2m-observe-attr-telemetry
formControlName="observeAttrTelemetry"> [required]="required"
</tb-profile-lwm2m-observe-attr-telemetry> formControlName="observeAttrTelemetry">
</div> </tb-profile-lwm2m-observe-attr-telemetry>
</div>
</ng-template>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'device-profile.lwm2m.bootstrap-tab' | translate }}"> <mat-tab label="{{ 'device-profile.lwm2m.bootstrap-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<mat-accordion multi="true" class="mat-body-1"> <div class="mat-padding">
<mat-expansion-panel> <mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel-header> <mat-expansion-panel>
<mat-panel-title> <mat-expansion-panel-header>
<div class="tb-panel-title">{{ 'device-profile.lwm2m.servers' | translate | uppercase }}</div> <mat-panel-title>
</mat-panel-title> <div class="tb-panel-title">{{ 'device-profile.lwm2m.servers' | translate | uppercase }}</div>
</mat-expansion-panel-header> </mat-panel-title>
<div fxLayout="column"> </mat-expansion-panel-header>
<div fxLayout="row" fxLayoutGap="8px"> <div fxLayout="column">
<mat-form-field fxFlex> <div fxLayout="row" fxLayoutGap="8px">
<mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> <mat-form-field fxFlex>
<input matInput type="number" formControlName="shortId" required> <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label>
<mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('shortId').hasError('required')"> <input matInput type="number" formControlName="shortId" required>
{{ 'device-profile.lwm2m.short-id' | translate }} <mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('shortId').hasError('required')">
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> {{ 'device-profile.lwm2m.short-id' | translate }}
</mat-error> <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-form-field> </mat-error>
<mat-form-field fxFlex> </mat-form-field>
<mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label> <mat-form-field fxFlex>
<input matInput type="number" formControlName="lifetime" required> <mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label>
<mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').hasError('required')"> <input matInput type="number" formControlName="lifetime" required>
{{ 'device-profile.lwm2m.lifetime' | translate }} <mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('lifetime').hasError('required')">
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> {{ 'device-profile.lwm2m.lifetime' | translate }}
</mat-error> <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-form-field> </mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px">
<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="lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').hasError('required')">
{{ 'device-profile.lwm2m.default-min-period' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<input matInput type="text" formControlName="binding" required>
<mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('binding').hasError('required')">
{{ 'device-profile.lwm2m.binding' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div>
<mat-checkbox formControlName="notifIfDisabled" color="primary">
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }}
</mat-checkbox>
</div>
</div> </div>
<div fxLayout="row" fxLayoutGap="8px"> </mat-expansion-panel>
<mat-form-field fxFlex> </mat-accordion>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label> <mat-accordion multi="true" class="mat-body-1">
<input matInput type="number" formControlName="defaultMinPeriod" required> <mat-expansion-panel>
<mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('defaultMinPeriod').hasError('required')"> <mat-expansion-panel-header>
{{ 'device-profile.lwm2m.default-min-period' | translate }} <mat-panel-title>
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> <div
</mat-error> class="tb-panel-title">{{ 'device-profile.lwm2m.bootstrap-server' | translate | uppercase }}</div>
</mat-form-field> </mat-panel-title>
<mat-form-field fxFlex> </mat-expansion-panel-header>
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label> <div class="mat-padding">
<input matInput type="text" formControlName="binding" required> <tb-profile-lwm2m-device-config-server
<mat-error *ngIf="lwm2mDeviceProfileTransportConfFormGroup.get('binding').hasError('required')"> [required]="required"
{{ 'device-profile.lwm2m.binding' | translate }} formControlName="bootstrapServer"
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> [bootstrapServerIs]=true>
</mat-error> </tb-profile-lwm2m-device-config-server>
</mat-form-field>
</div> </div>
<div> </mat-expansion-panel>
<mat-checkbox formControlName="notifIfDisabled" color="primary"> </mat-accordion>
{{ 'device-profile.lwm2m.notif-if-disabled' | translate }} <mat-accordion multi="true" class="mat-body-1">
</mat-checkbox> <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-expansion-panel-header>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[bootstrapServerIs]=false>
</tb-profile-lwm2m-device-config-server>
</div> </div>
</div> </mat-expansion-panel>
</mat-expansion-panel> </mat-accordion>
</mat-accordion> </div>
<mat-accordion multi="true" class="mat-body-1"> </ng-template>
<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-expansion-panel-header>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName = "bootstrapServer"
[bootstrapServerIs]=true>
</tb-profile-lwm2m-device-config-server>
</div>
</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-expansion-panel-header>
<div class="mat-padding">
<tb-profile-lwm2m-device-config-server
[required]="required"
formControlName="lwm2mServer"
[bootstrapServerIs]=false>
</tb-profile-lwm2m-device-config-server>
</div>
</mat-expansion-panel>
</mat-accordion>
</div>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'device-profile.lwm2m.config-json-tab' | translate }}"> <mat-tab label="{{ 'device-profile.lwm2m.config-json-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<tb-json-object-edit <div class="mat-padding">
[required]="required" <tb-json-object-edit
[sort] = "sortFunction" [required]="required"
label="{{ 'device-profile.transport-type-lwm2m' | translate }}" [sort]="sortFunction"
formControlName="configurationJson"> label="{{ 'device-profile.transport-type-lwm2m' | translate }}"
</tb-json-object-edit> formControlName="configurationJson">
</div> </tb-json-object-edit>
</div>
</ng-template>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</div> </div>

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

@ -34,10 +34,10 @@ import {
OBSERVE_ATTR, OBSERVE_ATTR,
TELEMETRY, TELEMETRY,
ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance, ProfileConfigModels, ResourceLwM2M ObjectLwM2M, getDefaultProfileConfig, KEY_NAME, Instance, ProfileConfigModels, ResourceLwM2M
} from "./profile-config.models"; } from './profile-config.models';
import { DeviceProfileService } from "@core/http/device-profile.service"; import { DeviceProfileService } from '@core/http/device-profile.service';
import { deepClone, isUndefined } from "@core/utils"; import { deepClone, isUndefined } from '@core/utils';
import { WINDOW } from "@core/services/window.service"; import { WINDOW } from '@core/services/window.service';
import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point';
import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined';
@ -65,7 +65,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
bootstrapServers: string; bootstrapServers: string;
bootstrapServer: string; bootstrapServer: string;
lwm2mServer: string; lwm2mServer: string;
sortFunction = this.sortObjectKeyPathJson; sortFunction: {};
get required(): boolean { get required(): boolean {
return this.requiredValue; return this.requiredValue;
@ -76,7 +76,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.requiredValue = coerceBooleanProperty(value); this.requiredValue = coerceBooleanProperty(value);
} }
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
private fb: FormBuilder, private fb: FormBuilder,
@ -109,6 +109,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
ngOnInit() { ngOnInit() {
this.sortFunction = this.sortObjectKeyPathJson;
} }
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
@ -130,22 +131,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.initWriteValue(); this.initWriteValue();
} }
private initWriteValue(): void { private initWriteValue = (): void => {
const modelValue = {objectIds: null, objectsList: []}; const modelValue = {objectIds: null, objectsList: []};
modelValue.objectIds = this.getObjectsFromJsonAllConfig(); modelValue.objectIds = this.getObjectsFromJsonAllConfig();
if (modelValue.objectIds !== null) { if (modelValue.objectIds !== null) {
this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe( this.deviceProfileService.getLwm2mObjects(modelValue.objectIds).subscribe(
(objectsList) => { (objectsList) => {
modelValue.objectsList = objectsList; modelValue.objectsList = objectsList;
this.updateWriteValue(modelValue); this.updateWriteValue(modelValue);
} }
); );
} else { } else {
this.updateWriteValue(modelValue); this.updateWriteValue(modelValue);
} }
} }
private updateWriteValue(value: any): void { private updateWriteValue = (value: any): void => {
const objectsList = deepClone(value.objectsList); const objectsList = deepClone(value.objectsList);
this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({
objectIds: value, objectIds: value,
@ -161,7 +162,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
{emitEvent: false}); {emitEvent: false});
} }
private updateModel() { private updateModel = (): void => {
let configuration: DeviceProfileTransportConfiguration = null; let configuration: DeviceProfileTransportConfiguration = null;
if (this.lwm2mDeviceProfileTransportConfFormGroup.valid) { if (this.lwm2mDeviceProfileTransportConfFormGroup.valid) {
this.upDateValueToJson(); this.upDateValueToJson();
@ -171,25 +172,25 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.propagateChange(configuration); this.propagateChange(configuration);
} }
private updateObserveAttrTelemetryObjectFormGroup(objectsList: ObjectLwM2M[]) { private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => {
this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({
observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)} observeAttrTelemetry: {clientLwM2M: this.getObserveAttrTelemetryObjects(objectsList)}
}, },
{emitEvent: false}); {emitEvent: false});
this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({
onlySelf: true onlySelf: true
}); });
} }
upDateValueToJson(): void { private upDateValueToJson = (): void => {
this.upDateValueToJsonTab_0(); this.upDateValueToJsonTab0();
this.upDateValueToJsonTab_1(); this.upDateValueToJsonTab1();
} }
upDateValueToJsonTab_0(): void { private upDateValueToJsonTab0 = (): void => {
if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').pristine) { if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').pristine) {
this.upDateObserveAttrTelemetryFromGroupToJson( this.upDateObserveAttrTelemetryFromGroupToJson(
this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M
); );
this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({ this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').markAsPristine({
onlySelf: true onlySelf: true
@ -198,7 +199,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
} }
upDateValueToJsonTab_1(): void { private upDateValueToJsonTab1 = (): void => {
this.upDateValueServersToJson(); this.upDateValueServersToJson();
if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) { if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').pristine) {
this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value; this.configurationValue.bootstrap.bootstrapServer = this.lwm2mDeviceProfileTransportConfFormGroup.get('bootstrapServer').value;
@ -216,7 +217,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
} }
upDateValueServersToJson(): void { private upDateValueServersToJson = (): void => {
const bootstrapServers = this.configurationValue.bootstrap.servers; const bootstrapServers = this.configurationValue.bootstrap.servers;
if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) { if (!this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').pristine) {
bootstrapServers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value; bootstrapServers.shortId = this.lwm2mDeviceProfileTransportConfFormGroup.get('shortId').value;
@ -255,7 +256,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
} }
getObserveAttrTelemetryObjects(listObject: ObjectLwM2M[]): ObjectLwM2M [] { private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): ObjectLwM2M [] => {
const clientObserveAttr = deepClone(listObject); const clientObserveAttr = deepClone(listObject);
if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr]) {
const observeArray = this.configurationValue[this.observeAttr][this.observe] as Array<string>; const observeArray = this.configurationValue[this.observeAttr][this.observe] as Array<string>;
@ -284,12 +285,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
return clientObserveAttr; return clientObserveAttr;
} }
includesInstancesNo(attributeArray: Array<string>, telemetryArray: Array<string>): boolean { private includesInstancesNo = (attributeArray: Array<string>, telemetryArray: Array<string>): boolean => {
const isIdIndex = (element) => !element.includes('/0/'); const isIdIndex = (element) => !element.includes('/0/');
return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0; return attributeArray.findIndex(isIdIndex) >= 0 || telemetryArray.findIndex(isIdIndex) >= 0;
} }
addInstances(attributeArray: Array<string>, telemetryArray: Array<string>, clientObserveAttr: ObjectLwM2M[]): void { private addInstances = (attributeArray: Array<string>, telemetryArray: Array<string>,
clientObserveAttr: ObjectLwM2M[]): void => {
const attr = [] as Array<string>; const attr = [] as Array<string>;
[...attributeArray].filter(x => (!x.includes('/0/'))).forEach(x => { [...attributeArray].filter(x => (!x.includes('/0/'))).forEach(x => {
attr.push(this.convertPathToInstance(x)); attr.push(this.convertPathToInstance(x));
@ -310,42 +312,43 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}); });
} }
convertPathToInstance(path: string): string { private convertPathToInstance = (path: string): string => {
const newX = Array.from(path.substring(1).split('/'), Number); const newX = Array.from(path.substring(1).split('/'), Number);
return [newX[0], newX[1]].join('/'); return [newX[0], newX[1]].join('/');
} }
updateObserveAttrTelemetryObjects(isParameter: Array<string>, clientObserveAttr: ObjectLwM2M[], nameParameter: string): void { private updateObserveAttrTelemetryObjects = (isParameter: Array<string>, clientObserveAttr: ObjectLwM2M[],
nameParameter: string): void => {
isParameter.forEach(attr => { isParameter.forEach(attr => {
const idKeys = Array.from(attr.substring(1).split('/'), Number); const idKeys = Array.from(attr.substring(1).split('/'), Number);
clientObserveAttr clientObserveAttr
.forEach(e => { .forEach(e => {
if (e.id === idKeys[0]) { if (e.id === idKeys[0]) {
const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]); const instance = e.instances.find(itrInstance => itrInstance.id === idKeys[1]);
if (isNotNullOrUndefined(instance)) { if (isNotNullOrUndefined(instance)) {
instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true; instance.resources.find(resource => resource.id === idKeys[2])[nameParameter] = true;
}
} }
}); }
});
}); });
} }
updateKeyNameObjects(nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void { private updateKeyNameObjects = (nameJson: JsonObject, clientObserveAttr: ObjectLwM2M[]): void => {
const keyName = JSON.parse(JSON.stringify(nameJson)); const keyName = JSON.parse(JSON.stringify(nameJson));
Object.keys(keyName).forEach(key => { Object.keys(keyName).forEach(key => {
const idKeys = Array.from(key.substring(1).split('/'), Number); const idKeys = Array.from(key.substring(1).split('/'), Number);
clientObserveAttr clientObserveAttr
.forEach(e => { .forEach(e => {
if (e.id === idKeys[0]) { if (e.id === idKeys[0]) {
e.instances e.instances
.find(instance => instance.id === idKeys[1]).resources .find(instance => instance.id === idKeys[1]).resources
.find(resource => resource.id === idKeys[2]).keyName = keyName[key]; .find(resource => resource.id === idKeys[2]).keyName = keyName[key];
} }
}); });
}); });
} }
upDateObserveAttrTelemetryFromGroupToJson(val: ObjectLwM2M[]): void { private upDateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => {
const observeArray: Array<string> = []; const observeArray: Array<string> = [];
const attributeArray: Array<string> = []; const attributeArray: Array<string> = [];
const telemetryArray: Array<string> = []; const telemetryArray: Array<string> = [];
@ -405,19 +408,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.updateKeyName(); this.updateKeyName();
} }
sortObjectKeyPathJson(key, value) { sortObjectKeyPathJson = (key: string, value: object): object => {
if (key === 'keyName') { if (key === 'keyName') {
return Object.keys(value).sort((a, b) => { return Object.keys(value).sort((a, b) => {
const aLC = Array.from(a.substring(1).split('/'), Number); const aLC = Array.from(a.substring(1).split('/'), Number);
const bLC = Array.from(b.substring(1).split('/'), Number); const bLC = Array.from(b.substring(1).split('/'), Number);
return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0];
}).reduce((r, k) => r[k] = value[k], {}); }).reduce((obj, keySort) => {
obj[keySort] = value[keySort];
return obj;
}, {});
} else { } else {
return value; return value;
} }
} }
updateKeyName(): void { private updateKeyName = (): void => {
const paths = new Set<string>(); const paths = new Set<string>();
if (this.configurationValue[this.observeAttr][this.attribute]) { if (this.configurationValue[this.observeAttr][this.attribute]) {
this.configurationValue[this.observeAttr][this.attribute].forEach(path => { this.configurationValue[this.observeAttr][this.attribute].forEach(path => {
@ -431,20 +437,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
const keyNameNew = {}; const keyNameNew = {};
paths.forEach(path => { paths.forEach(path => {
const pathParameter = this.findIndexsForIds(path); const pathParameter = this.findIndexesForIds(path);
if (pathParameter.length === 3) { if (pathParameter.length === 3) {
keyNameNew[path] = this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value keyNameNew[path] = this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value
.clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName]; .clientLwM2M[pathParameter[0]].instances[pathParameter[1]].resources[pathParameter[2]][this.keyName];
} }
}); });
this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew); this.configurationValue[this.observeAttr][this.keyName] = this.sortObjectKeyPathJson('keyName', keyNameNew);
} }
findIndexsForIds(path: string): number[] { private findIndexesForIds = (path: string): number[] => {
const pathParameter = Array.from(path.substring(1).split('/'), Number); const pathParameter = Array.from(path.substring(1).split('/'), Number);
const pathParameterIndexes: number[] = []; const pathParameterIndexes: number[] = [];
const objectsOld = deepClone( const objectsOld = deepClone(
this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[];
let isIdIndex = (element) => element.id === pathParameter[0]; let isIdIndex = (element) => element.id === pathParameter[0];
const objIndex = objectsOld.findIndex(isIdIndex); const objIndex = objectsOld.findIndex(isIdIndex);
if (objIndex >= 0) { if (objIndex >= 0) {
@ -463,7 +469,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
return pathParameterIndexes; return pathParameterIndexes;
} }
getObjectsFromJsonAllConfig(): number [] { private getObjectsFromJsonAllConfig = (): number [] => {
const objectsIds = new Set<number>(); const objectsIds = new Set<number>();
if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr]) {
if (this.configurationValue[this.observeAttr][this.observe]) { if (this.configurationValue[this.observeAttr][this.observe]) {
@ -485,7 +491,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
return (objectsIds.size > 0) ? Array.from(objectsIds) : null; return (objectsIds.size > 0) ? Array.from(objectsIds) : null;
} }
upDateJsonAllConfig(): void { private upDateJsonAllConfig = (): void => {
this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({ this.lwm2mDeviceProfileTransportConfFormGroup.patchValue({
configurationJson: this.configurationValue configurationJson: this.configurationValue
}, {emitEvent: false}); }, {emitEvent: false});
@ -494,11 +500,11 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}); });
} }
addObjectsList(value: ObjectLwM2M[]): void { addObjectsList = (value: ObjectLwM2M[]): void => {
this.updateObserveAttrTelemetryObjectFormGroup(deepClone(value)); this.updateObserveAttrTelemetryObjectFormGroup(deepClone(value));
} }
removeObjectsList(value: ObjectLwM2M): void { removeObjectsList = (value: ObjectLwM2M): void => {
const objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M); const objectsOld = deepClone(this.lwm2mDeviceProfileTransportConfFormGroup.get('observeAttrTelemetry').value.clientLwM2M);
const isIdIndex = (element) => element.id === value.id; const isIdIndex = (element) => element.id === value.id;
const index = objectsOld.findIndex(isIdIndex); const index = objectsOld.findIndex(isIdIndex);
@ -514,7 +520,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.upDateJsonAllConfig(); this.upDateJsonAllConfig();
} }
removeObserveAttrTelemetryFromJson(observeAttrTel: string, id: number): void { private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => {
const isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id; const isIdIndex = (element) => Array.from(element.substring(1).split('/'), Number)[0] === id;
let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex);
while (index >= 0) { while (index >= 0) {
@ -523,12 +529,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
} }
removeKeyNameFromJson(id: number): void { private removeKeyNameFromJson = (id: number): void => {
const keyNmaeJson = this.configurationValue[this.observeAttr][this.keyName]; const keyNameJson = this.configurationValue[this.observeAttr][this.keyName];
Object.keys(keyNmaeJson).forEach(key => { Object.keys(keyNameJson).forEach(key => {
const idKey = Array.from(key.substring(1).split('/'), Number)[0]; const idKey = Array.from(key.substring(1).split('/'), Number)[0];
if (idKey === id) { if (idKey === id) {
delete keyNmaeJson[key]; delete keyNameJson[key];
} }
}); });
} }
@ -538,10 +544,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
if (!isPath) { if (!isPath) {
isPath = this.findPathInJson(path, this.telemetry); isPath = this.findPathInJson(path, this.telemetry);
} }
return (isPath) ? true : false; return !!isPath;
} }
findPathInJson(path: string, side: string): string { private findPathInJson = (path: string, side: string): string => {
if (this.configurationValue[this.observeAttr]) { if (this.configurationValue[this.observeAttr]) {
if (this.configurationValue[this.observeAttr][side]) { if (this.configurationValue[this.observeAttr][side]) {
return this.configurationValue[this.observeAttr][side].find( return this.configurationValue[this.observeAttr][side].find(

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

@ -21,44 +21,45 @@ import {
OnInit, OnInit,
ViewChild, ViewChild,
ElementRef, ElementRef,
} from "@angular/core"; } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
FormBuilder, FormBuilder,
FormGroup, FormGroup,
NG_VALUE_ACCESSOR, Validators NG_VALUE_ACCESSOR, Validators
} from "@angular/forms"; } from '@angular/forms';
import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Store } from "@ngrx/store"; import { Store } from '@ngrx/store';
import { AppState } from "@core/core.state"; import { AppState } from '@core/core.state';
import { MatChipList } from '@angular/material/chips'; import { MatChipList } from '@angular/material/chips';
import { import {
INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MAX,
INSTANCES_ID_VALUE_MIN INSTANCES_ID_VALUE_MIN
} from "./profile-config.models"; } from './profile-config.models';
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from '@ngx-translate/core';
import { DeviceProfileService } from "@core/http/device-profile.service"; import { DeviceProfileService } from '@core/http/device-profile.service';
@Component({ @Component({
selector: 'tb-profile-lwm2m-object-add-instances-list', selector: 'tb-profile-lwm2m-object-add-instances-list',
templateUrl: './lwm2m-object-add-instances-list.component.html', templateUrl: './lwm2m-object-add-instances-list.component.html',
styleUrls: ['./lwm2m-object-add-instances-list.component.scss'], styleUrls: ['./lwm2m-object-add-instances-list.component.scss'],
providers: [{ providers: [{
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent), useExisting: forwardRef(() => Lwm2mObjectAddInstancesListComponent),
multi: true multi: true
}] }]
}) })
export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor, OnInit, Validators { export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccessor, OnInit, Validators {
lwm2mObjectListFormGroup: FormGroup;
private requiredValue: boolean; private requiredValue: boolean;
private instancesIdsList: Set<number> | null;
filteredObjectsList: Array<number>;
private disabled = false as boolean; private disabled = false as boolean;
private dirty = false as boolean; private dirty = false as boolean;
instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number
instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number lwm2mObjectListFormGroup: FormGroup;
instancesIdsList: Set<number> | null;
filteredObjectsList: Array<number>;
instanceIdValueMin = INSTANCES_ID_VALUE_MIN as number;
instanceIdValueMax = INSTANCES_ID_VALUE_MAX as number;
get required(): boolean { get required(): boolean {
return this.requiredValue; return this.requiredValue;
@ -76,8 +77,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso
@ViewChild('instanceIdInput') instanceIdInput: ElementRef<HTMLInputElement>; @ViewChild('instanceIdInput') instanceIdInput: ElementRef<HTMLInputElement>;
@ViewChild('chipList', {static: true}) chipList: MatChipList; @ViewChild('chipList', {static: true}) chipList: MatChipList;
private propagateChange = (v: any) => { private propagateChange = (v: any) => { };
};
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
public translate: TranslateService, public translate: TranslateService,
@ -89,7 +89,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso
}); });
} }
updateValidators() { private updateValidators = (): void => {
this.lwm2mObjectListFormGroup.get('instanceIdInput').setValidators([ this.lwm2mObjectListFormGroup.get('instanceIdInput').setValidators([
Validators.min(this.instanceIdValueMin), Validators.min(this.instanceIdValueMin),
Validators.max(this.instanceIdValueMax)]); Validators.max(this.instanceIdValueMax)]);
@ -128,41 +128,41 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso
this.dirty = false; this.dirty = false;
} }
add(value: number): void { add = (value: number): void => {
if (!isNaN(value) && this.lwm2mObjectListFormGroup.get('instanceIdInput').valid) { if (!isNaN(value) && this.lwm2mObjectListFormGroup.get('instanceIdInput').valid) {
this.instancesIdsList.add(value); this.instancesIdsList.add(value);
this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList);
this.propagateChange(this.instancesIdsList); this.propagateChange(this.instancesIdsList);
this.dirty = true this.dirty = true;
} }
this.clear(); this.clear();
} }
remove(object: number) { remove = (object: number): void => {
this.instancesIdsList.delete(object); this.instancesIdsList.delete(object);
this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList); this.lwm2mObjectListFormGroup.get('instancesIdsList').setValue(this.instancesIdsList);
this.propagateChange(this.instancesIdsList); this.propagateChange(this.instancesIdsList);
this.dirty = true this.dirty = true;
this.clear(); this.clear();
} }
//
// displayFn(object?: number): number | undefined {
// return object ? object : undefined;
// }
displayFn(object?: number): number | undefined { private clear = (): void => {
return object ? object : undefined;
}
clear() {
this.lwm2mObjectListFormGroup.get('instanceIdInput').patchValue(null, {emitEvent: true}); this.lwm2mObjectListFormGroup.get('instanceIdInput').patchValue(null, {emitEvent: true});
this.instanceIdInput.nativeElement.value = ""; this.instanceIdInput.nativeElement.value = '';
setTimeout(() => { setTimeout(() => {
this.instanceIdInput.nativeElement.blur(); this.instanceIdInput.nativeElement.blur();
this.instanceIdInput.nativeElement.focus(); this.instanceIdInput.nativeElement.focus();
}, 0); }, 0);
} }
onkeydown(e: KeyboardEvent) { onkeydown = (e: KeyboardEvent): boolean => {
if (e.keyCode == 189 || e.keyCode == 187 || e.keyCode == 109 || e.keyCode == 107) { if (e.keyCode === 189 || e.keyCode === 187 || e.keyCode === 109 || e.keyCode === 107) {
return false; return false;
} else if (e.keyCode == 8) { } else if (e.keyCode === 8) {
if (this.lwm2mObjectListFormGroup.get('instanceIdInput').value == null) { if (this.lwm2mObjectListFormGroup.get('instanceIdInput').value == null) {
this.clear(); this.clear();
} }
@ -170,7 +170,7 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso
} }
} }
onFocus() { onFocus = (): void => {
if (this.dirty) { if (this.dirty) {
this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.lwm2mObjectListFormGroup.get('instanceIdInput').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false; this.dirty = false;

2
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html

@ -42,7 +42,7 @@
<button mat-button color="primary" <button mat-button color="primary"
type="button" type="button"
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial> (click)="cancel()">
{{ 'action.cancel' | translate }} {{ 'action.cancel' | translate }}
</button> </button>
<button mat-button mat-raised-button color="primary" <button mat-button mat-raised-button color="primary"

6
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts

@ -36,8 +36,6 @@ export interface Lwm2mObjectAddInstancesData {
export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjectAddInstancesComponent, object> implements OnInit { export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjectAddInstancesComponent, object> implements OnInit {
jsonFormGroup: FormGroup; jsonFormGroup: FormGroup;
// title: string;
submitted = false; submitted = false;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
@ -52,7 +50,7 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjec
ngOnInit(): void { ngOnInit(): void {
this.jsonFormGroup = this.fb.group({ this.jsonFormGroup = this.fb.group({
instancesIds: this.data.instancesIds instancesIds: this.data.instancesIds
}) });
} }
cancel(): void { cancel(): void {
@ -60,7 +58,7 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjec
} }
add(): void { add(): void {
this.data.instancesIds = this.jsonFormGroup.get('instancesIds').value this.data.instancesIds = this.jsonFormGroup.get('instancesIds').value;
this.dialogRef.close(this.data); this.dialogRef.close(this.data);
} }
} }

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

@ -23,25 +23,25 @@ import {
ElementRef, ElementRef,
Output, Output,
EventEmitter EventEmitter
} from "@angular/core"; } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
FormBuilder, FormBuilder,
FormGroup, FormGroup,
NG_VALUE_ACCESSOR, Validators NG_VALUE_ACCESSOR, Validators
} from "@angular/forms"; } from '@angular/forms';
import {coerceBooleanProperty} from "@angular/cdk/coercion"; import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {Store} from "@ngrx/store"; import {Store} from '@ngrx/store';
import {AppState} from "@core/core.state"; import {AppState} from '@core/core.state';
import {MatChipList} from '@angular/material/chips'; import {MatChipList} from '@angular/material/chips';
import {MatAutocomplete} from "@angular/material/autocomplete"; import {MatAutocomplete} from '@angular/material/autocomplete';
import {Observable} from "rxjs"; import {Observable} from 'rxjs';
import {filter, map, mergeMap, share, tap} from 'rxjs/operators'; import {filter, map, mergeMap, share, tap} from 'rxjs/operators';
import {ObjectLwM2M} from "./profile-config.models"; import {ObjectLwM2M} from './profile-config.models';
import {TranslateService} from "@ngx-translate/core"; import {TranslateService} from '@ngx-translate/core';
import {DeviceProfileService} from "@core/http/device-profile.service"; import {DeviceProfileService} from '@core/http/device-profile.service';
import {PageLink} from "@shared/models/page/page-link"; import {PageLink} from '@shared/models/page/page-link';
import {Direction} from "@shared/models/page/sort-order"; import {Direction} from '@shared/models/page/sort-order';
@Component({ @Component({
selector: 'tb-profile-lwm2m-object-list', selector: 'tb-profile-lwm2m-object-list',
@ -56,14 +56,15 @@ import {Direction} from "@shared/models/page/sort-order";
}) })
export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validators { export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, Validators {
lwm2mObjectListFormGroup: FormGroup;
private requiredValue: boolean; private requiredValue: boolean;
private dirty = false as boolean;
lwm2mObjectListFormGroup: FormGroup;
modelValue: Array<number> | null; modelValue: Array<number> | null;
objectsList: Array<ObjectLwM2M> = []; objectsList: Array<ObjectLwM2M> = [];
filteredObjectsList: Observable<Array<ObjectLwM2M>>; filteredObjectsList: Observable<Array<ObjectLwM2M>>;
private disabled = false as boolean; disabled = false as boolean;
searchText = '' as string; searchText = '' as string;
private dirty = false as boolean;
get required(): boolean { get required(): boolean {
return this.requiredValue; return this.requiredValue;
@ -88,8 +89,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
@ViewChild('objectAutocomplete') matAutocomplete: MatAutocomplete; @ViewChild('objectAutocomplete') matAutocomplete: MatAutocomplete;
@ViewChild('chipList', {static: true}) chipList: MatChipList; @ViewChild('chipList', {static: true}) chipList: MatChipList;
private propagateChange = (v: any) => { private propagateChange = (v: any) => { };
};
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
public translate: TranslateService, public translate: TranslateService,
@ -101,7 +101,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}); });
} }
updateValidators() { private updateValidators = (): void => {
this.lwm2mObjectListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []); this.lwm2mObjectListFormGroup.get('objectLwm2m').setValidators(this.required ? [Validators.required] : []);
this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity(); this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity();
} }
@ -130,7 +130,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
); );
} }
ngAfterViewInit(): void { ngAfterViewInit = (): void => {
} }
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
@ -144,9 +144,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
writeValue(value: any): void { writeValue(value: any): void {
this.searchText = ''; this.searchText = '';
if (value.hasOwnProperty("objectIds") && value["objectIds"] != null && value["objectIds"].length > 0) { const objectIds = 'objectIds';
this.modelValue = [...value["objectIds"]]; if (value.hasOwnProperty(objectIds) && value[objectIds] != null && value[objectIds].length > 0) {
this.objectsList = value["objectsList"]; this.modelValue = [...value[objectIds]];
this.objectsList = value.objectsList;
this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList);
} else { } else {
this.objectsList = []; this.objectsList = [];
@ -156,19 +157,19 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
this.dirty = true; this.dirty = true;
} }
reset() { // reset() {
this.objectsList = []; // this.objectsList = [];
this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList); // this.lwm2mObjectListFormGroup.get('objectsList').setValue(this.objectsList);
this.modelValue = null; // this.modelValue = null;
if (this.objectInput) { // if (this.objectInput) {
this.objectInput.nativeElement.value = ''; // this.objectInput.nativeElement.value = '';
} // }
this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue('', {emitEvent: false}); // this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue('', {emitEvent: false});
this.propagateChange(this.modelValue); // this.propagateChange(this.modelValue);
this.dirty = true; // this.dirty = true;
} // }
add(object: ObjectLwM2M): void { private add = (object: ObjectLwM2M): void => {
if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) { if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) {
if (!this.modelValue) { if (!this.modelValue) {
this.modelValue = []; this.modelValue = [];
@ -182,7 +183,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
this.clear(); this.clear();
} }
remove(object: ObjectLwM2M) { remove = (object: ObjectLwM2M): void => {
let index = this.objectsList.indexOf(object); let index = this.objectsList.indexOf(object);
if (index >= 0) { if (index >= 0) {
this.objectsList.splice(index, 1); this.objectsList.splice(index, 1);
@ -198,11 +199,11 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
} }
} }
displayObjectLwm2mFn(object?: ObjectLwM2M): string | undefined { displayObjectLwm2mFn = (object?: ObjectLwM2M): string | undefined => {
return object ? object.name : undefined; return object ? object.name : undefined;
} }
fetchListObjects(searchText?: string): Observable<Array<ObjectLwM2M>> { private fetchListObjects = (searchText?: string): Observable<Array<ObjectLwM2M>> => {
this.searchText = searchText; this.searchText = searchText;
const pageLink = new PageLink(10, 0, searchText, { const pageLink = new PageLink(10, 0, searchText, {
property: 'name', property: 'name',
@ -210,20 +211,19 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}); });
return this.deviceProfileService.getLwm2mObjectsPage(pageLink, {ignoreLoading: true}).pipe( return this.deviceProfileService.getLwm2mObjectsPage(pageLink, {ignoreLoading: true}).pipe(
map(pageData => { map(pageData => {
let data = pageData.data; return pageData.data;
return data;
}) })
); );
} }
onFocus() { onFocus = (): void => {
if (this.dirty) { if (this.dirty) {
this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.lwm2mObjectListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false; this.dirty = false;
} }
} }
clear(value: string = '') { private clear = (value: string = ''): void => {
this.objectInput.nativeElement.value = value; this.objectInput.nativeElement.value = value;
this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); this.lwm2mObjectListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true});
setTimeout(() => { setTimeout(() => {

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

@ -14,13 +14,13 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, forwardRef, Input, OnInit } from "@angular/core"; import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
FormArray, FormBuilder, FormArray, FormBuilder,
FormGroup, FormGroup,
NG_VALUE_ACCESSOR, Validators NG_VALUE_ACCESSOR, Validators
} from "@angular/forms"; } from '@angular/forms';
import { import {
CAMEL_CASE_REGEXP, CAMEL_CASE_REGEXP,
ResourceLwM2M ResourceLwM2M
@ -45,10 +45,10 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor, OnInit, Validators { export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor, OnInit, Validators {
resourceFormGroup : FormGroup; private requiredValue: boolean;
resourceFormGroup: FormGroup;
disabled = false as boolean; disabled = false as boolean;
private requiredValue: boolean;
get required(): boolean { get required(): boolean {
return this.requiredValue; return this.requiredValue;
@ -63,7 +63,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA
} }
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
private fb: FormBuilder) { private fb: FormBuilder) {
this.resourceFormGroup = this.fb.group({'resources': this.fb.array([])}); this.resourceFormGroup = this.fb.group({resources: this.fb.array([])});
this.resourceFormGroup.valueChanges.subscribe(value => { this.resourceFormGroup.valueChanges.subscribe(value => {
if (!this.disabled) { if (!this.disabled) {
this.propagateChangeState(value.resources); this.propagateChangeState(value.resources);
@ -85,7 +85,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA
return this.resourceFormGroup.get('resources') as FormArray; return this.resourceFormGroup.get('resources') as FormArray;
} }
resourceLwm2mFormArray(instance: FormGroup): FormArray { resourceLwm2mFormArray = (instance: FormGroup): FormArray => {
return instance.get('resources') as FormArray; return instance.get('resources') as FormArray;
} }
@ -98,28 +98,28 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA
} }
} }
getDisabledState(): boolean { getDisabledState = (): boolean => {
return this.disabled; return this.disabled;
} }
updateValueKeyName (event: any, z: number): void { updateValueKeyName = (event: any, z: number): void => {
this.resourceFormArray.at(z).patchValue( {keyName: this.keysToCamel(deepClone(event.target.value))} ); this.resourceFormArray.at(z).patchValue( {keyName: this.keysToCamel(deepClone(event.target.value))} );
} }
keysToCamel(o: any): string { private keysToCamel = (o: any): string => {
let val = o.split(" "); const val = o.split(' ');
let playStore = []; const playStore = [];
val.forEach(function (item, k){ val.forEach((item, k) => {
item = item.replace(CAMEL_CASE_REGEXP, ''); item = item.replace(CAMEL_CASE_REGEXP, '');
item = (k===0)? item.charAt(0).toLowerCase() + item.substr(1) : item.charAt(0).toUpperCase() + item.substr(1) item = (k === 0) ? item.charAt(0).toLowerCase() + item.substr(1) : item.charAt(0).toUpperCase() + item.substr(1);
playStore.push(item); playStore.push(item);
}); });
return playStore.join(''); return playStore.join('');
} }
createResourceLwM2M(resourcesLwM2MJson: ResourceLwM2M []): void { private createResourceLwM2M = (resourcesLwM2MJson: ResourceLwM2M []): void => {
if(resourcesLwM2MJson.length === this.resourceFormArray.length) { if (resourcesLwM2MJson.length === this.resourceFormArray.length) {
this.resourceFormArray.patchValue(resourcesLwM2MJson, {emitEvent: false}) this.resourceFormArray.patchValue(resourcesLwM2MJson, {emitEvent: false});
} else { } else {
this.resourceFormArray.clear(); this.resourceFormArray.clear();
resourcesLwM2MJson.forEach(resourceLwM2M => { resourcesLwM2MJson.forEach(resourceLwM2M => {
@ -131,18 +131,17 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA
telemetry: resourceLwM2M.telemetry, telemetry: resourceLwM2M.telemetry,
keyName: [resourceLwM2M.keyName, Validators.required] keyName: [resourceLwM2M.keyName, Validators.required]
})); }));
}) });
} }
} }
private propagateChange = (v: any) => { private propagateChange = (v: any) => { };
};
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
this.propagateChange = fn; this.propagateChange = fn;
} }
private propagateChangeState(value: any): void { private propagateChangeState = (value: any): void => {
if (value && this.resourceFormGroup.valid) { if (value && this.resourceFormGroup.valid) {
this.propagateChange(value); this.propagateChange(value);
} else { } else {
@ -150,7 +149,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA
} }
} }
trackByParams(index: number): number { trackByParams = (index: number): number => {
return index; return index;
} }
} }

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

@ -15,7 +15,7 @@
/// ///
import { Component, forwardRef, Input, OnInit, Output } from "@angular/core"; import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { import {
AbstractControl, AbstractControl,
ControlValueAccessor, ControlValueAccessor,
@ -24,10 +24,10 @@ import {
FormGroup, FormGroup,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
Validators Validators
} from "@angular/forms"; } from '@angular/forms';
import { Store } from "@ngrx/store"; import { Store } from '@ngrx/store';
import { AppState } from "@core/core.state"; import { AppState } from '@core/core.state';
import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { import {
ATTR, ATTR,
Instance, Instance,
@ -35,7 +35,7 @@ import {
OBSERVE, OBSERVE,
ResourceLwM2M, ResourceLwM2M,
TELEMETRY TELEMETRY
} from "./profile-config.models"; } from './profile-config.models';
import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined'; import { isNotNullOrUndefined } from 'codelyzer/util/isNotNullOrUndefined';
import { deepClone, isUndefined } from '@core/utils'; import { deepClone, isUndefined } from '@core/utils';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@ -60,12 +60,13 @@ import {
export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, OnInit, Validators { export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, OnInit, Validators {
private requiredValue: boolean;
valuePrev = null as any; valuePrev = null as any;
observeAttrTelemetryFormGroup: FormGroup; observeAttrTelemetryFormGroup: FormGroup;
observe = OBSERVE as string; observe = OBSERVE as string;
attribute = ATTR as string; attribute = ATTR as string;
telemetry = TELEMETRY as string; telemetry = TELEMETRY as string;
private requiredValue: boolean;
get required(): boolean { get required(): boolean {
return this.requiredValue; return this.requiredValue;
@ -74,6 +75,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
@Input() @Input()
disabled: boolean; disabled: boolean;
// tslint:disable-next-line:adjacent-overload-signatures
@Input() @Input()
set required(value: boolean) { set required(value: boolean) {
const newVal = coerceBooleanProperty(value); const newVal = coerceBooleanProperty(value);
@ -86,7 +88,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
private fb: FormBuilder, private fb: FormBuilder,
private dialog: MatDialog, private dialog: MatDialog,
private translate: TranslateService) { public translate: TranslateService) {
this.observeAttrTelemetryFormGroup = this.fb.group({ this.observeAttrTelemetryFormGroup = this.fb.group({
clientLwM2M: this.fb.array([]) clientLwM2M: this.fb.array([])
}); });
@ -100,19 +102,18 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
ngOnInit(): void { ngOnInit(): void {
} }
private propagateChange = (v: any) => { private propagateChange = (v: any) => { };
};
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
this.propagateChange = fn; this.propagateChange = fn;
} }
private propagateChangeState(value: any): void { private propagateChangeState = (value: any): void => {
if (value) { if (value) {
if (this.valuePrev === null) { if (this.valuePrev === null) {
this.valuePrev = "init"; this.valuePrev = 'init';
} else if (this.valuePrev === "init") { } else if (this.valuePrev === 'init') {
this.valuePrev = value; this.valuePrev = value;
} else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) { } else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) {
this.valuePrev = value; this.valuePrev = value;
@ -138,7 +139,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
} }
} }
getDisabledState(): boolean { getDisabledState = (): boolean => {
return this.disabled; return this.disabled;
} }
@ -146,13 +147,13 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
this.buildClientObjectsLwM2M(value.clientLwM2M); this.buildClientObjectsLwM2M(value.clientLwM2M);
} }
private buildClientObjectsLwM2M(objectsLwM2M: ObjectLwM2M []): void { private buildClientObjectsLwM2M = (objectsLwM2M: ObjectLwM2M []): void => {
this.observeAttrTelemetryFormGroup.setControl('clientLwM2M', this.observeAttrTelemetryFormGroup.setControl('clientLwM2M',
this.createObjectsLwM2M(objectsLwM2M) this.createObjectsLwM2M(objectsLwM2M)
); );
} }
createObjectsLwM2M(objectsLwM2MJson: ObjectLwM2M []): FormArray { private createObjectsLwM2M = (objectsLwM2MJson: ObjectLwM2M []): FormArray => {
return this.fb.array(objectsLwM2MJson.map((objectLwM2M) => { return this.fb.array(objectsLwM2MJson.map((objectLwM2M) => {
return this.fb.group({ return this.fb.group({
id: objectLwM2M.id, id: objectLwM2M.id,
@ -160,62 +161,62 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
multiple: objectLwM2M.multiple, multiple: objectLwM2M.multiple,
mandatory: objectLwM2M.mandatory, mandatory: objectLwM2M.mandatory,
instances: this.createInstanceLwM2M(objectLwM2M.instances) instances: this.createInstanceLwM2M(objectLwM2M.instances)
}) });
})) }));
} }
createInstanceLwM2M(instanceLwM2MJson: Instance []): FormArray { private createInstanceLwM2M = (instanceLwM2MJson: Instance []): FormArray => {
return this.fb.array(instanceLwM2MJson.map((instanceLwM2M, index) => { return this.fb.array(instanceLwM2MJson.map((instanceLwM2M) => {
return this.fb.group({ return this.fb.group({
id: instanceLwM2M.id, id: instanceLwM2M.id,
[this.observe]: {value: false, disabled: this.disabled}, [this.observe]: {value: false, disabled: this.disabled},
[this.attribute]: {value: false, disabled: this.disabled}, [this.attribute]: {value: false, disabled: this.disabled},
[this.telemetry]: {value: false, disabled: this.disabled}, [this.telemetry]: {value: false, disabled: this.disabled},
resources: {value: instanceLwM2M.resources, disabled: this.disabled} resources: {value: instanceLwM2M.resources, disabled: this.disabled}
}) });
})) }));
} }
clientLwM2MFormArray(formGroup: FormGroup): FormArray { clientLwM2MFormArray = (formGroup: FormGroup): FormArray => {
return formGroup.get('clientLwM2M') as FormArray; return formGroup.get('clientLwM2M') as FormArray;
} }
instancesLwm2mFormArray(objectLwM2M: AbstractControl): FormArray { instancesLwm2mFormArray = (objectLwM2M: AbstractControl): FormArray => {
return objectLwM2M.get('instances') as FormArray; return objectLwM2M.get('instances') as FormArray;
} }
changeInstanceResourcesCheckBox(value: boolean, instance: AbstractControl, type: string): void { changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: string): void => {
let resources = instance.get('resources').value as ResourceLwM2M [] const resources = instance.get('resources').value as ResourceLwM2M [];
resources.forEach(resource => resource[type] = value); resources.forEach(resource => resource[type] = value);
instance.get('resources').patchValue(resources); instance.get('resources').patchValue(resources);
this.propagateChange(this.observeAttrTelemetryFormGroup.value); this.propagateChange(this.observeAttrTelemetryFormGroup.value);
} }
updateValidators() { private updateValidators = (): void => {
this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? [Validators.required] : []); this.observeAttrTelemetryFormGroup.get('clientLwM2M').setValidators(this.required ? [Validators.required] : []);
this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity();
} }
trackByParams(index: number): number { trackByParams = (index: number): number => {
return index; return index;
} }
getIndeterminate(instance: AbstractControl, type: string) { getIndeterminate = (instance: AbstractControl, type: string): boolean => {
const resources = instance.get('resources').value as ResourceLwM2M []; const resources = instance.get('resources').value as ResourceLwM2M [];
if (isNotNullOrUndefined(resources)) { if (isNotNullOrUndefined(resources)) {
const isType = (element) => element[type] === true; const isType = (element) => element[type] === true;
let checkedResource = resources.filter(isType); const checkedResource = resources.filter(isType);
if (checkedResource.length === 0) return false; if (checkedResource.length === 0) { return false; }
else if (checkedResource.length === resources.length) { else if (checkedResource.length === resources.length) {
instance.patchValue({[type]: true}); instance.patchValue({[type]: true});
return false; return false;
} else return true; } else { return true; }
} }
return false; return false;
} }
getChecked(instance: AbstractControl, type: string) { getChecked = (instance: AbstractControl, type: string): boolean => {
const resources = instance.get('resources').value as ResourceLwM2M []; const resources = instance.get('resources').value as ResourceLwM2M [];
if (isNotNullOrUndefined(resources)) { if (isNotNullOrUndefined(resources)) {
return resources.some(resource => resource[type]); return resources.some(resource => resource[type]);
@ -223,7 +224,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
return false; return false;
} }
getExpended(objectLwM2M: AbstractControl) { getExpended = (objectLwM2M: AbstractControl): boolean => {
return this.instancesLwm2mFormArray(objectLwM2M).length === 1; return this.instancesLwm2mFormArray(objectLwM2M).length === 1;
} }
@ -233,22 +234,24 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
* 2) Field in object: <Mandatory> == Mandatory/Optional * 2) Field in object: <Mandatory> == Mandatory/Optional
* If this field is “Multiple” then the number of Object Instance can be from 0 to many (Object Instance ID MAX_ID=65535). * If this field is “Multiple” then the number of Object Instance can be from 0 to many (Object Instance ID MAX_ID=65535).
* If this field is “Single” then the number of Object Instance can be from 0 to 1. (max count == 1) * If this field is “Single” then the number of Object Instance can be from 0 to 1. (max count == 1)
* If the Object field “Mandatory” is “Mandatory” and the Object field “Instances” is “Single” then, the number of Object Instance MUST be 1. * If the Object field “Mandatory” is “Mandatory” and the Object field “Instances” is “Single” then -
* 1. <MultipleInstances> == Multiple (true), <Mandatory> == Optional (false) => Object Instance ID MIN_ID=0 MAX_ID=65535 (может ни одного не быть) * the number of Object Instance MUST be 1.
* 2. <MultipleInstances> == Multiple (true), <Mandatory> == Mandatory (true) => Object Instance ID MIN_ID=0 MAX_ID=65535 (min один обязательный) * 1. <MultipleInstances> == Multiple (true), <Mandatory> == Optional (false) -
* 3. <MultipleInstances> == Single (false), <Mandatory> == Optional (false) => Object Instance ID cnt_max = 1 cnt_min = 0 (может ни одного не быть) * Object Instance ID MIN_ID=0 MAX_ID=65535 (может ни одного не быть)
* 4. <MultipleInstances> == Single (false), <Mandatory> == Mandatory (true) => Object Instance ID cnt_max = cnt_min = 1 (всегда есть один) * 2. <MultipleInstances> == Multiple (true), <Mandatory> == Mandatory (true) -
* @param $event * Object Instance ID MIN_ID=0 MAX_ID=65535 (min один обязательный)
* @param objectId * 3. <MultipleInstances> == Single (false), <Mandatory> == Optional (false) -
* @param objectName * Object Instance ID cnt_max = 1 cnt_min = 0 (может ни одного не быть)
* 4. <MultipleInstances> == Single (false), <Mandatory> == Mandatory (true) -
* Object Instance ID cnt_max = cnt_min = 1 (всегда есть один)
*/ */
addInstances($event: Event, object: ObjectLwM2M): void { addInstances = ($event: Event, object: ObjectLwM2M): void => {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
$event.preventDefault(); $event.preventDefault();
} }
let instancesIds = new Set<number>(); const instancesIds = new Set<number>();
object.instances.forEach(inst => { object.instances.forEach(inst => {
instancesIds.add(inst.id); instancesIds.add(inst.id);
}); });
@ -269,21 +272,22 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
); );
} }
updateInstancesIds(data: Lwm2mObjectAddInstancesData) { private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => {
let valueNew = new Set<number>(); const valueNew = new Set<number>();
let valueOld = new Set<number>(); const valueOld = new Set<number>();
data.instancesIds.forEach(value => { data.instancesIds.forEach(value => {
valueNew.add(value); valueNew.add(value);
}) });
let oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).find(e => e.id == data.objectId).instances; const oldInstances = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).
find(e => e.id === data.objectId).instances;
oldInstances.forEach(inst => { oldInstances.forEach(inst => {
valueOld.add(inst.id); valueOld.add(inst.id);
}); });
if (JSON.stringify(Array.from(valueOld)) != JSON.stringify(Array.from(valueNew))) { if (JSON.stringify(Array.from(valueOld)) !== JSON.stringify(Array.from(valueNew))) {
let idsDel = this.diffBetweenSet(valueNew, this.deepCloneSet(valueOld)); const idsDel = this.diffBetweenSet(valueNew, this.deepCloneSet(valueOld));
let idsAdd = this.diffBetweenSet(valueOld, this.deepCloneSet(valueNew)); const idsAdd = this.diffBetweenSet(valueOld, this.deepCloneSet(valueNew));
if (idsAdd.size) { if (idsAdd.size) {
this.addInstancesNew(data.objectId, idsAdd) this.addInstancesNew(data.objectId, idsAdd);
} }
if (idsDel.size) { if (idsDel.size) {
this.delInstances(data.objectId, idsDel); this.delInstances(data.objectId, idsDel);
@ -291,22 +295,25 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
} }
} }
delInstances(objectId: number, idsDel: Set<number>): void { private delInstances = (objectId: number, idsDel: Set<number>): void => {
let isIdIndex = (element) => element.id == objectId; let isIdIndex = (element) => element.id === objectId;
let objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).findIndex(isIdIndex); const objectIndex = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).findIndex(isIdIndex);
idsDel.forEach(x => { idsDel.forEach(x => {
isIdIndex = (element) => element.value.id == x; isIdIndex = (element) => element.value.id === x;
let instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls[objectIndex].get("instances") as FormArray); const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray)
let instanceIndex = instancesFormArray.controls.findIndex(isIdIndex); .controls[objectIndex].get('instances') as FormArray);
const instanceIndex = instancesFormArray.controls.findIndex(isIdIndex);
instancesFormArray.removeAt(instanceIndex); instancesFormArray.removeAt(instanceIndex);
}) });
} }
addInstancesNew(objectId: number, idsAdd: Set<number>): void { private addInstancesNew = (objectId: number, idsAdd: Set<number>): void => {
let instancesValue = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M []).find(e => e.id == objectId).instances; const instancesValue = (this.observeAttrTelemetryFormGroup.get('clientLwM2M').value as ObjectLwM2M [])
let instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls.find(e => e.value.id == objectId).get("instances") as FormArray) as FormArray; .find(e => e.id === objectId).instances;
const instancesFormArray = ((this.observeAttrTelemetryFormGroup.get('clientLwM2M') as FormArray).controls
.find(e => e.value.id === objectId).get('instances') as FormArray) as FormArray;
idsAdd.forEach(x => { idsAdd.forEach(x => {
let instanceNew = deepClone(instancesValue[0]) as Instance; const instanceNew = deepClone(instancesValue[0]) as Instance;
instanceNew.id = x; instanceNew.id = x;
instanceNew.resources.forEach(r => { instanceNew.resources.forEach(r => {
r.attribute = false; r.attribute = false;
@ -321,26 +328,26 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor,
resources: {value: instanceNew.resources, disabled: this.disabled} resources: {value: instanceNew.resources, disabled: this.disabled}
})); }));
}); });
(instancesFormArray.controls as FormGroup[]).sort((a,b) => a.value.id - b.value.id); (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id);
} }
deepCloneSet(oldSet: Set<any>): Set<any> { private deepCloneSet = (oldSet: Set<any>): Set<any> => {
let newSet = new Set<number>(); const newSet = new Set<number>();
oldSet.forEach(p => { oldSet.forEach(p => {
newSet.add(p); newSet.add(p);
}) });
return newSet; return newSet;
} }
diffBetweenSet(firstSet: Set<any>, secondSet: Set<any>): Set<any> { private diffBetweenSet = (firstSet: Set<any>, secondSet: Set<any>): Set<any> => {
firstSet.forEach(p => { firstSet.forEach(p => {
secondSet.delete(p); secondSet.delete(p);
}) });
return secondSet return secondSet;
} }
setInstancesIds(instances: Instance []): Set<number> { private setInstancesIds = (instances: Instance []): Set<number> => {
let instancesIds = new Set<number>(); const instancesIds = new Set<number>();
if (instances && instances.length) { if (instances && instances.length) {
instances.forEach(inst => { instances.forEach(inst => {
instancesIds.add(inst.id); instancesIds.add(inst.id);

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

@ -14,8 +14,6 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { AbstractControl, ValidationErrors } from '@angular/forms';
export const OBSERVE_ATTR = 'observeAttr'; export const OBSERVE_ATTR = 'observeAttr';
export const OBSERVE = 'observe'; export const OBSERVE = 'observe';
export const ATTR = 'attribute'; export const ATTR = 'attribute';
@ -23,33 +21,29 @@ export const TELEMETRY = 'telemetry';
export const KEY_NAME = 'keyName'; export const KEY_NAME = 'keyName';
export const DEFAULT_ID_SERVER = 123; export const DEFAULT_ID_SERVER = 123;
export const DEFAULT_ID_BOOTSTRAP = 111; export const DEFAULT_ID_BOOTSTRAP = 111;
export const DEFAULT_HOST_NAME = "localhost"; export const DEFAULT_HOST_NAME = 'localhost';
export const DEFAULT_PORT_SERVER_NO_SEC = 5685; export const DEFAULT_PORT_SERVER_NO_SEC = 5685;
export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5691; export const DEFAULT_PORT_BOOTSTRAP_NO_SEC = 5691;
export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1;
export const DEFAULT_LIFE_TIME = 300; export const DEFAULT_LIFE_TIME = 300;
export const DEFAULT_DEFAULT_MIN_PERIOD = 1; export const DEFAULT_MIN_PERIOD = 1;
export const DEFAULT_NOTIF_IF_DESIBLED = true; export const DEFAULT_NOTIF_IF_DESIBLED = true;
export const DEFAULT_BINDING = "U"; export const DEFAULT_BINDING = 'U';
export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0;
export const LEN_MAX_PUBLIC_KEY_PSK = 182; export const LEN_MAX_PUBLIC_KEY_RPK = 182;
export const LEN_MAX_PUBLIC_KEY_RPK_X509 = 3000; export const LEN_MAX_PUBLIC_KEY_X509 = 3000;
export const KEY_IDENT_REGEXP_PSK = /^[0-9a-fA-F]{64,64}$/; export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
export const KEY_PRIVATE_REGEXP = /^[0-9a-fA-F]{134,134}$/;
export const KEY_PUBLIC_REGEXP_PSK = /^[0-9a-fA-F]{182,182}$/;
export const KEY_PUBLIC_REGEXP_X509 = /^[0-9a-fA-F]{0,3000}$/;
export const CAMEL_CASE_REGEXP = /[-_&@.,*+!?^${}()|[\]\\]/g; export const CAMEL_CASE_REGEXP = /[-_&@.,*+!?^${}()|[\]\\]/g;
export const INSTANCES_ID_VALUE_MIN = 0; export const INSTANCES_ID_VALUE_MIN = 0;
export const INSTANCES_ID_VALUE_MAX = 65535; export const INSTANCES_ID_VALUE_MAX = 65535;
//ok
export enum SECURITY_CONFIG_MODE { export enum SECURITY_CONFIG_MODE {
PSK = 'PSK', PSK = 'PSK',
RPK = 'RPK', RPK = 'RPK',
X509 = 'X509', X509 = 'X509',
NO_SEC = 'NO_SEC' NO_SEC = 'NO_SEC'
} }
//ok
export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>(
[ [
[SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'],
@ -58,59 +52,54 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>(
[SECURITY_CONFIG_MODE.NO_SEC, 'No Security'], [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'],
] ]
); );
//ok
export interface BootstrapServersSecurityConfig { export interface BootstrapServersSecurityConfig {
shortId: number, shortId: number;
lifetime: number, lifetime: number;
defaultMinPeriod: number, defaultMinPeriod: number;
notifIfDisabled: boolean, notifIfDisabled: boolean;
binding: string binding: string;
} }
//ok
export interface ServerSecurityConfig { export interface ServerSecurityConfig {
host?: string, host?: string;
port?: number, port?: number;
bootstrapServerIs?: boolean, bootstrapServerIs?: boolean;
securityMode: string, securityMode: string;
clientPublicKeyOrId?: string, clientPublicKeyOrId?: string;
clientSecretKey?: string, clientSecretKey?: string;
serverPublicKey?: string; serverPublicKey?: string;
clientHoldOffTime?: number, clientHoldOffTime?: number;
serverId?: number, serverId?: number;
bootstrapServerAccountTimeout: number bootstrapServerAccountTimeout: number;
} }
//ok
interface BootstrapSecurityConfig { interface BootstrapSecurityConfig {
servers: BootstrapServersSecurityConfig, servers: BootstrapServersSecurityConfig;
bootstrapServer: ServerSecurityConfig, bootstrapServer: ServerSecurityConfig;
lwm2mServer: ServerSecurityConfig lwm2mServer: ServerSecurityConfig;
} }
//ok
export interface ProfileConfigModels { export interface ProfileConfigModels {
bootstrap: BootstrapSecurityConfig, bootstrap: BootstrapSecurityConfig;
observeAttr: { observeAttr: {
observe: string [], observe: string [],
attribute: string [], attribute: string [],
telemetry: string [], telemetry: string [],
keyName: [] keyName: []
} };
} }
//ok
export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig {
return { return {
shortId: DEFAULT_ID_SERVER, shortId: DEFAULT_ID_SERVER,
lifetime: DEFAULT_LIFE_TIME, lifetime: DEFAULT_LIFE_TIME,
defaultMinPeriod: DEFAULT_DEFAULT_MIN_PERIOD, defaultMinPeriod: DEFAULT_MIN_PERIOD,
notifIfDisabled: DEFAULT_NOTIF_IF_DESIBLED, notifIfDisabled: DEFAULT_NOTIF_IF_DESIBLED,
binding: DEFAULT_BINDING binding: DEFAULT_BINDING
} };
} }
//ok
export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig { export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSecurityConfig {
return { return {
host: hostname, host: hostname,
@ -121,9 +110,9 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: any): ServerSe
clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME, clientHoldOffTime: DEFAULT_CLIENT_HOLD_OFF_TIME,
serverId: DEFAULT_ID_BOOTSTRAP, serverId: DEFAULT_ID_BOOTSTRAP,
bootstrapServerAccountTimeout: DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT bootstrapServerAccountTimeout: DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT
} };
} }
//ok
export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig { export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig {
const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname); const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname);
DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false; DefaultLwM2MServerSecurityConfig.bootstrapServerIs = false;
@ -132,19 +121,17 @@ export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityCon
return DefaultLwM2MServerSecurityConfig; return DefaultLwM2MServerSecurityConfig;
} }
//ok
function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig { function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig {
return { return {
servers: getDefaultBootstrapServersSecurityConfig(), servers: getDefaultBootstrapServersSecurityConfig(),
bootstrapServer: getDefaultBootstrapServerSecurityConfig(hostname), bootstrapServer: getDefaultBootstrapServerSecurityConfig(hostname),
lwm2mServer: getDefaultLwM2MServerSecurityConfig(hostname) lwm2mServer: getDefaultLwM2MServerSecurityConfig(hostname)
} };
} }
//ok
export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels { export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels {
return { return {
bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname)? hostname : DEFAULT_HOST_NAME), bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME),
observeAttr: { observeAttr: {
observe: [], observe: [],
attribute: [], attribute: [],
@ -154,19 +141,18 @@ export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels {
}; };
} }
//ok
export interface ResourceLwM2M { export interface ResourceLwM2M {
id: number, id: number;
name: string, name: string;
observe: boolean, observe: boolean;
attribute: boolean, attribute: boolean;
telemetry: boolean, telemetry: boolean;
keyName: string keyName: string;
} }
//ok
export interface Instance { export interface Instance {
id: number, id: number;
resources: ResourceLwM2M[] resources: ResourceLwM2M[];
} }
/** /**
@ -176,10 +162,10 @@ export interface Instance {
* mandatory == false => Optional * mandatory == false => Optional
*/ */
export interface ObjectLwM2M { export interface ObjectLwM2M {
id: number, id: number;
name: string, name: string;
multiple?: boolean, multiple?: boolean;
mandatory?: boolean, mandatory?: boolean;
instances?: Instance [] instances?: Instance [];
} }

3
ui-ngx/src/app/modules/home/pages/device/device.module.ts

@ -25,8 +25,7 @@ import { HomeDialogsModule } from '../../dialogs/home-dialogs.module';
import { HomeComponentsModule } from '@modules/home/components/home-components.module'; import { HomeComponentsModule } from '@modules/home/components/home-components.module';
import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component'; import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component';
import { SecurityConfigComponent } from '@home/pages/device/lwm2m/security-config.component'; import { SecurityConfigComponent } from '@home/pages/device/lwm2m/security-config.component';
// TODO: @nickAS21 move to device profile import { SecurityConfigServerComponent } from '@home/pages/device/lwm2m/security-config-server.component';
import {SecurityConfigServerComponent} from "@home/pages/device/lwm2m/security-config-server.component";
import { DefaultDeviceConfigurationComponent } from './data/default-device-configuration.component'; import { DefaultDeviceConfigurationComponent } from './data/default-device-configuration.component';
import { DeviceConfigurationComponent } from './data/device-configuration.component'; import { DeviceConfigurationComponent } from './data/device-configuration.component';
import { DeviceDataComponent } from './data/device-data.component'; import { DeviceDataComponent } from './data/device-data.component';

57
ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config-server.component.html

@ -24,7 +24,7 @@
<mat-select formControlName="securityMode" <mat-select formControlName="securityMode"
(ngModelChange)="securityModeChanged($event)"> (ngModelChange)="securityModeChanged($event)">
<mat-option *ngFor="let securityMode of securityConfigLwM2MTypes" <mat-option *ngFor="let securityMode of securityConfigLwM2MTypes"
[value]="securityMode" > [value]="securityMode">
{{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }} {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityMode]) }}
</mat-option> </mat-option>
</mat-select> </mat-select>
@ -35,43 +35,64 @@
<div [fxShow]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC"> <div [fxShow]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label>{{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }}</mat-label> <mat-label>{{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }}</mat-label>
<textarea matInput type="text" rows="3" cols="1" formControlName="clientPublicKeyOrId" #clientPublicKeyOrId maxlength={{lenMaxClientPublicKeyOrId}} <textarea matInput
[required]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC"></textarea> #clientPublicKeyOrId
maxlength={{lenMaxClientPublicKeyOrId}}
cdkTextareaAutosize
cdkAutosizeMinRows="1"
style="overflow:hidden"
cols="1"
formControlName="clientPublicKeyOrId"
[required]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC">
</textarea>
<mat-hint align="end">{{clientPublicKeyOrId.value?.length || 0}}/{{lenMaxClientPublicKeyOrId}}</mat-hint> <mat-hint align="end">{{clientPublicKeyOrId.value?.length || 0}}/{{lenMaxClientPublicKeyOrId}}</mat-hint>
<mat-error *ngIf="serverFormGroup.get('clientPublicKeyOrId').hasError('required')"> <mat-error *ngIf="serverFormGroup.get('clientPublicKeyOrId').hasError('required')">
{{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }} {{ 'device.lwm2m-security-config.client-publicKey-or-id' | translate }}
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong> <strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('clientPublicKeyOrId').hasError('pattern') && <mat-error *ngIf="serverFormGroup.get('clientPublicKeyOrId').hasError('pattern')">
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK">
{{ 'device.lwm2m-security-config.client-key' | translate }} {{ 'device.lwm2m-security-config.client-key' | translate }}
<strong>{{ 'device.lwm2m-security-config.pattern_hex_dec_182' | translate }}</strong> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
count: 0
}) | async }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('clientPublicKeyOrId').hasError('pattern') && <mat-error *ngIf="(serverFormGroup.get('clientPublicKeyOrId').hasError('maxlength') ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509"> serverFormGroup.get('clientPublicKeyOrId').hasError('minlength'))">
{{ 'device.lwm2m-security-config.client-key' | translate }} {{ 'device.lwm2m-security-config.client-key' | translate }}
<strong>{{ 'device.lwm2m-security-config.pattern_hex_dec' | translate }}</strong> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
count: lenMaxClientPublicKeyOrId
}) | async }}</strong>
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label>{{ 'device.lwm2m-security-config.client-secret-key' | translate }}</mat-label> <mat-label>{{ 'device.lwm2m-security-config.client-secret-key' | translate }}</mat-label>
<textarea matInput type="text" rows="2" cols="1" formControlName="clientSecretKey" #clientSecretKey maxlength={{lenMaxClientSecretKey}} <textarea matInput
[required]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC"></textarea> #clientSecretKey
maxlength={{lenMaxClientSecretKey}}
cdkTextareaAutosize
cdkAutosizeMinRows="1"
style="overflow:hidden"
cols="1"
formControlName="clientSecretKey"
[required]="serverFormGroup.get('securityMode').value !== securityConfigLwM2MType.NO_SEC">
</textarea>
<mat-hint align="end">{{clientSecretKey.value?.length || 0}}/{{lenMaxClientSecretKey}}</mat-hint> <mat-hint align="end">{{clientSecretKey.value?.length || 0}}/{{lenMaxClientSecretKey}}</mat-hint>
<mat-error *ngIf="serverFormGroup.get('clientSecretKey').hasError('required')"> <mat-error *ngIf="serverFormGroup.get('clientSecretKey').hasError('required')">
{{ 'device.lwm2m-security-config.client-secret-key' | translate }} {{ 'device.lwm2m-security-config.client-secret-key' | translate }}
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong> <strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('clientSecretKey').hasError('pattern') && <mat-error *ngIf="serverFormGroup.get('clientSecretKey').hasError('pattern')">
(serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK ||
serverFormGroup.get('securityMode').value === securityConfigLwM2MType.X509)">
{{ 'device.lwm2m-security-config.client-key' | translate }} {{ 'device.lwm2m-security-config.client-key' | translate }}
<strong>{{ 'device.lwm2m-security-config.pattern_hex_dec_134' | translate }}</strong> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
count: 0
}) | async }}</strong>
</mat-error> </mat-error>
<mat-error *ngIf="serverFormGroup.get('clientSecretKey').hasError('pattern') && <mat-error *ngIf="(serverFormGroup.get('clientSecretKey').hasError('maxlength') ||
(serverFormGroup.get('securityMode').value === securityConfigLwM2MType.PSK)"> serverFormGroup.get('clientSecretKey').hasError('minlength'))">
{{ 'device.lwm2m-security-config.client-key' | translate }} {{ 'device.lwm2m-security-config.client-key' | translate }}
<strong>{{ 'device-profile.lwm2m.pattern_hex_dec_64' | translate }}</strong> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
count: lenMaxClientSecretKey
}) | async }}</strong>
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</div> </div>

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

@ -14,26 +14,25 @@
/// limitations under the License. /// limitations under the License.
/// ///
import {Component, forwardRef, Inject, Input, OnInit, ViewChild} from "@angular/core"; import { Component, forwardRef, Inject, Input, OnInit } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators
} from "@angular/forms"; } from '@angular/forms';
import { import {
SECURITY_CONFIG_MODE, SECURITY_CONFIG_MODE,
SECURITY_CONFIG_MODE_NAMES, SECURITY_CONFIG_MODE_NAMES,
KEY_IDENT_REGEXP_PSK, KEY_REGEXP_HEX_DEC,
ServerSecurityConfig, ServerSecurityConfig,
DeviceCredentialsDialogLwm2mData, DeviceCredentialsDialogLwm2mData,
LEN_MAX_PSK, LEN_MAX_PSK,
LEN_MAX_PRIVATE_KEY, LEN_MAX_PUBLIC_KEY_RPK, KEY_PRIVATE_REGEXP, LEN_MAX_PUBLIC_KEY_X509, KEY_PUBLIC_REGEXP_X509 LEN_MAX_PRIVATE_KEY, LEN_MAX_PUBLIC_KEY_RPK, LEN_MAX_PUBLIC_KEY_X509
} from "@home/pages/device/lwm2m/security-config.models"; } from '@home/pages/device/lwm2m/security-config.models';
import {Store} from "@ngrx/store"; import { Store } from '@ngrx/store';
import {AppState} from "@core/core.state"; import { AppState } from '@core/core.state';
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {PageComponent} from "@shared/components/page.component"; import { PageComponent } from '@shared/components/page.component';
import {MatPaginator} from "@angular/material/paginator";
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@Component({ @Component({
@ -54,13 +53,13 @@ export class SecurityConfigServerComponent extends PageComponent implements OnIn
securityConfigLwM2MType = SECURITY_CONFIG_MODE; securityConfigLwM2MType = SECURITY_CONFIG_MODE;
securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE); securityConfigLwM2MTypes = Object.keys(SECURITY_CONFIG_MODE);
credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES; credentialTypeLwM2MNamesMap = SECURITY_CONFIG_MODE_NAMES;
lenMaxClientPublicKeyOrId = LEN_MAX_PSK; lenMinClientPublicKeyOrId = 0;
lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK;
lenMinClientSecretKey = LEN_MAX_PRIVATE_KEY;
lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY;
@Input() serverFormGroup: FormGroup; @Input() serverFormGroup: FormGroup;
@ViewChild(MatPaginator) paginator: MatPaginator;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
@Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData, @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData,
public dialogRef: MatDialogRef<SecurityConfigServerComponent, object>, public dialogRef: MatDialogRef<SecurityConfigServerComponent, object>,
@ -73,40 +72,59 @@ export class SecurityConfigServerComponent extends PageComponent implements OnIn
this.registerDisableOnLoadFormControl(this.serverFormGroup.get('securityMode')); this.registerDisableOnLoadFormControl(this.serverFormGroup.get('securityMode'));
} }
updateValueFields(serverData: ServerSecurityConfig): void { private updateValueFields(serverData: ServerSecurityConfig): void {
this.serverFormGroup.patchValue(serverData, {emitEvent: false}); this.serverFormGroup.patchValue(serverData, {emitEvent: false});
const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE; const securityMode = this.serverFormGroup.get('securityMode').value as SECURITY_CONFIG_MODE;
this.updateValidate(securityMode); this.updateValidate(securityMode);
} }
updateValidate(securityMode: SECURITY_CONFIG_MODE): void { private updateValidate(securityMode: SECURITY_CONFIG_MODE): void {
switch (securityMode) { switch (securityMode) {
case SECURITY_CONFIG_MODE.NO_SEC: case SECURITY_CONFIG_MODE.NO_SEC:
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([]); this.serverFormGroup.get('clientPublicKeyOrId').setValidators([]);
this.serverFormGroup.get('clientSecretKey').setValidators([]); this.serverFormGroup.get('clientSecretKey').setValidators([]);
break; break;
case SECURITY_CONFIG_MODE.PSK: case SECURITY_CONFIG_MODE.PSK:
this.lenMinClientPublicKeyOrId = 0;
this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK; this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK;
this.lenMinClientSecretKey = LEN_MAX_PSK;
this.lenMaxClientSecretKey = LEN_MAX_PSK; this.lenMaxClientSecretKey = LEN_MAX_PSK;
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required]); this.setValidatorsSecurity(securityMode);
this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_IDENT_REGEXP_PSK)]);
break; break;
case SECURITY_CONFIG_MODE.RPK: case SECURITY_CONFIG_MODE.RPK:
this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_X509; this.lenMinClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK;
this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_RPK;
this.lenMinClientSecretKey = LEN_MAX_PRIVATE_KEY;
this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY;
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); this.setValidatorsSecurity(securityMode);
this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_PRIVATE_REGEXP)]);
break; break;
case SECURITY_CONFIG_MODE.X509: case SECURITY_CONFIG_MODE.X509:
this.lenMinClientPublicKeyOrId = 0;
this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_X509; this.lenMaxClientPublicKeyOrId = LEN_MAX_PUBLIC_KEY_X509;
this.lenMinClientSecretKey = LEN_MAX_PRIVATE_KEY;
this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY; this.lenMaxClientSecretKey = LEN_MAX_PRIVATE_KEY;
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_X509)]); this.setValidatorsSecurity(securityMode);
this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required, Validators.pattern(KEY_PRIVATE_REGEXP)]);
break; break;
} }
this.serverFormGroup.updateValueAndValidity(); this.serverFormGroup.updateValueAndValidity();
} }
private setValidatorsSecurity = (securityMode: SECURITY_CONFIG_MODE): void => {
if (securityMode === SECURITY_CONFIG_MODE.PSK) {
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required]);
} else {
this.serverFormGroup.get('clientPublicKeyOrId').setValidators([Validators.required,
Validators.pattern(KEY_REGEXP_HEX_DEC),
Validators.minLength(this.lenMinClientPublicKeyOrId),
Validators.maxLength(this.lenMaxClientPublicKeyOrId)]);
}
this.serverFormGroup.get('clientSecretKey').setValidators([Validators.required,
Validators.pattern(KEY_REGEXP_HEX_DEC),
Validators.minLength(this.lenMinClientSecretKey),
Validators.maxLength(this.lenMaxClientSecretKey)]);
}
securityModeChanged(securityMode: SECURITY_CONFIG_MODE): void { securityModeChanged(securityMode: SECURITY_CONFIG_MODE): void {
this.updateValidate(securityMode); this.updateValidate(securityMode);
} }

206
ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.html

@ -35,110 +35,124 @@
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong> <strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong>
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-tab-group dynamicHeight #tabGroup (selectedTabChange)="tabChanged($event)"> <mat-tab-group dynamicHeight (selectedTabChange)="tabChanged($event)">
<mat-tab label="{{ 'device.lwm2m-security-config.client-tab' | translate }}"> <mat-tab label="{{ 'device.lwm2m-security-config.client-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<mat-form-field class="mat-block"> <div class="mat-padding">
<mat-label translate>device.lwm2m-security-config.mode</mat-label>
<mat-select formControlName="securityConfigClientMode"
(ngModelChange)="securityConfigClientModeChanged($event)">
<mat-option *ngFor="let securityConfigClientMode of securityConfigLwM2MTypes"
[value]="securityConfigClientMode">
{{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityConfigClientMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
<div [fxShow]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label>{{ 'device.lwm2m-security-config.identity' | translate }}</mat-label> <mat-label translate>device.lwm2m-security-config.mode</mat-label>
<input matInput type="text" formControlName="identityPSK" <mat-select formControlName="securityConfigClientMode"
[required]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK"> (ngModelChange)="securityConfigClientModeChanged($event)">
<mat-error *ngIf="lwm2mConfigFormGroup.get('identityPSK').hasError('required')"> <mat-option *ngFor="let securityConfigClientMode of securityConfigLwM2MTypes"
{{ 'device.lwm2m-security-config.identity' | translate }} [value]="securityConfigClientMode">
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong> {{ credentialTypeLwM2MNamesMap.get(securityConfigLwM2MType[securityConfigClientMode]) }}
</mat-error> </mat-option>
</mat-select>
</mat-form-field> </mat-form-field>
</div> <div *ngIf="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK">
<div [fxShow]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.RPK || <mat-form-field class="mat-block">
<mat-label>{{ 'device.lwm2m-security-config.identity' | translate }}</mat-label>
<input matInput type="text" formControlName="identityPSK"
[required]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK">
<mat-error *ngIf="lwm2mConfigFormGroup.get('identityPSK').hasError('required')">
{{ 'device.lwm2m-security-config.identity' | translate }}
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div *ngIf="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.RPK ||
lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK"> lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label>{{ 'device.lwm2m-security-config.client-key' | translate }}</mat-label> <mat-label>{{ 'device.lwm2m-security-config.client-key' | translate }}</mat-label>
<textarea matInput #clientKey maxlength={{lenMinMaxClient}} type="text" rows="3" cols="1" <textarea matInput
formControlName="clientKey" #clientKey
[required]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.RPK || maxlength="{{lenMaxKeyClient}}"
lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK"></textarea> cdkTextareaAutosize
<mat-hint align="end">{{clientKey.value?.length || 0}}/{{lenMaxKeyClient}}</mat-hint> cdkAutosizeMinRows="1"
<mat-error *ngIf="lwm2mConfigFormGroup.get('clientKey').hasError('required')"> cols="1"
{{ 'device.lwm2m-security-config.client-key' | translate }} formControlName="clientKey"
<strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong> style="overflow:hidden"
</mat-error> [required]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.RPK ||
<mat-error *ngIf="lwm2mConfigFormGroup.get('clientKey').hasError('pattern') && lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK">
lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.PSK"> </textarea>
{{ 'device.lwm2m-security-config.client-key' | translate }} <mat-hint align="end">{{clientKey.value?.length || 0}}/{{lenMaxKeyClient}}</mat-hint>
<strong>{{ 'device-profile.lwm2m-security-config.pattern_hex_dec_64' | translate }}</strong> <mat-error *ngIf="lwm2mConfigFormGroup.get('clientKey').hasError('required')">
</mat-error> {{ 'device.lwm2m-security-config.client-key' | translate }}
<mat-error *ngIf="lwm2mConfigFormGroup.get('clientKey').hasError('pattern') && <strong>{{ 'device.lwm2m-security-config.required' | translate }}</strong>
lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.RPK"> </mat-error>
{{ 'device.lwm2m-security-config.client-key' | translate }} <mat-error *ngIf="lwm2mConfigFormGroup.get('clientKey').hasError('pattern')">
<strong>{{ 'device.lwm2m-security-config.pattern_hex_dec_182' | translate }}</strong> {{ 'device.lwm2m-security-config.client-key' | translate }}
</mat-error> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
</mat-form-field> count: 0 }) | async }}</strong>
</div> </mat-error>
<div [fxShow]="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.X509"> <mat-error *ngIf="(lwm2mConfigFormGroup.get('clientKey').hasError('maxlength') ||
<mat-checkbox formControlName="clientCertificate" color="primary"> lwm2mConfigFormGroup.get('clientKey').hasError('minlength'))">
{{ 'device.lwm2m-security-config.client-certificate' | translate }} {{ 'device.lwm2m-security-config.client-key' | translate }}
</mat-checkbox> <strong>{{ translate.get('device.lwm2m-security-config.pattern_hex_dec', {
count: lenMaxKeyClient }) | async }}</strong>
</mat-error>
</mat-form-field>
</div>
<div *ngIf="lwm2mConfigFormGroup.get('securityConfigClientMode').value === securityConfigLwM2MType.X509">
<mat-checkbox formControlName="clientCertificate" color="primary">
{{ 'device.lwm2m-security-config.client-certificate' | translate }}
</mat-checkbox>
</div>
</div> </div>
</div> </ng-template>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'device.lwm2m-security-config.bootstrap-tab' | translate }}"> <mat-tab label="{{ 'device.lwm2m-security-config.bootstrap-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<mat-accordion multi="true" class="mat-body-1"> <div class="mat-padding">
<mat-expansion-panel> <mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel-header> <mat-expansion-panel>
<mat-panel-title> <mat-expansion-panel-header>
<div <mat-panel-title>
class="tb-panel-title">{{ 'device.lwm2m-security-config.bootstrap-server' | translate | uppercase }}</div> <div
</mat-panel-title> class="tb-panel-title">{{ 'device.lwm2m-security-config.bootstrap-server' | translate | uppercase }}</div>
</mat-expansion-panel-header> </mat-panel-title>
<div class="mat-padding"> </mat-expansion-panel-header>
<tb-security-config-server-lwm2m <div class="mat-padding">
[formControlName]="bootstrapServer" <tb-security-config-server-lwm2m
[serverFormGroup]="bootstrapFormGroup"> [formControlName]="bootstrapServer"
</tb-security-config-server-lwm2m> [serverFormGroup]="bootstrapFormGroup">
</div> </tb-security-config-server-lwm2m>
</mat-expansion-panel> </div>
</mat-accordion> </mat-expansion-panel>
<mat-accordion multi="true" class="mat-body-1"> </mat-accordion>
<mat-expansion-panel> <mat-accordion multi="true" class="mat-body-1">
<mat-expansion-panel-header> <mat-expansion-panel>
<mat-panel-title> <mat-expansion-panel-header>
<div <mat-panel-title>
class="tb-panel-title">{{ 'device.lwm2m-security-config.lwm2m-server' | translate | uppercase }}</div> <div
</mat-panel-title> class="tb-panel-title">{{ 'device.lwm2m-security-config.lwm2m-server' | translate | uppercase }}</div>
</mat-expansion-panel-header> </mat-panel-title>
<div class="mat-padding"> </mat-expansion-panel-header>
<tb-security-config-server-lwm2m <div class="mat-padding">
[formControlName]="lwm2mServer" <tb-security-config-server-lwm2m
[serverFormGroup]="lwm2mServerFormGroup"> [formControlName]="lwm2mServer"
</tb-security-config-server-lwm2m> [serverFormGroup]="lwm2mServerFormGroup">
</div> </tb-security-config-server-lwm2m>
</mat-expansion-panel> </div>
</mat-accordion> </mat-expansion-panel>
</div> </mat-accordion>
</div>
</ng-template>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'device.lwm2m-security-config.config-json-tab' | translate }}"> <mat-tab label="{{ 'device.lwm2m-security-config.config-json-tab' | translate }}">
<div class="mat-padding"> <ng-template matTabContent>
<fieldset [disabled]="isLoading$ | async"> <div class="mat-padding">
<tb-json-object-edit <fieldset [disabled]="isLoading$ | async">
[formControlName]="formControlNameJsonAllConfig" <tb-json-object-edit
label="{{ 'device.lwm2m-value' | translate }}" [formControlName]="formControlNameJsonAllConfig"
validateContent="true" label="{{ 'device.lwm2m-value' | translate }}"
[required]="true" validateContent="true"
[fillHeight]="false"> [required]="true"
</tb-json-object-edit> [fillHeight]="false">
</fieldset> </tb-json-object-edit>
</div> </fieldset>
</div>
</ng-template>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</fieldset> </fieldset>
@ -148,7 +162,7 @@
<button mat-button color="primary" <button mat-button color="primary"
type="button" type="button"
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial> (click)="cancel()">
{{ 'action.cancel' | translate }} {{ 'action.cancel' | translate }}
</button> </button>
<button mat-button mat-raised-button color="primary" <button mat-button mat-raised-button color="primary"

185
ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.component.ts

@ -15,14 +15,14 @@
/// ///
import {Component, Inject, OnInit} from '@angular/core'; import {Component, Inject, OnInit } from '@angular/core';
import {DialogComponent} from '@shared/components/dialog.component'; import { DialogComponent } from '@shared/components/dialog.component';
import {Store} from '@ngrx/store'; import { Store } from '@ngrx/store';
import {AppState} from '@core/core.state'; import { AppState } from '@core/core.state';
import {Router} from '@angular/router'; import { Router } from '@angular/router';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {FormBuilder, FormGroup, Validators} from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import {TranslateService} from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
SECURITY_CONFIG_MODE_NAMES, SECURITY_CONFIG_MODE_NAMES,
SECURITY_CONFIG_MODE, SECURITY_CONFIG_MODE,
@ -30,22 +30,20 @@ import {
ClientSecurityConfigPSK, ClientSecurityConfigPSK,
ClientSecurityConfigRPK, ClientSecurityConfigRPK,
JSON_ALL_CONFIG, JSON_ALL_CONFIG,
KEY_IDENT_REGEXP_PSK, KEY_REGEXP_HEX_DEC,
KEY_PUBLIC_REGEXP_PSK,
DeviceCredentialsDialogLwm2mData, DeviceCredentialsDialogLwm2mData,
BOOTSTRAP_SERVER, BOOTSTRAP_SERVER,
BOOTSTRAP_SERVERS, BOOTSTRAP_SERVERS,
LWM2M_SERVER, LWM2M_SERVER,
ClientSecurityConfigX509, ClientSecurityConfigX509,
ClientSecurityConfigNO_SEC, ClientSecurityConfigNoSEC,
getDefaultClientSecurityConfigType, getDefaultClientSecurityConfigType,
LEN_MAX_PSK, LEN_MAX_PSK,
LEN_MAX_PUBLIC_KEY_RPK LEN_MAX_PUBLIC_KEY_RPK
} from "./security-config.models"; } from './security-config.models';
import {WINDOW} from "@core/services/window.service"; import { WINDOW } from '@core/services/window.service';
import {MatTabChangeEvent, MatTabGroup} from "@angular/material/tabs"; import { MatTabChangeEvent } from '@angular/material/tabs';
import {MatTab} from "@angular/material/tabs/tab"; import { MatTab } from '@angular/material/tabs/tab';
@Component({ @Component({
selector: 'tb-security-config-lwm2m', selector: 'tb-security-config-lwm2m',
@ -67,8 +65,8 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
bootstrapServer: string; bootstrapServer: string;
lwm2mServer: string; lwm2mServer: string;
jsonObserveData: {}; jsonObserveData: {};
lenMaxKeyClient = LEN_MAX_PSK; lenMaxKeyClient = LEN_MAX_PSK as number;
tabPrevious: MatTab tabPrevious: MatTab;
tabIndexPrevious = 0 as number; tabIndexPrevious = 0 as number;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
@ -76,7 +74,7 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
@Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData, @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogLwm2mData,
public dialogRef: MatDialogRef<SecurityConfigComponent, object>, public dialogRef: MatDialogRef<SecurityConfigComponent, object>,
public fb: FormBuilder, public fb: FormBuilder,
private translate: TranslateService, public translate: TranslateService,
@Inject(WINDOW) private window: Window) { @Inject(WINDOW) private window: Window) {
super(store, router, dialogRef); super(store, router, dialogRef);
} }
@ -85,13 +83,13 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
this.jsonAllConfig = JSON.parse(JSON.stringify(this.data.jsonAllConfig)) as SecurityConfigModels; this.jsonAllConfig = JSON.parse(JSON.stringify(this.data.jsonAllConfig)) as SecurityConfigModels;
this.initConstants(); this.initConstants();
this.lwm2mConfigFormGroup = this.initLwm2mConfigFormGroup(); this.lwm2mConfigFormGroup = this.initLwm2mConfigFormGroup();
this.title = this.translate.instant('device.lwm2m-security-info') + ": " + this.data.endPoint this.title = this.translate.instant('device.lwm2m-security-info') + ': ' + this.data.endPoint;
this.lwm2mConfigFormGroup.get('clientCertificate').disable(); this.lwm2mConfigFormGroup.get('clientCertificate').disable();
this.initClientSecurityConfig(this.lwm2mConfigFormGroup.get('jsonAllConfig').value); this.initClientSecurityConfig(this.lwm2mConfigFormGroup.get('jsonAllConfig').value);
this.registerDisableOnLoadFormControl(this.lwm2mConfigFormGroup.get('securityConfigClientMode')); this.registerDisableOnLoadFormControl(this.lwm2mConfigFormGroup.get('securityConfigClientMode'));
} }
initConstants(): void { private initConstants = (): void => {
this.bootstrapServers = BOOTSTRAP_SERVERS; this.bootstrapServers = BOOTSTRAP_SERVERS;
this.bootstrapServer = BOOTSTRAP_SERVER; this.bootstrapServer = BOOTSTRAP_SERVER;
this.lwm2mServer = LWM2M_SERVER; this.lwm2mServer = LWM2M_SERVER;
@ -112,7 +110,7 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
return this.lwm2mConfigFormGroup.get('observeFormGroup') as FormGroup; return this.lwm2mConfigFormGroup.get('observeFormGroup') as FormGroup;
} }
initClientSecurityConfig(jsonAllConfig: SecurityConfigModels): void { private initClientSecurityConfig = (jsonAllConfig: SecurityConfigModels): void => {
switch (jsonAllConfig.client.securityConfigClientMode.toString()) { switch (jsonAllConfig.client.securityConfigClientMode.toString()) {
case SECURITY_CONFIG_MODE.NO_SEC.toString(): case SECURITY_CONFIG_MODE.NO_SEC.toString():
break; break;
@ -139,106 +137,110 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
this.securityConfigClientUpdateValidators(this.lwm2mConfigFormGroup.get('securityConfigClientMode').value); this.securityConfigClientUpdateValidators(this.lwm2mConfigFormGroup.get('securityConfigClientMode').value);
} }
securityConfigClientModeChanged(mode: SECURITY_CONFIG_MODE): void { securityConfigClientModeChanged = (mode: SECURITY_CONFIG_MODE): void => {
switch (mode) { switch (mode) {
case SECURITY_CONFIG_MODE.NO_SEC: case SECURITY_CONFIG_MODE.NO_SEC:
let clientSecurityConfigNO_SEC = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigNO_SEC; const clientSecurityConfigNoSEC = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigNoSEC;
this.jsonAllConfig.client = clientSecurityConfigNO_SEC; this.jsonAllConfig.client = clientSecurityConfigNoSEC;
this.lwm2mConfigFormGroup.patchValue({ this.lwm2mConfigFormGroup.patchValue({
jsonAllConfig: this.jsonAllConfig, jsonAllConfig: this.jsonAllConfig,
clientCertificate: false clientCertificate: false
}, {emitEvent: true}); }, {emitEvent: false});
break; break;
case SECURITY_CONFIG_MODE.PSK: case SECURITY_CONFIG_MODE.PSK:
let clientSecurityConfigPSK = getDefaultClientSecurityConfigType(mode, this.lwm2mConfigFormGroup.get('endPoint').value) as ClientSecurityConfigPSK; const clientSecurityConfigPSK = getDefaultClientSecurityConfigType(mode, this.lwm2mConfigFormGroup.get('endPoint')
.value) as ClientSecurityConfigPSK;
clientSecurityConfigPSK.identity = this.data.endPoint; clientSecurityConfigPSK.identity = this.data.endPoint;
clientSecurityConfigPSK.key = this.lwm2mConfigFormGroup.get('clientKey').value; clientSecurityConfigPSK.key = this.lwm2mConfigFormGroup.get('clientKey').value;
this.jsonAllConfig.client = clientSecurityConfigPSK; this.jsonAllConfig.client = clientSecurityConfigPSK;
this.lwm2mConfigFormGroup.patchValue({ this.lwm2mConfigFormGroup.patchValue({
identityPSK: clientSecurityConfigPSK.identity, identityPSK: clientSecurityConfigPSK.identity,
clientCertificate: false clientCertificate: false
}, {emitEvent: true}); }, {emitEvent: false});
break; break;
case SECURITY_CONFIG_MODE.RPK: case SECURITY_CONFIG_MODE.RPK:
let clientSecurityConfigRPK = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigRPK; const clientSecurityConfigRPK = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigRPK;
clientSecurityConfigRPK.key = this.lwm2mConfigFormGroup.get('clientKey').value; clientSecurityConfigRPK.key = this.lwm2mConfigFormGroup.get('clientKey').value;
this.jsonAllConfig.client = clientSecurityConfigRPK; this.jsonAllConfig.client = clientSecurityConfigRPK;
this.lwm2mConfigFormGroup.patchValue({ this.lwm2mConfigFormGroup.patchValue({
jsonAllConfig: this.jsonAllConfig,
clientCertificate: false clientCertificate: false
}, {emitEvent: true}) }, {emitEvent: false});
break; break;
case SECURITY_CONFIG_MODE.X509: case SECURITY_CONFIG_MODE.X509:
let clientSecurityConfigX509 = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigX509; this.jsonAllConfig.client = getDefaultClientSecurityConfigType(mode) as ClientSecurityConfigX509;
this.jsonAllConfig.client = clientSecurityConfigX509;
this.lwm2mConfigFormGroup.patchValue({ this.lwm2mConfigFormGroup.patchValue({
jsonAllConfig: this.jsonAllConfig,
clientCertificate: true clientCertificate: true
}, {emitEvent: true}) }, {emitEvent: false});
break; break;
} }
this.securityConfigClientUpdateValidators(mode); this.securityConfigClientUpdateValidators(mode);
} }
securityConfigClientUpdateValidators(mode: SECURITY_CONFIG_MODE): void { private securityConfigClientUpdateValidators = (mode: SECURITY_CONFIG_MODE): void => {
switch (mode) { switch (mode) {
case SECURITY_CONFIG_MODE.NO_SEC: case SECURITY_CONFIG_MODE.NO_SEC:
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); this.setValidatorsNoSecX509();
this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity();
this.lwm2mConfigFormGroup.get('clientKey').setValidators([]);
this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity();
break; break;
case SECURITY_CONFIG_MODE.PSK: case SECURITY_CONFIG_MODE.PSK:
this.lenMaxKeyClient = LEN_MAX_PSK; this.lenMaxKeyClient = LEN_MAX_PSK;
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); this.setValidatorsPskRpk(mode);
this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity();
this.lwm2mConfigFormGroup.get('clientKey').setValidators([Validators.required, Validators.pattern(KEY_IDENT_REGEXP_PSK)]);
this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity();
break; break;
case SECURITY_CONFIG_MODE.RPK: case SECURITY_CONFIG_MODE.RPK:
this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK; this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK;
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); this.setValidatorsPskRpk(mode);
this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity();
this.lwm2mConfigFormGroup.get('clientKey').setValidators([Validators.required, Validators.pattern(KEY_PUBLIC_REGEXP_PSK)]);
this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity();
break; break;
case SECURITY_CONFIG_MODE.X509: case SECURITY_CONFIG_MODE.X509:
this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK; this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK;
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]); this.setValidatorsNoSecX509();
this.lwm2mConfigFormGroup.get('identityPSK').updateValueAndValidity();
this.lwm2mConfigFormGroup.get('clientKey').setValidators([]);
this.lwm2mConfigFormGroup.get('clientKey').updateValueAndValidity();
break; break;
} }
this.lwm2mConfigFormGroup.updateValueAndValidity();
}
private setValidatorsNoSecX509 = (): void => {
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]);
this.lwm2mConfigFormGroup.get('clientKey').setValidators([]);
}
private setValidatorsPskRpk = (mode: SECURITY_CONFIG_MODE): void => {
if (mode === SECURITY_CONFIG_MODE.PSK) {
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([Validators.required]);
} else {
this.lwm2mConfigFormGroup.get('identityPSK').setValidators([]);
}
this.lwm2mConfigFormGroup.get('clientKey').setValidators([Validators.required,
Validators.pattern(KEY_REGEXP_HEX_DEC),
Validators.maxLength(this.lenMaxKeyClient), Validators.minLength(this.lenMaxKeyClient)]);
} }
tabChanged = (tabChangeEvent: MatTabChangeEvent): void => { tabChanged = (tabChangeEvent: MatTabChangeEvent): void => {
if (this.tabIndexPrevious !== tabChangeEvent.index) this.upDateValueToJson(); if (this.tabIndexPrevious !== tabChangeEvent.index) { this.upDateValueToJson(); }
this.tabIndexPrevious = tabChangeEvent.index; this.tabIndexPrevious = tabChangeEvent.index;
} }
upDateValueToJson(): void { private upDateValueToJson(): void {
switch (this.tabIndexPrevious) { switch (this.tabIndexPrevious) {
case 0: case 0:
this.upDateValueToJsonTab_0(); this.upDateValueToJsonTab0();
break; break;
case 1: case 1:
this.upDateValueToJsonTab_1(); this.upDateValueToJsonTab1();
break; break;
case 2: case 2:
this.upDateValueToJsonTab_2(); this.upDateValueToJsonTab2();
break; break;
} }
} }
upDateValueToJsonTab_0(): void { private upDateValueToJsonTab0 = (): void => {
if (this.lwm2mConfigFormGroup !== null) { if (this.lwm2mConfigFormGroup !== null) {
if (!this.lwm2mConfigFormGroup.get('endPoint').pristine && this.lwm2mConfigFormGroup.get('endPoint').valid) { if (!this.lwm2mConfigFormGroup.get('endPoint').pristine && this.lwm2mConfigFormGroup.get('endPoint').valid) {
this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value; this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value;
// Client mode == PSK // Client mode == PSK
if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) { if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) {
this.jsonAllConfig.client["endpoint"] = this.data.endPoint; const endPoint = 'endpoint';
this.jsonAllConfig.client["endpoint"].markAsPristine({ this.jsonAllConfig.client[endPoint] = this.data.endPoint;
this.jsonAllConfig.client[endPoint].markAsPristine({
onlySelf: true onlySelf: true
}); });
this.upDateJsonAllConfig(); this.upDateJsonAllConfig();
@ -261,7 +263,7 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
} }
} }
upDateValueToJsonTab_1(): void { private upDateValueToJsonTab1 = (): void => {
if (this.lwm2mConfigFormGroup !== null) { if (this.lwm2mConfigFormGroup !== null) {
if (this.bootstrapFormGroup !== null && !this.bootstrapFormGroup.pristine && this.bootstrapFormGroup.valid) { if (this.bootstrapFormGroup !== null && !this.bootstrapFormGroup.pristine && this.bootstrapFormGroup.valid) {
this.jsonAllConfig.bootstrap.bootstrapServer = this.bootstrapFormGroup.value; this.jsonAllConfig.bootstrap.bootstrapServer = this.bootstrapFormGroup.value;
@ -281,8 +283,9 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
} }
} }
upDateValueToJsonTab_2(): void { private upDateValueToJsonTab2 = (): void => {
if (!this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).pristine && this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).valid) { if (!this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).pristine &&
this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).valid) {
this.jsonAllConfig = this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).value; this.jsonAllConfig = this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).value;
this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).markAsPristine({ this.lwm2mConfigFormGroup.get(this.formControlNameJsonAllConfig).markAsPristine({
onlySelf: true onlySelf: true
@ -290,15 +293,17 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
} }
} }
updateIdentityPSK(): void { private updateIdentityPSK = (): void => {
if (this.lwm2mConfigFormGroup.get('bootstrapServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { const securityMode = 'securityMode';
if (this.lwm2mConfigFormGroup.get('bootstrapServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK.toString()) {
this.lwm2mConfigFormGroup.get('bootstrapFormGroup').patchValue({ this.lwm2mConfigFormGroup.get('bootstrapFormGroup').patchValue({
clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value
}); });
this.jsonAllConfig.client['identity'] = this.lwm2mConfigFormGroup.get('identityPSK').value; const identity = 'identity';
this.jsonAllConfig.client[identity] = this.lwm2mConfigFormGroup.get('identityPSK').value;
this.upDateJsonAllConfig(); this.upDateJsonAllConfig();
} }
if (this.lwm2mConfigFormGroup.get('lwm2mServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { if (this.lwm2mConfigFormGroup.get('lwm2mServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK.toString()) {
this.lwm2mConfigFormGroup.get('lwm2mServerFormGroup').patchValue({ this.lwm2mConfigFormGroup.get('lwm2mServerFormGroup').patchValue({
clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value clientPublicKeyOrId: this.lwm2mConfigFormGroup.get('identityPSK').value
}); });
@ -307,32 +312,26 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
} }
} }
updateClientKey(): void { private updateClientKey = (): void => {
this.jsonAllConfig.client["key"] = this.lwm2mConfigFormGroup.get('clientKey').value; const key = 'key';
if (this.lwm2mConfigFormGroup.get('bootstrapServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { const securityMode = 'securityMode';
this.jsonAllConfig.client[key] = this.lwm2mConfigFormGroup.get('clientKey').value;
if (this.lwm2mConfigFormGroup.get('bootstrapServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK.toString()) {
this.lwm2mConfigFormGroup.get('bootstrapServer').patchValue({ this.lwm2mConfigFormGroup.get('bootstrapServer').patchValue({
clientSecretKey: this.jsonAllConfig.client["key"] clientSecretKey: this.jsonAllConfig.client[key]
}, {emitEvent: false}); }, {emitEvent: false});
this.jsonAllConfig.bootstrap.bootstrapServer.clientSecretKey = this.jsonAllConfig.client["key"]; this.jsonAllConfig.bootstrap.bootstrapServer.clientSecretKey = this.jsonAllConfig.client[key];
} }
if (this.lwm2mConfigFormGroup.get('lwm2mServer').value['securityMode'] === SECURITY_CONFIG_MODE.PSK.toString()) { if (this.lwm2mConfigFormGroup.get('lwm2mServer').value[securityMode] === SECURITY_CONFIG_MODE.PSK.toString()) {
this.lwm2mConfigFormGroup.get('lwm2mServer').patchValue({ this.lwm2mConfigFormGroup.get('lwm2mServer').patchValue({
clientSecretKey: this.jsonAllConfig.client["key"] clientSecretKey: this.jsonAllConfig.client[key]
}, {emitEvent: false}); }, {emitEvent: false});
this.jsonAllConfig.bootstrap.lwm2mServer.clientSecretKey = this.jsonAllConfig.client["key"]; this.jsonAllConfig.bootstrap.lwm2mServer.clientSecretKey = this.jsonAllConfig.client[key];
} }
this.upDateJsonAllConfig(); this.upDateJsonAllConfig();
} }
upDateJsonAllConfig(): void { private upDateJsonAllConfig = (): void => {
this.data.jsonAllConfig = JSON.parse(JSON.stringify(this.jsonAllConfig));
this.lwm2mConfigFormGroup.patchValue({
jsonAllConfig: JSON.parse(JSON.stringify(this.jsonAllConfig))
}, {emitEvent: false});
this.lwm2mConfigFormGroup.markAsDirty();
}
upDateBootstrapFormGroup(): void {
this.data.jsonAllConfig = JSON.parse(JSON.stringify(this.jsonAllConfig)); this.data.jsonAllConfig = JSON.parse(JSON.stringify(this.jsonAllConfig));
this.lwm2mConfigFormGroup.patchValue({ this.lwm2mConfigFormGroup.patchValue({
jsonAllConfig: JSON.parse(JSON.stringify(this.jsonAllConfig)) jsonAllConfig: JSON.parse(JSON.stringify(this.jsonAllConfig))
@ -340,9 +339,10 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
this.lwm2mConfigFormGroup.markAsDirty(); this.lwm2mConfigFormGroup.markAsDirty();
} }
initLwm2mConfigFormGroup(): FormGroup { private initLwm2mConfigFormGroup = (): FormGroup => {
if (SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()] === SECURITY_CONFIG_MODE.PSK) { if (SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()] === SECURITY_CONFIG_MODE.PSK) {
this.data.endPoint = this.jsonAllConfig.client['endpoint']; const endpoint = 'endpoint';
this.data.endPoint = this.jsonAllConfig.client[endpoint];
} }
return this.fb.group({ return this.fb.group({
securityConfigClientMode: [SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()], []], securityConfigClientMode: [SECURITY_CONFIG_MODE[this.jsonAllConfig.client.securityConfigClientMode.toString()], []],
@ -351,27 +351,28 @@ export class SecurityConfigComponent extends DialogComponent<SecurityConfigCompo
clientCertificate: [false, []], clientCertificate: [false, []],
bootstrapServer: [this.jsonAllConfig.bootstrap[this.bootstrapServer], []], bootstrapServer: [this.jsonAllConfig.bootstrap[this.bootstrapServer], []],
lwm2mServer: [this.jsonAllConfig.bootstrap[this.lwm2mServer], []], lwm2mServer: [this.jsonAllConfig.bootstrap[this.lwm2mServer], []],
bootstrapFormGroup: this.getServerGroup(true), bootstrapFormGroup: this.getServerGroup(),
lwm2mServerFormGroup: this.getServerGroup(false), lwm2mServerFormGroup: this.getServerGroup(),
endPoint: [this.data.endPoint, []], endPoint: [this.data.endPoint, []],
jsonAllConfig: [this.jsonAllConfig, []] jsonAllConfig: [this.jsonAllConfig, []]
}); });
} }
getServerGroup(bootstrapServerIs: boolean): FormGroup { private getServerGroup = (): FormGroup => {
return this.fb.group({ return this.fb.group({
securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC), []], securityMode: [this.fb.control(SECURITY_CONFIG_MODE.NO_SEC), []],
clientPublicKeyOrId: ['', []], clientPublicKeyOrId: ['', []],
clientSecretKey: ['', []] clientSecretKey: ['', []]
}) });
} }
save(): void { save(): void {
this.upDateValueToJson(); this.upDateValueToJson();
this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value.split('\"').join(''); this.data.endPoint = this.lwm2mConfigFormGroup.get('endPoint').value.split('\'').join('');
this.data.jsonAllConfig = this.jsonAllConfig; this.data.jsonAllConfig = this.jsonAllConfig;
if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) { if (this.lwm2mConfigFormGroup.get('securityConfigClientMode').value === SECURITY_CONFIG_MODE.PSK) {
this.data.endPoint = this.data.jsonAllConfig.client["identity"]; const identity = 'identity';
this.data.endPoint = this.data.jsonAllConfig.client[identity];
} }
this.dialogRef.close(this.data); this.dialogRef.close(this.data);
} }

54
ui-ngx/src/app/modules/home/pages/device/lwm2m/security-config.models.ts

@ -25,10 +25,8 @@ export const LEN_MAX_PSK = 64;
export const LEN_MAX_PRIVATE_KEY = 134; export const LEN_MAX_PRIVATE_KEY = 134;
export const LEN_MAX_PUBLIC_KEY_RPK = 182; export const LEN_MAX_PUBLIC_KEY_RPK = 182;
export const LEN_MAX_PUBLIC_KEY_X509 = 3000; export const LEN_MAX_PUBLIC_KEY_X509 = 3000;
export const KEY_IDENT_REGEXP_PSK = /^[0-9a-fA-F]{64,64}$/; export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/;
export const KEY_PRIVATE_REGEXP = /^[0-9a-fA-F]{134,134}$/;
export const KEY_PUBLIC_REGEXP_PSK = /^[0-9a-fA-F]{182,182}$/;
export const KEY_PUBLIC_REGEXP_X509 = /^[0-9a-fA-F]{0,3000}$/;
export interface DeviceCredentialsDialogLwm2mData { export interface DeviceCredentialsDialogLwm2mData {
jsonAllConfig?: SecurityConfigModels; jsonAllConfig?: SecurityConfigModels;
@ -55,43 +53,43 @@ export type ClientSecurityConfigType =
ClientSecurityConfigPSK ClientSecurityConfigPSK
| ClientSecurityConfigRPK | ClientSecurityConfigRPK
| ClientSecurityConfigX509 | ClientSecurityConfigX509
| ClientSecurityConfigNO_SEC; | ClientSecurityConfigNoSEC;
export interface ClientSecurityConfigPSK { export interface ClientSecurityConfigPSK {
securityConfigClientMode: string, securityConfigClientMode: string;
endpoint: string, endpoint: string;
identity: string, identity: string;
key: string key: string;
} }
export interface ClientSecurityConfigRPK { export interface ClientSecurityConfigRPK {
securityConfigClientMode: string, securityConfigClientMode: string;
key: string key: string;
} }
export interface ClientSecurityConfigX509 { export interface ClientSecurityConfigX509 {
securityConfigClientMode: string, securityConfigClientMode: string;
x509: boolean x509: boolean;
} }
export interface ClientSecurityConfigNO_SEC { export interface ClientSecurityConfigNoSEC {
securityConfigClientMode: string securityConfigClientMode: string;
} }
export interface ServerSecurityConfig { export interface ServerSecurityConfig {
securityMode: string, securityMode: string;
clientPublicKeyOrId?: string, clientPublicKeyOrId?: string;
clientSecretKey?: string clientSecretKey?: string;
} }
interface BootstrapSecurityConfig { interface BootstrapSecurityConfig {
bootstrapServer: ServerSecurityConfig, bootstrapServer: ServerSecurityConfig;
lwm2mServer: ServerSecurityConfig lwm2mServer: ServerSecurityConfig;
} }
export interface SecurityConfigModels { export interface SecurityConfigModels {
client: ClientSecurityConfigType, client: ClientSecurityConfigType;
bootstrap: BootstrapSecurityConfig bootstrap: BootstrapSecurityConfig;
} }
export function getDefaultClientSecurityConfigType(securityConfigMode: SECURITY_CONFIG_MODE, endPoint?: string): ClientSecurityConfigType { export function getDefaultClientSecurityConfigType(securityConfigMode: SECURITY_CONFIG_MODE, endPoint?: string): ClientSecurityConfigType {
@ -103,24 +101,24 @@ export function getDefaultClientSecurityConfigType(securityConfigMode: SECURITY_
endpoint: endPoint, endpoint: endPoint,
identity: endPoint, identity: endPoint,
key: '' key: ''
} };
break; break;
case SECURITY_CONFIG_MODE.RPK: case SECURITY_CONFIG_MODE.RPK:
security = { security = {
securityConfigClientMode: '', securityConfigClientMode: '',
key: '' key: ''
} };
break; break;
case SECURITY_CONFIG_MODE.X509: case SECURITY_CONFIG_MODE.X509:
security = { security = {
securityConfigClientMode: '', securityConfigClientMode: '',
x509: true x509: true
} };
break; break;
case SECURITY_CONFIG_MODE.NO_SEC: case SECURITY_CONFIG_MODE.NO_SEC:
security = { security = {
securityConfigClientMode: '' securityConfigClientMode: ''
} };
break; break;
} }
security.securityConfigClientMode = securityConfigMode.toString(); security.securityConfigClientMode = securityConfigMode.toString();
@ -132,14 +130,14 @@ export function getDefaultServerSecurityConfig(): ServerSecurityConfig {
securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(), securityMode: SECURITY_CONFIG_MODE.NO_SEC.toString(),
clientPublicKeyOrId: '', clientPublicKeyOrId: '',
clientSecretKey: '' clientSecretKey: ''
} };
} }
function getDefaultBootstrapSecurityConfig(): BootstrapSecurityConfig { function getDefaultBootstrapSecurityConfig(): BootstrapSecurityConfig {
return { return {
bootstrapServer: getDefaultServerSecurityConfig(), bootstrapServer: getDefaultServerSecurityConfig(),
lwm2mServer: getDefaultServerSecurityConfig() lwm2mServer: getDefaultServerSecurityConfig()
} };
} }
export function getDefaultSecurityConfig(): SecurityConfigModels { export function getDefaultSecurityConfig(): SecurityConfigModels {

6
ui-ngx/src/app/shared/components/json-object-edit.component.ts

@ -61,6 +61,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
@Input() editorStyle: { [klass: string]: any }; @Input() editorStyle: { [klass: string]: any };
// tslint:disable-next-line:ban-types
@Input() sort: Function; @Input() sort: Function;
private requiredValue: boolean; private requiredValue: boolean;
@ -226,9 +227,10 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
try { try {
if (this.modelValue) { if (this.modelValue) {
this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? null :
// tslint:disable-next-line:no-shadowed-variable
(key, value) => { (key, value) => {
return this.sort(key, value) return this.sort(key, value);
}, 2); }, 2);
this.objectValid = true; this.objectValid = true;
} else { } else {

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

@ -893,9 +893,8 @@
"lwm2m-server": "LwM2M Server", "lwm2m-server": "LwM2M Server",
"client-publicKey-or-id": "Client Public Key or Id", "client-publicKey-or-id": "Client Public Key or Id",
"client-secret-key": "Client Secret Key", "client-secret-key": "Client Secret Key",
"config-json-tab": "Json Client Security Config", "config-json-tab": "Json Client Security Config",
"pattern_hex_dec_64": "must be hex decimal format and 64 characters", "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }"
"pattern_hex_dec_182": "must be hex decimal format and 182 characters"
}, },
"client-id": "Client ID", "client-id": "Client ID",
"client-id-pattern": "Contains invalid character.", "client-id-pattern": "Contains invalid character.",
@ -1121,10 +1120,7 @@
"key-name_label": "Key Name in Camel format", "key-name_label": "Key Name in Camel format",
"required": " value is required.", "required": " value is required.",
"mode": "Security config mode", "mode": "Security config mode",
"pattern_hex_dec_64": "must be hex decimal format and 64 characters", "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }",
"pattern_hex_dec_134": "must be hex decimal format and 134 characters",
"pattern_hex_dec_182": "must be hex decimal format and 182 characters",
"pattern_hex_dec": "must be hex decimal format",
"bootstrap-tab": "Bootstrap", "bootstrap-tab": "Bootstrap",
"servers": "Servers", "servers": "Servers",
"short-id": "Short ID", "short-id": "Short ID",

Loading…
Cancel
Save