Commit 688a272035747cf0a411157eef82d67b906a59ee
Committed by
GitHub
Merge pull request #4780 from vvlladd28/refactoring/lwm2m/device-profile
UI: Refactoring LwM2M device profile
Showing
18 changed files
with
646 additions
and
539 deletions
@@ -21,18 +21,23 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; | @@ -21,18 +21,23 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; | ||
21 | import { Observable, of, throwError } from 'rxjs'; | 21 | import { Observable, of, throwError } from 'rxjs'; |
22 | import { PageData } from '@shared/models/page/page-data'; | 22 | import { PageData } from '@shared/models/page/page-data'; |
23 | import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; | 23 | import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; |
24 | -import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; | ||
25 | -import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; | 24 | +import { deepClone, isDefinedAndNotNull, isEmptyStr } from '@core/utils'; |
25 | +import { | ||
26 | + ObjectLwM2M, | ||
27 | + securityConfigMode, | ||
28 | + ServerSecurityConfig, | ||
29 | + ServerSecurityConfigInfo | ||
30 | +} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; | ||
26 | import { SortOrder } from '@shared/models/page/sort-order'; | 31 | import { SortOrder } from '@shared/models/page/sort-order'; |
27 | import { OtaPackageService } from '@core/http/ota-package.service'; | 32 | import { OtaPackageService } from '@core/http/ota-package.service'; |
28 | -import { mergeMap, tap } from 'rxjs/operators'; | 33 | +import { map, mergeMap, tap } from 'rxjs/operators'; |
29 | 34 | ||
30 | @Injectable({ | 35 | @Injectable({ |
31 | providedIn: 'root' | 36 | providedIn: 'root' |
32 | }) | 37 | }) |
33 | export class DeviceProfileService { | 38 | export class DeviceProfileService { |
34 | 39 | ||
35 | - private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfig>(); | 40 | + private lwm2mBootstrapSecurityInfoInMemoryCache = new Map<boolean, ServerSecurityConfigInfo>(); |
36 | 41 | ||
37 | constructor( | 42 | constructor( |
38 | private http: HttpClient, | 43 | private http: HttpClient, |
@@ -60,12 +65,12 @@ export class DeviceProfileService { | @@ -60,12 +65,12 @@ export class DeviceProfileService { | ||
60 | return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config)); | 65 | return this.http.get<Array<ObjectLwM2M>>(url, defaultHttpOptionsFromConfig(config)); |
61 | } | 66 | } |
62 | 67 | ||
63 | - public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfig> { | 68 | + public getLwm2mBootstrapSecurityInfo(isBootstrapServer: boolean, config?: RequestConfig): Observable<ServerSecurityConfigInfo> { |
64 | const securityConfig = this.lwm2mBootstrapSecurityInfoInMemoryCache.get(isBootstrapServer); | 69 | const securityConfig = this.lwm2mBootstrapSecurityInfoInMemoryCache.get(isBootstrapServer); |
65 | if (securityConfig) { | 70 | if (securityConfig) { |
66 | return of(securityConfig); | 71 | return of(securityConfig); |
67 | } else { | 72 | } else { |
68 | - return this.http.get<ServerSecurityConfig>( | 73 | + return this.http.get<ServerSecurityConfigInfo>( |
69 | `/api/lwm2m/deviceProfile/bootstrap/${isBootstrapServer}`, | 74 | `/api/lwm2m/deviceProfile/bootstrap/${isBootstrapServer}`, |
70 | defaultHttpOptionsFromConfig(config) | 75 | defaultHttpOptionsFromConfig(config) |
71 | ).pipe( | 76 | ).pipe( |
@@ -74,6 +79,31 @@ export class DeviceProfileService { | @@ -74,6 +79,31 @@ export class DeviceProfileService { | ||
74 | } | 79 | } |
75 | } | 80 | } |
76 | 81 | ||
82 | + public getLwm2mBootstrapSecurityInfoBySecurityType(isBootstrapServer: boolean, securityMode = securityConfigMode.NO_SEC, | ||
83 | + config?: RequestConfig): Observable<ServerSecurityConfig> { | ||
84 | + return this.getLwm2mBootstrapSecurityInfo(isBootstrapServer, config).pipe( | ||
85 | + map(securityConfig => { | ||
86 | + const serverSecurityConfigInfo = deepClone(securityConfig); | ||
87 | + switch (securityMode) { | ||
88 | + case securityConfigMode.PSK: | ||
89 | + serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; | ||
90 | + serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; | ||
91 | + serverSecurityConfigInfo.serverPublicKey = ''; | ||
92 | + break; | ||
93 | + case securityConfigMode.RPK: | ||
94 | + case securityConfigMode.X509: | ||
95 | + serverSecurityConfigInfo.port = serverSecurityConfigInfo.securityPort; | ||
96 | + serverSecurityConfigInfo.host = serverSecurityConfigInfo.securityHost; | ||
97 | + break; | ||
98 | + case securityConfigMode.NO_SEC: | ||
99 | + serverSecurityConfigInfo.serverPublicKey = ''; | ||
100 | + break; | ||
101 | + } | ||
102 | + return serverSecurityConfigInfo; | ||
103 | + }) | ||
104 | + ); | ||
105 | + } | ||
106 | + | ||
77 | public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> { | 107 | public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> { |
78 | return this.http.get<Array<ObjectLwM2M>>( | 108 | return this.http.get<Array<ObjectLwM2M>>( |
79 | `/api/resource/lwm2m/page${pageLink.toQuery()}`, | 109 | `/api/resource/lwm2m/page${pageLink.toQuery()}`, |
@@ -89,9 +89,10 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu | @@ -89,9 +89,10 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu | ||
89 | if (configuration) { | 89 | if (configuration) { |
90 | delete configuration.type; | 90 | delete configuration.type; |
91 | } | 91 | } |
92 | + this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | ||
92 | setTimeout(() => { | 93 | setTimeout(() => { |
93 | - this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | ||
94 | - }); | 94 | + this.deviceProfileTransportConfigurationFormGroup.updateValueAndValidity(); |
95 | + }, 0); | ||
95 | } | 96 | } |
96 | 97 | ||
97 | private updateModel() { | 98 | private updateModel() { |
@@ -15,12 +15,11 @@ | @@ -15,12 +15,11 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<form [formGroup]="attributeLwm2mDialogFormGroup" (ngSubmit)="save()" style="width: 500px;"> | 18 | +<form [formGroup]="attributeFormGroup" (ngSubmit)="save()" style="min-width: 500px;"> |
19 | <mat-toolbar color="primary"> | 19 | <mat-toolbar color="primary"> |
20 | - <div fxFlex fxLayout="column" fxLayoutAlign="start"> | ||
21 | - <h2>{{ (readonly ? 'device-profile.lwm2m.attribute-lwm2m-toolbar-view' : | ||
22 | - 'device-profile.lwm2m.attribute-lwm2m-toolbar-edit') | translate }}</h2> | ||
23 | - </div> | 20 | + <h2> |
21 | + {{ (readonly ? 'device-profile.lwm2m.view-attributes' : 'device-profile.lwm2m.edit-attributes') | translate : {name: name} }} | ||
22 | + </h2> | ||
24 | <span fxFlex></span> | 23 | <span fxFlex></span> |
25 | <button mat-icon-button | 24 | <button mat-icon-button |
26 | (click)="cancel()" | 25 | (click)="cancel()" |
@@ -32,8 +31,8 @@ | @@ -32,8 +31,8 @@ | ||
32 | </mat-progress-bar> | 31 | </mat-progress-bar> |
33 | <div mat-dialog-content> | 32 | <div mat-dialog-content> |
34 | <tb-lwm2m-attributes-key-list | 33 | <tb-lwm2m-attributes-key-list |
35 | - formControlName="keyFilters" | ||
36 | - titleText="{{data.destName}}"> | 34 | + [isResource]="isResource" |
35 | + formControlName="attributes"> | ||
37 | </tb-lwm2m-attributes-key-list> | 36 | </tb-lwm2m-attributes-key-list> |
38 | </div> | 37 | </div> |
39 | <div mat-dialog-actions fxLayoutAlign="end center"> | 38 | <div mat-dialog-actions fxLayoutAlign="end center"> |
@@ -46,7 +45,7 @@ | @@ -46,7 +45,7 @@ | ||
46 | <button mat-raised-button color="primary" | 45 | <button mat-raised-button color="primary" |
47 | *ngIf="!readonly" | 46 | *ngIf="!readonly" |
48 | type="submit" | 47 | type="submit" |
49 | - [disabled]="(isLoading$ | async) || attributeLwm2mDialogFormGroup.invalid || !attributeLwm2mDialogFormGroup.dirty"> | 48 | + [disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty"> |
50 | {{ 'action.save' | translate }} | 49 | {{ 'action.save' | translate }} |
51 | </button> | 50 | </button> |
52 | </div> | 51 | </div> |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; | 17 | +import { Component, Inject, SkipSelf } from '@angular/core'; |
18 | import { ErrorStateMatcher } from '@angular/material/core'; | 18 | import { ErrorStateMatcher } from '@angular/material/core'; |
19 | import { DialogComponent } from '@shared/components/dialog.component'; | 19 | import { DialogComponent } from '@shared/components/dialog.component'; |
20 | import { Store } from '@ngrx/store'; | 20 | import { Store } from '@ngrx/store'; |
@@ -22,12 +22,13 @@ import { AppState } from '@core/core.state'; | @@ -22,12 +22,13 @@ import { AppState } from '@core/core.state'; | ||
22 | import { Router } from '@angular/router'; | 22 | import { Router } from '@angular/router'; |
23 | import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; | 23 | import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
24 | import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms'; | 24 | import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms'; |
25 | -import { JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; | 25 | +import { AttributesNameValueMap } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; |
26 | 26 | ||
27 | export interface Lwm2mAttributesDialogData { | 27 | export interface Lwm2mAttributesDialogData { |
28 | readonly: boolean; | 28 | readonly: boolean; |
29 | - attributeLwm2m: JsonObject; | ||
30 | - destName: string; | 29 | + attributes: AttributesNameValueMap; |
30 | + modelName: string; | ||
31 | + isResource: boolean; | ||
31 | } | 32 | } |
32 | 33 | ||
33 | @Component({ | 34 | @Component({ |
@@ -36,42 +37,37 @@ export interface Lwm2mAttributesDialogData { | @@ -36,42 +37,37 @@ export interface Lwm2mAttributesDialogData { | ||
36 | styleUrls: ['./lwm2m-attributes.component.scss'], | 37 | styleUrls: ['./lwm2m-attributes.component.scss'], |
37 | providers: [{provide: ErrorStateMatcher, useExisting: Lwm2mAttributesDialogComponent}], | 38 | providers: [{provide: ErrorStateMatcher, useExisting: Lwm2mAttributesDialogComponent}], |
38 | }) | 39 | }) |
39 | -export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttributesDialogComponent, object> | ||
40 | - implements OnInit, ErrorStateMatcher { | 40 | +export class Lwm2mAttributesDialogComponent |
41 | + extends DialogComponent<Lwm2mAttributesDialogComponent, AttributesNameValueMap> implements ErrorStateMatcher { | ||
41 | 42 | ||
42 | - readonly = this.data.readonly; | ||
43 | - | ||
44 | - attributeLwm2m = this.data.attributeLwm2m; | ||
45 | - | ||
46 | - submitted = false; | 43 | + readonly: boolean; |
44 | + name: string; | ||
45 | + isResource: boolean; | ||
47 | 46 | ||
48 | - dirtyValue = false; | 47 | + private submitted = false; |
49 | 48 | ||
50 | - attributeLwm2mDialogFormGroup: FormGroup; | 49 | + attributeFormGroup: FormGroup; |
51 | 50 | ||
52 | constructor(protected store: Store<AppState>, | 51 | constructor(protected store: Store<AppState>, |
53 | protected router: Router, | 52 | protected router: Router, |
54 | - @Inject(MAT_DIALOG_DATA) public data: Lwm2mAttributesDialogData, | 53 | + @Inject(MAT_DIALOG_DATA) private data: Lwm2mAttributesDialogData, |
55 | @SkipSelf() private errorStateMatcher: ErrorStateMatcher, | 54 | @SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
56 | - public dialogRef: MatDialogRef<Lwm2mAttributesDialogComponent, object>, | 55 | + public dialogRef: MatDialogRef<Lwm2mAttributesDialogComponent, AttributesNameValueMap>, |
57 | private fb: FormBuilder) { | 56 | private fb: FormBuilder) { |
58 | super(store, router, dialogRef); | 57 | super(store, router, dialogRef); |
59 | 58 | ||
60 | - this.attributeLwm2mDialogFormGroup = this.fb.group({ | ||
61 | - keyFilters: [{}, []] | ||
62 | - }); | ||
63 | - this.attributeLwm2mDialogFormGroup.patchValue({keyFilters: this.attributeLwm2m}); | ||
64 | - this.attributeLwm2mDialogFormGroup.get('keyFilters').valueChanges.subscribe((attributes) => { | ||
65 | - this.attributeLwm2m = attributes; | 59 | + this.readonly = data.readonly; |
60 | + this.name = data.modelName; | ||
61 | + this.isResource = data.isResource; | ||
62 | + | ||
63 | + this.attributeFormGroup = this.fb.group({ | ||
64 | + attributes: [data.attributes] | ||
66 | }); | 65 | }); |
67 | if (this.readonly) { | 66 | if (this.readonly) { |
68 | - this.attributeLwm2mDialogFormGroup.disable({emitEvent: false}); | 67 | + this.attributeFormGroup.disable({emitEvent: false}); |
69 | } | 68 | } |
70 | } | 69 | } |
71 | 70 | ||
72 | - ngOnInit(): void { | ||
73 | - } | ||
74 | - | ||
75 | isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { | 71 | isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { |
76 | const originalErrorState = this.errorStateMatcher.isErrorState(control, form); | 72 | const originalErrorState = this.errorStateMatcher.isErrorState(control, form); |
77 | const customErrorState = !!(control && control.invalid && this.submitted); | 73 | const customErrorState = !!(control && control.invalid && this.submitted); |
@@ -80,7 +76,7 @@ export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttribu | @@ -80,7 +76,7 @@ export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttribu | ||
80 | 76 | ||
81 | save(): void { | 77 | save(): void { |
82 | this.submitted = true; | 78 | this.submitted = true; |
83 | - this.dialogRef.close(this.attributeLwm2m); | 79 | + this.dialogRef.close(this.attributeFormGroup.get('attributes').value); |
84 | } | 80 | } |
85 | 81 | ||
86 | cancel(): void { | 82 | cancel(): void { |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component.html
@@ -15,69 +15,60 @@ | @@ -15,69 +15,60 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<section fxLayout="column" class="tb-kv-map" [formGroup]="kvListFormGroup"> | ||
19 | - <div> | ||
20 | - <mat-label translate class="tb-title no-padding">device-profile.lwm2m.attribute-lwm2m-destination</mat-label> | ||
21 | - <mat-label class="tb-editor-area-title-panel">{{ titleText }}</mat-label> | ||
22 | - </div> | 18 | +<section fxLayout="column" class="name-value-map" [formGroup]="attributesValueFormGroup"> |
23 | <div fxLayout="row" fxLayoutGap="8px" style="max-height: 40px; margin-top: 8px;"> | 19 | <div fxLayout="row" fxLayoutGap="8px" style="max-height: 40px; margin-top: 8px;"> |
24 | - <mat-label fxFlex class="tb-title no-padding" translate>device-profile.lwm2m.attribute-lwm2m-name</mat-label> | ||
25 | - <mat-label fxFlex class="tb-title no-padding" translate>device-profile.lwm2m.attribute-lwm2m-value</mat-label> | ||
26 | - <div [fxShow]="!disabled" style="width: 40px;"></div> | 20 | + <label fxFlex="40" class="tb-title no-padding" style="min-width: 230px;" translate>device-profile.lwm2m.attribute-name</label> |
21 | + <label fxFlex="60" class="tb-title no-padding" translate>device-profile.lwm2m.attribute-value</label> | ||
22 | + <span [fxShow]="!disabled" style="width: 40px;"></span> | ||
27 | </div> | 23 | </div> |
28 | - <div fxLayout="column" formArrayName="keyVals" | ||
29 | - *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index"> | ||
30 | - <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> | ||
31 | - <mat-form-field class="mat-block" style="max-heights: 400px"> | 24 | + <div fxLayout="column" class="map-list" |
25 | + *ngFor="let nameValueControl of attributesValueFormArray().controls; let $index = index" | ||
26 | + [formGroup]="nameValueControl"> | ||
27 | + <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> | ||
28 | + <mat-form-field fxFlex="40" floatLabel="always" hideRequiredMarker> | ||
32 | <mat-label></mat-label> | 29 | <mat-label></mat-label> |
33 | - <mat-select [formControl]="keyValControl.get('key')"> | ||
34 | - <mat-option *ngFor="let attributeLwm2m of attrKeys" | ||
35 | - [value]="attributeLwm2m"> | ||
36 | - {{ attributeLwm2mMap.get(attrKey[attributeLwm2m]) }} | 30 | + <mat-select formControlName="name" required> |
31 | + <mat-option *ngFor="let attributeName of attributeNames" [value]="attributeName" | ||
32 | + [disabled]="isDisabledAttributeName(attributeName, $index)"> | ||
33 | + {{ attributeNameTranslationMap.get(attributeName) | translate }} | ||
37 | </mat-option> | 34 | </mat-option> |
38 | </mat-select> | 35 | </mat-select> |
36 | + <mat-error *ngIf="nameValueControl.get('name').hasError('required')"> | ||
37 | + {{ 'device-profile.lwm2m.attribute-name-required' | translate }} | ||
38 | + </mat-error> | ||
39 | </mat-form-field> | 39 | </mat-form-field> |
40 | - <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="mat-block" | ||
41 | - style="max-height: 40px;"> | 40 | + <mat-form-field fxFlex="60" floatLabel="always" hideRequiredMarker> |
42 | <mat-label></mat-label> | 41 | <mat-label></mat-label> |
43 | - <input [formControl]="keyValControl.get('value')" matInput | ||
44 | - placeholder="{{ ('key-val.value') | translate }}"/> | 42 | + <input formControlName="value" matInput required type="number" |
43 | + placeholder="{{ 'key-val.value' | translate }}"> | ||
44 | + <mat-error fxLayout="row" *ngIf="nameValueControl.get('value').hasError('required')"> | ||
45 | + {{ 'device-profile.lwm2m.attribute-value-required' | translate }} | ||
46 | + </mat-error> | ||
47 | + <mat-error fxLayout="row" *ngIf="nameValueControl.get('value').hasError('min') || | ||
48 | + nameValueControl.get('value').hasError('pattern')"> | ||
49 | + {{ 'device-profile.lwm2m.attribute-value-pattern' | translate }} | ||
50 | + </mat-error> | ||
45 | </mat-form-field> | 51 | </mat-form-field> |
46 | - <button mat-button mat-icon-button color="primary" | ||
47 | - [fxShow]="!disabled" | 52 | + <button *ngIf="!disabled" |
53 | + mat-icon-button color="primary" style="min-width: 40px;" | ||
48 | type="button" | 54 | type="button" |
49 | (click)="removeKeyVal($index)" | 55 | (click)="removeKeyVal($index)" |
50 | - [disabled]="isLoading$ | async" | ||
51 | - matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-remove-tip' | translate }}" | 56 | + matTooltip="{{ 'device-profile.lwm2m.remove-attribute' | translate }}" |
52 | matTooltipPosition="above"> | 57 | matTooltipPosition="above"> |
53 | <mat-icon>close</mat-icon> | 58 | <mat-icon>close</mat-icon> |
54 | </button> | 59 | </button> |
55 | </div> | 60 | </div> |
56 | - <mat-error *ngIf="keyValControl.get('key').hasError('required')" style="font-size: smaller"> | ||
57 | - {{ 'device-profile.lwm2m.key-name' | translate }} | ||
58 | - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | ||
59 | - </mat-error> | ||
60 | - <mat-error fxLayout="row" *ngIf="keyValControl.get('key').hasError('validAttributeKey')" | ||
61 | - style="font-size: smaller"> | ||
62 | - {{ 'device-profile.lwm2m.valid-attribute-lwm2m-key' | translate: {attrEnums: attrKeys} }} | ||
63 | - </mat-error> | ||
64 | - <mat-error fxLayout="row" *ngIf="keyValControl.get('value').hasError('validAttributeValue')" | ||
65 | - style="font-size: smaller"> | ||
66 | - {{ 'device-profile.lwm2m.valid-attribute-lwm2m-value' | translate: {attrEnums: attrKeys} }} | ||
67 | - </mat-error> | ||
68 | </div> | 61 | </div> |
69 | - <span [fxShow]="!keyValsFormArray().length" | ||
70 | - fxLayoutAlign="center center" [ngClass]="{'disabled': disabled}" | ||
71 | - class="no-data-found" translate>{{noDataText ? noDataText : 'device-profile.lwm2m.no-data'}}</span> | ||
72 | - <div style="margin-top: 8px;"> | ||
73 | - <button mat-button mat-raised-button color="primary" | ||
74 | - [fxShow]="!disabled" | 62 | + <div [fxShow]="!attributesValueFormArray().length" |
63 | + fxLayoutAlign="center center" | ||
64 | + class="map-list" translate>device-profile.lwm2m.no-attributes-set</div> | ||
65 | + <div style="margin-top: 9px;" *ngIf="!disabled && isAddEnabled"> | ||
66 | + <button mat-stroked-button color="primary" | ||
75 | [disabled]="isLoading$ | async" | 67 | [disabled]="isLoading$ | async" |
76 | - (click)="addKeyVal()" | ||
77 | type="button" | 68 | type="button" |
78 | - matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-add-tip' | translate }}" | ||
79 | - matTooltipPosition="above"> | ||
80 | - {{ 'action.add' | translate }} | 69 | + (click)="addKeyVal()"> |
70 | + <mat-icon class="button-icon">add_circle_outline</mat-icon> | ||
71 | + {{ 'device-profile.lwm2m.add-attribute' | translate }} | ||
81 | </button> | 72 | </button> |
82 | </div> | 73 | </div> |
83 | </section> | 74 | </section> |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component.scss
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +:host { | ||
17 | + .name-value-map { | ||
18 | + span.no-data-found { | ||
19 | + position: relative; | ||
20 | + display: flex; | ||
21 | + height: 40px; | ||
22 | + | ||
23 | + &.disabled { | ||
24 | + color: rgba(0, 0, 0, .38); | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + .map-list{ | ||
29 | + height: 45px; | ||
30 | + } | ||
31 | + } | ||
32 | +} | ||
33 | + | ||
34 | +:host ::ng-deep { | ||
35 | + .mat-form-field-wrapper { | ||
36 | + padding-bottom: 0; | ||
37 | + } | ||
38 | + .mat-form-field-infix { | ||
39 | + border-top: 0; | ||
40 | + } | ||
41 | + .mat-form-field-underline { | ||
42 | + bottom: 0; | ||
43 | + } | ||
44 | + | ||
45 | + .button-icon{ | ||
46 | + font-size: 20px; | ||
47 | + width: 20px; | ||
48 | + height: 20px; | ||
49 | + } | ||
50 | + | ||
51 | + .map-list { | ||
52 | + mat-form-field { | ||
53 | + .mat-form-field-wrapper { | ||
54 | + padding-bottom: 0; | ||
55 | + .mat-form-field-infix { | ||
56 | + border-top-width: 0.2em; | ||
57 | + width: auto; | ||
58 | + min-width: auto; | ||
59 | + } | ||
60 | + .mat-form-field-underline { | ||
61 | + bottom: 0; | ||
62 | + } | ||
63 | + .mat-form-field-subscript-wrapper{ | ||
64 | + margin-top: 1.8em; | ||
65 | + } | ||
66 | + } | ||
67 | + } | ||
68 | + } | ||
69 | +} |
@@ -14,35 +14,36 @@ | @@ -14,35 +14,36 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, forwardRef, Input, OnInit } from '@angular/core'; | 17 | +import { Component, forwardRef, Input, OnDestroy } from '@angular/core'; |
18 | import { | 18 | import { |
19 | AbstractControl, | 19 | AbstractControl, |
20 | ControlValueAccessor, | 20 | ControlValueAccessor, |
21 | FormArray, | 21 | FormArray, |
22 | FormBuilder, | 22 | FormBuilder, |
23 | - FormControl, | ||
24 | FormGroup, | 23 | FormGroup, |
25 | NG_VALIDATORS, | 24 | NG_VALIDATORS, |
26 | NG_VALUE_ACCESSOR, | 25 | NG_VALUE_ACCESSOR, |
27 | Validator, | 26 | Validator, |
28 | Validators | 27 | Validators |
29 | } from '@angular/forms'; | 28 | } from '@angular/forms'; |
30 | -import { Subscription } from 'rxjs'; | 29 | +import { Subject, Subscription } from 'rxjs'; |
31 | import { | 30 | import { |
32 | - ATTRIBUTE_KEYS, | ||
33 | - ATTRIBUTE_LWM2M_ENUM, | ||
34 | - ATTRIBUTE_LWM2M_MAP | 31 | + AttributeName, |
32 | + AttributeNameTranslationMap, | ||
33 | + AttributesNameValue, | ||
34 | + AttributesNameValueMap, | ||
35 | + valueValidatorByAttributeName | ||
35 | } from './lwm2m-profile-config.models'; | 36 | } from './lwm2m-profile-config.models'; |
36 | -import { isDefinedAndNotNull, isEmpty, isEmptyStr, isUndefinedOrNull } from '@core/utils'; | 37 | +import { isUndefinedOrNull } from '@core/utils'; |
37 | import { Store } from '@ngrx/store'; | 38 | import { Store } from '@ngrx/store'; |
38 | import { AppState } from '@core/core.state'; | 39 | import { AppState } from '@core/core.state'; |
39 | import { PageComponent } from '@shared/components/page.component'; | 40 | import { PageComponent } from '@shared/components/page.component'; |
40 | - | 41 | +import { takeUntil } from 'rxjs/operators'; |
41 | 42 | ||
42 | @Component({ | 43 | @Component({ |
43 | selector: 'tb-lwm2m-attributes-key-list', | 44 | selector: 'tb-lwm2m-attributes-key-list', |
44 | templateUrl: './lwm2m-attributes-key-list.component.html', | 45 | templateUrl: './lwm2m-attributes-key-list.component.html', |
45 | - styleUrls: ['./lwm2m-attributes.component.scss'], | 46 | + styleUrls: ['./lwm2m-attributes-key-list.component.scss'], |
46 | providers: [ | 47 | providers: [ |
47 | { | 48 | { |
48 | provide: NG_VALUE_ACCESSOR, | 49 | provide: NG_VALUE_ACCESSOR, |
@@ -56,39 +57,46 @@ import { PageComponent } from '@shared/components/page.component'; | @@ -56,39 +57,46 @@ import { PageComponent } from '@shared/components/page.component'; | ||
56 | } | 57 | } |
57 | ] | 58 | ] |
58 | }) | 59 | }) |
59 | -export class Lwm2mAttributesKeyListComponent extends PageComponent implements ControlValueAccessor, OnInit, Validator { | ||
60 | - | ||
61 | - attrKeys = ATTRIBUTE_KEYS; | ||
62 | - | ||
63 | - attrKey = ATTRIBUTE_LWM2M_ENUM; | 60 | +export class Lwm2mAttributesKeyListComponent extends PageComponent implements ControlValueAccessor, OnDestroy, OnDestroy, Validator { |
64 | 61 | ||
65 | - attributeLwm2mMap = ATTRIBUTE_LWM2M_MAP; | 62 | + attributeNames; |
63 | + attributeNameTranslationMap = AttributeNameTranslationMap; | ||
66 | 64 | ||
67 | @Input() disabled: boolean; | 65 | @Input() disabled: boolean; |
68 | 66 | ||
69 | - @Input() titleText: string; | 67 | + @Input() |
68 | + isResource = false; | ||
70 | 69 | ||
71 | - @Input() noDataText: string; | ||
72 | - | ||
73 | - kvListFormGroup: FormGroup; | 70 | + attributesValueFormGroup: FormGroup; |
74 | 71 | ||
75 | private propagateChange = null; | 72 | private propagateChange = null; |
76 | - | ||
77 | - private valueChangeSubscription: Subscription = null; | 73 | + private valueChange$: Subscription = null; |
74 | + private destroy$ = new Subject(); | ||
75 | + private usedAttributesName: AttributeName[] = []; | ||
78 | 76 | ||
79 | constructor(protected store: Store<AppState>, | 77 | constructor(protected store: Store<AppState>, |
80 | private fb: FormBuilder) { | 78 | private fb: FormBuilder) { |
81 | super(store); | 79 | super(store); |
80 | + this.attributesValueFormGroup = this.fb.group({ | ||
81 | + attributesValue: this.fb.array([]) | ||
82 | + }); | ||
82 | } | 83 | } |
83 | 84 | ||
84 | - ngOnInit(): void { | ||
85 | - this.kvListFormGroup = this.fb.group({}); | ||
86 | - this.kvListFormGroup.addControl('keyVals', | ||
87 | - this.fb.array([])); | 85 | + ngOnInit() { |
86 | + if (this.isResource) { | ||
87 | + this.attributeNames = Object.values(AttributeName); | ||
88 | + } else { | ||
89 | + this.attributeNames = Object.values(AttributeName) | ||
90 | + .filter(item => ![AttributeName.lt, AttributeName.gt, AttributeName.st].includes(item)); | ||
91 | + } | ||
88 | } | 92 | } |
89 | 93 | ||
90 | - keyValsFormArray(): FormArray { | ||
91 | - return this.kvListFormGroup.get('keyVals') as FormArray; | 94 | + ngOnDestroy() { |
95 | + if (this.valueChange$) { | ||
96 | + this.valueChange$.unsubscribe(); | ||
97 | + } | ||
98 | + this.destroy$.next(); | ||
99 | + this.destroy$.complete(); | ||
92 | } | 100 | } |
93 | 101 | ||
94 | registerOnChange(fn: any): void { | 102 | registerOnChange(fn: any): void { |
@@ -101,127 +109,111 @@ export class Lwm2mAttributesKeyListComponent extends PageComponent implements Co | @@ -101,127 +109,111 @@ export class Lwm2mAttributesKeyListComponent extends PageComponent implements Co | ||
101 | setDisabledState(isDisabled: boolean): void { | 109 | setDisabledState(isDisabled: boolean): void { |
102 | this.disabled = isDisabled; | 110 | this.disabled = isDisabled; |
103 | if (this.disabled) { | 111 | if (this.disabled) { |
104 | - this.kvListFormGroup.disable({emitEvent: false}); | 112 | + this.attributesValueFormGroup.disable({emitEvent: false}); |
105 | } else { | 113 | } else { |
106 | - this.kvListFormGroup.enable({emitEvent: false}); | 114 | + this.attributesValueFormGroup.enable({emitEvent: false}); |
107 | } | 115 | } |
108 | } | 116 | } |
109 | 117 | ||
110 | - writeValue(keyValMap: { [key: string]: string }): void { | ||
111 | - if (this.valueChangeSubscription) { | ||
112 | - this.valueChangeSubscription.unsubscribe(); | 118 | + writeValue(keyValMap: AttributesNameValueMap): void { |
119 | + if (this.valueChange$) { | ||
120 | + this.valueChange$.unsubscribe(); | ||
113 | } | 121 | } |
114 | - const keyValsControls: Array<AbstractControl> = []; | 122 | + const attributesValueControls: Array<AbstractControl> = []; |
115 | if (keyValMap) { | 123 | if (keyValMap) { |
116 | - for (const property of Object.keys(keyValMap)) { | ||
117 | - if (Object.prototype.hasOwnProperty.call(keyValMap, property)) { | ||
118 | - keyValsControls.push(this.fb.group({ | ||
119 | - key: [property, [Validators.required, this.attributeLwm2mKeyValidator]], | ||
120 | - value: [keyValMap[property], this.attributeLwm2mValueValidator(property)] | ||
121 | - })); | ||
122 | - } | ||
123 | - } | 124 | + (Object.keys(keyValMap) as AttributeName[]).forEach(name => { |
125 | + attributesValueControls.push(this.createdFormGroup({name, value: keyValMap[name]})); | ||
126 | + }); | ||
124 | } | 127 | } |
125 | - this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls)); | ||
126 | - this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { | ||
127 | - // this.updateValidate(); | ||
128 | - this.updateModel(); | ||
129 | - }); | 128 | + this.attributesValueFormGroup.setControl('attributesValue', this.fb.array(attributesValueControls)); |
130 | if (this.disabled) { | 129 | if (this.disabled) { |
131 | - this.kvListFormGroup.disable({emitEvent: false}); | 130 | + this.attributesValueFormGroup.disable({emitEvent: false}); |
132 | } else { | 131 | } else { |
133 | - this.kvListFormGroup.enable({emitEvent: false}); | 132 | + this.attributesValueFormGroup.enable({emitEvent: false}); |
134 | } | 133 | } |
134 | + this.valueChange$ = this.attributesValueFormGroup.valueChanges.subscribe(() => { | ||
135 | + this.updateModel(); | ||
136 | + }); | ||
137 | + this.updateUsedAttributesName(); | ||
138 | + } | ||
139 | + | ||
140 | + attributesValueFormArray(): FormArray { | ||
141 | + return this.attributesValueFormGroup.get('attributesValue') as FormArray; | ||
135 | } | 142 | } |
136 | 143 | ||
137 | public removeKeyVal(index: number) { | 144 | public removeKeyVal(index: number) { |
138 | - (this.kvListFormGroup.get('keyVals') as FormArray).removeAt(index); | 145 | + this.attributesValueFormArray().removeAt(index); |
139 | } | 146 | } |
140 | 147 | ||
141 | public addKeyVal() { | 148 | public addKeyVal() { |
142 | - const keyValsFormArray = this.kvListFormGroup.get('keyVals') as FormArray; | ||
143 | - keyValsFormArray.push(this.fb.group({ | ||
144 | - key: ['', [Validators.required, this.attributeLwm2mKeyValidator]], | ||
145 | - value: ['', []] | ||
146 | - })); | ||
147 | - } | ||
148 | - | ||
149 | - public validate(c?: FormControl) { | ||
150 | - const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value; | ||
151 | - let valid = true; | ||
152 | - for (const entry of kvList) { | ||
153 | - if (isUndefinedOrNull(entry.key) || isEmptyStr(entry.key) || !ATTRIBUTE_KEYS.includes(entry.key)) { | ||
154 | - valid = false; | ||
155 | - break; | ||
156 | - } | ||
157 | - if (entry.key !== 'ver' && isNaN(Number(entry.value))) { | ||
158 | - valid = false; | ||
159 | - break; | ||
160 | - } | 149 | + this.attributesValueFormArray().push(this.createdFormGroup()); |
150 | + this.attributesValueFormGroup.updateValueAndValidity({emitEvent: false}); | ||
151 | + if (this.attributesValueFormGroup.invalid) { | ||
152 | + this.updateModel(); | ||
161 | } | 153 | } |
162 | - return (valid) ? null : { | ||
163 | - keyVals: { | ||
164 | - valid: false, | ||
165 | - }, | ||
166 | - }; | ||
167 | } | 154 | } |
168 | 155 | ||
169 | - private updateValidate() { | ||
170 | - const kvList = this.kvListFormGroup.get('keyVals') as FormArray; | ||
171 | - kvList.controls.forEach(fg => { | ||
172 | - if (fg.get('key').value === 'ver') { | ||
173 | - fg.get('value').setValidators(null); | ||
174 | - fg.get('value').setErrors(null); | ||
175 | - } | ||
176 | - else { | ||
177 | - fg.get('value').setValidators(this.attributeLwm2mValueNumberValidator); | ||
178 | - fg.get('value').setErrors(this.attributeLwm2mValueNumberValidator(fg.get('value'))); | ||
179 | - } | 156 | + private createdFormGroup(value?: AttributesNameValue): FormGroup { |
157 | + if (isUndefinedOrNull(value)) { | ||
158 | + value = { | ||
159 | + name: this.getFirstUnusedAttributesName(), | ||
160 | + value: null | ||
161 | + }; | ||
162 | + } | ||
163 | + const form = this.fb.group({ | ||
164 | + name: [value.name, Validators.required], | ||
165 | + value: [value.value, valueValidatorByAttributeName(value.name)] | ||
180 | }); | 166 | }); |
167 | + form.get('name').valueChanges.pipe( | ||
168 | + takeUntil(this.destroy$) | ||
169 | + ).subscribe(name => { | ||
170 | + form.get('value').setValidators(valueValidatorByAttributeName(name)); | ||
171 | + form.get('value').updateValueAndValidity(); | ||
172 | + }); | ||
173 | + return form; | ||
174 | + } | ||
175 | + | ||
176 | + public validate() { | ||
177 | + return this.attributesValueFormGroup.valid ? null : { | ||
178 | + attributesValue: { | ||
179 | + valid: false | ||
180 | + } | ||
181 | + }; | ||
181 | } | 182 | } |
182 | 183 | ||
183 | private updateModel() { | 184 | private updateModel() { |
184 | - this.updateValidate(); | ||
185 | - if (this.validate() === null) { | ||
186 | - const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value; | ||
187 | - const keyValMap: { [key: string]: string | number } = {}; | ||
188 | - kvList.forEach((entry) => { | ||
189 | - if (isUndefinedOrNull(entry.value) || entry.key === 'ver' || isEmptyStr(entry.value.toString())) { | ||
190 | - keyValMap[entry.key] = entry.value.toString(); | ||
191 | - } else { | ||
192 | - keyValMap[entry.key] = Number(entry.value); | ||
193 | - } | ||
194 | - }); | ||
195 | - this.propagateChange(keyValMap); | ||
196 | - } | ||
197 | - else { | ||
198 | - this.propagateChange(null); | ||
199 | - } | 185 | + const value: AttributesNameValue[] = this.attributesValueFormGroup.get('attributesValue').value; |
186 | + const attributesNameValueMap: AttributesNameValueMap = {}; | ||
187 | + value.forEach(attribute => { | ||
188 | + attributesNameValueMap[attribute.name] = attribute.value; | ||
189 | + }); | ||
190 | + this.updateUsedAttributesName(); | ||
191 | + this.propagateChange(attributesNameValueMap); | ||
200 | } | 192 | } |
201 | 193 | ||
194 | + public isDisabledAttributeName(type: AttributeName, index: number): boolean { | ||
195 | + const usedIndex = this.usedAttributesName.indexOf(type); | ||
196 | + return usedIndex > -1 && usedIndex !== index; | ||
197 | + } | ||
202 | 198 | ||
203 | - private attributeLwm2mKeyValidator = (control: AbstractControl) => { | ||
204 | - const key = control.value as string; | ||
205 | - if (isDefinedAndNotNull(key) && !isEmpty(key)) { | ||
206 | - if (!ATTRIBUTE_KEYS.includes(key)) { | ||
207 | - return { | ||
208 | - validAttributeKey: true | ||
209 | - }; | 199 | + private getFirstUnusedAttributesName(): AttributeName { |
200 | + for (const attributeName of this.attributeNames) { | ||
201 | + if (this.usedAttributesName.indexOf(attributeName) === -1) { | ||
202 | + return attributeName; | ||
210 | } | 203 | } |
211 | } | 204 | } |
212 | return null; | 205 | return null; |
213 | } | 206 | } |
214 | 207 | ||
215 | - private attributeLwm2mValueNumberValidator = (control: AbstractControl) => { | ||
216 | - if (isNaN(Number(control.value)) || Number(control.value) < 0) { | ||
217 | - return { | ||
218 | - validAttributeValue: true | ||
219 | - }; | ||
220 | - } | ||
221 | - return null; | 208 | + private updateUsedAttributesName() { |
209 | + this.usedAttributesName = []; | ||
210 | + const value: AttributesNameValue[] = this.attributesValueFormGroup.get('attributesValue').value; | ||
211 | + value.forEach((attributesValue, index) => { | ||
212 | + this.usedAttributesName[index] = attributesValue.name; | ||
213 | + }); | ||
222 | } | 214 | } |
223 | 215 | ||
224 | - private attributeLwm2mValueValidator = (property: string): object[] => { | ||
225 | - return property === 'ver' ? [] : [this.attributeLwm2mValueNumberValidator]; | 216 | + get isAddEnabled(): boolean { |
217 | + return this.attributesValueFormArray().length !== this.attributeNames.length; | ||
226 | } | 218 | } |
227 | } | 219 | } |
@@ -15,18 +15,14 @@ | @@ -15,18 +15,14 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div fxLayout="row" [formGroup]="attributeLwm2mFormGroup"> | ||
19 | - <div fxFlex fxLayout="column" class="resource-name-lw-end" fxLayoutAlign="center" | ||
20 | - [matTooltip]="isToolTipLabel()" matTooltipPosition="above"> | ||
21 | - {{attributeLwm2mToString()}} | ||
22 | - </div> | 18 | +<div fxLayout="row" [fxHide]="disabled && isEmpty()" fxLayoutAlign="end center" matTooltip="{{ tooltipSetAttributesTelemetry | translate }}" matTooltipPosition="above"> |
23 | <button type="button" | 19 | <button type="button" |
24 | [disabled]="isDisableBtn()" | 20 | [disabled]="isDisableBtn()" |
25 | mat-button mat-icon-button | 21 | mat-button mat-icon-button |
26 | (click)="editAttributesLwm2m($event)" | 22 | (click)="editAttributesLwm2m($event)" |
27 | - [matTooltip]="(isIconView() ? 'action.view' : isIconEditAdd() ? 'action.edit' : 'action.add' ) | translate" | 23 | + matTooltip="{{ tooltipButton | translate }}" |
28 | matTooltipPosition="above"> | 24 | matTooltipPosition="above"> |
29 | <mat-icon | 25 | <mat-icon |
30 | - class="material-icons">{{isIconView() ? 'visibility' : isIconEditAdd() ? 'edit' : 'add' }}</mat-icon> | 26 | + class="material-icons">{{ iconButton }}</mat-icon> |
31 | </button> | 27 | </button> |
32 | </div> | 28 | </div> |
@@ -14,48 +14,20 @@ | @@ -14,48 +14,20 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | :host { | 16 | :host { |
17 | - .tb-kv-map { | ||
18 | - span.no-data-found { | ||
19 | - position: relative; | ||
20 | - display: flex; | ||
21 | - height: 40px; | ||
22 | - | ||
23 | - &.disabled { | ||
24 | - color: rgba(0, 0, 0, .38); | ||
25 | - } | ||
26 | - } | 17 | + .resource-name-lw-end{ |
18 | + white-space: nowrap; | ||
19 | + overflow: hidden; | ||
20 | + text-overflow: ellipsis; | ||
21 | + text-align:end; | ||
22 | + //width: 80px; | ||
23 | + cursor: pointer; | ||
27 | } | 24 | } |
28 | -} | ||
29 | 25 | ||
30 | -:host ::ng-deep { | ||
31 | - .mat-form-field-wrapper { | ||
32 | - padding-bottom: 0; | ||
33 | - } | ||
34 | - .mat-form-field-infix { | ||
35 | - border-top: 0; | 26 | + .resource-name-lw{ |
27 | + white-space: nowrap; | ||
28 | + overflow: hidden; | ||
29 | + text-overflow: ellipsis; | ||
30 | + cursor: pointer; | ||
36 | } | 31 | } |
37 | - .mat-form-field-underline { | ||
38 | - bottom: 0; | ||
39 | - } | ||
40 | -} | ||
41 | - | ||
42 | -.vertical-padding { | ||
43 | - padding: 0 0 10px 20px; | ||
44 | -} | ||
45 | - | ||
46 | -.resource-name-lw-end{ | ||
47 | - white-space: nowrap; | ||
48 | - overflow: hidden; | ||
49 | - text-overflow: ellipsis; | ||
50 | - text-align:end; | ||
51 | - //width: 80px; | ||
52 | - cursor: pointer; | ||
53 | -} | ||
54 | - | ||
55 | -.resource-name-lw{ | ||
56 | - white-space: nowrap; | ||
57 | - overflow: hidden; | ||
58 | - text-overflow: ellipsis; | ||
59 | - cursor: pointer; | ||
60 | } | 32 | } |
61 | 33 |
@@ -17,11 +17,10 @@ | @@ -17,11 +17,10 @@ | ||
17 | import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; | 17 | import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; |
18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; | 18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; |
19 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 19 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
20 | -import { deepClone, isDefinedAndNotNull, isEmpty } from '@core/utils'; | 20 | +import { isEmpty, isUndefinedOrNull } from '@core/utils'; |
21 | import { Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData } from './lwm2m-attributes-dialog.component'; | 21 | import { Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData } from './lwm2m-attributes-dialog.component'; |
22 | import { MatDialog } from '@angular/material/dialog'; | 22 | import { MatDialog } from '@angular/material/dialog'; |
23 | -import { TranslateService } from '@ngx-translate/core'; | ||
24 | -import { ATTRIBUTE_LWM2M_LABEL } from './lwm2m-profile-config.models'; | 23 | +import { AttributesNameValueMap } from './lwm2m-profile-config.models'; |
25 | 24 | ||
26 | 25 | ||
27 | @Component({ | 26 | @Component({ |
@@ -36,22 +35,21 @@ import { ATTRIBUTE_LWM2M_LABEL } from './lwm2m-profile-config.models'; | @@ -36,22 +35,21 @@ import { ATTRIBUTE_LWM2M_LABEL } from './lwm2m-profile-config.models'; | ||
36 | }) | 35 | }) |
37 | export class Lwm2mAttributesComponent implements ControlValueAccessor { | 36 | export class Lwm2mAttributesComponent implements ControlValueAccessor { |
38 | attributeLwm2mFormGroup: FormGroup; | 37 | attributeLwm2mFormGroup: FormGroup; |
39 | - attributeLwm2mLabel = ATTRIBUTE_LWM2M_LABEL; | ||
40 | 38 | ||
41 | private requiredValue: boolean; | 39 | private requiredValue: boolean; |
42 | 40 | ||
43 | @Input() | 41 | @Input() |
44 | - attributeLwm2m: {}; | ||
45 | - | ||
46 | - @Input() | ||
47 | isAttributeTelemetry: boolean; | 42 | isAttributeTelemetry: boolean; |
48 | 43 | ||
49 | @Input() | 44 | @Input() |
50 | - destName: string; | 45 | + modelName: string; |
51 | 46 | ||
52 | @Input() | 47 | @Input() |
53 | disabled: boolean; | 48 | disabled: boolean; |
54 | 49 | ||
50 | + @Input() | ||
51 | + isResource = false; | ||
52 | + | ||
55 | @Output() | 53 | @Output() |
56 | updateAttributeLwm2m = new EventEmitter<any>(); | 54 | updateAttributeLwm2m = new EventEmitter<any>(); |
57 | 55 | ||
@@ -64,8 +62,7 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor { | @@ -64,8 +62,7 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor { | ||
64 | } | 62 | } |
65 | 63 | ||
66 | constructor(private dialog: MatDialog, | 64 | constructor(private dialog: MatDialog, |
67 | - private fb: FormBuilder, | ||
68 | - private translate: TranslateService) {} | 65 | + private fb: FormBuilder) {} |
69 | 66 | ||
70 | registerOnChange(fn: any): void { | 67 | registerOnChange(fn: any): void { |
71 | this.propagateChange = fn; | 68 | this.propagateChange = fn; |
@@ -85,63 +82,66 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor { | @@ -85,63 +82,66 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor { | ||
85 | 82 | ||
86 | ngOnInit() { | 83 | ngOnInit() { |
87 | this.attributeLwm2mFormGroup = this.fb.group({ | 84 | this.attributeLwm2mFormGroup = this.fb.group({ |
88 | - attributeLwm2m: [this.attributeLwm2m] | 85 | + attributes: [{}] |
89 | }); | 86 | }); |
90 | } | 87 | } |
91 | 88 | ||
92 | - writeValue(value: {} | null): void {} | ||
93 | - | ||
94 | - attributeLwm2mToString = (): string => { | ||
95 | - return this.isIconEditAdd () ? this.attributeLwm2mLabelToString() : this.translate.instant('device-profile.lwm2m.no-data'); | 89 | + writeValue(value: AttributesNameValueMap | null) { |
90 | + this.attributeLwm2mFormGroup.patchValue({attributes: value}, {emitEvent: false}); | ||
96 | } | 91 | } |
97 | 92 | ||
98 | - private attributeLwm2mLabelToString = (): string => { | ||
99 | - let label = JSON.stringify(this.attributeLwm2m); | ||
100 | - label = deepClone(label.replace('{', '')); | ||
101 | - label = deepClone(label.replace('}', '')); | ||
102 | - this.attributeLwm2mLabel.forEach((value: string, key: string) => { | ||
103 | - const dest = '\"' + key + '\"\:'; | ||
104 | - label = deepClone(label.replace(dest, value)); | ||
105 | - }); | ||
106 | - return label; | 93 | + get attributesValueMap(): AttributesNameValueMap { |
94 | + return this.attributeLwm2mFormGroup.get('attributes').value; | ||
107 | } | 95 | } |
108 | 96 | ||
109 | isDisableBtn(): boolean { | 97 | isDisableBtn(): boolean { |
110 | - return this.disabled || this.isAttributeTelemetry ? !(isDefinedAndNotNull(this.attributeLwm2m) && | ||
111 | - !isEmpty(this.attributeLwm2m) && this.disabled) : this.disabled; | 98 | + return !this.disabled && this.isAttributeTelemetry; |
112 | } | 99 | } |
113 | 100 | ||
114 | - isIconView(): boolean { | ||
115 | - return this.isAttributeTelemetry || this.disabled; | 101 | + isEmpty(): boolean { |
102 | + const value = this.attributesValueMap; | ||
103 | + return isUndefinedOrNull(value) || isEmpty(value); | ||
116 | } | 104 | } |
117 | 105 | ||
118 | - isIconEditAdd(): boolean { | ||
119 | - return isDefinedAndNotNull(this.attributeLwm2m) && !isEmpty(this.attributeLwm2m); | 106 | + get tooltipSetAttributesTelemetry(): string { |
107 | + return this.isDisableBtn() ? 'device-profile.lwm2m.edit-attributes-select' : ''; | ||
120 | } | 108 | } |
121 | 109 | ||
122 | - isToolTipLabel(): string { | ||
123 | - return this.disabled ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip') : | ||
124 | - this.isAttributeTelemetry ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-disable-tip') : | ||
125 | - this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip'); | 110 | + get tooltipButton(): string { |
111 | + if (this.disabled) { | ||
112 | + return 'device-profile.lwm2m.view-attribute'; | ||
113 | + } else if (this.isEmpty()) { | ||
114 | + return 'device-profile.lwm2m.add-attribute'; | ||
115 | + } | ||
116 | + return 'device-profile.lwm2m.edit-attribute'; | ||
117 | + } | ||
118 | + | ||
119 | + get iconButton(): string { | ||
120 | + if (this.disabled) { | ||
121 | + return 'visibility'; | ||
122 | + } else if (this.isEmpty()) { | ||
123 | + return 'add'; | ||
124 | + } | ||
125 | + return 'edit'; | ||
126 | } | 126 | } |
127 | 127 | ||
128 | public editAttributesLwm2m = ($event: Event): void => { | 128 | public editAttributesLwm2m = ($event: Event): void => { |
129 | if ($event) { | 129 | if ($event) { |
130 | $event.stopPropagation(); | 130 | $event.stopPropagation(); |
131 | } | 131 | } |
132 | - this.dialog.open<Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData, object>(Lwm2mAttributesDialogComponent, { | 132 | + this.dialog.open<Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData, AttributesNameValueMap>(Lwm2mAttributesDialogComponent, { |
133 | disableClose: true, | 133 | disableClose: true, |
134 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | 134 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
135 | data: { | 135 | data: { |
136 | readonly: this.disabled, | 136 | readonly: this.disabled, |
137 | - attributeLwm2m: this.disabled ? this.attributeLwm2m : deepClone(this.attributeLwm2m), | ||
138 | - destName: this.destName | 137 | + attributes: this.attributesValueMap, |
138 | + modelName: this.modelName, | ||
139 | + isResource: this.isResource | ||
139 | } | 140 | } |
140 | }).afterClosed().subscribe((result) => { | 141 | }).afterClosed().subscribe((result) => { |
141 | if (result) { | 142 | if (result) { |
142 | - this.attributeLwm2m = result; | ||
143 | - this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: this.attributeLwm2m}); | ||
144 | - this.updateAttributeLwm2m.next(this.attributeLwm2m); | 143 | + this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: result}); |
144 | + this.updateAttributeLwm2m.next(result); | ||
145 | } | 145 | } |
146 | }); | 146 | }); |
147 | } | 147 | } |
@@ -35,19 +35,33 @@ | @@ -35,19 +35,33 @@ | ||
35 | </mat-form-field> | 35 | </mat-form-field> |
36 | <mat-form-field fxFlex> | 36 | <mat-form-field fxFlex> |
37 | <mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label> | 37 | <mat-label>{{ 'device-profile.lwm2m.server-port' | translate }}</mat-label> |
38 | - <input matInput type="number" formControlName="port" required min="0"> | 38 | + <input matInput type="number" formControlName="port" required min="0" max="65535"> |
39 | <mat-error *ngIf="serverFormGroup.get('port').hasError('required')"> | 39 | <mat-error *ngIf="serverFormGroup.get('port').hasError('required')"> |
40 | {{ 'device-profile.lwm2m.server-port-required' | translate }} | 40 | {{ 'device-profile.lwm2m.server-port-required' | translate }} |
41 | </mat-error> | 41 | </mat-error> |
42 | + <mat-error *ngIf="serverFormGroup.get('port').hasError('pattern')"> | ||
43 | + {{ 'device-profile.lwm2m.server-port-pattern' | translate }} | ||
44 | + </mat-error> | ||
45 | + <mat-error *ngIf="serverFormGroup.get('port').hasError('min') || | ||
46 | + serverFormGroup.get('port').hasError('max')"> | ||
47 | + {{ 'device-profile.lwm2m.server-port-range' | translate }} | ||
48 | + </mat-error> | ||
42 | </mat-form-field> | 49 | </mat-form-field> |
43 | </div> | 50 | </div> |
44 | <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px"> | 51 | <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px"> |
45 | <mat-form-field fxFlex> | 52 | <mat-form-field fxFlex> |
46 | <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> | 53 | <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> |
47 | - <input matInput type="number" formControlName="serverId" required min="0"> | 54 | + <input matInput type="number" min="1" max="65534" formControlName="serverId" required> |
48 | <mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')"> | 55 | <mat-error *ngIf="serverFormGroup.get('serverId').hasError('required')"> |
49 | {{ 'device-profile.lwm2m.short-id-required' | translate }} | 56 | {{ 'device-profile.lwm2m.short-id-required' | translate }} |
50 | </mat-error> | 57 | </mat-error> |
58 | + <mat-error *ngIf="serverFormGroup.get('serverId').hasError('pattern')"> | ||
59 | + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} | ||
60 | + </mat-error> | ||
61 | + <mat-error *ngIf="serverFormGroup.get('serverId').hasError('min') || | ||
62 | + serverFormGroup.get('serverId').hasError('max')"> | ||
63 | + {{ 'device-profile.lwm2m.short-id-range' | translate }} | ||
64 | + </mat-error> | ||
51 | </mat-form-field> | 65 | </mat-form-field> |
52 | <mat-form-field fxFlex> | 66 | <mat-form-field fxFlex> |
53 | <mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label> | 67 | <mat-label>{{ 'device-profile.lwm2m.client-hold-off-time' | translate }}</mat-label> |
@@ -57,6 +71,10 @@ | @@ -57,6 +71,10 @@ | ||
57 | <mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')"> | 71 | <mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('required')"> |
58 | {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }} | 72 | {{ 'device-profile.lwm2m.client-hold-off-time-required' | translate }} |
59 | </mat-error> | 73 | </mat-error> |
74 | + <mat-error *ngIf="serverFormGroup.get('clientHoldOffTime').hasError('min') || | ||
75 | + serverFormGroup.get('clientHoldOffTime').hasError('pattern')"> | ||
76 | + {{ 'device-profile.lwm2m.client-hold-off-time-pattern' | translate }} | ||
77 | + </mat-error> | ||
60 | </mat-form-field> | 78 | </mat-form-field> |
61 | <mat-form-field fxFlex> | 79 | <mat-form-field fxFlex> |
62 | <mat-label>{{ 'device-profile.lwm2m.account-after-timeout' | translate }}</mat-label> | 80 | <mat-label>{{ 'device-profile.lwm2m.account-after-timeout' | translate }}</mat-label> |
@@ -66,6 +84,10 @@ | @@ -66,6 +84,10 @@ | ||
66 | <mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')"> | 84 | <mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('required')"> |
67 | {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }} | 85 | {{ 'device-profile.lwm2m.account-after-timeout-required' | translate }} |
68 | </mat-error> | 86 | </mat-error> |
87 | + <mat-error *ngIf="serverFormGroup.get('bootstrapServerAccountTimeout').hasError('min') || | ||
88 | + serverFormGroup.get('bootstrapServerAccountTimeout').hasError('pattern')"> | ||
89 | + {{ 'device-profile.lwm2m.account-after-timeout-pattern' | translate }} | ||
90 | + </mat-error> | ||
69 | </mat-form-field> | 91 | </mat-form-field> |
70 | </div> | 92 | </div> |
71 | <div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK || | 93 | <div *ngIf="serverFormGroup.get('securityMode').value === securityConfigLwM2MType.RPK || |
@@ -15,7 +15,16 @@ | @@ -15,7 +15,16 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; | 17 | import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; |
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | 18 | +import { |
19 | + ControlValueAccessor, | ||
20 | + FormBuilder, | ||
21 | + FormGroup, | ||
22 | + NG_VALIDATORS, | ||
23 | + NG_VALUE_ACCESSOR, | ||
24 | + ValidationErrors, | ||
25 | + Validator, | ||
26 | + Validators | ||
27 | +} from '@angular/forms'; | ||
19 | import { | 28 | import { |
20 | DEFAULT_PORT_BOOTSTRAP_NO_SEC, | 29 | DEFAULT_PORT_BOOTSTRAP_NO_SEC, |
21 | DEFAULT_PORT_SERVER_NO_SEC, | 30 | DEFAULT_PORT_SERVER_NO_SEC, |
@@ -27,10 +36,9 @@ import { | @@ -27,10 +36,9 @@ import { | ||
27 | ServerSecurityConfig | 36 | ServerSecurityConfig |
28 | } from './lwm2m-profile-config.models'; | 37 | } from './lwm2m-profile-config.models'; |
29 | import { DeviceProfileService } from '@core/http/device-profile.service'; | 38 | import { DeviceProfileService } from '@core/http/device-profile.service'; |
30 | -import { of, Subject } from 'rxjs'; | ||
31 | -import { map, mergeMap, takeUntil, tap } from 'rxjs/operators'; | 39 | +import { Subject } from 'rxjs'; |
40 | +import { mergeMap, takeUntil, tap } from 'rxjs/operators'; | ||
32 | import { Observable } from 'rxjs/internal/Observable'; | 41 | import { Observable } from 'rxjs/internal/Observable'; |
33 | -import { deepClone } from '@core/utils'; | ||
34 | 42 | ||
35 | @Component({ | 43 | @Component({ |
36 | selector: 'tb-profile-lwm2m-device-config-server', | 44 | selector: 'tb-profile-lwm2m-device-config-server', |
@@ -40,16 +48,21 @@ import { deepClone } from '@core/utils'; | @@ -40,16 +48,21 @@ import { deepClone } from '@core/utils'; | ||
40 | provide: NG_VALUE_ACCESSOR, | 48 | provide: NG_VALUE_ACCESSOR, |
41 | useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent), | 49 | useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent), |
42 | multi: true | 50 | multi: true |
43 | - } | 51 | + }, |
52 | + { | ||
53 | + provide: NG_VALIDATORS, | ||
54 | + useExisting: forwardRef(() => Lwm2mDeviceConfigServerComponent), | ||
55 | + multi: true | ||
56 | + }, | ||
44 | ] | 57 | ] |
45 | }) | 58 | }) |
46 | 59 | ||
47 | -export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, OnDestroy { | 60 | +export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAccessor, Validator, OnDestroy { |
48 | 61 | ||
49 | private disabled = false; | 62 | private disabled = false; |
50 | private destroy$ = new Subject(); | 63 | private destroy$ = new Subject(); |
51 | 64 | ||
52 | - private securityDefaultConfig: ServerSecurityConfig; | 65 | + private isDataLoadedIntoCache = false; |
53 | 66 | ||
54 | serverFormGroup: FormGroup; | 67 | serverFormGroup: FormGroup; |
55 | securityConfigLwM2MType = securityConfigMode; | 68 | securityConfigLwM2MType = securityConfigMode; |
@@ -70,12 +83,13 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | @@ -70,12 +83,13 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | ||
70 | ngOnInit(): void { | 83 | ngOnInit(): void { |
71 | this.serverFormGroup = this.fb.group({ | 84 | this.serverFormGroup = this.fb.group({ |
72 | host: ['', Validators.required], | 85 | host: ['', Validators.required], |
73 | - port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, [Validators.required, Validators.min(0)]], | 86 | + port: [this.isBootstrapServer ? DEFAULT_PORT_BOOTSTRAP_NO_SEC : DEFAULT_PORT_SERVER_NO_SEC, |
87 | + [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]], | ||
74 | securityMode: [securityConfigMode.NO_SEC], | 88 | securityMode: [securityConfigMode.NO_SEC], |
75 | - serverPublicKey: ['', Validators.required], | ||
76 | - clientHoldOffTime: ['', [Validators.required, Validators.min(0)]], | ||
77 | - serverId: ['', [Validators.required, Validators.min(0)]], | ||
78 | - bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0)]], | 89 | + serverPublicKey: [''], |
90 | + clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | ||
91 | + serverId: ['', [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], | ||
92 | + bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | ||
79 | }); | 93 | }); |
80 | this.serverFormGroup.get('securityMode').valueChanges.pipe( | 94 | this.serverFormGroup.get('securityMode').valueChanges.pipe( |
81 | tap(securityMode => this.updateValidate(securityMode)), | 95 | tap(securityMode => this.updateValidate(securityMode)), |
@@ -101,7 +115,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | @@ -101,7 +115,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | ||
101 | this.serverFormGroup.patchValue(serverData, {emitEvent: false}); | 115 | this.serverFormGroup.patchValue(serverData, {emitEvent: false}); |
102 | this.updateValidate(serverData.securityMode); | 116 | this.updateValidate(serverData.securityMode); |
103 | } | 117 | } |
104 | - if (!this.securityDefaultConfig){ | 118 | + if (!this.isDataLoadedIntoCache){ |
105 | this.getLwm2mBootstrapSecurityInfo().subscribe(value => { | 119 | this.getLwm2mBootstrapSecurityInfo().subscribe(value => { |
106 | if (!serverData) { | 120 | if (!serverData) { |
107 | this.serverFormGroup.patchValue(value); | 121 | this.serverFormGroup.patchValue(value); |
@@ -159,43 +173,19 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | @@ -159,43 +173,19 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc | ||
159 | 173 | ||
160 | private propagateChangeState = (value: ServerSecurityConfig): void => { | 174 | private propagateChangeState = (value: ServerSecurityConfig): void => { |
161 | if (value !== undefined) { | 175 | if (value !== undefined) { |
162 | - if (this.serverFormGroup.valid) { | ||
163 | - this.propagateChange(value); | ||
164 | - } else { | ||
165 | - this.propagateChange(null); | ||
166 | - } | 176 | + this.propagateChange(value); |
167 | } | 177 | } |
168 | } | 178 | } |
169 | 179 | ||
170 | private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable<ServerSecurityConfig> { | 180 | private getLwm2mBootstrapSecurityInfo(securityMode = securityConfigMode.NO_SEC): Observable<ServerSecurityConfig> { |
171 | - if (this.securityDefaultConfig) { | ||
172 | - return of(this.processingBootstrapSecurityInfo(this.securityDefaultConfig, securityMode)); | ||
173 | - } | ||
174 | - return this.deviceProfileService.getLwm2mBootstrapSecurityInfo(this.isBootstrapServer).pipe( | ||
175 | - map(securityInfo => { | ||
176 | - this.securityDefaultConfig = securityInfo; | ||
177 | - return this.processingBootstrapSecurityInfo(securityInfo, securityMode); | ||
178 | - }) | 181 | + return this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(this.isBootstrapServer, securityMode).pipe( |
182 | + tap(() => this.isDataLoadedIntoCache = true) | ||
179 | ); | 183 | ); |
180 | } | 184 | } |
181 | 185 | ||
182 | - private processingBootstrapSecurityInfo(securityConfig: ServerSecurityConfig, securityMode: securityConfigMode): ServerSecurityConfig { | ||
183 | - const config = deepClone(securityConfig); | ||
184 | - switch (securityMode) { | ||
185 | - case securityConfigMode.PSK: | ||
186 | - config.port = config.securityPort; | ||
187 | - config.host = config.securityHost; | ||
188 | - config.serverPublicKey = ''; | ||
189 | - break; | ||
190 | - case securityConfigMode.RPK: | ||
191 | - case securityConfigMode.X509: | ||
192 | - config.port = config.securityPort; | ||
193 | - config.host = config.securityHost; | ||
194 | - break; | ||
195 | - case securityConfigMode.NO_SEC: | ||
196 | - config.serverPublicKey = ''; | ||
197 | - break; | ||
198 | - } | ||
199 | - return config; | 186 | + validate(): ValidationErrors | null { |
187 | + return this.serverFormGroup.valid ? null : { | ||
188 | + serverFormGroup: true | ||
189 | + }; | ||
200 | } | 190 | } |
201 | } | 191 | } |
@@ -34,53 +34,62 @@ | @@ -34,53 +34,62 @@ | ||
34 | </ng-template> | 34 | </ng-template> |
35 | </mat-tab> | 35 | </mat-tab> |
36 | <mat-tab label="{{ 'device-profile.lwm2m.servers' | translate }}"> | 36 | <mat-tab label="{{ 'device-profile.lwm2m.servers' | translate }}"> |
37 | - <ng-template matTabContent> | ||
38 | - <section [formGroup]="lwm2mDeviceProfileFormGroup" style="padding: 4px 2px"> | 37 | + <section [formGroup]="lwm2mDeviceProfileFormGroup"> |
38 | + <section formGroupName="bootstrap" style="padding: 4px 2px"> | ||
39 | <mat-accordion multi="true"> | 39 | <mat-accordion multi="true"> |
40 | <mat-expansion-panel> | 40 | <mat-expansion-panel> |
41 | <mat-expansion-panel-header> | 41 | <mat-expansion-panel-header> |
42 | <mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title> | 42 | <mat-panel-title>{{ 'device-profile.lwm2m.servers' | translate }}</mat-panel-title> |
43 | </mat-expansion-panel-header> | 43 | </mat-expansion-panel-header> |
44 | - <ng-template matExpansionPanelContent> | 44 | + <ng-template matExpansionPanelContent formGroupName="servers"> |
45 | <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px"> | 45 | <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxLayoutGap.xs="0px"> |
46 | <mat-form-field fxFlex> | 46 | <mat-form-field fxFlex> |
47 | <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> | 47 | <mat-label>{{ 'device-profile.lwm2m.short-id' | translate }}</mat-label> |
48 | - <input matInput type="number" formControlName="shortId" required> | ||
49 | - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('shortId').hasError('required')"> | ||
50 | - {{ 'device-profile.lwm2m.short-id' | translate }} | ||
51 | - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | 48 | + <input matInput type="number" min="1" max="65534" formControlName="shortId" required> |
49 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('required')"> | ||
50 | + {{ 'device-profile.lwm2m.short-id-required' | translate }} | ||
51 | + </mat-error> | ||
52 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('min') || | ||
53 | + lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('max')"> | ||
54 | + {{ 'device-profile.lwm2m.short-id-range' | translate }} | ||
55 | + </mat-error> | ||
56 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.shortId').hasError('pattern')"> | ||
57 | + {{ 'device-profile.lwm2m.short-id-pattern' | translate }} | ||
52 | </mat-error> | 58 | </mat-error> |
53 | </mat-form-field> | 59 | </mat-form-field> |
54 | <mat-form-field fxFlex> | 60 | <mat-form-field fxFlex> |
55 | <mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label> | 61 | <mat-label>{{ 'device-profile.lwm2m.lifetime' | translate }}</mat-label> |
56 | - <input matInput type="number" formControlName="lifetime" required> | ||
57 | - <mat-error | ||
58 | - *ngIf="lwm2mDeviceProfileFormGroup.get('lifetime').hasError('required')"> | ||
59 | - {{ 'device-profile.lwm2m.lifetime' | translate }} | ||
60 | - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | 62 | + <input matInput type="number" min="0" formControlName="lifetime" required> |
63 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('required')"> | ||
64 | + {{ 'device-profile.lwm2m.lifetime-required' | translate }} | ||
65 | + </mat-error> | ||
66 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('pattern') || | ||
67 | + lwm2mDeviceProfileFormGroup.get('bootstrap.servers.lifetime').hasError('min')"> | ||
68 | + {{ 'device-profile.lwm2m.lifetime-pattern' | translate }} | ||
61 | </mat-error> | 69 | </mat-error> |
62 | </mat-form-field> | 70 | </mat-form-field> |
63 | <mat-form-field fxFlex> | 71 | <mat-form-field fxFlex> |
64 | <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label> | 72 | <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label> |
65 | - <input matInput type="number" formControlName="defaultMinPeriod" required> | ||
66 | - <mat-error | ||
67 | - *ngIf="lwm2mDeviceProfileFormGroup.get('defaultMinPeriod').hasError('required')"> | ||
68 | - {{ 'device-profile.lwm2m.default-min-period' | translate }} | ||
69 | - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | 73 | + <input matInput type="number" min="0" formControlName="defaultMinPeriod" required> |
74 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('required')"> | ||
75 | + {{ 'device-profile.lwm2m.default-min-period-required' | translate }} | ||
76 | + </mat-error> | ||
77 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('pattern') || | ||
78 | + lwm2mDeviceProfileFormGroup.get('bootstrap.servers.defaultMinPeriod').hasError('min')"> | ||
79 | + {{ 'device-profile.lwm2m.default-min-period-pattern' | translate }} | ||
70 | </mat-error> | 80 | </mat-error> |
71 | </mat-form-field> | 81 | </mat-form-field> |
72 | </div> | 82 | </div> |
73 | <mat-form-field class="mat-block"> | 83 | <mat-form-field class="mat-block"> |
74 | <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label> | 84 | <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label> |
75 | <mat-select formControlName="binding"> | 85 | <mat-select formControlName="binding"> |
76 | - <mat-option *ngFor="let bindingMode of bindingModeTypes" | ||
77 | - [value]="bindingMode"> | ||
78 | - {{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }} | 86 | + <mat-option *ngFor="let bindingMode of bindingModeTypes" [value]="bindingMode"> |
87 | + {{ bindingModeTypeNamesMap.get(bindingMode) | translate }} | ||
79 | </mat-option> | 88 | </mat-option> |
80 | </mat-select> | 89 | </mat-select> |
81 | </mat-form-field> | 90 | </mat-form-field> |
82 | <mat-checkbox formControlName="notifIfDisabled" color="primary"> | 91 | <mat-checkbox formControlName="notifIfDisabled" color="primary"> |
83 | - {{ 'device-profile.lwm2m.notif-if-disabled' | translate }} | 92 | + {{ 'device-profile.lwm2m.notification-storing' | translate }} |
84 | </mat-checkbox> | 93 | </mat-checkbox> |
85 | </ng-template> | 94 | </ng-template> |
86 | </mat-expansion-panel> | 95 | </mat-expansion-panel> |
@@ -90,7 +99,6 @@ | @@ -90,7 +99,6 @@ | ||
90 | </mat-expansion-panel-header> | 99 | </mat-expansion-panel-header> |
91 | <ng-template matExpansionPanelContent> | 100 | <ng-template matExpansionPanelContent> |
92 | <tb-profile-lwm2m-device-config-server | 101 | <tb-profile-lwm2m-device-config-server |
93 | - [required]="required" | ||
94 | formControlName="bootstrapServer" | 102 | formControlName="bootstrapServer" |
95 | [isBootstrapServer]="true"> | 103 | [isBootstrapServer]="true"> |
96 | </tb-profile-lwm2m-device-config-server> | 104 | </tb-profile-lwm2m-device-config-server> |
@@ -102,7 +110,6 @@ | @@ -102,7 +110,6 @@ | ||
102 | </mat-expansion-panel-header> | 110 | </mat-expansion-panel-header> |
103 | <ng-template matExpansionPanelContent> | 111 | <ng-template matExpansionPanelContent> |
104 | <tb-profile-lwm2m-device-config-server | 112 | <tb-profile-lwm2m-device-config-server |
105 | - [required]="required" | ||
106 | formControlName="lwm2mServer" | 113 | formControlName="lwm2mServer" |
107 | [isBootstrapServer]="false"> | 114 | [isBootstrapServer]="false"> |
108 | </tb-profile-lwm2m-device-config-server> | 115 | </tb-profile-lwm2m-device-config-server> |
@@ -110,11 +117,11 @@ | @@ -110,11 +117,11 @@ | ||
110 | </mat-expansion-panel> | 117 | </mat-expansion-panel> |
111 | </mat-accordion> | 118 | </mat-accordion> |
112 | </section> | 119 | </section> |
113 | - </ng-template> | 120 | + </section> |
114 | </mat-tab> | 121 | </mat-tab> |
115 | <mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}"> | 122 | <mat-tab label="{{ 'device-profile.lwm2m.others-tab' | translate }}"> |
116 | - <ng-template matTabContent> | ||
117 | - <section [formGroup]="lwm2mDeviceProfileFormGroup"> | 123 | + <ng-template matTabContent [formGroup]="lwm2mDeviceProfileFormGroup"> |
124 | + <section formGroupName="clientLwM2mSettings"> | ||
118 | <fieldset class="fields-group"> | 125 | <fieldset class="fields-group"> |
119 | <legend class="group-title" translate>device-profile.lwm2m.fw-update</legend> | 126 | <legend class="group-title" translate>device-profile.lwm2m.fw-update</legend> |
120 | <mat-form-field class="mat-block" fxFlex> | 127 | <mat-form-field class="mat-block" fxFlex> |
@@ -128,7 +135,7 @@ | @@ -128,7 +135,7 @@ | ||
128 | <mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy"> | 135 | <mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy"> |
129 | <mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label> | 136 | <mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label> |
130 | <input matInput formControlName="fwUpdateRecourse" required> | 137 | <input matInput formControlName="fwUpdateRecourse" required> |
131 | - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').hasError('required')"> | 138 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').hasError('required')"> |
132 | {{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }} | 139 | {{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }} |
133 | </mat-error> | 140 | </mat-error> |
134 | </mat-form-field> | 141 | </mat-form-field> |
@@ -145,7 +152,7 @@ | @@ -145,7 +152,7 @@ | ||
145 | <mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy"> | 152 | <mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy"> |
146 | <mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label> | 153 | <mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label> |
147 | <input matInput formControlName="swUpdateRecourse" required> | 154 | <input matInput formControlName="swUpdateRecourse" required> |
148 | - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').hasError('required')"> | 155 | + <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').hasError('required')"> |
149 | {{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }} | 156 | {{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }} |
150 | </mat-error> | 157 | </mat-error> |
151 | </mat-form-field> | 158 | </mat-form-field> |
@@ -182,6 +189,7 @@ | @@ -182,6 +189,7 @@ | ||
182 | <ng-template matTabContent> | 189 | <ng-template matTabContent> |
183 | <section [formGroup]="lwm2mDeviceConfigFormGroup" style="padding: 8px 0"> | 190 | <section [formGroup]="lwm2mDeviceConfigFormGroup" style="padding: 8px 0"> |
184 | <tb-json-object-edit | 191 | <tb-json-object-edit |
192 | + readonly | ||
185 | [required]="required" | 193 | [required]="required" |
186 | [sort]="sortFunction" | 194 | [sort]="sortFunction" |
187 | label="{{ 'device-profile.transport-type-lwm2m' | translate }}" | 195 | label="{{ 'device-profile.transport-type-lwm2m' | translate }}" |
@@ -20,11 +20,19 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida | @@ -20,11 +20,19 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida | ||
20 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 20 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
21 | import { | 21 | import { |
22 | ATTRIBUTE, | 22 | ATTRIBUTE, |
23 | - BINDING_MODE, | ||
24 | - BINDING_MODE_NAMES, | 23 | + BingingMode, |
24 | + BingingModeTranslationsMap, | ||
25 | + DEFAULT_BINDING, | ||
25 | DEFAULT_FW_UPDATE_RESOURCE, | 26 | DEFAULT_FW_UPDATE_RESOURCE, |
27 | + DEFAULT_ID_SERVER, | ||
28 | + DEFAULT_LIFE_TIME, | ||
29 | + DEFAULT_MIN_PERIOD, | ||
30 | + DEFAULT_NOTIF_IF_DESIBLED, | ||
26 | DEFAULT_SW_UPDATE_RESOURCE, | 31 | DEFAULT_SW_UPDATE_RESOURCE, |
27 | - getDefaultProfileConfig, | 32 | + getDefaultBootstrapServerSecurityConfig, |
33 | + getDefaultBootstrapServersSecurityConfig, getDefaultLwM2MServerSecurityConfig, | ||
34 | + getDefaultProfileClientLwM2mSettingsConfig, | ||
35 | + getDefaultProfileObserveAttrConfig, | ||
28 | Instance, | 36 | Instance, |
29 | INSTANCES, | 37 | INSTANCES, |
30 | KEY_NAME, | 38 | KEY_NAME, |
@@ -33,7 +41,7 @@ import { | @@ -33,7 +41,7 @@ import { | ||
33 | ObjectLwM2M, | 41 | ObjectLwM2M, |
34 | OBSERVE, | 42 | OBSERVE, |
35 | OBSERVE_ATTR_TELEMETRY, | 43 | OBSERVE_ATTR_TELEMETRY, |
36 | - RESOURCES, | 44 | + RESOURCES, ServerSecurityConfig, |
37 | TELEMETRY | 45 | TELEMETRY |
38 | } from './lwm2m-profile-config.models'; | 46 | } from './lwm2m-profile-config.models'; |
39 | import { DeviceProfileService } from '@core/http/device-profile.service'; | 47 | import { DeviceProfileService } from '@core/http/device-profile.service'; |
@@ -61,14 +69,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -61,14 +69,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
61 | private disabled = false; | 69 | private disabled = false; |
62 | private destroy$ = new Subject(); | 70 | private destroy$ = new Subject(); |
63 | 71 | ||
64 | - bindingModeType = BINDING_MODE; | ||
65 | - bindingModeTypes = Object.keys(BINDING_MODE); | ||
66 | - bindingModeTypeNamesMap = BINDING_MODE_NAMES; | 72 | + bindingModeTypes = Object.values(BingingMode); |
73 | + bindingModeTypeNamesMap = BingingModeTranslationsMap; | ||
67 | lwm2mDeviceProfileFormGroup: FormGroup; | 74 | lwm2mDeviceProfileFormGroup: FormGroup; |
68 | lwm2mDeviceConfigFormGroup: FormGroup; | 75 | lwm2mDeviceConfigFormGroup: FormGroup; |
69 | - bootstrapServers: string; | ||
70 | - bootstrapServer: string; | ||
71 | - lwm2mServer: string; | ||
72 | sortFunction: (key: string, value: object) => object; | 76 | sortFunction: (key: string, value: object) => object; |
73 | isFwUpdateStrategy: boolean; | 77 | isFwUpdateStrategy: boolean; |
74 | isSwUpdateStrategy: boolean; | 78 | isSwUpdateStrategy: boolean; |
@@ -90,45 +94,53 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -90,45 +94,53 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
90 | this.lwm2mDeviceProfileFormGroup = this.fb.group({ | 94 | this.lwm2mDeviceProfileFormGroup = this.fb.group({ |
91 | objectIds: [null, Validators.required], | 95 | objectIds: [null, Validators.required], |
92 | observeAttrTelemetry: [null, Validators.required], | 96 | observeAttrTelemetry: [null, Validators.required], |
93 | - shortId: [null, Validators.required], | ||
94 | - lifetime: [null, Validators.required], | ||
95 | - defaultMinPeriod: [null, Validators.required], | ||
96 | - notifIfDisabled: [true, []], | ||
97 | - binding: [], | ||
98 | - bootstrapServer: [null, Validators.required], | ||
99 | - lwm2mServer: [null, Validators.required], | ||
100 | - clientOnlyObserveAfterConnect: [1, []], | ||
101 | - fwUpdateStrategy: [1, []], | ||
102 | - swUpdateStrategy: [1, []], | ||
103 | - fwUpdateRecourse: [{value: '', disabled: true}, []], | ||
104 | - swUpdateRecourse: [{value: '', disabled: true}, []] | 97 | + bootstrap: this.fb.group({ |
98 | + servers: this.fb.group({ | ||
99 | + binding: [DEFAULT_BINDING], | ||
100 | + shortId: [DEFAULT_ID_SERVER, [Validators.required, Validators.min(1), Validators.max(65534), Validators.pattern('[0-9]*')]], | ||
101 | + lifetime: [DEFAULT_LIFE_TIME, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | ||
102 | + notifIfDisabled: [DEFAULT_NOTIF_IF_DESIBLED, []], | ||
103 | + defaultMinPeriod: [DEFAULT_MIN_PERIOD, [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], | ||
104 | + }), | ||
105 | + bootstrapServer: [null, Validators.required], | ||
106 | + lwm2mServer: [null, Validators.required] | ||
107 | + }), | ||
108 | + clientLwM2mSettings: this.fb.group({ | ||
109 | + clientOnlyObserveAfterConnect: [1, []], | ||
110 | + fwUpdateStrategy: [1, []], | ||
111 | + swUpdateStrategy: [1, []], | ||
112 | + fwUpdateRecourse: [{value: '', disabled: true}, []], | ||
113 | + swUpdateRecourse: [{value: '', disabled: true}, []] | ||
114 | + }) | ||
105 | }); | 115 | }); |
106 | this.lwm2mDeviceConfigFormGroup = this.fb.group({ | 116 | this.lwm2mDeviceConfigFormGroup = this.fb.group({ |
107 | configurationJson: [null, Validators.required] | 117 | configurationJson: [null, Validators.required] |
108 | }); | 118 | }); |
109 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateStrategy').valueChanges.pipe( | 119 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateStrategy').valueChanges.pipe( |
110 | takeUntil(this.destroy$) | 120 | takeUntil(this.destroy$) |
111 | ).subscribe((fwStrategy) => { | 121 | ).subscribe((fwStrategy) => { |
112 | if (fwStrategy === 2) { | 122 | if (fwStrategy === 2) { |
113 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').enable({emitEvent: false}); | ||
114 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false}); | 123 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').enable({emitEvent: false}); |
124 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse') | ||
125 | + .patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false}); | ||
115 | this.isFwUpdateStrategy = true; | 126 | this.isFwUpdateStrategy = true; |
116 | } else { | 127 | } else { |
117 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').disable({emitEvent: false}); | 128 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').disable({emitEvent: false}); |
118 | this.isFwUpdateStrategy = false; | 129 | this.isFwUpdateStrategy = false; |
119 | } | 130 | } |
120 | this.otaUpdateFwStrategyValidate(true); | 131 | this.otaUpdateFwStrategyValidate(true); |
121 | }); | 132 | }); |
122 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateStrategy').valueChanges.pipe( | 133 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateStrategy').valueChanges.pipe( |
123 | takeUntil(this.destroy$) | 134 | takeUntil(this.destroy$) |
124 | ).subscribe((swStrategy) => { | 135 | ).subscribe((swStrategy) => { |
125 | if (swStrategy === 2) { | 136 | if (swStrategy === 2) { |
126 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').enable({emitEvent: false}); | ||
127 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false}); | 137 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').enable({emitEvent: false}); |
138 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse') | ||
139 | + .patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false}); | ||
128 | this.isSwUpdateStrategy = true; | 140 | this.isSwUpdateStrategy = true; |
129 | } else { | 141 | } else { |
130 | this.isSwUpdateStrategy = false; | 142 | this.isSwUpdateStrategy = false; |
131 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').disable({emitEvent: false}); | 143 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').disable({emitEvent: false}); |
132 | } | 144 | } |
133 | this.otaUpdateSwStrategyValidate(true); | 145 | this.otaUpdateSwStrategyValidate(true); |
134 | }); | 146 | }); |
@@ -168,12 +180,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -168,12 +180,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
168 | } | 180 | } |
169 | } | 181 | } |
170 | 182 | ||
171 | - writeValue(value: Lwm2mProfileConfigModels | null): void { | 183 | + async writeValue(value: Lwm2mProfileConfigModels | null) { |
172 | if (isDefinedAndNotNull(value)) { | 184 | if (isDefinedAndNotNull(value)) { |
173 | - if (Object.keys(value).length !== 0 && (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap)) { | 185 | + if (value?.clientLwM2mSettings || value?.observeAttr || value?.bootstrap) { |
174 | this.configurationValue = value; | 186 | this.configurationValue = value; |
175 | } else { | 187 | } else { |
176 | - this.configurationValue = getDefaultProfileConfig(); | 188 | + this.configurationValue = await this.defaultProfileConfig(); |
177 | } | 189 | } |
178 | this.lwm2mDeviceConfigFormGroup.patchValue({ | 190 | this.lwm2mDeviceConfigFormGroup.patchValue({ |
179 | configurationJson: this.configurationValue | 191 | configurationJson: this.configurationValue |
@@ -182,6 +194,29 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -182,6 +194,29 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
182 | } | 194 | } |
183 | } | 195 | } |
184 | 196 | ||
197 | + private async defaultProfileConfig(): Promise<Lwm2mProfileConfigModels> { | ||
198 | + let bootstrap: ServerSecurityConfig; | ||
199 | + let lwm2m: ServerSecurityConfig; | ||
200 | + try { | ||
201 | + [bootstrap, lwm2m] = await Promise.all([ | ||
202 | + this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(true).toPromise(), | ||
203 | + this.deviceProfileService.getLwm2mBootstrapSecurityInfoBySecurityType(false).toPromise() | ||
204 | + ]); | ||
205 | + } catch (e) { | ||
206 | + bootstrap = getDefaultBootstrapServerSecurityConfig(); | ||
207 | + lwm2m = getDefaultLwM2MServerSecurityConfig(); | ||
208 | + } | ||
209 | + return { | ||
210 | + observeAttr: getDefaultProfileObserveAttrConfig(), | ||
211 | + bootstrap: { | ||
212 | + servers: getDefaultBootstrapServersSecurityConfig(), | ||
213 | + bootstrapServer: bootstrap, | ||
214 | + lwm2mServer: lwm2m | ||
215 | + }, | ||
216 | + clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig() | ||
217 | + }; | ||
218 | + } | ||
219 | + | ||
185 | private initWriteValue = (): void => { | 220 | private initWriteValue = (): void => { |
186 | const modelValue = {objectIds: [], objectsList: []} as ModelValue; | 221 | const modelValue = {objectIds: [], objectsList: []} as ModelValue; |
187 | modelValue.objectIds = this.getObjectsFromJsonAllConfig(); | 222 | modelValue.objectIds = this.getObjectsFromJsonAllConfig(); |
@@ -209,18 +244,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -209,18 +244,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
209 | this.lwm2mDeviceProfileFormGroup.patchValue({ | 244 | this.lwm2mDeviceProfileFormGroup.patchValue({ |
210 | objectIds: value, | 245 | objectIds: value, |
211 | observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList), | 246 | observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList), |
212 | - shortId: this.configurationValue.bootstrap.servers.shortId, | ||
213 | - lifetime: this.configurationValue.bootstrap.servers.lifetime, | ||
214 | - defaultMinPeriod: this.configurationValue.bootstrap.servers.defaultMinPeriod, | ||
215 | - notifIfDisabled: this.configurationValue.bootstrap.servers.notifIfDisabled, | ||
216 | - binding: this.configurationValue.bootstrap.servers.binding, | ||
217 | - bootstrapServer: this.configurationValue.bootstrap.bootstrapServer, | ||
218 | - lwm2mServer: this.configurationValue.bootstrap.lwm2mServer, | ||
219 | - clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect, | ||
220 | - fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, | ||
221 | - swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1, | ||
222 | - fwUpdateRecourse: fwResource, | ||
223 | - swUpdateRecourse: swResource | 247 | + bootstrap: this.configurationValue.bootstrap, |
248 | + clientLwM2mSettings: { | ||
249 | + clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect, | ||
250 | + fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, | ||
251 | + swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1, | ||
252 | + fwUpdateRecourse: fwResource, | ||
253 | + swUpdateRecourse: swResource | ||
254 | + } | ||
224 | }, | 255 | }, |
225 | {emitEvent: false}); | 256 | {emitEvent: false}); |
226 | this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource; | 257 | this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource; |
@@ -249,21 +280,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -249,21 +280,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
249 | private updateDeviceProfileValue(config): void { | 280 | private updateDeviceProfileValue(config): void { |
250 | if (this.lwm2mDeviceProfileFormGroup.valid) { | 281 | if (this.lwm2mDeviceProfileFormGroup.valid) { |
251 | this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); | 282 | this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); |
252 | - this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer; | ||
253 | - this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer; | ||
254 | - const bootstrapServers = this.configurationValue.bootstrap.servers; | ||
255 | - bootstrapServers.shortId = config.shortId; | ||
256 | - bootstrapServers.lifetime = config.lifetime; | ||
257 | - bootstrapServers.defaultMinPeriod = config.defaultMinPeriod; | ||
258 | - bootstrapServers.notifIfDisabled = config.notifIfDisabled; | ||
259 | - bootstrapServers.binding = config.binding; | ||
260 | - this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect = config.clientOnlyObserveAfterConnect; | ||
261 | - this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy; | ||
262 | - this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy; | ||
263 | - this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse; | ||
264 | - this.configurationValue.clientLwM2mSettings.swUpdateRecourse = config.swUpdateRecourse; | ||
265 | - this.upDateJsonAllConfig(); | ||
266 | } | 283 | } |
284 | + this.configurationValue.bootstrap.bootstrapServer = config.bootstrap.bootstrapServer; | ||
285 | + this.configurationValue.bootstrap.lwm2mServer = config.bootstrap.lwm2mServer; | ||
286 | + this.configurationValue.bootstrap.servers = config.bootstrap.servers; | ||
287 | + this.configurationValue.clientLwM2mSettings = config.clientLwM2mSettings; | ||
288 | + this.upDateJsonAllConfig(); | ||
267 | this.updateModel(); | 289 | this.updateModel(); |
268 | } | 290 | } |
269 | 291 | ||
@@ -539,20 +561,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -539,20 +561,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
539 | 561 | ||
540 | private otaUpdateFwStrategyValidate(updated = false): void { | 562 | private otaUpdateFwStrategyValidate(updated = false): void { |
541 | if (this.isFwUpdateStrategy) { | 563 | if (this.isFwUpdateStrategy) { |
542 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').setValidators([Validators.required]); | 564 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').setValidators([Validators.required]); |
543 | } else { | 565 | } else { |
544 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').clearValidators(); | 566 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').clearValidators(); |
545 | } | 567 | } |
546 | - this.lwm2mDeviceProfileFormGroup.get('fwUpdateRecourse').updateValueAndValidity({emitEvent: updated}); | 568 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').updateValueAndValidity({emitEvent: updated}); |
547 | } | 569 | } |
548 | 570 | ||
549 | private otaUpdateSwStrategyValidate(updated = false): void { | 571 | private otaUpdateSwStrategyValidate(updated = false): void { |
550 | if (this.isSwUpdateStrategy) { | 572 | if (this.isSwUpdateStrategy) { |
551 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').setValidators([Validators.required]); | 573 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').setValidators([Validators.required]); |
552 | } else { | 574 | } else { |
553 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').clearValidators(); | 575 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').clearValidators(); |
554 | } | 576 | } |
555 | - this.lwm2mDeviceProfileFormGroup.get('swUpdateRecourse').updateValueAndValidity({emitEvent: updated}); | 577 | + this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').updateValueAndValidity({emitEvent: updated}); |
556 | } | 578 | } |
557 | 579 | ||
558 | } | 580 | } |
@@ -20,27 +20,24 @@ | @@ -20,27 +20,24 @@ | ||
20 | *ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams"> | 20 | *ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams"> |
21 | <div class="vertical-padding" fxLayout="column" fxFill [formGroupName]="i"> | 21 | <div class="vertical-padding" fxLayout="column" fxFill [formGroupName]="i"> |
22 | <div fxLayout="row" fxFill fxLayoutAlign="start center" [fxShow]="!i"> | 22 | <div fxLayout="row" fxFill fxLayoutAlign="start center" [fxShow]="!i"> |
23 | - <div fxFlex="20"> | 23 | + <div fxFlex="30"> |
24 | <mat-label translate>device-profile.lwm2m.resource-label</mat-label> | 24 | <mat-label translate>device-profile.lwm2m.resource-label</mat-label> |
25 | </div> | 25 | </div> |
26 | - <div fxFlex="10"> | 26 | + <div fxFlex="10" style="text-align: center"> |
27 | <mat-label translate>device-profile.lwm2m.attribute-label</mat-label> | 27 | <mat-label translate>device-profile.lwm2m.attribute-label</mat-label> |
28 | </div> | 28 | </div> |
29 | - <div fxFlex="10"> | 29 | + <div fxFlex="10" style="text-align: center"> |
30 | <mat-label translate>device-profile.lwm2m.telemetry-label</mat-label> | 30 | <mat-label translate>device-profile.lwm2m.telemetry-label</mat-label> |
31 | </div> | 31 | </div> |
32 | - <div fxFlex="10"> | 32 | + <div fxFlex="10" style="text-align: center"> |
33 | <mat-label translate>device-profile.lwm2m.observe-label</mat-label> | 33 | <mat-label translate>device-profile.lwm2m.observe-label</mat-label> |
34 | </div> | 34 | </div> |
35 | <div fxFlex> | 35 | <div fxFlex> |
36 | <mat-label translate>device-profile.lwm2m.key-name-label</mat-label> | 36 | <mat-label translate>device-profile.lwm2m.key-name-label</mat-label> |
37 | </div> | 37 | </div> |
38 | - <div fxFlex="17" fxFlexOffset="0"> | ||
39 | - <mat-label translate>device-profile.lwm2m.attribute-lwm2m-label</mat-label> | ||
40 | - </div> | ||
41 | </div> | 38 | </div> |
42 | <div fxLayout="row" fxFill fxLayoutAlign="start center"> | 39 | <div fxLayout="row" fxFill fxLayoutAlign="start center"> |
43 | - <div class="resource-name-lw" fxFlex="25" | 40 | + <div class="resource-name-lw" fxFlex="30" |
44 | matTooltip="{{'device-profile.lwm2m.resource-tip' | translate}}" matTooltipPosition="above"> | 41 | matTooltip="{{'device-profile.lwm2m.resource-tip' | translate}}" matTooltipPosition="above"> |
45 | <<b>{{resourceLwM2M.get('id').value}}</b>> <b><i>{{resourceLwM2M.get('name').value}}</i></b> | 42 | <<b>{{resourceLwM2M.get('id').value}}</b>> <b><i>{{resourceLwM2M.get('name').value}}</i></b> |
46 | </div> | 43 | </div> |
@@ -65,7 +62,7 @@ | @@ -65,7 +62,7 @@ | ||
65 | matTooltipPosition="above"> | 62 | matTooltipPosition="above"> |
66 | </mat-checkbox> | 63 | </mat-checkbox> |
67 | </div> | 64 | </div> |
68 | - <mat-form-field fxFlex="25"> | 65 | + <mat-form-field fxFlex="33"> |
69 | <mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')"> | 66 | <mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')"> |
70 | {{ 'device-profile.lwm2m.key-name-label' | translate }}</mat-label> | 67 | {{ 'device-profile.lwm2m.key-name-label' | translate }}</mat-label> |
71 | <input class="resource-name-lw" matInput type="text" formControlName="keyName" required | 68 | <input class="resource-name-lw" matInput type="text" formControlName="keyName" required |
@@ -77,12 +74,13 @@ | @@ -77,12 +74,13 @@ | ||
77 | <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | 74 | <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> |
78 | </mat-error> | 75 | </mat-error> |
79 | </mat-form-field> | 76 | </mat-form-field> |
80 | - <div fxFlex="20" class="resource-name-lw-end" fxFlexOffset="5"> | 77 | + <span fxFlex></span> |
78 | + <div class="resource-name-lw-end"> | ||
81 | <tb-profile-lwm2m-attributes | 79 | <tb-profile-lwm2m-attributes |
82 | formControlName="attributeLwm2m" | 80 | formControlName="attributeLwm2m" |
83 | - [attributeLwm2m]="resourceLwM2M.get('attributeLwm2m').value" | ||
84 | [isAttributeTelemetry]="disableObserve(i)" | 81 | [isAttributeTelemetry]="disableObserve(i)" |
85 | - [destName]="getNameResourceLwm2m(resourceLwM2M.value)" | 82 | + isResource="true" |
83 | + [modelName]="getNameResourceLwm2m(resourceLwM2M.value)" | ||
86 | [disabled]="this.disabled" | 84 | [disabled]="this.disabled" |
87 | (updateAttributeLwm2m)="updateAttributeLwm2m($event, i)"> | 85 | (updateAttributeLwm2m)="updateAttributeLwm2m($event, i)"> |
88 | </tb-profile-lwm2m-attributes> | 86 | </tb-profile-lwm2m-attributes> |
@@ -26,17 +26,15 @@ | @@ -26,17 +26,15 @@ | ||
26 | <div fxFlex class="resource-name-lw-end"> | 26 | <div fxFlex class="resource-name-lw-end"> |
27 | <tb-profile-lwm2m-attributes | 27 | <tb-profile-lwm2m-attributes |
28 | formControlName="attributeLwm2m" | 28 | formControlName="attributeLwm2m" |
29 | - [attributeLwm2m]="objectLwM2M.get('attributeLwm2m').value" | ||
30 | [isAttributeTelemetry]="disableObserveObject(i)" | 29 | [isAttributeTelemetry]="disableObserveObject(i)" |
31 | - [destName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)" | 30 | + [modelName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)" |
32 | [disabled]="this.disabled" | 31 | [disabled]="this.disabled" |
33 | (updateAttributeLwm2m)="updateAttributeLwm2mObject($event, objectLwM2M.get('keyId').value)"> | 32 | (updateAttributeLwm2m)="updateAttributeLwm2mObject($event, objectLwM2M.get('keyId').value)"> |
34 | </tb-profile-lwm2m-attributes> | 33 | </tb-profile-lwm2m-attributes> |
35 | </div> | 34 | </div> |
36 | </mat-panel-title> | 35 | </mat-panel-title> |
37 | - <mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled"> | 36 | + <mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled && objectLwM2M.get('multiple').value"> |
38 | <button type="button" | 37 | <button type="button" |
39 | - [fxShow]="objectLwM2M.get('multiple').value" | ||
40 | mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)" | 38 | mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)" |
41 | matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}" | 39 | matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}" |
42 | matTooltipPosition="above"> | 40 | matTooltipPosition="above"> |
@@ -56,7 +54,7 @@ | @@ -56,7 +54,7 @@ | ||
56 | <mat-panel-title> | 54 | <mat-panel-title> |
57 | <div class="tb-panel-title-height" fxFlex="100"> | 55 | <div class="tb-panel-title-height" fxFlex="100"> |
58 | <div fxLayout="row" fxFill> | 56 | <div fxLayout="row" fxFill> |
59 | - <div fxFlex="22"> | 57 | + <div fxFlex="30"> |
60 | {{'device-profile.lwm2m.instance-label' | translate}} <<b>{{instances.get('id').value}}</b>> | 58 | {{'device-profile.lwm2m.instance-label' | translate}} <<b>{{instances.get('id').value}}</b>> |
61 | </div> | 59 | </div> |
62 | <div class="checkbox-padding" fxFlex="10"> | 60 | <div class="checkbox-padding" fxFlex="10"> |
@@ -95,14 +93,13 @@ | @@ -95,14 +93,13 @@ | ||
95 | matTooltipPosition="above"> | 93 | matTooltipPosition="above"> |
96 | </mat-checkbox> | 94 | </mat-checkbox> |
97 | </div> | 95 | </div> |
98 | - <div fxFlex="10"> | 96 | + <div fxFlex="7"> |
99 | </div> | 97 | </div> |
100 | <div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5"> | 98 | <div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5"> |
101 | <tb-profile-lwm2m-attributes | 99 | <tb-profile-lwm2m-attributes |
102 | formControlName="attributeLwm2m" | 100 | formControlName="attributeLwm2m" |
103 | - [attributeLwm2m]="instances.get('attributeLwm2m').value" | ||
104 | [isAttributeTelemetry]="disableObserveInstance(instances)" | 101 | [isAttributeTelemetry]="disableObserveInstance(instances)" |
105 | - [destName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)" | 102 | + [modelName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)" |
106 | [disabled]="this.disabled" | 103 | [disabled]="this.disabled" |
107 | (updateAttributeLwm2m)="updateAttributeLwm2mInstance($event, y, objectLwM2M.get('keyId').value)"> | 104 | (updateAttributeLwm2m)="updateAttributeLwm2mInstance($event, y, objectLwM2M.get('keyId').value)"> |
108 | </tb-profile-lwm2m-attributes> | 105 | </tb-profile-lwm2m-attributes> |
@@ -14,6 +14,8 @@ | @@ -14,6 +14,8 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | +import { ValidatorFn, Validators } from '@angular/forms'; | ||
18 | + | ||
17 | export const PAGE_SIZE_LIMIT = 50; | 19 | export const PAGE_SIZE_LIMIT = 50; |
18 | export const INSTANCES = 'instances'; | 20 | export const INSTANCES = 'instances'; |
19 | export const INSTANCE = 'instance'; | 21 | export const INSTANCE = 'instance'; |
@@ -39,7 +41,7 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; | @@ -39,7 +41,7 @@ export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; | ||
39 | export const LEN_MAX_PUBLIC_KEY_RPK = 182; | 41 | export const LEN_MAX_PUBLIC_KEY_RPK = 182; |
40 | export const LEN_MAX_PUBLIC_KEY_X509 = 3000; | 42 | export const LEN_MAX_PUBLIC_KEY_X509 = 3000; |
41 | export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; | 43 | export const KEY_REGEXP_HEX_DEC = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; |
42 | -export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; | 44 | +export const KEY_REGEXP_NUMBER = /^(-?|\+?)\d*$/; |
43 | export const INSTANCES_ID_VALUE_MIN = 0; | 45 | export const INSTANCES_ID_VALUE_MIN = 0; |
44 | export const INSTANCES_ID_VALUE_MAX = 65535; | 46 | export const INSTANCES_ID_VALUE_MAX = 65535; |
45 | export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://'; | 47 | export const DEFAULT_OTA_UPDATE_PROTOCOL = 'coap://'; |
@@ -47,7 +49,7 @@ export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_ | @@ -47,7 +49,7 @@ export const DEFAULT_FW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_ | ||
47 | export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC; | 49 | export const DEFAULT_SW_UPDATE_RESOURCE = DEFAULT_OTA_UPDATE_PROTOCOL + DEFAULT_LOCAL_HOST_NAME + ':' + DEFAULT_PORT_SERVER_NO_SEC; |
48 | 50 | ||
49 | 51 | ||
50 | -export enum BINDING_MODE { | 52 | +export enum BingingMode { |
51 | U = 'U', | 53 | U = 'U', |
52 | UQ = 'UQ', | 54 | UQ = 'UQ', |
53 | T = 'T', | 55 | T = 'T', |
@@ -60,58 +62,43 @@ export enum BINDING_MODE { | @@ -60,58 +62,43 @@ export enum BINDING_MODE { | ||
60 | TQS = 'TQS' | 62 | TQS = 'TQS' |
61 | } | 63 | } |
62 | 64 | ||
63 | -export const BINDING_MODE_NAMES = new Map<BINDING_MODE, string>( | 65 | +export const BingingModeTranslationsMap = new Map<BingingMode, string>( |
64 | [ | 66 | [ |
65 | - [BINDING_MODE.U, 'U: UDP connection in standard mode'], | ||
66 | - [BINDING_MODE.UQ, 'UQ: UDP connection in queue mode'], | ||
67 | - [BINDING_MODE.US, 'US: both UDP and SMS connections active, both in standard mode'], | ||
68 | - [BINDING_MODE.UQS, 'UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode'], | ||
69 | - [BINDING_MODE.T, 'T: TCP connection in standard mode'], | ||
70 | - [BINDING_MODE.TQ, 'TQ: TCP connection in queue mode'], | ||
71 | - [BINDING_MODE.TS, 'TS: both TCP and SMS connections active, both in standard mode'], | ||
72 | - [BINDING_MODE.TQS, 'TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode'], | ||
73 | - [BINDING_MODE.S, 'S: SMS connection in standard mode'], | ||
74 | - [BINDING_MODE.SQ, 'SQ: SMS connection in queue mode'] | 67 | + [BingingMode.U, 'device-profile.lwm2m.binding-type.u'], |
68 | + [BingingMode.UQ, 'device-profile.lwm2m.binding-type.uq'], | ||
69 | + [BingingMode.US, 'device-profile.lwm2m.binding-type.us'], | ||
70 | + [BingingMode.UQS, 'device-profile.lwm2m.binding-type.uqs'], | ||
71 | + [BingingMode.T, 'device-profile.lwm2m.binding-type.t'], | ||
72 | + [BingingMode.TQ, 'device-profile.lwm2m.binding-type.tq'], | ||
73 | + [BingingMode.TS, 'device-profile.lwm2m.binding-type.ts'], | ||
74 | + [BingingMode.TQS, 'device-profile.lwm2m.binding-type.tqs'], | ||
75 | + [BingingMode.S, 'device-profile.lwm2m.binding-type.s'], | ||
76 | + [BingingMode.SQ, 'device-profile.lwm2m.binding-type.sq'] | ||
75 | ] | 77 | ] |
76 | ); | 78 | ); |
77 | - | ||
78 | -export enum ATTRIBUTE_LWM2M_ENUM { | ||
79 | - dim = 'dim', | ||
80 | - ver = 'ver', | 79 | +// TODO: wait release Leshan for issues: https://github.com/eclipse/leshan/issues/1026 |
80 | +export enum AttributeName { | ||
81 | pmin = 'pmin', | 81 | pmin = 'pmin', |
82 | pmax = 'pmax', | 82 | pmax = 'pmax', |
83 | gt = 'gt', | 83 | gt = 'gt', |
84 | lt = 'lt', | 84 | lt = 'lt', |
85 | st = 'st' | 85 | st = 'st' |
86 | + // epmin = 'epmin', | ||
87 | + // epmax = 'epmax' | ||
86 | } | 88 | } |
87 | 89 | ||
88 | -export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>( | 90 | +export const AttributeNameTranslationMap = new Map<AttributeName, string>( |
89 | [ | 91 | [ |
90 | - [ATTRIBUTE_LWM2M_ENUM.dim, 'dim='], | ||
91 | - [ATTRIBUTE_LWM2M_ENUM.ver, 'ver='], | ||
92 | - [ATTRIBUTE_LWM2M_ENUM.pmin, 'pmin='], | ||
93 | - [ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='], | ||
94 | - [ATTRIBUTE_LWM2M_ENUM.gt, '>'], | ||
95 | - [ATTRIBUTE_LWM2M_ENUM.lt, '<'], | ||
96 | - [ATTRIBUTE_LWM2M_ENUM.st, 'st='] | ||
97 | - ] | ||
98 | -); | ||
99 | - | ||
100 | -export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>( | ||
101 | - [ | ||
102 | - [ATTRIBUTE_LWM2M_ENUM.dim, 'Dimension'], | ||
103 | - [ATTRIBUTE_LWM2M_ENUM.ver, 'Object version'], | ||
104 | - [ATTRIBUTE_LWM2M_ENUM.pmin, 'Minimum period'], | ||
105 | - [ATTRIBUTE_LWM2M_ENUM.pmax, 'Maximum period'], | ||
106 | - [ATTRIBUTE_LWM2M_ENUM.gt, 'Greater than'], | ||
107 | - [ATTRIBUTE_LWM2M_ENUM.lt, 'Lesser than'], | ||
108 | - [ATTRIBUTE_LWM2M_ENUM.st, 'Step'], | ||
109 | - | 92 | + [AttributeName.pmin, 'device-profile.lwm2m.attributes-name.min-period'], |
93 | + [AttributeName.pmax, 'device-profile.lwm2m.attributes-name.max-period'], | ||
94 | + [AttributeName.gt, 'device-profile.lwm2m.attributes-name.greater-than'], | ||
95 | + [AttributeName.lt, 'device-profile.lwm2m.attributes-name.less-than'], | ||
96 | + [AttributeName.st, 'device-profile.lwm2m.attributes-name.step'], | ||
97 | + // [AttributeName.epmin, 'device-profile.lwm2m.attributes-name.min-evaluation-period'], | ||
98 | + // [AttributeName.epmax, 'device-profile.lwm2m.attributes-name.max-evaluation-period'] | ||
110 | ] | 99 | ] |
111 | ); | 100 | ); |
112 | 101 | ||
113 | -export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[]; | ||
114 | - | ||
115 | export enum securityConfigMode { | 102 | export enum securityConfigMode { |
116 | PSK = 'PSK', | 103 | PSK = 'PSK', |
117 | RPK = 'RPK', | 104 | RPK = 'RPK', |
@@ -143,18 +130,20 @@ export interface BootstrapServersSecurityConfig { | @@ -143,18 +130,20 @@ export interface BootstrapServersSecurityConfig { | ||
143 | 130 | ||
144 | export interface ServerSecurityConfig { | 131 | export interface ServerSecurityConfig { |
145 | host?: string; | 132 | host?: string; |
146 | - securityHost?: string; | ||
147 | port?: number; | 133 | port?: number; |
148 | - securityPort?: number; | ||
149 | securityMode: securityConfigMode; | 134 | securityMode: securityConfigMode; |
150 | - clientPublicKeyOrId?: string; | ||
151 | - clientSecretKey?: string; | ||
152 | serverPublicKey?: string; | 135 | serverPublicKey?: string; |
153 | clientHoldOffTime?: number; | 136 | clientHoldOffTime?: number; |
154 | serverId?: number; | 137 | serverId?: number; |
155 | bootstrapServerAccountTimeout: number; | 138 | bootstrapServerAccountTimeout: number; |
156 | } | 139 | } |
157 | 140 | ||
141 | +export interface ServerSecurityConfigInfo extends ServerSecurityConfig { | ||
142 | + securityHost?: string; | ||
143 | + securityPort?: number; | ||
144 | + bootstrapServerIs: boolean; | ||
145 | +} | ||
146 | + | ||
158 | interface BootstrapSecurityConfig { | 147 | interface BootstrapSecurityConfig { |
159 | servers: BootstrapServersSecurityConfig; | 148 | servers: BootstrapServersSecurityConfig; |
160 | bootstrapServer: ServerSecurityConfig; | 149 | bootstrapServer: ServerSecurityConfig; |
@@ -180,7 +169,7 @@ export interface ObservableAttributes { | @@ -180,7 +169,7 @@ export interface ObservableAttributes { | ||
180 | attribute: string[]; | 169 | attribute: string[]; |
181 | telemetry: string[]; | 170 | telemetry: string[]; |
182 | keyName: {}; | 171 | keyName: {}; |
183 | - attributeLwm2m: {}; | 172 | + attributeLwm2m?: AttributesNameValueMap; |
184 | } | 173 | } |
185 | 174 | ||
186 | export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { | 175 | export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { |
@@ -193,9 +182,9 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu | @@ -193,9 +182,9 @@ export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecu | ||
193 | }; | 182 | }; |
194 | } | 183 | } |
195 | 184 | ||
196 | -export function getDefaultBootstrapServerSecurityConfig(hostname: string): ServerSecurityConfig { | 185 | +export function getDefaultBootstrapServerSecurityConfig(): ServerSecurityConfig { |
197 | return { | 186 | return { |
198 | - host: hostname, | 187 | + host: DEFAULT_LOCAL_HOST_NAME, |
199 | port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, | 188 | port: DEFAULT_PORT_BOOTSTRAP_NO_SEC, |
200 | securityMode: securityConfigMode.NO_SEC, | 189 | securityMode: securityConfigMode.NO_SEC, |
201 | serverPublicKey: '', | 190 | serverPublicKey: '', |
@@ -205,22 +194,14 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: string): Serve | @@ -205,22 +194,14 @@ export function getDefaultBootstrapServerSecurityConfig(hostname: string): Serve | ||
205 | }; | 194 | }; |
206 | } | 195 | } |
207 | 196 | ||
208 | -export function getDefaultLwM2MServerSecurityConfig(hostname): ServerSecurityConfig { | ||
209 | - const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(hostname); | 197 | +export function getDefaultLwM2MServerSecurityConfig(): ServerSecurityConfig { |
198 | + const DefaultLwM2MServerSecurityConfig = getDefaultBootstrapServerSecurityConfig(); | ||
210 | DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC; | 199 | DefaultLwM2MServerSecurityConfig.port = DEFAULT_PORT_SERVER_NO_SEC; |
211 | DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; | 200 | DefaultLwM2MServerSecurityConfig.serverId = DEFAULT_ID_SERVER; |
212 | return DefaultLwM2MServerSecurityConfig; | 201 | return DefaultLwM2MServerSecurityConfig; |
213 | } | 202 | } |
214 | 203 | ||
215 | -function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecurityConfig { | ||
216 | - return { | ||
217 | - servers: getDefaultBootstrapServersSecurityConfig(), | ||
218 | - bootstrapServer: getDefaultBootstrapServerSecurityConfig(hostname), | ||
219 | - lwm2mServer: getDefaultLwM2MServerSecurityConfig(hostname) | ||
220 | - }; | ||
221 | -} | ||
222 | - | ||
223 | -function getDefaultProfileObserveAttrConfig(): ObservableAttributes { | 204 | +export function getDefaultProfileObserveAttrConfig(): ObservableAttributes { |
224 | return { | 205 | return { |
225 | observe: [], | 206 | observe: [], |
226 | attribute: [], | 207 | attribute: [], |
@@ -230,15 +211,7 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes { | @@ -230,15 +211,7 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes { | ||
230 | }; | 211 | }; |
231 | } | 212 | } |
232 | 213 | ||
233 | -export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModels { | ||
234 | - return { | ||
235 | - clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(), | ||
236 | - observeAttr: getDefaultProfileObserveAttrConfig(), | ||
237 | - bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_LOCAL_HOST_NAME) | ||
238 | - }; | ||
239 | -} | ||
240 | - | ||
241 | -function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { | 214 | +export function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { |
242 | return { | 215 | return { |
243 | clientOnlyObserveAfterConnect: 1, | 216 | clientOnlyObserveAfterConnect: 1, |
244 | fwUpdateStrategy: 1, | 217 | fwUpdateStrategy: 1, |
@@ -255,12 +228,12 @@ export interface ResourceLwM2M { | @@ -255,12 +228,12 @@ export interface ResourceLwM2M { | ||
255 | attribute: boolean; | 228 | attribute: boolean; |
256 | telemetry: boolean; | 229 | telemetry: boolean; |
257 | keyName: string; | 230 | keyName: string; |
258 | - attributeLwm2m?: {}; | 231 | + attributeLwm2m?: AttributesNameValueMap; |
259 | } | 232 | } |
260 | 233 | ||
261 | export interface Instance { | 234 | export interface Instance { |
262 | id: number; | 235 | id: number; |
263 | - attributeLwm2m?: {}; | 236 | + attributeLwm2m?: AttributesNameValueMap; |
264 | resources: ResourceLwM2M[]; | 237 | resources: ResourceLwM2M[]; |
265 | } | 238 | } |
266 | 239 | ||
@@ -271,12 +244,33 @@ export interface Instance { | @@ -271,12 +244,33 @@ export interface Instance { | ||
271 | * mandatory == false => Optional | 244 | * mandatory == false => Optional |
272 | */ | 245 | */ |
273 | export interface ObjectLwM2M { | 246 | export interface ObjectLwM2M { |
274 | - | ||
275 | id: number; | 247 | id: number; |
276 | keyId: string; | 248 | keyId: string; |
277 | name: string; | 249 | name: string; |
278 | multiple?: boolean; | 250 | multiple?: boolean; |
279 | mandatory?: boolean; | 251 | mandatory?: boolean; |
280 | - attributeLwm2m?: {}; | 252 | + attributeLwm2m?: AttributesNameValueMap; |
281 | instances?: Instance []; | 253 | instances?: Instance []; |
282 | } | 254 | } |
255 | + | ||
256 | +export type AttributesNameValueMap = { | ||
257 | + [key in AttributeName]?: number; | ||
258 | +}; | ||
259 | + | ||
260 | +export interface AttributesNameValue { | ||
261 | + name: AttributeName; | ||
262 | + value: number; | ||
263 | +} | ||
264 | + | ||
265 | +export function valueValidatorByAttributeName(attributeName: AttributeName): ValidatorFn[] { | ||
266 | + const validators = [Validators.required]; | ||
267 | + switch (attributeName) { | ||
268 | + case AttributeName.pmin: | ||
269 | + case AttributeName.pmax: | ||
270 | + // case AttributeName.epmin: | ||
271 | + // case AttributeName.epmax: | ||
272 | + validators.push(Validators.min(0), Validators.pattern('[0-9]*')); | ||
273 | + break; | ||
274 | + } | ||
275 | + return validators; | ||
276 | +} |
@@ -1231,36 +1231,53 @@ | @@ -1231,36 +1231,53 @@ | ||
1231 | "attribute-label": "Attribute", | 1231 | "attribute-label": "Attribute", |
1232 | "telemetry-label": "Telemetry", | 1232 | "telemetry-label": "Telemetry", |
1233 | "key-name-label": "Key Name", | 1233 | "key-name-label": "Key Name", |
1234 | - "attribute-lwm2m-label": "AttrLwm2m", | ||
1235 | "resource-tip": "ID & Original Name of the Resource (only Operations isReadable)", | 1234 | "resource-tip": "ID & Original Name of the Resource (only Operations isReadable)", |
1236 | "is-observe-tip": "Is Observe", | 1235 | "is-observe-tip": "Is Observe", |
1237 | "not-observe-tip": "To observe select telemetry or attributes first", | 1236 | "not-observe-tip": "To observe select telemetry or attributes first", |
1238 | "is-attr-tip": "Is Attribute", | 1237 | "is-attr-tip": "Is Attribute", |
1239 | "is-telemetry-tip": "Is Telemetry", | 1238 | "is-telemetry-tip": "Is Telemetry", |
1240 | "key-name-tip": "Key Name in Camel format", | 1239 | "key-name-tip": "Key Name in Camel format", |
1241 | - "attribute-lwm2m-tip": "Attributes Lwm2m", | ||
1242 | - "attribute-lwm2m-disable-tip": "To edit Attributes Lwm2m select telemetry or attributes first", | ||
1243 | - "valid-attribute-lwm2m-key": "Name have be only '{{attrEnums}}'", | ||
1244 | - "valid-attribute-lwm2m-value": "Value have be Long, Double and greater than zero or null/empty", | ||
1245 | - "no-data": "No attributes", | 1240 | + "edit-attributes-select": "To edit attributes select telemetry or attributes", |
1241 | + "no-attributes-set": "No attributes set", | ||
1246 | "key-name": "Key Name", | 1242 | "key-name": "Key Name", |
1247 | - "attribute-lwm2m-name": "Name attribute", | ||
1248 | - "attribute-lwm2m-value": "Value", | ||
1249 | - "attribute-lwm2m-toolbar-edit": "Edit attributes Lwm2m", | ||
1250 | - "attribute-lwm2m-toolbar-view": "View Attributes Lwm2m", | ||
1251 | - "attribute-lwm2m-destination": "Destination:", | ||
1252 | - "attribute-lwm2m-add-tip": "Add attribute lwm2m", | ||
1253 | - "attribute-lwm2m-remove-tip": "Remove attribute lwm2m", | ||
1254 | - "required": " value is required.", | 1243 | + "attribute-name": "Name attribute", |
1244 | + "attribute-name-required": "Name attribute is required.", | ||
1245 | + "attribute-value": "Attribute value", | ||
1246 | + "attribute-value-required": "Attribute value is required.", | ||
1247 | + "attribute-value-pattern": "Attribute value must be a positive integer.", | ||
1248 | + "edit-attributes": "Edit attributes: {{ name }}", | ||
1249 | + "view-attributes": "View attributes: {{ name }}", | ||
1250 | + "add-attribute": "Add attribute", | ||
1251 | + "edit-attribute": "Edit attribute", | ||
1252 | + "view-attribute": "View attribute", | ||
1253 | + "remove-attribute": "Remove attribute", | ||
1255 | "mode": "Security config mode", | 1254 | "mode": "Security config mode", |
1256 | "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", | 1255 | "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", |
1257 | "servers": "Servers", | 1256 | "servers": "Servers", |
1258 | "short-id": "Short ID", | 1257 | "short-id": "Short ID", |
1259 | "short-id-required": "Short ID is required.", | 1258 | "short-id-required": "Short ID is required.", |
1260 | - "lifetime": "Lifetime of the registration for this LwM2M client", | ||
1261 | - "default-min-period": "Minimum Period between two notifications (sec)", | ||
1262 | - "notif-if-disabled": "Notification Storing When Disabled or Offline", | 1259 | + "short-id-range": "Short ID should be in a range from 1 to 65534.", |
1260 | + "short-id-pattern": "Short ID must be a positive integer.", | ||
1261 | + "lifetime": "Client registration lifetime", | ||
1262 | + "lifetime-required": "Client registration lifetime is required.", | ||
1263 | + "lifetime-pattern": "Client registration lifetime must be a positive integer.", | ||
1264 | + "default-min-period": "Minimum period between two notifications (s)", | ||
1265 | + "default-min-period-required": "Minimum period is required.", | ||
1266 | + "default-min-period-pattern": "Minimum period must be a positive integer.", | ||
1267 | + "notification-storing": "Notification storing when disabled or offline", | ||
1263 | "binding": "Binding", | 1268 | "binding": "Binding", |
1269 | + "binding-type": { | ||
1270 | + "u": "U: UDP connection in standard mode", | ||
1271 | + "uq": "UQ: UDP connection in queue mode", | ||
1272 | + "us": "US: both UDP and SMS connections active, both in standard mode", | ||
1273 | + "uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode", | ||
1274 | + "t": "T: TCP connection in standard mode", | ||
1275 | + "tq": "TQ: TCP connection in queue mode", | ||
1276 | + "ts": "TS: both TCP and SMS connections active, both in standard mode", | ||
1277 | + "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode", | ||
1278 | + "s": "S: SMS connection in standard mode", | ||
1279 | + "sq": "SQ: SMS connection in queue mode" | ||
1280 | + }, | ||
1264 | "bootstrap-tab": "Bootstrap", | 1281 | "bootstrap-tab": "Bootstrap", |
1265 | "bootstrap-server": "Bootstrap Server", | 1282 | "bootstrap-server": "Bootstrap Server", |
1266 | "lwm2m-server": "LwM2M Server", | 1283 | "lwm2m-server": "LwM2M Server", |
@@ -1268,15 +1285,19 @@ | @@ -1268,15 +1285,19 @@ | ||
1268 | "server-host-required": "Host is required.", | 1285 | "server-host-required": "Host is required.", |
1269 | "server-port": "Port", | 1286 | "server-port": "Port", |
1270 | "server-port-required": "Port is required.", | 1287 | "server-port-required": "Port is required.", |
1288 | + "server-port-pattern": "Port must be a positive integer.", | ||
1289 | + "server-port-range": "Port should be in a range from 1 to 65535.", | ||
1271 | "server-public-key": "Server Public Key", | 1290 | "server-public-key": "Server Public Key", |
1272 | "server-public-key-required": "Server Public Key is required.", | 1291 | "server-public-key-required": "Server Public Key is required.", |
1273 | "server-public-key-pattern": "Server Public Key must be hex decimal format.", | 1292 | "server-public-key-pattern": "Server Public Key must be hex decimal format.", |
1274 | "server-public-key-length": "Server Public Key must be {{ count }} characters.", | 1293 | "server-public-key-length": "Server Public Key must be {{ count }} characters.", |
1275 | "client-hold-off-time": "Hold Off Time", | 1294 | "client-hold-off-time": "Hold Off Time", |
1276 | "client-hold-off-time-required": "Hold Off Time is required.", | 1295 | "client-hold-off-time-required": "Hold Off Time is required.", |
1296 | + "client-hold-off-time-pattern": "Hold Off Time must be a positive integer.", | ||
1277 | "client-hold-off-time-tooltip": "Client Hold Off Time for use with a Bootstrap-Server only", | 1297 | "client-hold-off-time-tooltip": "Client Hold Off Time for use with a Bootstrap-Server only", |
1278 | "account-after-timeout": "Account after the timeout", | 1298 | "account-after-timeout": "Account after the timeout", |
1279 | "account-after-timeout-required": "Account after the timeout is required.", | 1299 | "account-after-timeout-required": "Account after the timeout is required.", |
1300 | + "account-after-timeout-pattern": "Account after the timeout must be a positive integer.", | ||
1280 | "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.", | 1301 | "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.", |
1281 | "others-tab": "Other settings", | 1302 | "others-tab": "Other settings", |
1282 | "client-strategy": "Client strategy when connecting", | 1303 | "client-strategy": "Client strategy when connecting", |
@@ -1296,7 +1317,16 @@ | @@ -1296,7 +1317,16 @@ | ||
1296 | "fw-update-recourse-required": "Firmware update CoAP recourse is required.", | 1317 | "fw-update-recourse-required": "Firmware update CoAP recourse is required.", |
1297 | "sw-update-recourse": "Software update CoAP recourse", | 1318 | "sw-update-recourse": "Software update CoAP recourse", |
1298 | "sw-update-recourse-required": "Software update CoAP recourse is required.", | 1319 | "sw-update-recourse-required": "Software update CoAP recourse is required.", |
1299 | - "config-json-tab": "Json Config Profile Device" | 1320 | + "config-json-tab": "Json Config Profile Device", |
1321 | + "attributes-name": { | ||
1322 | + "min-period": "Minimum period", | ||
1323 | + "max-period": "Maximum period", | ||
1324 | + "greater-than": "Greater than", | ||
1325 | + "less-than": "Less than", | ||
1326 | + "step": "Step", | ||
1327 | + "min-evaluation-period": "Minimum evaluation period", | ||
1328 | + "max-evaluation-period": "Maximum evaluation period" | ||
1329 | + } | ||
1300 | }, | 1330 | }, |
1301 | "snmp": { | 1331 | "snmp": { |
1302 | "add-communication-config": "Add communication config", | 1332 | "add-communication-config": "Add communication config", |