Commit c634859e906d866b09b571cab27e69abc89a1e57
Committed by
GitHub
1 parent
1b531e28
lwm2m: front start add attributes Lwm2m (#4388)
* lwm2m: front start add attributes Lwm2m * lwm2m: front finish add attributes Lwm2m for resources * lwm2m: front add attributes Lwm2m for resources if isAttribte or isTelemetry * lwm2m: front add attributes Lwm2m for objects if isAttribte or isTelemetry * lwm2m: back add resource one * lwm2m: back fix bug resource controller test
Showing
27 changed files
with
1065 additions
and
179 deletions
@@ -30,7 +30,6 @@ import org.springframework.web.bind.annotation.ResponseBody; | @@ -30,7 +30,6 @@ import org.springframework.web.bind.annotation.ResponseBody; | ||
30 | import org.springframework.web.bind.annotation.RestController; | 30 | import org.springframework.web.bind.annotation.RestController; |
31 | import org.thingsboard.server.common.data.TbResource; | 31 | import org.thingsboard.server.common.data.TbResource; |
32 | import org.thingsboard.server.common.data.TbResourceInfo; | 32 | import org.thingsboard.server.common.data.TbResourceInfo; |
33 | -import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | ||
34 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 33 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
35 | import org.thingsboard.server.common.data.id.TbResourceId; | 34 | import org.thingsboard.server.common.data.id.TbResourceId; |
36 | import org.thingsboard.server.common.data.lwm2m.LwM2mObject; | 35 | import org.thingsboard.server.common.data.lwm2m.LwM2mObject; |
@@ -42,10 +41,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; | @@ -42,10 +41,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; | ||
42 | import org.thingsboard.server.service.security.permission.Operation; | 41 | import org.thingsboard.server.service.security.permission.Operation; |
43 | import org.thingsboard.server.service.security.permission.Resource; | 42 | import org.thingsboard.server.service.security.permission.Resource; |
44 | 43 | ||
45 | -import java.util.ArrayList; | ||
46 | import java.util.Base64; | 44 | import java.util.Base64; |
47 | import java.util.List; | 45 | import java.util.List; |
48 | -import java.util.StringJoiner; | ||
49 | 46 | ||
50 | @Slf4j | 47 | @Slf4j |
51 | @RestController | 48 | @RestController |
@@ -111,25 +108,13 @@ public class TbResourceController extends BaseController { | @@ -111,25 +108,13 @@ public class TbResourceController extends BaseController { | ||
111 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | 108 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
112 | @RequestMapping(value = "/resource", method = RequestMethod.POST) | 109 | @RequestMapping(value = "/resource", method = RequestMethod.POST) |
113 | @ResponseBody | 110 | @ResponseBody |
114 | - public List<TbResource> saveResources(@RequestBody List<TbResource> resources) throws ThingsboardException { | 111 | + public TbResource saveResource(@RequestBody TbResource resource) throws ThingsboardException { |
115 | try { | 112 | try { |
116 | - List<TbResource> addResources = new ArrayList<>(); | ||
117 | - StringJoiner noSaveResources = new StringJoiner("; "); | ||
118 | - resources.forEach(resource -> { | ||
119 | - try { | ||
120 | resource.setTenantId(getTenantId()); | 113 | resource.setTenantId(getTenantId()); |
121 | checkEntity(resource.getId(), resource, Resource.TB_RESOURCE); | 114 | checkEntity(resource.getId(), resource, Resource.TB_RESOURCE); |
122 | - addResources.add(addResource(resource)); | ||
123 | - } catch (Exception e) { | ||
124 | - noSaveResources.add(resource.getFileName()); | ||
125 | - log.warn("Fail save resource: [{}]", resource.getFileName(), e); | 115 | + return addResource(resource); |
126 | } | 116 | } |
127 | - }); | ||
128 | - if (noSaveResources.length() > 0) { | ||
129 | - throw new ThingsboardException(String.format("Fail save resource: %s", noSaveResources.toString()), ThingsboardErrorCode.INVALID_ARGUMENTS); | ||
130 | - } | ||
131 | - return addResources; | ||
132 | - } catch (Exception e) { | 117 | + catch (Exception e) { |
133 | throw handleException(e); | 118 | throw handleException(e); |
134 | } | 119 | } |
135 | } | 120 | } |
@@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.security.Authority; | @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.security.Authority; | ||
32 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
33 | import java.util.Collections; | 33 | import java.util.Collections; |
34 | import java.util.List; | 34 | import java.util.List; |
35 | -import java.util.stream.Collectors; | ||
36 | 35 | ||
37 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | 36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
38 | 37 | ||
@@ -110,7 +109,7 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | @@ -110,7 +109,7 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | ||
110 | TbResource savedResource = save(resource); | 109 | TbResource savedResource = save(resource); |
111 | 110 | ||
112 | loginDifferentTenant(); | 111 | loginDifferentTenant(); |
113 | - doPostWithTypedResponse("/api/resource", Collections.singletonList(savedResource), new TypeReference<>(){}, status().isBadRequest()); | 112 | + doPostWithTypedResponse("/api/resource", savedResource, new TypeReference<>(){}, status().isForbidden()); |
114 | deleteDifferentTenant(); | 113 | deleteDifferentTenant(); |
115 | } | 114 | } |
116 | 115 | ||
@@ -148,18 +147,15 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | @@ -148,18 +147,15 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | ||
148 | 147 | ||
149 | @Test | 148 | @Test |
150 | public void testFindTenantTbResources() throws Exception { | 149 | public void testFindTenantTbResources() throws Exception { |
151 | - List<TbResource> resourcesToSave = new ArrayList<>(); | 150 | + List<TbResourceInfo> resources = new ArrayList<>(); |
152 | for (int i = 0; i < 173; i++) { | 151 | for (int i = 0; i < 173; i++) { |
153 | TbResource resource = new TbResource(); | 152 | TbResource resource = new TbResource(); |
154 | resource.setTitle("Resource" + i); | 153 | resource.setTitle("Resource" + i); |
155 | resource.setResourceType(ResourceType.JKS); | 154 | resource.setResourceType(ResourceType.JKS); |
156 | resource.setFileName(i + DEFAULT_FILE_NAME); | 155 | resource.setFileName(i + DEFAULT_FILE_NAME); |
157 | resource.setData("Test Data"); | 156 | resource.setData("Test Data"); |
158 | - resourcesToSave.add(resource); | 157 | + resources.add(new TbResourceInfo(save(resource))); |
159 | } | 158 | } |
160 | - | ||
161 | - List<TbResourceInfo> resources =save(resourcesToSave).stream().map(TbResourceInfo::new).collect(Collectors.toList()); | ||
162 | - | ||
163 | List<TbResourceInfo> loadedResources = new ArrayList<>(); | 159 | List<TbResourceInfo> loadedResources = new ArrayList<>(); |
164 | PageLink pageLink = new PageLink(24); | 160 | PageLink pageLink = new PageLink(24); |
165 | PageData<TbResourceInfo> pageData; | 161 | PageData<TbResourceInfo> pageData; |
@@ -287,10 +283,6 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | @@ -287,10 +283,6 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes | ||
287 | } | 283 | } |
288 | 284 | ||
289 | private TbResource save(TbResource tbResource) throws Exception { | 285 | private TbResource save(TbResource tbResource) throws Exception { |
290 | - return save(Collections.singletonList(tbResource)).get(0); | ||
291 | - } | ||
292 | - | ||
293 | - private List<TbResource> save(List<TbResource> tbResources) throws Exception { | ||
294 | - return doPostWithTypedResponse("/api/resource", tbResources, new TypeReference<>(){}); | 286 | + return doPostWithTypedResponse("/api/resource", tbResource, new TypeReference<>(){}); |
295 | } | 287 | } |
296 | } | 288 | } |
@@ -28,6 +28,7 @@ import java.util.Arrays; | @@ -28,6 +28,7 @@ import java.util.Arrays; | ||
28 | @ClasspathSuite.ClassnameFilters({ | 28 | @ClasspathSuite.ClassnameFilters({ |
29 | // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", | 29 | // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", |
30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", | 30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", |
31 | +// "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", | ||
31 | "org.thingsboard.server.controller.sql.*Test", | 32 | "org.thingsboard.server.controller.sql.*Test", |
32 | }) | 33 | }) |
33 | public class ControllerSqlTestSuite { | 34 | public class ControllerSqlTestSuite { |
@@ -122,7 +122,7 @@ public class LwM2mTransportRequest { | @@ -122,7 +122,7 @@ public class LwM2mTransportRequest { | ||
122 | DownlinkRequest request = null; | 122 | DownlinkRequest request = null; |
123 | ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; | 123 | ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; |
124 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); | 124 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
125 | - ResourceModel resource = lwM2MClient.getResourceModel(target); | 125 | + ResourceModel resource = lwM2MClient.getResourceModel(targetIdVer); |
126 | timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; | 126 | timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; |
127 | switch (typeOper) { | 127 | switch (typeOper) { |
128 | case GET_TYPE_OPER_READ: | 128 | case GET_TYPE_OPER_READ: |
@@ -22,7 +22,7 @@ import {Observable} from 'rxjs'; | @@ -22,7 +22,7 @@ import {Observable} 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'; | 24 | import {isDefinedAndNotNull, isEmptyStr} from '@core/utils'; |
25 | -import {ObjectLwM2M, ServerSecurityConfig} from '@home/components/profile/device/lwm2m/profile-config.models'; | 25 | +import {ObjectLwM2M, ServerSecurityConfig} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; |
26 | import {SortOrder} from '@shared/models/page/sort-order'; | 26 | import {SortOrder} from '@shared/models/page/sort-order'; |
27 | 27 | ||
28 | @Injectable({ | 28 | @Injectable({ |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2021 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<form [formGroup]="attributeLwm2mDialogFormGroup" (ngSubmit)="save()" style="width: 500px;"> | ||
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> | ||
24 | + <span fxFlex></span> | ||
25 | + <button mat-icon-button | ||
26 | + (click)="cancel()" | ||
27 | + type="button"> | ||
28 | + <mat-icon class="material-icons">close</mat-icon> | ||
29 | + </button> | ||
30 | + </mat-toolbar> | ||
31 | + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> | ||
32 | + </mat-progress-bar> | ||
33 | + <div mat-dialog-content> | ||
34 | + <tb-lwm2m-attributes-key-list | ||
35 | + formControlName="keyFilters" | ||
36 | + titleText="{{data.destName}}"> | ||
37 | + </tb-lwm2m-attributes-key-list> | ||
38 | + </div> | ||
39 | + <div mat-dialog-actions fxLayoutAlign="end center"> | ||
40 | + <button mat-button color="primary" | ||
41 | + type="button" | ||
42 | + [disabled]="(isLoading$ | async)" | ||
43 | + (click)="cancel()" cdkFocusInitial> | ||
44 | + {{ (readonly ? 'action.close' : 'action.cancel') | translate }} | ||
45 | + </button> | ||
46 | + <button mat-raised-button color="primary" | ||
47 | + *ngIf="!readonly" | ||
48 | + type="submit" | ||
49 | + [disabled]="(isLoading$ | async) || attributeLwm2mDialogFormGroup.invalid || !attributeLwm2mDialogFormGroup.dirty"> | ||
50 | + {{ 'action.save' | translate }} | ||
51 | + </button> | ||
52 | + </div> | ||
53 | +</form> |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component.ts
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 | + | ||
17 | +import {Component, Inject, OnInit, SkipSelf} from "@angular/core"; | ||
18 | +import {ErrorStateMatcher} from "@angular/material/core"; | ||
19 | +import {DialogComponent} from "@shared/components/dialog.component"; | ||
20 | +import {Store} from "@ngrx/store"; | ||
21 | +import {AppState} from "@core/core.state"; | ||
22 | +import {Router} from "@angular/router"; | ||
23 | +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; | ||
24 | +import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm} from "@angular/forms"; | ||
25 | +import {TranslateService} from "@ngx-translate/core"; | ||
26 | +import {JsonObject} from "@angular/compiler-cli/ngcc/src/packages/entry_point"; | ||
27 | + | ||
28 | +export interface Lwm2mAttributesDialogData { | ||
29 | + readonly: boolean; | ||
30 | + attributeLwm2m: JsonObject; | ||
31 | + destName: string | ||
32 | +} | ||
33 | + | ||
34 | +@Component({ | ||
35 | + selector: 'tb-lwm2m-attributes-dialog', | ||
36 | + templateUrl: './lwm2m-attributes-dialog.component.html', | ||
37 | + styleUrls: ['./lwm2m-attributes.component.scss'], | ||
38 | + providers: [{provide: ErrorStateMatcher, useExisting: Lwm2mAttributesDialogComponent}], | ||
39 | +}) | ||
40 | +export class Lwm2mAttributesDialogComponent extends DialogComponent<Lwm2mAttributesDialogComponent, Object> implements OnInit, ErrorStateMatcher { | ||
41 | + | ||
42 | + readonly = this.data.readonly; | ||
43 | + | ||
44 | + attributeLwm2m = this.data.attributeLwm2m; | ||
45 | + | ||
46 | + submitted = false; | ||
47 | + | ||
48 | + dirtyValue = false; | ||
49 | + | ||
50 | + attributeLwm2mDialogFormGroup: FormGroup; | ||
51 | + | ||
52 | + constructor(protected store: Store<AppState>, | ||
53 | + protected router: Router, | ||
54 | + @Inject(MAT_DIALOG_DATA) public data: Lwm2mAttributesDialogData, | ||
55 | + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, | ||
56 | + public dialogRef: MatDialogRef<Lwm2mAttributesDialogComponent, object>, | ||
57 | + private fb: FormBuilder, | ||
58 | + public translate: TranslateService) { | ||
59 | + super(store, router, dialogRef); | ||
60 | + | ||
61 | + this.attributeLwm2mDialogFormGroup = this.fb.group({ | ||
62 | + keyFilters: [{}, []] | ||
63 | + }); | ||
64 | + this.attributeLwm2mDialogFormGroup.patchValue({keyFilters: this.attributeLwm2m}); | ||
65 | + this.attributeLwm2mDialogFormGroup.get('keyFilters').valueChanges.subscribe((attributes) => { | ||
66 | + this.attributeLwm2m = attributes; | ||
67 | + }); | ||
68 | + if (this.readonly) { | ||
69 | + this.attributeLwm2mDialogFormGroup.disable({emitEvent: false}); | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + ngOnInit(): void { | ||
74 | + } | ||
75 | + | ||
76 | + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { | ||
77 | + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); | ||
78 | + const customErrorState = !!(control && control.invalid && this.submitted); | ||
79 | + return originalErrorState || customErrorState; | ||
80 | + } | ||
81 | + | ||
82 | + save(): void { | ||
83 | + this.submitted = true; | ||
84 | + this.dialogRef.close(this.attributeLwm2m); | ||
85 | + } | ||
86 | + | ||
87 | + cancel(): void { | ||
88 | + this.dialogRef.close(null); | ||
89 | + } | ||
90 | +} |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2021 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
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> | ||
23 | + <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> | ||
27 | + </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"> | ||
32 | + <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]) }} | ||
37 | + </mat-option> | ||
38 | + </mat-select> | ||
39 | + </mat-form-field> | ||
40 | + <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="mat-block" | ||
41 | + style="max-height: 40px;"> | ||
42 | + <mat-label></mat-label> | ||
43 | + <input [formControl]="keyValControl.get('value')" matInput | ||
44 | + placeholder="{{ ('key-val.value') | translate }}"/> | ||
45 | + </mat-form-field> | ||
46 | + <button mat-button mat-icon-button color="primary" | ||
47 | + [fxShow]="!disabled" | ||
48 | + type="button" | ||
49 | + (click)="removeKeyVal($index)" | ||
50 | + [disabled]="isLoading$ | async" | ||
51 | + matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-remove-tip' | translate }}" | ||
52 | + matTooltipPosition="above"> | ||
53 | + <mat-icon>close</mat-icon> | ||
54 | + </button> | ||
55 | + </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> | ||
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" | ||
75 | + [disabled]="isLoading$ | async" | ||
76 | + (click)="addKeyVal()" | ||
77 | + type="button" | ||
78 | + matTooltip="{{ 'device-profile.lwm2m.attribute-lwm2m-add-tip' | translate }}" | ||
79 | + matTooltipPosition="above"> | ||
80 | + {{ 'action.add' | translate }} | ||
81 | + </button> | ||
82 | + </div> | ||
83 | +</section> |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-key-list.component.ts
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 | + | ||
17 | +import {Component, forwardRef, Input, OnInit} from "@angular/core"; | ||
18 | +import { | ||
19 | + AbstractControl, | ||
20 | + ControlValueAccessor, | ||
21 | + FormArray, | ||
22 | + FormBuilder, | ||
23 | + FormControl, | ||
24 | + FormGroup, | ||
25 | + NG_VALIDATORS, | ||
26 | + NG_VALUE_ACCESSOR, | ||
27 | + Validator, | ||
28 | + Validators | ||
29 | +} from "@angular/forms"; | ||
30 | +import {Subscription} from "rxjs"; | ||
31 | +import {PageComponent} from "@shared/components/page.component"; | ||
32 | +import {Store} from "@ngrx/store"; | ||
33 | +import {AppState} from "@core/core.state"; | ||
34 | +import { | ||
35 | + ATTRIBUTE_KEYS, | ||
36 | + ATTRIBUTE_LWM2M_ENUM, | ||
37 | + ATTRIBUTE_LWM2M_MAP | ||
38 | +} from "@home/components/profile/device/lwm2m/lwm2m-profile-config.models"; | ||
39 | +import {isDefinedAndNotNull, isEmpty, isEmptyStr, isUndefinedOrNull} from "@core/utils"; | ||
40 | + | ||
41 | + | ||
42 | +@Component({ | ||
43 | + selector: 'tb-lwm2m-attributes-key-list', | ||
44 | + templateUrl: './lwm2m-attributes-key-list.component.html', | ||
45 | + styleUrls: ['./lwm2m-attributes.component.scss'], | ||
46 | + providers: [ | ||
47 | + { | ||
48 | + provide: NG_VALUE_ACCESSOR, | ||
49 | + useExisting: forwardRef(() => Lwm2mAttributesKeyListComponent), | ||
50 | + multi: true | ||
51 | + }, | ||
52 | + { | ||
53 | + provide: NG_VALIDATORS, | ||
54 | + useExisting: forwardRef(() => Lwm2mAttributesKeyListComponent), | ||
55 | + multi: true, | ||
56 | + } | ||
57 | + ] | ||
58 | +}) | ||
59 | +export class Lwm2mAttributesKeyListComponent extends PageComponent implements ControlValueAccessor, OnInit, Validator { | ||
60 | + | ||
61 | + attrKeys = ATTRIBUTE_KEYS; | ||
62 | + | ||
63 | + attrKey = ATTRIBUTE_LWM2M_ENUM; | ||
64 | + | ||
65 | + attributeLwm2mMap = ATTRIBUTE_LWM2M_MAP; | ||
66 | + | ||
67 | + @Input() disabled: boolean; | ||
68 | + | ||
69 | + @Input() titleText: string; | ||
70 | + | ||
71 | + @Input() noDataText: string; | ||
72 | + | ||
73 | + kvListFormGroup: FormGroup; | ||
74 | + | ||
75 | + private propagateChange = null; | ||
76 | + | ||
77 | + private valueChangeSubscription: Subscription = null; | ||
78 | + | ||
79 | + constructor(protected store: Store<AppState>, | ||
80 | + private fb: FormBuilder) { | ||
81 | + super(store); | ||
82 | + } | ||
83 | + | ||
84 | + ngOnInit(): void { | ||
85 | + this.kvListFormGroup = this.fb.group({}); | ||
86 | + this.kvListFormGroup.addControl('keyVals', | ||
87 | + this.fb.array([])); | ||
88 | + } | ||
89 | + | ||
90 | + keyValsFormArray(): FormArray { | ||
91 | + return this.kvListFormGroup.get('keyVals') as FormArray; | ||
92 | + } | ||
93 | + | ||
94 | + registerOnChange(fn: any): void { | ||
95 | + this.propagateChange = fn; | ||
96 | + } | ||
97 | + | ||
98 | + registerOnTouched(fn: any): void { | ||
99 | + } | ||
100 | + | ||
101 | + setDisabledState?(isDisabled: boolean): void { | ||
102 | + this.disabled = isDisabled; | ||
103 | + if (this.disabled) { | ||
104 | + this.kvListFormGroup.disable({emitEvent: false}); | ||
105 | + } else { | ||
106 | + this.kvListFormGroup.enable({emitEvent: false}); | ||
107 | + } | ||
108 | + } | ||
109 | + | ||
110 | + writeValue(keyValMap: { [key: string]: string }): void { | ||
111 | + if (this.valueChangeSubscription) { | ||
112 | + this.valueChangeSubscription.unsubscribe(); | ||
113 | + } | ||
114 | + const keyValsControls: Array<AbstractControl> = []; | ||
115 | + 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 | + } | ||
125 | + this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls)); | ||
126 | + this.valueChangeSubscription = this.kvListFormGroup.valueChanges.subscribe(() => { | ||
127 | + // this.updateValidate(); | ||
128 | + this.updateModel(); | ||
129 | + }); | ||
130 | + if (this.disabled) { | ||
131 | + this.kvListFormGroup.disable({emitEvent: false}); | ||
132 | + } else { | ||
133 | + this.kvListFormGroup.enable({emitEvent: false}); | ||
134 | + } | ||
135 | + } | ||
136 | + | ||
137 | + public removeKeyVal(index: number) { | ||
138 | + (this.kvListFormGroup.get('keyVals') as FormArray).removeAt(index); | ||
139 | + } | ||
140 | + | ||
141 | + 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 | + } | ||
161 | + } | ||
162 | + return (valid) ? null : { | ||
163 | + keyVals: { | ||
164 | + valid: false, | ||
165 | + }, | ||
166 | + }; | ||
167 | + } | ||
168 | + | ||
169 | + private updateValidate (c?: FormControl) { | ||
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 | + } | ||
180 | + }); | ||
181 | + } | ||
182 | + | ||
183 | + 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 | + } | ||
200 | + } | ||
201 | + | ||
202 | + | ||
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 | + }; | ||
210 | + } | ||
211 | + } | ||
212 | + return null; | ||
213 | + } | ||
214 | + | ||
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; | ||
222 | + } | ||
223 | + | ||
224 | + private attributeLwm2mValueValidator = (property: string): Object [] => { | ||
225 | + return property === 'ver'? [] : [this.attributeLwm2mValueNumberValidator]; | ||
226 | + } | ||
227 | +} |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2021 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
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> | ||
23 | + <button type="button" | ||
24 | + [disabled]="isDisableBtn()" | ||
25 | + mat-button mat-icon-button | ||
26 | + (click)="editAttributesLwm2m($event)" | ||
27 | + [matTooltip]="(isIconView() ? 'action.view' : isIconEditAdd() ? 'action.edit' : 'action.add' ) | translate" | ||
28 | + matTooltipPosition="above"> | ||
29 | + <mat-icon | ||
30 | + class="material-icons">{{isIconView() ? 'visibility' : isIconEditAdd() ? 'edit' : 'add' }}</mat-icon> | ||
31 | + </button> | ||
32 | +</div> |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.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 | + .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 | + } | ||
27 | + } | ||
28 | +} | ||
29 | + | ||
30 | +:host ::ng-deep { | ||
31 | + .mat-form-field-wrapper { | ||
32 | + padding-bottom: 0; | ||
33 | + } | ||
34 | + .mat-form-field-infix { | ||
35 | + border-top: 0; | ||
36 | + } | ||
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 | +} | ||
61 | + |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.ts
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 | + | ||
17 | +import {Component, EventEmitter, forwardRef, Inject, Input, Output} from "@angular/core"; | ||
18 | +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR} from "@angular/forms"; | ||
19 | +import {coerceBooleanProperty} from "@angular/cdk/coercion"; | ||
20 | +import {Store} from "@ngrx/store"; | ||
21 | +import {AppState} from "@core/core.state"; | ||
22 | +import {DeviceProfileService} from "@core/http/device-profile.service"; | ||
23 | +import {WINDOW} from "@core/services/window.service"; | ||
24 | +import {deepClone, isDefinedAndNotNull, isEmpty} from "@core/utils"; | ||
25 | +import { | ||
26 | + Lwm2mAttributesDialogComponent, | ||
27 | + Lwm2mAttributesDialogData | ||
28 | +} from "@home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component"; | ||
29 | +import {MatDialog} from "@angular/material/dialog"; | ||
30 | +import {TranslateService} from "@ngx-translate/core"; | ||
31 | +import {ATTRIBUTE_LWM2M_LABEL} from "@home/components/profile/device/lwm2m/lwm2m-profile-config.models"; | ||
32 | + | ||
33 | + | ||
34 | +@Component({ | ||
35 | + selector: 'tb-profile-lwm2m-attributes', | ||
36 | + templateUrl: './lwm2m-attributes.component.html', | ||
37 | + styleUrls: ['./lwm2m-attributes.component.scss'], | ||
38 | + providers: [{ | ||
39 | + provide: NG_VALUE_ACCESSOR, | ||
40 | + useExisting: forwardRef(() => Lwm2mAttributesComponent), | ||
41 | + multi: true | ||
42 | + }] | ||
43 | +}) | ||
44 | +export class Lwm2mAttributesComponent implements ControlValueAccessor { | ||
45 | + attributeLwm2mFormGroup: FormGroup; | ||
46 | + attributeLwm2mLabel = ATTRIBUTE_LWM2M_LABEL; | ||
47 | + | ||
48 | + private requiredValue: boolean; | ||
49 | + private dirty = false; | ||
50 | + | ||
51 | + @Input() | ||
52 | + attributeLwm2m: {}; | ||
53 | + | ||
54 | + @Input() | ||
55 | + isAttributeTelemetry: boolean; | ||
56 | + | ||
57 | + @Input() | ||
58 | + destName: string; | ||
59 | + | ||
60 | + @Input() | ||
61 | + disabled: boolean; | ||
62 | + | ||
63 | + @Output() | ||
64 | + updateAttributeLwm2m = new EventEmitter<any>(); | ||
65 | + | ||
66 | + @Input() | ||
67 | + set required(value: boolean) { | ||
68 | + this.requiredValue = coerceBooleanProperty(value); | ||
69 | + } | ||
70 | + | ||
71 | + private propagateChange = (v: any) => { | ||
72 | + } | ||
73 | + | ||
74 | + constructor(private store: Store<AppState>, | ||
75 | + private dialog: MatDialog, | ||
76 | + private fb: FormBuilder, | ||
77 | + private deviceProfileService: DeviceProfileService, | ||
78 | + private translate: TranslateService, | ||
79 | + @Inject(WINDOW) private window: Window) {} | ||
80 | + | ||
81 | + registerOnChange(fn: any): void { | ||
82 | + this.propagateChange = fn; | ||
83 | + } | ||
84 | + | ||
85 | + registerOnTouched(fn: any): void { | ||
86 | + } | ||
87 | + | ||
88 | + setDisabledState(isDisabled: boolean): void { | ||
89 | + this.disabled = isDisabled; | ||
90 | + if (isDisabled) { | ||
91 | + this.attributeLwm2mFormGroup.disable({emitEvent: false}); | ||
92 | + } else { | ||
93 | + this.attributeLwm2mFormGroup.enable({emitEvent: false}); | ||
94 | + } | ||
95 | + } | ||
96 | + | ||
97 | + ngOnInit() { | ||
98 | + this.attributeLwm2mFormGroup = this.fb.group({ | ||
99 | + attributeLwm2m: [this.attributeLwm2m] | ||
100 | + }); | ||
101 | + } | ||
102 | + | ||
103 | + writeValue(value: {} | null): void {} | ||
104 | + | ||
105 | + attributeLwm2mToString = (): string => { | ||
106 | + return this.isIconEditAdd () ? this.attributeLwm2mLabelToString() : this.translate.instant('device-profile.lwm2m.no-data'); | ||
107 | + } | ||
108 | + | ||
109 | + private attributeLwm2mLabelToString = (): string => { | ||
110 | + let label = JSON.stringify(this.attributeLwm2m); | ||
111 | + label = deepClone(label.replace('{', '')); | ||
112 | + label = deepClone(label.replace('}', '')); | ||
113 | + this.attributeLwm2mLabel.forEach((value: string, key: string) => { | ||
114 | + const dest = '\"' + key + '\"\:'; | ||
115 | + label = deepClone(label.replace(dest, value)); | ||
116 | + }); | ||
117 | + return label; | ||
118 | + } | ||
119 | + | ||
120 | + isDisableBtn (): boolean { | ||
121 | + return this.disabled || this.isAttributeTelemetry ? !(isDefinedAndNotNull(this.attributeLwm2m) && | ||
122 | + !isEmpty(this.attributeLwm2m) && this.disabled) : this.disabled; | ||
123 | + } | ||
124 | + | ||
125 | + isIconView (): boolean { | ||
126 | + return this.isAttributeTelemetry || this.disabled; | ||
127 | + } | ||
128 | + | ||
129 | + isIconEditAdd (): boolean { | ||
130 | + return isDefinedAndNotNull(this.attributeLwm2m) && !isEmpty(this.attributeLwm2m); | ||
131 | + } | ||
132 | + | ||
133 | + isToolTipLabel (): string { | ||
134 | + return this.disabled ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip') : | ||
135 | + this.isAttributeTelemetry ? this.translate.instant('device-profile.lwm2m.attribute-lwm2m-disable-tip') : | ||
136 | + this.translate.instant('device-profile.lwm2m.attribute-lwm2m-tip'); | ||
137 | + } | ||
138 | + | ||
139 | + public editAttributesLwm2m = ($event: Event): void => { | ||
140 | + if ($event) { | ||
141 | + $event.stopPropagation(); | ||
142 | + } | ||
143 | + this.dialog.open<Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData, Object>(Lwm2mAttributesDialogComponent, { | ||
144 | + disableClose: true, | ||
145 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
146 | + data: { | ||
147 | + readonly: this.disabled, | ||
148 | + attributeLwm2m: this.disabled ? this.attributeLwm2m : deepClone(this.attributeLwm2m), | ||
149 | + destName: this.destName | ||
150 | + } | ||
151 | + }).afterClosed().subscribe((result) => { | ||
152 | + if (result) { | ||
153 | + this.attributeLwm2m = result; | ||
154 | + this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: this.attributeLwm2m}); | ||
155 | + this.updateAttributeLwm2m.next(this.attributeLwm2m); | ||
156 | + } | ||
157 | + }); | ||
158 | + } | ||
159 | +} |
@@ -14,8 +14,8 @@ | @@ -14,8 +14,8 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, forwardRef, Inject, Input } from '@angular/core'; | ||
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | 17 | +import {Component, forwardRef, Inject, Input} from '@angular/core'; |
18 | +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | ||
19 | import { | 19 | import { |
20 | DEFAULT_CLIENT_HOLD_OFF_TIME, | 20 | DEFAULT_CLIENT_HOLD_OFF_TIME, |
21 | DEFAULT_ID_SERVER, | 21 | DEFAULT_ID_SERVER, |
@@ -27,13 +27,13 @@ import { | @@ -27,13 +27,13 @@ import { | ||
27 | SECURITY_CONFIG_MODE, | 27 | SECURITY_CONFIG_MODE, |
28 | SECURITY_CONFIG_MODE_NAMES, | 28 | SECURITY_CONFIG_MODE_NAMES, |
29 | ServerSecurityConfig | 29 | ServerSecurityConfig |
30 | -} from './profile-config.models'; | ||
31 | -import { Store } from '@ngrx/store'; | ||
32 | -import { AppState } from '@core/core.state'; | ||
33 | -import { coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
34 | -import { WINDOW } from '@core/services/window.service'; | ||
35 | -import { pairwise, startWith } from 'rxjs/operators'; | ||
36 | -import { DeviceProfileService } from '@core/http/device-profile.service'; | 30 | +} from './lwm2m-profile-config.models'; |
31 | +import {Store} from '@ngrx/store'; | ||
32 | +import {AppState} from '@core/core.state'; | ||
33 | +import {coerceBooleanProperty} from '@angular/cdk/coercion'; | ||
34 | +import {WINDOW} from '@core/services/window.service'; | ||
35 | +import {pairwise, startWith} from 'rxjs/operators'; | ||
36 | +import {DeviceProfileService} from '@core/http/device-profile.service'; | ||
37 | 37 | ||
38 | @Component({ | 38 | @Component({ |
39 | selector: 'tb-profile-lwm2m-device-config-server', | 39 | selector: 'tb-profile-lwm2m-device-config-server', |
@@ -22,19 +22,20 @@ import {AppState} from '@app/core/core.state'; | @@ -22,19 +22,20 @@ import {AppState} from '@app/core/core.state'; | ||
22 | import {coerceBooleanProperty} from '@angular/cdk/coercion'; | 22 | import {coerceBooleanProperty} from '@angular/cdk/coercion'; |
23 | import { | 23 | import { |
24 | ATTRIBUTE, | 24 | ATTRIBUTE, |
25 | + DEFAULT_BINDING, | ||
25 | getDefaultProfileConfig, | 26 | getDefaultProfileConfig, |
26 | INSTANCES, | 27 | INSTANCES, |
27 | KEY_NAME, | 28 | KEY_NAME, |
29 | + Lwm2mProfileConfigModels, | ||
28 | ModelValue, | 30 | ModelValue, |
29 | ObjectLwM2M, | 31 | ObjectLwM2M, |
30 | OBSERVE, | 32 | OBSERVE, |
31 | OBSERVE_ATTR_TELEMETRY, | 33 | OBSERVE_ATTR_TELEMETRY, |
32 | - ProfileConfigModels, | ||
33 | RESOURCES, | 34 | RESOURCES, |
34 | TELEMETRY | 35 | TELEMETRY |
35 | -} from './profile-config.models'; | 36 | +} from './lwm2m-profile-config.models'; |
36 | import {DeviceProfileService} from '@core/http/device-profile.service'; | 37 | import {DeviceProfileService} from '@core/http/device-profile.service'; |
37 | -import {deepClone, isDefinedAndNotNull, isUndefined} from '@core/utils'; | 38 | +import {deepClone, isDefinedAndNotNull, isEmpty, isUndefined} from '@core/utils'; |
38 | import {WINDOW} from '@core/services/window.service'; | 39 | import {WINDOW} from '@core/services/window.service'; |
39 | import {JsonArray, JsonObject} from '@angular/compiler-cli/ngcc/src/packages/entry_point'; | 40 | import {JsonArray, JsonObject} from '@angular/compiler-cli/ngcc/src/packages/entry_point'; |
40 | import {Direction} from '@shared/models/page/sort-order'; | 41 | import {Direction} from '@shared/models/page/sort-order'; |
@@ -50,7 +51,7 @@ import {Direction} from '@shared/models/page/sort-order'; | @@ -50,7 +51,7 @@ import {Direction} from '@shared/models/page/sort-order'; | ||
50 | }) | 51 | }) |
51 | export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators { | 52 | export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators { |
52 | 53 | ||
53 | - private configurationValue: ProfileConfigModels; | 54 | + private configurationValue: Lwm2mProfileConfigModels; |
54 | private requiredValue: boolean; | 55 | private requiredValue: boolean; |
55 | private disabled = false; | 56 | private disabled = false; |
56 | 57 | ||
@@ -70,7 +71,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -70,7 +71,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
70 | this.requiredValue = coerceBooleanProperty(value); | 71 | this.requiredValue = coerceBooleanProperty(value); |
71 | } | 72 | } |
72 | 73 | ||
73 | - private propagateChange = (v: any) => { } | 74 | + private propagateChange = (v: any) => { |
75 | + } | ||
74 | 76 | ||
75 | constructor(private store: Store<AppState>, | 77 | constructor(private store: Store<AppState>, |
76 | private fb: FormBuilder, | 78 | private fb: FormBuilder, |
@@ -84,7 +86,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -84,7 +86,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
84 | lifetime: [null, Validators.required], | 86 | lifetime: [null, Validators.required], |
85 | defaultMinPeriod: [null, Validators.required], | 87 | defaultMinPeriod: [null, Validators.required], |
86 | notifIfDisabled: [true, []], | 88 | notifIfDisabled: [true, []], |
87 | - binding: ['U', Validators.required], | 89 | + binding: [DEFAULT_BINDING, Validators.required], |
88 | bootstrapServer: [null, Validators.required], | 90 | bootstrapServer: [null, Validators.required], |
89 | lwm2mServer: [null, Validators.required], | 91 | lwm2mServer: [null, Validators.required], |
90 | }); | 92 | }); |
@@ -118,7 +120,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -118,7 +120,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
118 | } | 120 | } |
119 | } | 121 | } |
120 | 122 | ||
121 | - writeValue(value: ProfileConfigModels | null): void { | 123 | + writeValue(value: Lwm2mProfileConfigModels | null): void { |
122 | this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; | 124 | this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; |
123 | this.lwm2mDeviceConfigFormGroup.patchValue({ | 125 | this.lwm2mDeviceConfigFormGroup.patchValue({ |
124 | configurationJson: this.configurationValue | 126 | configurationJson: this.configurationValue |
@@ -171,7 +173,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -171,7 +173,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
171 | } | 173 | } |
172 | 174 | ||
173 | private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { | 175 | private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { |
174 | - this.lwm2mDeviceProfileFormGroup.patchValue({ | 176 | + this.lwm2mDeviceProfileFormGroup.patchValue({ |
175 | observeAttrTelemetry: deepClone(this.getObserveAttrTelemetryObjects(objectsList)) | 177 | observeAttrTelemetry: deepClone(this.getObserveAttrTelemetryObjects(objectsList)) |
176 | }, | 178 | }, |
177 | {emitEvent: false}); | 179 | {emitEvent: false}); |
@@ -198,15 +200,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -198,15 +200,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
198 | private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => { | 200 | private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => { |
199 | const objectLwM2MS = deepClone(objectList); | 201 | const objectLwM2MS = deepClone(objectList); |
200 | if (this.configurationValue.observeAttr && objectLwM2MS.length > 0) { | 202 | if (this.configurationValue.observeAttr && objectLwM2MS.length > 0) { |
201 | - const observeArray = this.configurationValue.observeAttr.observe; | ||
202 | const attributeArray = this.configurationValue.observeAttr.attribute; | 203 | const attributeArray = this.configurationValue.observeAttr.attribute; |
203 | const telemetryArray = this.configurationValue.observeAttr.telemetry; | 204 | const telemetryArray = this.configurationValue.observeAttr.telemetry; |
204 | let keyNameJson = this.configurationValue.observeAttr.keyName; | 205 | let keyNameJson = this.configurationValue.observeAttr.keyName; |
205 | if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { | 206 | if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { |
206 | this.addInstances(attributeArray, telemetryArray, objectLwM2MS); | 207 | this.addInstances(attributeArray, telemetryArray, objectLwM2MS); |
207 | } | 208 | } |
208 | - if (isDefinedAndNotNull(observeArray) && observeArray.length > 0) { | ||
209 | - this.updateObserveAttrTelemetryObjects(observeArray, objectLwM2MS, OBSERVE); | 209 | + if (isDefinedAndNotNull(this.configurationValue.observeAttr.observe) && |
210 | + this.configurationValue.observeAttr.observe.length > 0) { | ||
211 | + this.updateObserveAttrTelemetryObjects(this.configurationValue.observeAttr.observe, objectLwM2MS, OBSERVE); | ||
210 | } | 212 | } |
211 | if (isDefinedAndNotNull(attributeArray) && attributeArray.length > 0) { | 213 | if (isDefinedAndNotNull(attributeArray) && attributeArray.length > 0) { |
212 | this.updateObserveAttrTelemetryObjects(attributeArray, objectLwM2MS, ATTRIBUTE); | 214 | this.updateObserveAttrTelemetryObjects(attributeArray, objectLwM2MS, ATTRIBUTE); |
@@ -214,6 +216,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -214,6 +216,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
214 | if (isDefinedAndNotNull(telemetryArray) && telemetryArray.length > 0) { | 216 | if (isDefinedAndNotNull(telemetryArray) && telemetryArray.length > 0) { |
215 | this.updateObserveAttrTelemetryObjects(telemetryArray, objectLwM2MS, TELEMETRY); | 217 | this.updateObserveAttrTelemetryObjects(telemetryArray, objectLwM2MS, TELEMETRY); |
216 | } | 218 | } |
219 | + if (isDefinedAndNotNull(this.configurationValue.observeAttr.attributeLwm2m)) { | ||
220 | + this.updateAttributeLwm2m(objectLwM2MS); | ||
221 | + } | ||
217 | if (isDefinedAndNotNull(keyNameJson)) { | 222 | if (isDefinedAndNotNull(keyNameJson)) { |
218 | this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray); | 223 | this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray); |
219 | this.upDateJsonAllConfig(); | 224 | this.upDateJsonAllConfig(); |
@@ -256,45 +261,72 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -256,45 +261,72 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
256 | [nameParameter] = true; | 261 | [nameParameter] = true; |
257 | } | 262 | } |
258 | }); | 263 | }); |
264 | + } | ||
259 | 265 | ||
266 | + private updateAttributeLwm2m = (objectLwM2MS: ObjectLwM2M[]): void => { | ||
267 | + Object.keys(this.configurationValue.observeAttr.attributeLwm2m).forEach(key => { | ||
268 | + const [objectKeyId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), String); | ||
269 | + let objectLwM2M = objectLwM2MS.find(objectLwm2m => objectLwm2m.keyId === objectKeyId); | ||
270 | + if (objectLwM2M && instanceId) { | ||
271 | + let instance = objectLwM2M.instances.find(instance => instance.id === +instanceId) | ||
272 | + if (instance && resourceId) { | ||
273 | + instance.resources.find(resource => resource.id === +resourceId) | ||
274 | + .attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key]; | ||
275 | + } else if (instance) { | ||
276 | + instance.attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key]; | ||
277 | + } | ||
278 | + } else if (objectLwM2M) { | ||
279 | + objectLwM2M.attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key]; | ||
280 | + } | ||
281 | + }); | ||
260 | } | 282 | } |
261 | 283 | ||
262 | - private updateKeyNameObjects = (clientObserveAttrTelemetry: ObjectLwM2M[]): void => { | 284 | + private updateKeyNameObjects = (objectLwM2MS: ObjectLwM2M[]): void => { |
263 | Object.keys(this.configurationValue.observeAttr.keyName).forEach(key => { | 285 | Object.keys(this.configurationValue.observeAttr.keyName).forEach(key => { |
264 | const [objectKeyId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), String); | 286 | const [objectKeyId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), String); |
265 | - const objectLwM2M = clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.keyId === objectKeyId) | 287 | + const objectLwM2M = objectLwM2MS.find(objectLwm2m => objectLwm2m.keyId === objectKeyId) |
266 | if (objectLwM2M) { | 288 | if (objectLwM2M) { |
267 | objectLwM2M.instances.find(instance => instance.id === +instanceId) | 289 | objectLwM2M.instances.find(instance => instance.id === +instanceId) |
268 | - .resources.find(resource => resource.id === +resourceId) | ||
269 | - .keyName = this.configurationValue.observeAttr.keyName[key]; | ||
270 | - }}); | 290 | + .resources.find(resource => resource.id === +resourceId) |
291 | + .keyName = this.configurationValue.observeAttr.keyName[key]; | ||
292 | + } | ||
293 | + }); | ||
271 | } | 294 | } |
272 | 295 | ||
273 | private validateKeyNameObjects = (nameJson: JsonObject, attributeArray: JsonArray, telemetryArray: JsonArray): {} => { | 296 | private validateKeyNameObjects = (nameJson: JsonObject, attributeArray: JsonArray, telemetryArray: JsonArray): {} => { |
274 | const keyName = JSON.parse(JSON.stringify(nameJson)); | 297 | const keyName = JSON.parse(JSON.stringify(nameJson)); |
275 | let keyNameValidate = {}; | 298 | let keyNameValidate = {}; |
276 | - const keyAttrTelemetry = attributeArray.concat(telemetryArray) ; | 299 | + const keyAttrTelemetry = attributeArray.concat(telemetryArray); |
277 | Object.keys(keyName).forEach(key => { | 300 | Object.keys(keyName).forEach(key => { |
278 | if (keyAttrTelemetry.includes(key)) { | 301 | if (keyAttrTelemetry.includes(key)) { |
279 | keyNameValidate[key] = keyName[key]; | 302 | keyNameValidate[key] = keyName[key]; |
280 | } | 303 | } |
281 | }); | 304 | }); |
282 | - return keyNameValidate; | 305 | + return keyNameValidate; |
283 | } | 306 | } |
284 | 307 | ||
285 | private updateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { | 308 | private updateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { |
286 | const observeArray: Array<string> = []; | 309 | const observeArray: Array<string> = []; |
287 | const attributeArray: Array<string> = []; | 310 | const attributeArray: Array<string> = []; |
288 | const telemetryArray: Array<string> = []; | 311 | const telemetryArray: Array<string> = []; |
312 | + const attributeLwm2m: any = {}; | ||
289 | const keyNameNew = {}; | 313 | const keyNameNew = {}; |
290 | const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); | 314 | const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); |
291 | observeJson.forEach(obj => { | 315 | observeJson.forEach(obj => { |
316 | + if (isDefinedAndNotNull(obj.attributeLwm2m) && !isEmpty(obj.attributeLwm2m)) { | ||
317 | + const pathObject = `/${obj.keyId}`; | ||
318 | + attributeLwm2m[pathObject] = obj.attributeLwm2m; | ||
319 | + } | ||
292 | if (obj.hasOwnProperty(INSTANCES) && Array.isArray(obj.instances)) { | 320 | if (obj.hasOwnProperty(INSTANCES) && Array.isArray(obj.instances)) { |
293 | obj.instances.forEach(instance => { | 321 | obj.instances.forEach(instance => { |
322 | + if (isDefinedAndNotNull(instance.attributeLwm2m) && !isEmpty(instance.attributeLwm2m)) { | ||
323 | + const pathInstance = `/${obj.keyId}/${instance.id}`; | ||
324 | + attributeLwm2m[pathInstance] = instance.attributeLwm2m; | ||
325 | + } | ||
294 | if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { | 326 | if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { |
295 | instance.resources.forEach(resource => { | 327 | instance.resources.forEach(resource => { |
296 | if (resource.attribute || resource.telemetry) { | 328 | if (resource.attribute || resource.telemetry) { |
297 | - let pathRes = `/${obj.keyId}/${instance.id}/${resource.id}`; | 329 | + const pathRes = `/${obj.keyId}/${instance.id}/${resource.id}`; |
298 | if (resource.observe) { | 330 | if (resource.observe) { |
299 | observeArray.push(pathRes); | 331 | observeArray.push(pathRes); |
300 | } | 332 | } |
@@ -305,6 +337,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -305,6 +337,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
305 | telemetryArray.push(pathRes); | 337 | telemetryArray.push(pathRes); |
306 | } | 338 | } |
307 | keyNameNew[pathRes] = resource.keyName; | 339 | keyNameNew[pathRes] = resource.keyName; |
340 | + if (isDefinedAndNotNull(resource.attributeLwm2m) && !isEmpty(resource.attributeLwm2m)) { | ||
341 | + attributeLwm2m[pathRes] = resource.attributeLwm2m; | ||
342 | + } | ||
308 | } | 343 | } |
309 | }) | 344 | }) |
310 | } | 345 | } |
@@ -316,13 +351,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -316,13 +351,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
316 | observe: observeArray, | 351 | observe: observeArray, |
317 | attribute: attributeArray, | 352 | attribute: attributeArray, |
318 | telemetry: telemetryArray, | 353 | telemetry: telemetryArray, |
319 | - keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew) | 354 | + keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew), |
355 | + attributeLwm2m: attributeLwm2m | ||
320 | }; | 356 | }; |
321 | } else { | 357 | } else { |
322 | this.configurationValue.observeAttr.observe = observeArray; | 358 | this.configurationValue.observeAttr.observe = observeArray; |
323 | this.configurationValue.observeAttr.attribute = attributeArray; | 359 | this.configurationValue.observeAttr.attribute = attributeArray; |
324 | this.configurationValue.observeAttr.telemetry = telemetryArray; | 360 | this.configurationValue.observeAttr.telemetry = telemetryArray; |
325 | - this.configurationValue.observeAttr.keyName = this.sortObjectKeyPathJson(KEY_NAME, keyNameNew); | 361 | + this.configurationValue.observeAttr.attributeLwm2m = attributeLwm2m; |
326 | } | 362 | } |
327 | } | 363 | } |
328 | 364 | ||
@@ -392,6 +428,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -392,6 +428,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
392 | this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.keyId); | 428 | this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.keyId); |
393 | this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.keyId); | 429 | this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.keyId); |
394 | this.removeKeyNameFromJson(value.keyId); | 430 | this.removeKeyNameFromJson(value.keyId); |
431 | + this.removeAttributeLwm2mFromJson(value.keyId); | ||
395 | this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); | 432 | this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); |
396 | this.upDateJsonAllConfig(); | 433 | this.upDateJsonAllConfig(); |
397 | } | 434 | } |
@@ -413,4 +450,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -413,4 +450,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
413 | } | 450 | } |
414 | }); | 451 | }); |
415 | } | 452 | } |
453 | + | ||
454 | + private removeAttributeLwm2mFromJson = (keyId: string): void => { | ||
455 | + debugger | ||
456 | + const keyNameJson = this.configurationValue.observeAttr.attributeLwm2m; | ||
457 | + Object.keys(keyNameJson).forEach(key => { | ||
458 | + if (key.startsWith(`/${keyId}`)) { | ||
459 | + delete keyNameJson[key]; | ||
460 | + } | ||
461 | + }); | ||
462 | + } | ||
416 | } | 463 | } |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component.html
renamed from
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.html
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | --> | 17 | --> |
18 | <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> | 18 | <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> |
19 | <mat-toolbar fxLayout="row" color="primary"> | 19 | <mat-toolbar fxLayout="row" color="primary"> |
20 | - <b><i>{{data.objectName}}</i></b> (object [<b>{{data.objectKeyId}}</b>]) | 20 | + <b><i>{{data.objectName}}</i></b> (object <<b>{{data.objectKeyId}}</b>>) |
21 | <span fxFlex></span> | 21 | <span fxFlex></span> |
22 | <button mat-button mat-icon-button | 22 | <button mat-button mat-icon-button |
23 | (click)="cancel()" | 23 | (click)="cancel()" |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component.ts
renamed from
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances.component.ts
@@ -30,9 +30,10 @@ export interface Lwm2mObjectAddInstancesData { | @@ -30,9 +30,10 @@ export interface Lwm2mObjectAddInstancesData { | ||
30 | 30 | ||
31 | @Component({ | 31 | @Component({ |
32 | selector: 'tb-lwm2m-object-add-instances', | 32 | selector: 'tb-lwm2m-object-add-instances', |
33 | - templateUrl: './lwm2m-object-add-instances.component.html' | 33 | + templateUrl: './lwm2m-object-add-instances-dialog.component.html' |
34 | }) | 34 | }) |
35 | -export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjectAddInstancesComponent, object> implements OnInit { | 35 | +export class Lwm2mObjectAddInstancesDialogComponent extends DialogComponent<Lwm2mObjectAddInstancesDialogComponent, object> |
36 | + implements OnInit { | ||
36 | 37 | ||
37 | instancesFormGroup: FormGroup; | 38 | instancesFormGroup: FormGroup; |
38 | submitted = false; | 39 | submitted = false; |
@@ -40,7 +41,7 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjec | @@ -40,7 +41,7 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjec | ||
40 | constructor(protected store: Store<AppState>, | 41 | constructor(protected store: Store<AppState>, |
41 | protected router: Router, | 42 | protected router: Router, |
42 | @Inject(MAT_DIALOG_DATA) public data: Lwm2mObjectAddInstancesData, | 43 | @Inject(MAT_DIALOG_DATA) public data: Lwm2mObjectAddInstancesData, |
43 | - public dialogRef: MatDialogRef<Lwm2mObjectAddInstancesComponent, object>, | 44 | + public dialogRef: MatDialogRef<Lwm2mObjectAddInstancesDialogComponent, object>, |
44 | public fb: FormBuilder) { | 45 | public fb: FormBuilder) { |
45 | super(store, router, dialogRef); | 46 | super(store, router, dialogRef); |
46 | } | 47 | } |
@@ -14,11 +14,11 @@ | @@ -14,11 +14,11 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import {Component, forwardRef,} from '@angular/core'; | 17 | +import {Component, forwardRef} from '@angular/core'; |
18 | import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | 18 | import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; |
19 | import {Store} from '@ngrx/store'; | 19 | import {Store} from '@ngrx/store'; |
20 | import {AppState} from '@core/core.state'; | 20 | import {AppState} from '@core/core.state'; |
21 | -import {INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER} from './profile-config.models'; | 21 | +import {INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER} from './lwm2m-profile-config.models'; |
22 | 22 | ||
23 | @Component({ | 23 | @Component({ |
24 | selector: 'tb-profile-lwm2m-object-add-instances-list', | 24 | selector: 'tb-profile-lwm2m-object-add-instances-list', |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | [selectable]="!disabled" | 22 | [selectable]="!disabled" |
23 | [removable]="!disabled" | 23 | [removable]="!disabled" |
24 | (removed)="remove(objectLwm2m)"> | 24 | (removed)="remove(objectLwm2m)"> |
25 | - {{objectLwm2m.name}} | 25 | + {{objectLwm2m.name}} <{{objectLwm2m.keyId}}> |
26 | <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> | 26 | <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> |
27 | </mat-chip> | 27 | </mat-chip> |
28 | <input matInput type="text" placeholder="{{ !disabled ? ('device-profile.lwm2m.object-list' | translate) : '' }}" | 28 | <input matInput type="text" placeholder="{{ !disabled ? ('device-profile.lwm2m.object-list' | translate) : '' }}" |
@@ -21,7 +21,7 @@ import {Store} from '@ngrx/store'; | @@ -21,7 +21,7 @@ import {Store} from '@ngrx/store'; | ||
21 | import {AppState} from '@core/core.state'; | 21 | import {AppState} from '@core/core.state'; |
22 | import {Observable} from 'rxjs'; | 22 | import {Observable} from 'rxjs'; |
23 | import {filter, map, mergeMap, publishReplay, refCount, tap} from 'rxjs/operators'; | 23 | import {filter, map, mergeMap, publishReplay, refCount, tap} from 'rxjs/operators'; |
24 | -import {ModelValue, ObjectLwM2M, PAGE_SIZE_LIMIT} from './profile-config.models'; | 24 | +import {ModelValue, ObjectLwM2M, PAGE_SIZE_LIMIT} from './lwm2m-profile-config.models'; |
25 | import {DeviceProfileService} from '@core/http/device-profile.service'; | 25 | import {DeviceProfileService} from '@core/http/device-profile.service'; |
26 | import {Direction} from '@shared/models/page/sort-order'; | 26 | import {Direction} from '@shared/models/page/sort-order'; |
27 | import {isDefined, isDefinedAndNotNull, isString} from '@core/utils'; | 27 | import {isDefined, isDefinedAndNotNull, isString} from '@core/utils'; |
@@ -19,58 +19,56 @@ | @@ -19,58 +19,56 @@ | ||
19 | <div fxLayout="row" fxFill formArrayName="resources" | 19 | <div fxLayout="row" fxFill formArrayName="resources" |
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 [fxShow]="!i"> | ||
23 | - <div fxFlex="55"></div> | ||
24 | - <div fxFlex="10" fxLayoutAlign="start center"> | ||
25 | - <b> | ||
26 | - <mat-label translate>device-profile.lwm2m.observe-label</mat-label> | ||
27 | - </b> | 22 | + <div fxLayout="row" fxFill fxLayoutAlign="start center" [fxShow]="!i"> |
23 | + <div fxFlex="20"> | ||
24 | + <mat-label translate>device-profile.lwm2m.resource-label</mat-label> | ||
28 | </div> | 25 | </div> |
29 | <div fxFlex="10"> | 26 | <div fxFlex="10"> |
30 | - <b> | ||
31 | <mat-label translate>device-profile.lwm2m.attribute-label</mat-label> | 27 | <mat-label translate>device-profile.lwm2m.attribute-label</mat-label> |
32 | - </b> | ||
33 | </div> | 28 | </div> |
34 | <div fxFlex="10"> | 29 | <div fxFlex="10"> |
35 | - <b> | ||
36 | <mat-label translate>device-profile.lwm2m.telemetry-label</mat-label> | 30 | <mat-label translate>device-profile.lwm2m.telemetry-label</mat-label> |
37 | - </b> | ||
38 | </div> | 31 | </div> |
39 | - <div fxFlex="25"> | ||
40 | - <b> | 32 | + <div fxFlex="10"> |
33 | + <mat-label translate>device-profile.lwm2m.observe-label</mat-label> | ||
34 | + </div> | ||
35 | + <div fxFlex> | ||
41 | <mat-label translate>device-profile.lwm2m.key-name-label</mat-label> | 36 | <mat-label translate>device-profile.lwm2m.key-name-label</mat-label> |
42 | - </b> | ||
43 | </div> | 37 | </div> |
44 | - </div> | ||
45 | - <div fxLayout="row" fxFill fxLayoutAlign="center center"> | ||
46 | - <div fxFlex="55"> | ||
47 | - Resource[<b>{{resourceLwM2M.get('id').value}}</b>] | ||
48 | - name:<b><i>{{resourceLwM2M.get('name').value}}</i></b> | 38 | + <div fxFlex="17" fxFlexOffset="0"> |
39 | + <mat-label translate>device-profile.lwm2m.attribute-lwm2m-label</mat-label> | ||
49 | </div> | 40 | </div> |
50 | - <div fxFlex="10" fxLayoutAlign="start center"> | ||
51 | - <mat-checkbox formControlName="observe" color="primary" | ||
52 | - matTooltip="{{'device-profile.lwm2m.is-observe-tip' | translate}}" | ||
53 | - matTooltipPosition="above"> | ||
54 | - </mat-checkbox> | 41 | + </div> |
42 | + <div fxLayout="row" fxFill fxLayoutAlign="start center"> | ||
43 | + <div class="resource-name-lw" fxFlex="25" | ||
44 | + matTooltip="{{'device-profile.lwm2m.resource-tip' | translate}}" matTooltipPosition="above"> | ||
45 | + <<b>{{resourceLwM2M.get('id').value}}</b>> <b><i>{{resourceLwM2M.get('name').value}}</i></b> | ||
55 | </div> | 46 | </div> |
56 | - <div fxFlex="10"> | 47 | + <div fxFlex="10" fxLayoutAlign="center center"> |
57 | <mat-checkbox formControlName="attribute" color="warn" | 48 | <mat-checkbox formControlName="attribute" color="warn" |
58 | [checked]="updateObserve(i)" | 49 | [checked]="updateObserve(i)" |
59 | matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}" | 50 | matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}" |
60 | matTooltipPosition="above"> | 51 | matTooltipPosition="above"> |
61 | </mat-checkbox> | 52 | </mat-checkbox> |
62 | </div> | 53 | </div> |
63 | - <div fxFlex="10"> | 54 | + <div fxFlex="10" fxLayoutAlign="center center"> |
64 | <mat-checkbox formControlName="telemetry" color="primary" | 55 | <mat-checkbox formControlName="telemetry" color="primary" |
65 | [checked]="updateObserve(i)" | 56 | [checked]="updateObserve(i)" |
66 | matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}" | 57 | matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}" |
67 | matTooltipPosition="above"> | 58 | matTooltipPosition="above"> |
68 | </mat-checkbox> | 59 | </mat-checkbox> |
69 | </div> | 60 | </div> |
61 | + <div fxFlex="10" fxLayoutAlign="center center"> | ||
62 | + <mat-checkbox formControlName="observe" color="primary" | ||
63 | + [disabled]="disableObserve(i)" | ||
64 | + matTooltip="{{(disableObserve(i) ? 'device-profile.lwm2m.not-observe-tip' : 'device-profile.lwm2m.is-observe-tip') | translate}}" | ||
65 | + matTooltipPosition="above"> | ||
66 | + </mat-checkbox> | ||
67 | + </div> | ||
70 | <mat-form-field fxFlex="25"> | 68 | <mat-form-field fxFlex="25"> |
71 | <mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')"> | 69 | <mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')"> |
72 | - {{ 'device-profile.lwm2m.key-name_label' | translate }}</mat-label> | ||
73 | - <input matInput type="text" formControlName="keyName" required | 70 | + {{ 'device-profile.lwm2m.key-name-label' | translate }}</mat-label> |
71 | + <input class="resource-name-lw" matInput type="text" formControlName="keyName" required | ||
74 | matTooltip="{{'device-profile.lwm2m.key-name-tip' | translate}}" | 72 | matTooltip="{{'device-profile.lwm2m.key-name-tip' | translate}}" |
75 | (input)="updateValueKeyName($event, i)" | 73 | (input)="updateValueKeyName($event, i)" |
76 | matTooltipPosition="above"> | 74 | matTooltipPosition="above"> |
@@ -79,6 +77,16 @@ | @@ -79,6 +77,16 @@ | ||
79 | <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> | 77 | <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> |
80 | </mat-error> | 78 | </mat-error> |
81 | </mat-form-field> | 79 | </mat-form-field> |
80 | + <div fxFlex="20" class="resource-name-lw-end" fxFlexOffset="5"> | ||
81 | + <tb-profile-lwm2m-attributes | ||
82 | + formControlName="attributeLwm2m" | ||
83 | + [attributeLwm2m]="resourceLwM2M.get('attributeLwm2m').value" | ||
84 | + [isAttributeTelemetry]="disableObserve(i)" | ||
85 | + [destName]="getNameResourceLwm2m(resourceLwM2M.value)" | ||
86 | + [disabled]="this.disabled" | ||
87 | + (updateAttributeLwm2m)="updateAttributeLwm2m($event, i)"> | ||
88 | + </tb-profile-lwm2m-attributes> | ||
89 | + </div> | ||
82 | </div> | 90 | </div> |
83 | </div> | 91 | </div> |
84 | </div> | 92 | </div> |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | 16 | ||
17 | import {Component, forwardRef, Input} from '@angular/core'; | 17 | import {Component, forwardRef, Input} from '@angular/core'; |
18 | import {ControlValueAccessor, FormArray, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | 18 | import {ControlValueAccessor, FormArray, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; |
19 | -import {ResourceLwM2M} from '@home/components/profile/device/lwm2m/profile-config.models'; | 19 | +import {ResourceLwM2M, RESOURCES} from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; |
20 | import {Store} from '@ngrx/store'; | 20 | import {Store} from '@ngrx/store'; |
21 | import {AppState} from '@core/core.state'; | 21 | import {AppState} from '@core/core.state'; |
22 | import _ from 'lodash'; | 22 | import _ from 'lodash'; |
@@ -25,6 +25,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; | @@ -25,6 +25,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; | ||
25 | @Component({ | 25 | @Component({ |
26 | selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource', | 26 | selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource', |
27 | templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html', | 27 | templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html', |
28 | + styleUrls: ['./lwm2m-attributes.component.scss'], | ||
28 | providers: [ | 29 | providers: [ |
29 | { | 30 | { |
30 | provide: NG_VALUE_ACCESSOR, | 31 | provide: NG_VALUE_ACCESSOR, |
@@ -73,7 +74,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | @@ -73,7 +74,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | ||
73 | } | 74 | } |
74 | 75 | ||
75 | get resourceFormArray(): FormArray{ | 76 | get resourceFormArray(): FormArray{ |
76 | - return this.resourceFormGroup.get('resources') as FormArray; | 77 | + return this.resourceFormGroup.get(RESOURCES) as FormArray; |
77 | } | 78 | } |
78 | 79 | ||
79 | setDisabledState(isDisabled: boolean): void { | 80 | setDisabledState(isDisabled: boolean): void { |
@@ -89,6 +90,14 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | @@ -89,6 +90,14 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | ||
89 | this.resourceFormArray.at(index).patchValue({keyName: _.camelCase((event.target as HTMLInputElement).value)}); | 90 | this.resourceFormArray.at(index).patchValue({keyName: _.camelCase((event.target as HTMLInputElement).value)}); |
90 | } | 91 | } |
91 | 92 | ||
93 | + updateAttributeLwm2m = (event: Event, index: number): void => { | ||
94 | + this.resourceFormArray.at(index).patchValue({attributeLwm2m: event}); | ||
95 | + } | ||
96 | + | ||
97 | + getNameResourceLwm2m = (resourceLwM2M: ResourceLwM2M): string => { | ||
98 | + return '<' + resourceLwM2M.id +'> ' + resourceLwM2M.name; | ||
99 | + } | ||
100 | + | ||
92 | createResourceLwM2M(resourcesLwM2M: ResourceLwM2M[]): void { | 101 | createResourceLwM2M(resourcesLwM2M: ResourceLwM2M[]): void { |
93 | if (resourcesLwM2M.length === this.resourceFormArray.length) { | 102 | if (resourcesLwM2M.length === this.resourceFormArray.length) { |
94 | this.resourceFormArray.patchValue(resourcesLwM2M, {emitEvent: false}); | 103 | this.resourceFormArray.patchValue(resourcesLwM2M, {emitEvent: false}); |
@@ -101,7 +110,8 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | @@ -101,7 +110,8 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | ||
101 | observe: resourceLwM2M.observe, | 110 | observe: resourceLwM2M.observe, |
102 | attribute: resourceLwM2M.attribute, | 111 | attribute: resourceLwM2M.attribute, |
103 | telemetry: resourceLwM2M.telemetry, | 112 | telemetry: resourceLwM2M.telemetry, |
104 | - keyName: [resourceLwM2M.keyName, Validators.required] | 113 | + keyName: [resourceLwM2M.keyName, Validators.required], |
114 | + attributeLwm2m: [resourceLwM2M.attributeLwm2m] | ||
105 | })); | 115 | })); |
106 | }); | 116 | }); |
107 | } | 117 | } |
@@ -128,6 +138,11 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | @@ -128,6 +138,11 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA | ||
128 | updateObserve = (index: number): void =>{ | 138 | updateObserve = (index: number): void =>{ |
129 | if (this.resourceFormArray.at(index).value.attribute === false && this.resourceFormArray.at(index).value.telemetry === false) { | 139 | if (this.resourceFormArray.at(index).value.attribute === false && this.resourceFormArray.at(index).value.telemetry === false) { |
130 | this.resourceFormArray.at(index).patchValue({observe: false}); | 140 | this.resourceFormArray.at(index).patchValue({observe: false}); |
141 | + this.resourceFormArray.at(index).patchValue({attributeLwm2m: {}}); | ||
131 | } | 142 | } |
132 | } | 143 | } |
144 | + | ||
145 | + disableObserve = (index: number): boolean =>{ | ||
146 | + return !this.resourceFormArray.at(index).value.telemetry && !this.resourceFormArray.at(index).value.attribute; | ||
147 | + } | ||
133 | } | 148 | } |
@@ -20,17 +20,27 @@ | @@ -20,17 +20,27 @@ | ||
20 | <mat-expansion-panel | 20 | <mat-expansion-panel |
21 | *ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;" | 21 | *ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;" |
22 | [formGroupName]="i"> | 22 | [formGroupName]="i"> |
23 | - <mat-expansion-panel-header> | ||
24 | - <mat-panel-title fxLayoutAlign="start center"> | ||
25 | - <b><i>{{ objectLwM2M.get('name').value}}</i></b> <id: {{ objectLwM2M.get('keyId').value}}> | 23 | + <mat-expansion-panel-header > |
24 | + <mat-panel-title fxLayoutAlign="start center" > | ||
25 | + <b><i>{{ objectLwM2M.get('name').value}}</i></b> <{{ objectLwM2M.get('keyId').value}}> | ||
26 | + <div fxFlex class="resource-name-lw-end"> | ||
27 | + <tb-profile-lwm2m-attributes | ||
28 | + formControlName="attributeLwm2m" | ||
29 | + [attributeLwm2m]="objectLwM2M.get('attributeLwm2m').value" | ||
30 | + [isAttributeTelemetry]="disableObserveObject(i)" | ||
31 | + [destName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)" | ||
32 | + [disabled]="this.disabled" | ||
33 | + (updateAttributeLwm2m)="updateAttributeLwm2mObject($event, objectLwM2M.get('keyId').value)"> | ||
34 | + </tb-profile-lwm2m-attributes> | ||
35 | + </div> | ||
26 | </mat-panel-title> | 36 | </mat-panel-title> |
27 | - <mat-panel-description fxLayoutAlign="end center" *ngIf="!disabled"> | 37 | + <mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled"> |
28 | <button type="button" | 38 | <button type="button" |
29 | [fxShow]="objectLwM2M.get('multiple').value" | 39 | [fxShow]="objectLwM2M.get('multiple').value" |
30 | mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)" | 40 | mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)" |
31 | matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}" | 41 | matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}" |
32 | matTooltipPosition="above"> | 42 | matTooltipPosition="above"> |
33 | - <mat-icon class="material-icons">{{'add'}}</mat-icon> | 43 | + <mat-icon class="material-icons">{{'note_add'}}</mat-icon> |
34 | </button> | 44 | </button> |
35 | </mat-panel-description> | 45 | </mat-panel-description> |
36 | </mat-expansion-panel-header> | 46 | </mat-expansion-panel-header> |
@@ -45,22 +55,10 @@ | @@ -45,22 +55,10 @@ | ||
45 | <mat-panel-title> | 55 | <mat-panel-title> |
46 | <div class="tb-panel-title-height" fxFlex="100"> | 56 | <div class="tb-panel-title-height" fxFlex="100"> |
47 | <div fxLayout="row" fxFill> | 57 | <div fxLayout="row" fxFill> |
48 | - <div fxFlex="44"> | ||
49 | - Instance [<b>{{instances.get('id').value}}</b>] | 58 | + <div fxFlex="22"> |
59 | + {{'device-profile.lwm2m.instance-label' | translate}} <<b>{{instances.get('id').value}}</b>> | ||
50 | </div> | 60 | </div> |
51 | - <div class="checkbox-padding" fxFlex="10"> | ||
52 | - <mat-checkbox color="primary" | ||
53 | - [disabled]="this.disabled" | ||
54 | - [checked]="getChecked(instances, 'observe')" | ||
55 | - (click)="$event.stopPropagation()" | ||
56 | - (change)="changeInstanceResourcesCheckBox($event.checked, instances, 'observe')" | ||
57 | - (keydown)="$event.stopPropagation()" | ||
58 | - [indeterminate]="getIndeterminate(instances, 'observe')" | ||
59 | - matTooltip="{{'device-profile.lwm2m.is-observe-tip' | translate}}" | ||
60 | - matTooltipPosition="above"> | ||
61 | - </mat-checkbox> | ||
62 | - </div> | ||
63 | - <div class="checkbox-padding" fxFlex="10"> | 61 | + <div class="checkbox-padding" fxFlex="10"> |
64 | <mat-checkbox color="warn" | 62 | <mat-checkbox color="warn" |
65 | [disabled]="this.disabled" | 63 | [disabled]="this.disabled" |
66 | [checked]="getChecked(instances, 'attribute')" | 64 | [checked]="getChecked(instances, 'attribute')" |
@@ -84,7 +82,29 @@ | @@ -84,7 +82,29 @@ | ||
84 | matTooltipPosition="above"> | 82 | matTooltipPosition="above"> |
85 | </mat-checkbox> | 83 | </mat-checkbox> |
86 | </div> | 84 | </div> |
87 | - <div class="checkbox-padding" fxFlex="25"> | 85 | + <div class="checkbox-padding" fxFlex="10"> |
86 | + <mat-checkbox color="primary" | ||
87 | + [disabled]="this.disabled" | ||
88 | + [checked]="getChecked(instances, 'observe')" | ||
89 | + (click)="$event.stopPropagation()" | ||
90 | + (change)="changeInstanceResourcesCheckBox($event.checked, instances, 'observe')" | ||
91 | + (keydown)="$event.stopPropagation()" | ||
92 | + [indeterminate]="getIndeterminate(instances, 'observe')" | ||
93 | + matTooltip="{{'device-profile.lwm2m.is-observe-tip' | translate}}" | ||
94 | + matTooltipPosition="above"> | ||
95 | + </mat-checkbox> | ||
96 | + </div> | ||
97 | + <div fxFlex="10"> | ||
98 | + </div> | ||
99 | + <div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5" disabled="false"> | ||
100 | + <tb-profile-lwm2m-attributes | ||
101 | + formControlName="attributeLwm2m" | ||
102 | + [attributeLwm2m]="instances.get('attributeLwm2m').value" | ||
103 | + [isAttributeTelemetry]="disableObserveInstance(instances)" | ||
104 | + [destName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)" | ||
105 | + [disabled]="this.disabled" | ||
106 | + (updateAttributeLwm2m)="updateAttributeLwm2mInstance($event, y, objectLwM2M.get('keyId').value)"> | ||
107 | + </tb-profile-lwm2m-attributes> | ||
88 | </div> | 108 | </div> |
89 | </div> | 109 | </div> |
90 | </div> | 110 | </div> |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss
renamed from
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.css
@@ -13,14 +13,6 @@ | @@ -13,14 +13,6 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -.vertical-padding { | ||
17 | - padding: 0 0 10px 20px; | ||
18 | -} | ||
19 | - | ||
20 | -.left-padding { | ||
21 | - padding-left: 5px; | ||
22 | -} | ||
23 | - | ||
24 | .tb-panel-title-height { | 16 | .tb-panel-title-height { |
25 | user-select: none; | 17 | user-select: none; |
26 | min-height: 32px; | 18 | min-height: 32px; |
@@ -28,21 +20,5 @@ | @@ -28,21 +20,5 @@ | ||
28 | 20 | ||
29 | .checkbox-padding { | 21 | .checkbox-padding { |
30 | padding-left: 22px; | 22 | padding-left: 22px; |
31 | -} | ||
32 | - | ||
33 | -.label-resource { | ||
34 | - /*padding: 4px;*/ | ||
35 | - color: #002699; | ||
36 | - /*text-transform: uppercase;*/ | ||
37 | - background: rgba(220, 220, 220, .35); | ||
38 | - border-radius: 20px; | ||
39 | - width: inherit; | ||
40 | - /*margin: 10px 0;*/ | ||
41 | - overflow: hidden; | ||
42 | - font-size: 15px; | ||
43 | - text-overflow: ellipsis; | ||
44 | - white-space: nowrap; | ||
45 | - opacity: .8; | ||
46 | text-align:center; | 23 | text-align:center; |
47 | } | 24 | } |
48 | - |
@@ -14,7 +14,6 @@ | @@ -14,7 +14,6 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | - | ||
18 | import {Component, forwardRef, Input} from '@angular/core'; | 17 | import {Component, forwardRef, Input} from '@angular/core'; |
19 | import { | 18 | import { |
20 | AbstractControl, | 19 | AbstractControl, |
@@ -28,19 +27,29 @@ import { | @@ -28,19 +27,29 @@ import { | ||
28 | import {Store} from '@ngrx/store'; | 27 | import {Store} from '@ngrx/store'; |
29 | import {AppState} from '@core/core.state'; | 28 | import {AppState} from '@core/core.state'; |
30 | import {coerceBooleanProperty} from '@angular/cdk/coercion'; | 29 | import {coerceBooleanProperty} from '@angular/cdk/coercion'; |
31 | -import {CLIENT_LWM2M, Instance, INSTANCES, ObjectLwM2M, ResourceLwM2M, RESOURCES} from './profile-config.models'; | 30 | +import { |
31 | + ATTRIBUTE, | ||
32 | + ATTRIBUTE_LWM2M, | ||
33 | + CLIENT_LWM2M, | ||
34 | + Instance, | ||
35 | + INSTANCES, | ||
36 | + ObjectLwM2M, | ||
37 | + ResourceLwM2M, | ||
38 | + RESOURCES, | ||
39 | + TELEMETRY | ||
40 | +} from './lwm2m-profile-config.models'; | ||
32 | import {deepClone, isDefinedAndNotNull, isEqual, isUndefined} from '@core/utils'; | 41 | import {deepClone, isDefinedAndNotNull, isEqual, isUndefined} from '@core/utils'; |
33 | import {MatDialog} from '@angular/material/dialog'; | 42 | import {MatDialog} from '@angular/material/dialog'; |
34 | import {TranslateService} from '@ngx-translate/core'; | 43 | import {TranslateService} from '@ngx-translate/core'; |
35 | import { | 44 | import { |
36 | - Lwm2mObjectAddInstancesComponent, | ||
37 | - Lwm2mObjectAddInstancesData | ||
38 | -} from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances.component'; | 45 | + Lwm2mObjectAddInstancesData, |
46 | + Lwm2mObjectAddInstancesDialogComponent | ||
47 | +} from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component'; | ||
39 | 48 | ||
40 | @Component({ | 49 | @Component({ |
41 | selector: 'tb-profile-lwm2m-observe-attr-telemetry', | 50 | selector: 'tb-profile-lwm2m-observe-attr-telemetry', |
42 | templateUrl: './lwm2m-observe-attr-telemetry.component.html', | 51 | templateUrl: './lwm2m-observe-attr-telemetry.component.html', |
43 | - styleUrls: ['./lwm2m-observe-attr-telemetry.component.css'], | 52 | + styleUrls: [ './lwm2m-observe-attr-telemetry.component.scss'], |
44 | providers: [ | 53 | providers: [ |
45 | { | 54 | { |
46 | provide: NG_VALUE_ACCESSOR, | 55 | provide: NG_VALUE_ACCESSOR, |
@@ -56,6 +65,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -56,6 +65,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
56 | 65 | ||
57 | valuePrev = null as any; | 66 | valuePrev = null as any; |
58 | observeAttrTelemetryFormGroup: FormGroup; | 67 | observeAttrTelemetryFormGroup: FormGroup; |
68 | + resources = RESOURCES; | ||
59 | 69 | ||
60 | get required(): boolean { | 70 | get required(): boolean { |
61 | return this.requiredValue; | 71 | return this.requiredValue; |
@@ -143,6 +153,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -143,6 +153,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
143 | name: objectLwM2M.name, | 153 | name: objectLwM2M.name, |
144 | multiple: objectLwM2M.multiple, | 154 | multiple: objectLwM2M.multiple, |
145 | mandatory: objectLwM2M.mandatory, | 155 | mandatory: objectLwM2M.mandatory, |
156 | + attributeLwm2m: objectLwM2M.attributeLwm2m, | ||
146 | instances: this.createInstanceLwM2M(objectLwM2M.instances) | 157 | instances: this.createInstanceLwM2M(objectLwM2M.instances) |
147 | }); | 158 | }); |
148 | })); | 159 | })); |
@@ -152,6 +163,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -152,6 +163,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
152 | return this.fb.array(instancesLwM2M.map((instanceLwM2M) => { | 163 | return this.fb.array(instancesLwM2M.map((instanceLwM2M) => { |
153 | return this.fb.group({ | 164 | return this.fb.group({ |
154 | id: instanceLwM2M.id, | 165 | id: instanceLwM2M.id, |
166 | + attributeLwm2m: {value: instanceLwM2M.attributeLwm2m, disabled: this.disabled}, | ||
155 | resources: {value: instanceLwM2M.resources, disabled: this.disabled} | 167 | resources: {value: instanceLwM2M.resources, disabled: this.disabled} |
156 | }); | 168 | }); |
157 | })); | 169 | })); |
@@ -222,7 +234,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -222,7 +234,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
222 | $event.stopPropagation(); | 234 | $event.stopPropagation(); |
223 | $event.preventDefault(); | 235 | $event.preventDefault(); |
224 | } | 236 | } |
225 | - this.dialog.open<Lwm2mObjectAddInstancesComponent, Lwm2mObjectAddInstancesData, object>(Lwm2mObjectAddInstancesComponent, { | 237 | + this.dialog.open<Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesData, object>(Lwm2mObjectAddInstancesDialogComponent, { |
226 | disableClose: true, | 238 | disableClose: true, |
227 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | 239 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
228 | data: { | 240 | data: { |
@@ -240,6 +252,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -240,6 +252,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
240 | } | 252 | } |
241 | 253 | ||
242 | private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { | 254 | private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { |
255 | + debugger | ||
243 | const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls | 256 | const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls |
244 | .find(e => e.value.keyId === data.objectKeyId) as FormGroup; | 257 | .find(e => e.value.keyId === data.objectKeyId) as FormGroup; |
245 | const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; | 258 | const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; |
@@ -249,6 +262,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -249,6 +262,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
249 | r.attribute = false; | 262 | r.attribute = false; |
250 | r.telemetry = false; | 263 | r.telemetry = false; |
251 | r.observe = false; | 264 | r.observe = false; |
265 | + r.keyName = {}; | ||
266 | + r.attributeLwm2m = {}; | ||
252 | }); | 267 | }); |
253 | const valueOld = this.instancesToSetId(instancesArray); | 268 | const valueOld = this.instancesToSetId(instancesArray); |
254 | if (!isEqual(valueOld, data.instancesIds)) { | 269 | if (!isEqual(valueOld, data.instancesIds)) { |
@@ -286,6 +301,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -286,6 +301,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
286 | private pushInstance = (instancesFormArray: FormArray, x: number, instanceNew: Instance): void => { | 301 | private pushInstance = (instancesFormArray: FormArray, x: number, instanceNew: Instance): void => { |
287 | instancesFormArray.push(this.fb.group({ | 302 | instancesFormArray.push(this.fb.group({ |
288 | id: x, | 303 | id: x, |
304 | + attributeLwm2m: instanceNew.attributeLwm2m, | ||
289 | resources: {value: instanceNew.resources, disabled: this.disabled} | 305 | resources: {value: instanceNew.resources, disabled: this.disabled} |
290 | })); | 306 | })); |
291 | } | 307 | } |
@@ -297,4 +313,54 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -297,4 +313,54 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
297 | private instancesToSetId = (instances: Instance[]): Set<number> => { | 313 | private instancesToSetId = (instances: Instance[]): Set<number> => { |
298 | return new Set(instances.map(x => x.id)); | 314 | return new Set(instances.map(x => x.id)); |
299 | } | 315 | } |
316 | + | ||
317 | + getNameObjectLwm2m = (objectName: string, idVerObj: string): string => { | ||
318 | + return objectName + ' <' + idVerObj + '>'; | ||
319 | + } | ||
320 | + getNameInstanceLwm2m = (instance: Instance, idVerObj: string): string => { | ||
321 | + return ' instance <' + idVerObj + '/' + instance.id +'>'; | ||
322 | + } | ||
323 | + | ||
324 | + updateAttributeLwm2mObject = (event: Event, objectKeyId: number): void => { | ||
325 | + const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls | ||
326 | + .find(e => e.value.keyId === objectKeyId) as FormGroup; | ||
327 | + objectLwM2MFormGroup.patchValue({attributeLwm2m: event}); | ||
328 | + } | ||
329 | + | ||
330 | + updateAttributeLwm2mInstance = (event: Event, indexInstance: number, objectKeyId: number): void => { | ||
331 | + | ||
332 | + const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls | ||
333 | + .find(e => e.value.keyId === objectKeyId) as FormGroup; | ||
334 | + const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray; | ||
335 | + instancesFormArray.at(indexInstance).patchValue({attributeLwm2m: event}); | ||
336 | + } | ||
337 | + | ||
338 | + disableObserveInstance = (instance: AbstractControl): boolean => { | ||
339 | + const checkedAttrTelemetry = this.observeInstance(instance); | ||
340 | + if (checkedAttrTelemetry) { | ||
341 | + instance.get(ATTRIBUTE_LWM2M).patchValue(null); | ||
342 | + } | ||
343 | + return checkedAttrTelemetry; | ||
344 | + } | ||
345 | + | ||
346 | + disableObserveObject = (index: number): boolean => { | ||
347 | + const object = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).at(index) as FormGroup; | ||
348 | + const instances = object.controls.instances as FormArray; | ||
349 | + const checkedAttrTelemetry = instances.controls.filter(instance => !this.disableObserveInstance(instance)); | ||
350 | + if (checkedAttrTelemetry.length === 0) { | ||
351 | + object.controls.attributeLwm2m.patchValue(null); | ||
352 | + } | ||
353 | + return checkedAttrTelemetry.length === 0; | ||
354 | + } | ||
355 | + | ||
356 | + | ||
357 | + observeInstance = (instance: AbstractControl): boolean => { | ||
358 | + const resources = instance.get(RESOURCES).value as ResourceLwM2M[]; | ||
359 | + if (isDefinedAndNotNull(resources)) { | ||
360 | + const checkedAttribute = resources.filter(resource => resource[ATTRIBUTE]); | ||
361 | + const checkedTelemetry = resources.filter(resource => resource[TELEMETRY]); | ||
362 | + return checkedAttribute.length === 0 && checkedTelemetry.length === 0; | ||
363 | + } | ||
364 | + return false; | ||
365 | + } | ||
300 | } | 366 | } |
@@ -14,16 +14,19 @@ | @@ -14,16 +14,19 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { NgModule } from '@angular/core'; | ||
18 | -import { Lwm2mDeviceProfileTransportConfigurationComponent } from './lwm2m-device-profile-transport-configuration.component'; | ||
19 | -import { Lwm2mObjectListComponent } from './lwm2m-object-list.component'; | ||
20 | -import { Lwm2mObserveAttrTelemetryComponent } from './lwm2m-observe-attr-telemetry.component'; | ||
21 | -import { Lwm2mObserveAttrTelemetryResourceComponent } from './lwm2m-observe-attr-telemetry-resource.component'; | ||
22 | -import { Lwm2mDeviceConfigServerComponent } from './lwm2m-device-config-server.component'; | ||
23 | -import { Lwm2mObjectAddInstancesComponent } from './lwm2m-object-add-instances.component'; | ||
24 | -import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component'; | ||
25 | -import { CommonModule } from '@angular/common'; | ||
26 | -import { SharedModule } from '@app/shared/shared.module'; | 17 | +import {NgModule} from '@angular/core'; |
18 | +import {Lwm2mDeviceProfileTransportConfigurationComponent} from './lwm2m-device-profile-transport-configuration.component'; | ||
19 | +import {Lwm2mObjectListComponent} from './lwm2m-object-list.component'; | ||
20 | +import {Lwm2mObserveAttrTelemetryComponent} from './lwm2m-observe-attr-telemetry.component'; | ||
21 | +import {Lwm2mObserveAttrTelemetryResourceComponent} from './lwm2m-observe-attr-telemetry-resource.component'; | ||
22 | +import {Lwm2mAttributesDialogComponent} from './lwm2m-attributes-dialog.component'; | ||
23 | +import {Lwm2mAttributesComponent} from './lwm2m-attributes.component'; | ||
24 | +import {Lwm2mAttributesKeyListComponent} from './lwm2m-attributes-key-list.component'; | ||
25 | +import {Lwm2mDeviceConfigServerComponent} from './lwm2m-device-config-server.component'; | ||
26 | +import {Lwm2mObjectAddInstancesDialogComponent} from './lwm2m-object-add-instances-dialog.component'; | ||
27 | +import {Lwm2mObjectAddInstancesListComponent} from './lwm2m-object-add-instances-list.component'; | ||
28 | +import {CommonModule} from '@angular/common'; | ||
29 | +import {SharedModule} from '@app/shared/shared.module'; | ||
27 | 30 | ||
28 | @NgModule({ | 31 | @NgModule({ |
29 | declarations: | 32 | declarations: |
@@ -32,8 +35,11 @@ import { SharedModule } from '@app/shared/shared.module'; | @@ -32,8 +35,11 @@ import { SharedModule } from '@app/shared/shared.module'; | ||
32 | Lwm2mObjectListComponent, | 35 | Lwm2mObjectListComponent, |
33 | Lwm2mObserveAttrTelemetryComponent, | 36 | Lwm2mObserveAttrTelemetryComponent, |
34 | Lwm2mObserveAttrTelemetryResourceComponent, | 37 | Lwm2mObserveAttrTelemetryResourceComponent, |
38 | + Lwm2mAttributesDialogComponent, | ||
39 | + Lwm2mAttributesComponent, | ||
40 | + Lwm2mAttributesKeyListComponent, | ||
35 | Lwm2mDeviceConfigServerComponent, | 41 | Lwm2mDeviceConfigServerComponent, |
36 | - Lwm2mObjectAddInstancesComponent, | 42 | + Lwm2mObjectAddInstancesDialogComponent, |
37 | Lwm2mObjectAddInstancesListComponent | 43 | Lwm2mObjectAddInstancesListComponent |
38 | ], | 44 | ], |
39 | imports: [ | 45 | imports: [ |
@@ -45,8 +51,11 @@ import { SharedModule } from '@app/shared/shared.module'; | @@ -45,8 +51,11 @@ import { SharedModule } from '@app/shared/shared.module'; | ||
45 | Lwm2mObjectListComponent, | 51 | Lwm2mObjectListComponent, |
46 | Lwm2mObserveAttrTelemetryComponent, | 52 | Lwm2mObserveAttrTelemetryComponent, |
47 | Lwm2mObserveAttrTelemetryResourceComponent, | 53 | Lwm2mObserveAttrTelemetryResourceComponent, |
54 | + Lwm2mAttributesDialogComponent, | ||
55 | + Lwm2mAttributesComponent, | ||
56 | + Lwm2mAttributesKeyListComponent, | ||
48 | Lwm2mDeviceConfigServerComponent, | 57 | Lwm2mDeviceConfigServerComponent, |
49 | - Lwm2mObjectAddInstancesComponent, | 58 | + Lwm2mObjectAddInstancesDialogComponent, |
50 | Lwm2mObjectAddInstancesListComponent | 59 | Lwm2mObjectAddInstancesListComponent |
51 | ], | 60 | ], |
52 | providers: [ | 61 | providers: [ |
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
renamed from
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/profile-config.models.ts
@@ -16,7 +16,9 @@ | @@ -16,7 +16,9 @@ | ||
16 | 16 | ||
17 | export const PAGE_SIZE_LIMIT = 50; | 17 | export const PAGE_SIZE_LIMIT = 50; |
18 | export const INSTANCES = 'instances'; | 18 | export const INSTANCES = 'instances'; |
19 | +export const INSTANCE = 'instance'; | ||
19 | export const RESOURCES = 'resources'; | 20 | export const RESOURCES = 'resources'; |
21 | +export const ATTRIBUTE_LWM2M = 'attributeLwm2m'; | ||
20 | export const CLIENT_LWM2M = 'clientLwM2M'; | 22 | export const CLIENT_LWM2M = 'clientLwM2M'; |
21 | export const CLIENT_LWM2M_SETTINGS = 'clientLwM2mSettings'; | 23 | export const CLIENT_LWM2M_SETTINGS = 'clientLwM2mSettings'; |
22 | export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; | 24 | export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; |
@@ -33,7 +35,7 @@ export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; | @@ -33,7 +35,7 @@ export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; | ||
33 | export const DEFAULT_LIFE_TIME = 300; | 35 | export const DEFAULT_LIFE_TIME = 300; |
34 | export const DEFAULT_MIN_PERIOD = 1; | 36 | export const DEFAULT_MIN_PERIOD = 1; |
35 | export const DEFAULT_NOTIF_IF_DESIBLED = true; | 37 | export const DEFAULT_NOTIF_IF_DESIBLED = true; |
36 | -export const DEFAULT_BINDING = 'U'; | 38 | +export const DEFAULT_BINDING = 'UQ'; |
37 | export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; | 39 | export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; |
38 | export const LEN_MAX_PUBLIC_KEY_RPK = 182; | 40 | export const LEN_MAX_PUBLIC_KEY_RPK = 182; |
39 | export const LEN_MAX_PUBLIC_KEY_X509 = 3000; | 41 | export const LEN_MAX_PUBLIC_KEY_X509 = 3000; |
@@ -42,6 +44,44 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; | @@ -42,6 +44,44 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; | ||
42 | export const INSTANCES_ID_VALUE_MIN = 0; | 44 | export const INSTANCES_ID_VALUE_MIN = 0; |
43 | export const INSTANCES_ID_VALUE_MAX = 65535; | 45 | export const INSTANCES_ID_VALUE_MAX = 65535; |
44 | 46 | ||
47 | +export enum ATTRIBUTE_LWM2M_ENUM { | ||
48 | + dim = 'dim', | ||
49 | + ver = 'ver', | ||
50 | + pmin = 'pmin', | ||
51 | + pmax = 'pmax', | ||
52 | + gt = 'gt', | ||
53 | + lt = 'lt', | ||
54 | + st = 'st' | ||
55 | +} | ||
56 | + | ||
57 | +export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>( | ||
58 | + [ | ||
59 | + [ATTRIBUTE_LWM2M_ENUM.dim, 'dim='], | ||
60 | + [ATTRIBUTE_LWM2M_ENUM.ver, 'ver='], | ||
61 | + [ATTRIBUTE_LWM2M_ENUM.pmin, 'pmin='], | ||
62 | + [ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='], | ||
63 | + [ATTRIBUTE_LWM2M_ENUM.gt, '>'], | ||
64 | + [ATTRIBUTE_LWM2M_ENUM.lt, '<'], | ||
65 | + [ATTRIBUTE_LWM2M_ENUM.st, 'st='], | ||
66 | + | ||
67 | + ] | ||
68 | +); | ||
69 | + | ||
70 | +export const ATTRIBUTE_LWM2M_MAP = new Map<ATTRIBUTE_LWM2M_ENUM, string>( | ||
71 | + [ | ||
72 | + [ATTRIBUTE_LWM2M_ENUM.dim, 'Dimension'], | ||
73 | + [ATTRIBUTE_LWM2M_ENUM.ver, 'Object version'], | ||
74 | + [ATTRIBUTE_LWM2M_ENUM.pmin, 'Minimum period'], | ||
75 | + [ATTRIBUTE_LWM2M_ENUM.pmax, 'Maximum period'], | ||
76 | + [ATTRIBUTE_LWM2M_ENUM.gt, 'Greater than'], | ||
77 | + [ATTRIBUTE_LWM2M_ENUM.lt, 'Lesser than'], | ||
78 | + [ATTRIBUTE_LWM2M_ENUM.st, 'Step'], | ||
79 | + | ||
80 | + ] | ||
81 | +); | ||
82 | + | ||
83 | +export const ATTRIBUTE_KEYS = Object.keys(ATTRIBUTE_LWM2M_ENUM) as string[]; | ||
84 | + | ||
45 | export enum SECURITY_CONFIG_MODE { | 85 | export enum SECURITY_CONFIG_MODE { |
46 | PSK = 'PSK', | 86 | PSK = 'PSK', |
47 | RPK = 'RPK', | 87 | RPK = 'RPK', |
@@ -54,7 +94,7 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( | @@ -54,7 +94,7 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( | ||
54 | [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], | 94 | [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], |
55 | [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'], | 95 | [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'], |
56 | [SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'], | 96 | [SECURITY_CONFIG_MODE.X509, 'X.509 Certificate'], |
57 | - [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'], | 97 | + [SECURITY_CONFIG_MODE.NO_SEC, 'No Security'] |
58 | ] | 98 | ] |
59 | ); | 99 | ); |
60 | 100 | ||
@@ -90,7 +130,7 @@ interface BootstrapSecurityConfig { | @@ -90,7 +130,7 @@ interface BootstrapSecurityConfig { | ||
90 | lwm2mServer: ServerSecurityConfig; | 130 | lwm2mServer: ServerSecurityConfig; |
91 | } | 131 | } |
92 | 132 | ||
93 | -export interface ProfileConfigModels { | 133 | +export interface Lwm2mProfileConfigModels { |
94 | clientLwM2mSettings: ClientLwM2mSettings; | 134 | clientLwM2mSettings: ClientLwM2mSettings; |
95 | observeAttr: ObservableAttributes; | 135 | observeAttr: ObservableAttributes; |
96 | bootstrap: BootstrapSecurityConfig; | 136 | bootstrap: BootstrapSecurityConfig; |
@@ -100,11 +140,13 @@ export interface ProfileConfigModels { | @@ -100,11 +140,13 @@ export interface ProfileConfigModels { | ||
100 | export interface ClientLwM2mSettings { | 140 | export interface ClientLwM2mSettings { |
101 | clientOnlyObserveAfterConnect: number; | 141 | clientOnlyObserveAfterConnect: number; |
102 | } | 142 | } |
143 | + | ||
103 | export interface ObservableAttributes { | 144 | export interface ObservableAttributes { |
104 | observe: string[]; | 145 | observe: string[]; |
105 | attribute: string[]; | 146 | attribute: string[]; |
106 | telemetry: string[]; | 147 | telemetry: string[]; |
107 | keyName: {}; | 148 | keyName: {}; |
149 | + attributeLwm2m: {}; | ||
108 | } | 150 | } |
109 | 151 | ||
110 | export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { | 152 | export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { |
@@ -151,21 +193,22 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes { | @@ -151,21 +193,22 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes { | ||
151 | observe: [], | 193 | observe: [], |
152 | attribute: [], | 194 | attribute: [], |
153 | telemetry: [], | 195 | telemetry: [], |
154 | - keyName: {} | 196 | + keyName: {}, |
197 | + attributeLwm2m: {} | ||
155 | }; | 198 | }; |
156 | } | 199 | } |
157 | 200 | ||
158 | -function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { | 201 | +export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModels { |
159 | return { | 202 | return { |
160 | - clientOnlyObserveAfterConnect: 1 | 203 | + clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(), |
204 | + observeAttr: getDefaultProfileObserveAttrConfig(), | ||
205 | + bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME) | ||
161 | }; | 206 | }; |
162 | } | 207 | } |
163 | 208 | ||
164 | -export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels { | 209 | +function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { |
165 | return { | 210 | return { |
166 | - clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(), | ||
167 | - observeAttr: getDefaultProfileObserveAttrConfig(), | ||
168 | - bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME) | 211 | + clientOnlyObserveAfterConnect: 1 |
169 | }; | 212 | }; |
170 | } | 213 | } |
171 | 214 | ||
@@ -175,11 +218,13 @@ export interface ResourceLwM2M { | @@ -175,11 +218,13 @@ export interface ResourceLwM2M { | ||
175 | observe: boolean; | 218 | observe: boolean; |
176 | attribute: boolean; | 219 | attribute: boolean; |
177 | telemetry: boolean; | 220 | telemetry: boolean; |
178 | - keyName: string; | 221 | + keyName: {}; |
222 | + attributeLwm2m?: {}; | ||
179 | } | 223 | } |
180 | 224 | ||
181 | export interface Instance { | 225 | export interface Instance { |
182 | id: number; | 226 | id: number; |
227 | + attributeLwm2m?: {}; | ||
183 | resources: ResourceLwM2M[]; | 228 | resources: ResourceLwM2M[]; |
184 | } | 229 | } |
185 | 230 | ||
@@ -190,11 +235,12 @@ export interface Instance { | @@ -190,11 +235,12 @@ export interface Instance { | ||
190 | * mandatory == false => Optional | 235 | * mandatory == false => Optional |
191 | */ | 236 | */ |
192 | export interface ObjectLwM2M { | 237 | export interface ObjectLwM2M { |
238 | + | ||
193 | id: number; | 239 | id: number; |
194 | keyId: string; | 240 | keyId: string; |
195 | name: string; | 241 | name: string; |
196 | multiple?: boolean; | 242 | multiple?: boolean; |
197 | mandatory?: boolean; | 243 | mandatory?: boolean; |
244 | + attributeLwm2m?: {}; | ||
198 | instances?: Instance []; | 245 | instances?: Instance []; |
199 | } | 246 | } |
200 | - |
@@ -1171,17 +1171,32 @@ | @@ -1171,17 +1171,32 @@ | ||
1171 | "instances-list": "Instances list", | 1171 | "instances-list": "Instances list", |
1172 | "instances-input": "Input Instance Id value", | 1172 | "instances-input": "Input Instance Id value", |
1173 | "instances-input-holder": "Input Instance number...", | 1173 | "instances-input-holder": "Input Instance number...", |
1174 | - "resource-label": "Resource", | 1174 | + "instance-label": "Instance", |
1175 | + "resource-label": "<id> Resource name", | ||
1175 | "observe-label": "Observe", | 1176 | "observe-label": "Observe", |
1176 | "attribute-label": "Attribute", | 1177 | "attribute-label": "Attribute", |
1177 | "telemetry-label": "Telemetry", | 1178 | "telemetry-label": "Telemetry", |
1178 | "key-name-label": "Key Name", | 1179 | "key-name-label": "Key Name", |
1180 | + "attribute-lwm2m-label": "AttrLwm2m", | ||
1181 | + "resource-tip": "ID & Original Name of the Resource", | ||
1179 | "is-observe-tip": "Is Observe", | 1182 | "is-observe-tip": "Is Observe", |
1183 | + "not-observe-tip": "To observe select telemetry or attributes first", | ||
1180 | "is-attr-tip": "Is Attribute", | 1184 | "is-attr-tip": "Is Attribute", |
1181 | "is-telemetry-tip": "Is Telemetry", | 1185 | "is-telemetry-tip": "Is Telemetry", |
1182 | - "key-name-tip": "Key Name", | 1186 | + "key-name-tip": "Key Name in Camel format", |
1187 | + "attribute-lwm2m-tip": "Attributes Lwm2m", | ||
1188 | + "attribute-lwm2m-disable-tip": "To edit Attributes Lwm2m select telemetry or attributes first", | ||
1189 | + "valid-attribute-lwm2m-key": "Name have be only '{{attrEnums}}'", | ||
1190 | + "valid-attribute-lwm2m-value": "Value have be Long, Double and greater than zero or null/empty", | ||
1191 | + "no-data": "No attributes", | ||
1183 | "key-name": "Key Name", | 1192 | "key-name": "Key Name", |
1184 | - "key-name_label": "Key Name in Camel format", | 1193 | + "attribute-lwm2m-name": "Name attribute", |
1194 | + "attribute-lwm2m-value": "Value", | ||
1195 | + "attribute-lwm2m-toolbar-edit": "Edit attributes Lwm2m", | ||
1196 | + "attribute-lwm2m-toolbar-view": "View Attributes Lwm2m", | ||
1197 | + "attribute-lwm2m-destination": "Destination:", | ||
1198 | + "attribute-lwm2m-add-tip": "Add attribute lwm2m", | ||
1199 | + "attribute-lwm2m-remove-tip": "Remove attribute lwm2m", | ||
1185 | "required": " value is required.", | 1200 | "required": " value is required.", |
1186 | "mode": "Security config mode", | 1201 | "mode": "Security config mode", |
1187 | "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", | 1202 | "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", |