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 | 30 | import org.springframework.web.bind.annotation.RestController; |
31 | 31 | import org.thingsboard.server.common.data.TbResource; |
32 | 32 | import org.thingsboard.server.common.data.TbResourceInfo; |
33 | -import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
34 | 33 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
35 | 34 | import org.thingsboard.server.common.data.id.TbResourceId; |
36 | 35 | import org.thingsboard.server.common.data.lwm2m.LwM2mObject; |
... | ... | @@ -42,10 +41,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; |
42 | 41 | import org.thingsboard.server.service.security.permission.Operation; |
43 | 42 | import org.thingsboard.server.service.security.permission.Resource; |
44 | 43 | |
45 | -import java.util.ArrayList; | |
46 | 44 | import java.util.Base64; |
47 | 45 | import java.util.List; |
48 | -import java.util.StringJoiner; | |
49 | 46 | |
50 | 47 | @Slf4j |
51 | 48 | @RestController |
... | ... | @@ -111,25 +108,13 @@ public class TbResourceController extends BaseController { |
111 | 108 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
112 | 109 | @RequestMapping(value = "/resource", method = RequestMethod.POST) |
113 | 110 | @ResponseBody |
114 | - public List<TbResource> saveResources(@RequestBody List<TbResource> resources) throws ThingsboardException { | |
111 | + public TbResource saveResource(@RequestBody TbResource resource) throws ThingsboardException { | |
115 | 112 | try { |
116 | - List<TbResource> addResources = new ArrayList<>(); | |
117 | - StringJoiner noSaveResources = new StringJoiner("; "); | |
118 | - resources.forEach(resource -> { | |
119 | - try { | |
120 | 113 | resource.setTenantId(getTenantId()); |
121 | 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 | 118 | throw handleException(e); |
134 | 119 | } |
135 | 120 | } | ... | ... |
... | ... | @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.security.Authority; |
32 | 32 | import java.util.ArrayList; |
33 | 33 | import java.util.Collections; |
34 | 34 | import java.util.List; |
35 | -import java.util.stream.Collectors; | |
36 | 35 | |
37 | 36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
38 | 37 | |
... | ... | @@ -110,7 +109,7 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes |
110 | 109 | TbResource savedResource = save(resource); |
111 | 110 | |
112 | 111 | loginDifferentTenant(); |
113 | - doPostWithTypedResponse("/api/resource", Collections.singletonList(savedResource), new TypeReference<>(){}, status().isBadRequest()); | |
112 | + doPostWithTypedResponse("/api/resource", savedResource, new TypeReference<>(){}, status().isForbidden()); | |
114 | 113 | deleteDifferentTenant(); |
115 | 114 | } |
116 | 115 | |
... | ... | @@ -148,18 +147,15 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes |
148 | 147 | |
149 | 148 | @Test |
150 | 149 | public void testFindTenantTbResources() throws Exception { |
151 | - List<TbResource> resourcesToSave = new ArrayList<>(); | |
150 | + List<TbResourceInfo> resources = new ArrayList<>(); | |
152 | 151 | for (int i = 0; i < 173; i++) { |
153 | 152 | TbResource resource = new TbResource(); |
154 | 153 | resource.setTitle("Resource" + i); |
155 | 154 | resource.setResourceType(ResourceType.JKS); |
156 | 155 | resource.setFileName(i + DEFAULT_FILE_NAME); |
157 | 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 | 159 | List<TbResourceInfo> loadedResources = new ArrayList<>(); |
164 | 160 | PageLink pageLink = new PageLink(24); |
165 | 161 | PageData<TbResourceInfo> pageData; |
... | ... | @@ -287,10 +283,6 @@ public abstract class BaseTbResourceControllerTest extends AbstractControllerTes |
287 | 283 | } |
288 | 284 | |
289 | 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 | 28 | @ClasspathSuite.ClassnameFilters({ |
29 | 29 | // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", |
30 | 30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", |
31 | +// "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", | |
31 | 32 | "org.thingsboard.server.controller.sql.*Test", |
32 | 33 | }) |
33 | 34 | public class ControllerSqlTestSuite { | ... | ... |
... | ... | @@ -122,7 +122,7 @@ public class LwM2mTransportRequest { |
122 | 122 | DownlinkRequest request = null; |
123 | 123 | ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; |
124 | 124 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
125 | - ResourceModel resource = lwM2MClient.getResourceModel(target); | |
125 | + ResourceModel resource = lwM2MClient.getResourceModel(targetIdVer); | |
126 | 126 | timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; |
127 | 127 | switch (typeOper) { |
128 | 128 | case GET_TYPE_OPER_READ: | ... | ... |
... | ... | @@ -22,7 +22,7 @@ import {Observable} from 'rxjs'; |
22 | 22 | import {PageData} from '@shared/models/page/page-data'; |
23 | 23 | import {DeviceProfile, DeviceProfileInfo, DeviceTransportType} from '@shared/models/device.models'; |
24 | 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 | 26 | import {SortOrder} from '@shared/models/page/sort-order'; |
27 | 27 | |
28 | 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 | 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 | 19 | import { |
20 | 20 | DEFAULT_CLIENT_HOLD_OFF_TIME, |
21 | 21 | DEFAULT_ID_SERVER, |
... | ... | @@ -27,13 +27,13 @@ import { |
27 | 27 | SECURITY_CONFIG_MODE, |
28 | 28 | SECURITY_CONFIG_MODE_NAMES, |
29 | 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 | 38 | @Component({ |
39 | 39 | selector: 'tb-profile-lwm2m-device-config-server', | ... | ... |
... | ... | @@ -22,19 +22,20 @@ import {AppState} from '@app/core/core.state'; |
22 | 22 | import {coerceBooleanProperty} from '@angular/cdk/coercion'; |
23 | 23 | import { |
24 | 24 | ATTRIBUTE, |
25 | + DEFAULT_BINDING, | |
25 | 26 | getDefaultProfileConfig, |
26 | 27 | INSTANCES, |
27 | 28 | KEY_NAME, |
29 | + Lwm2mProfileConfigModels, | |
28 | 30 | ModelValue, |
29 | 31 | ObjectLwM2M, |
30 | 32 | OBSERVE, |
31 | 33 | OBSERVE_ATTR_TELEMETRY, |
32 | - ProfileConfigModels, | |
33 | 34 | RESOURCES, |
34 | 35 | TELEMETRY |
35 | -} from './profile-config.models'; | |
36 | +} from './lwm2m-profile-config.models'; | |
36 | 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 | 39 | import {WINDOW} from '@core/services/window.service'; |
39 | 40 | import {JsonArray, JsonObject} from '@angular/compiler-cli/ngcc/src/packages/entry_point'; |
40 | 41 | import {Direction} from '@shared/models/page/sort-order'; |
... | ... | @@ -50,7 +51,7 @@ import {Direction} from '@shared/models/page/sort-order'; |
50 | 51 | }) |
51 | 52 | export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, Validators { |
52 | 53 | |
53 | - private configurationValue: ProfileConfigModels; | |
54 | + private configurationValue: Lwm2mProfileConfigModels; | |
54 | 55 | private requiredValue: boolean; |
55 | 56 | private disabled = false; |
56 | 57 | |
... | ... | @@ -70,7 +71,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
70 | 71 | this.requiredValue = coerceBooleanProperty(value); |
71 | 72 | } |
72 | 73 | |
73 | - private propagateChange = (v: any) => { } | |
74 | + private propagateChange = (v: any) => { | |
75 | + } | |
74 | 76 | |
75 | 77 | constructor(private store: Store<AppState>, |
76 | 78 | private fb: FormBuilder, |
... | ... | @@ -84,7 +86,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
84 | 86 | lifetime: [null, Validators.required], |
85 | 87 | defaultMinPeriod: [null, Validators.required], |
86 | 88 | notifIfDisabled: [true, []], |
87 | - binding: ['U', Validators.required], | |
89 | + binding: [DEFAULT_BINDING, Validators.required], | |
88 | 90 | bootstrapServer: [null, Validators.required], |
89 | 91 | lwm2mServer: [null, Validators.required], |
90 | 92 | }); |
... | ... | @@ -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 | 124 | this.configurationValue = (Object.keys(value).length === 0) ? getDefaultProfileConfig() : value; |
123 | 125 | this.lwm2mDeviceConfigFormGroup.patchValue({ |
124 | 126 | configurationJson: this.configurationValue |
... | ... | @@ -171,7 +173,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
171 | 173 | } |
172 | 174 | |
173 | 175 | private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { |
174 | - this.lwm2mDeviceProfileFormGroup.patchValue({ | |
176 | + this.lwm2mDeviceProfileFormGroup.patchValue({ | |
175 | 177 | observeAttrTelemetry: deepClone(this.getObserveAttrTelemetryObjects(objectsList)) |
176 | 178 | }, |
177 | 179 | {emitEvent: false}); |
... | ... | @@ -198,15 +200,15 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
198 | 200 | private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => { |
199 | 201 | const objectLwM2MS = deepClone(objectList); |
200 | 202 | if (this.configurationValue.observeAttr && objectLwM2MS.length > 0) { |
201 | - const observeArray = this.configurationValue.observeAttr.observe; | |
202 | 203 | const attributeArray = this.configurationValue.observeAttr.attribute; |
203 | 204 | const telemetryArray = this.configurationValue.observeAttr.telemetry; |
204 | 205 | let keyNameJson = this.configurationValue.observeAttr.keyName; |
205 | 206 | if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { |
206 | 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 | 213 | if (isDefinedAndNotNull(attributeArray) && attributeArray.length > 0) { |
212 | 214 | this.updateObserveAttrTelemetryObjects(attributeArray, objectLwM2MS, ATTRIBUTE); |
... | ... | @@ -214,6 +216,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
214 | 216 | if (isDefinedAndNotNull(telemetryArray) && telemetryArray.length > 0) { |
215 | 217 | this.updateObserveAttrTelemetryObjects(telemetryArray, objectLwM2MS, TELEMETRY); |
216 | 218 | } |
219 | + if (isDefinedAndNotNull(this.configurationValue.observeAttr.attributeLwm2m)) { | |
220 | + this.updateAttributeLwm2m(objectLwM2MS); | |
221 | + } | |
217 | 222 | if (isDefinedAndNotNull(keyNameJson)) { |
218 | 223 | this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray); |
219 | 224 | this.upDateJsonAllConfig(); |
... | ... | @@ -256,45 +261,72 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
256 | 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 | 285 | Object.keys(this.configurationValue.observeAttr.keyName).forEach(key => { |
264 | 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 | 288 | if (objectLwM2M) { |
267 | 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 | 296 | private validateKeyNameObjects = (nameJson: JsonObject, attributeArray: JsonArray, telemetryArray: JsonArray): {} => { |
274 | 297 | const keyName = JSON.parse(JSON.stringify(nameJson)); |
275 | 298 | let keyNameValidate = {}; |
276 | - const keyAttrTelemetry = attributeArray.concat(telemetryArray) ; | |
299 | + const keyAttrTelemetry = attributeArray.concat(telemetryArray); | |
277 | 300 | Object.keys(keyName).forEach(key => { |
278 | 301 | if (keyAttrTelemetry.includes(key)) { |
279 | 302 | keyNameValidate[key] = keyName[key]; |
280 | 303 | } |
281 | 304 | }); |
282 | - return keyNameValidate; | |
305 | + return keyNameValidate; | |
283 | 306 | } |
284 | 307 | |
285 | 308 | private updateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { |
286 | 309 | const observeArray: Array<string> = []; |
287 | 310 | const attributeArray: Array<string> = []; |
288 | 311 | const telemetryArray: Array<string> = []; |
312 | + const attributeLwm2m: any = {}; | |
289 | 313 | const keyNameNew = {}; |
290 | 314 | const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); |
291 | 315 | observeJson.forEach(obj => { |
316 | + if (isDefinedAndNotNull(obj.attributeLwm2m) && !isEmpty(obj.attributeLwm2m)) { | |
317 | + const pathObject = `/${obj.keyId}`; | |
318 | + attributeLwm2m[pathObject] = obj.attributeLwm2m; | |
319 | + } | |
292 | 320 | if (obj.hasOwnProperty(INSTANCES) && Array.isArray(obj.instances)) { |
293 | 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 | 326 | if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { |
295 | 327 | instance.resources.forEach(resource => { |
296 | 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 | 330 | if (resource.observe) { |
299 | 331 | observeArray.push(pathRes); |
300 | 332 | } |
... | ... | @@ -305,6 +337,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro |
305 | 337 | telemetryArray.push(pathRes); |
306 | 338 | } |
307 | 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 | 351 | observe: observeArray, |
317 | 352 | attribute: attributeArray, |
318 | 353 | telemetry: telemetryArray, |
319 | - keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew) | |
354 | + keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew), | |
355 | + attributeLwm2m: attributeLwm2m | |
320 | 356 | }; |
321 | 357 | } else { |
322 | 358 | this.configurationValue.observeAttr.observe = observeArray; |
323 | 359 | this.configurationValue.observeAttr.attribute = attributeArray; |
324 | 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 | 428 | this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.keyId); |
393 | 429 | this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.keyId); |
394 | 430 | this.removeKeyNameFromJson(value.keyId); |
431 | + this.removeAttributeLwm2mFromJson(value.keyId); | |
395 | 432 | this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); |
396 | 433 | this.upDateJsonAllConfig(); |
397 | 434 | } |
... | ... | @@ -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 | 17 | --> |
18 | 18 | <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> |
19 | 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 | 21 | <span fxFlex></span> |
22 | 22 | <button mat-button mat-icon-button |
23 | 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 | 30 | |
31 | 31 | @Component({ |
32 | 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 | 38 | instancesFormGroup: FormGroup; |
38 | 39 | submitted = false; |
... | ... | @@ -40,7 +41,7 @@ export class Lwm2mObjectAddInstancesComponent extends DialogComponent<Lwm2mObjec |
40 | 41 | constructor(protected store: Store<AppState>, |
41 | 42 | protected router: Router, |
42 | 43 | @Inject(MAT_DIALOG_DATA) public data: Lwm2mObjectAddInstancesData, |
43 | - public dialogRef: MatDialogRef<Lwm2mObjectAddInstancesComponent, object>, | |
44 | + public dialogRef: MatDialogRef<Lwm2mObjectAddInstancesDialogComponent, object>, | |
44 | 45 | public fb: FormBuilder) { |
45 | 46 | super(store, router, dialogRef); |
46 | 47 | } | ... | ... |
... | ... | @@ -14,11 +14,11 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import {Component, forwardRef,} from '@angular/core'; | |
17 | +import {Component, forwardRef} from '@angular/core'; | |
18 | 18 | import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; |
19 | 19 | import {Store} from '@ngrx/store'; |
20 | 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 | 23 | @Component({ |
24 | 24 | selector: 'tb-profile-lwm2m-object-add-instances-list', | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | [selectable]="!disabled" |
23 | 23 | [removable]="!disabled" |
24 | 24 | (removed)="remove(objectLwm2m)"> |
25 | - {{objectLwm2m.name}} | |
25 | + {{objectLwm2m.name}} <{{objectLwm2m.keyId}}> | |
26 | 26 | <mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> |
27 | 27 | </mat-chip> |
28 | 28 | <input matInput type="text" placeholder="{{ !disabled ? ('device-profile.lwm2m.object-list' | translate) : '' }}" | ... | ... |
... | ... | @@ -21,7 +21,7 @@ import {Store} from '@ngrx/store'; |
21 | 21 | import {AppState} from '@core/core.state'; |
22 | 22 | import {Observable} from 'rxjs'; |
23 | 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 | 25 | import {DeviceProfileService} from '@core/http/device-profile.service'; |
26 | 26 | import {Direction} from '@shared/models/page/sort-order'; |
27 | 27 | import {isDefined, isDefinedAndNotNull, isString} from '@core/utils'; | ... | ... |
... | ... | @@ -19,58 +19,56 @@ |
19 | 19 | <div fxLayout="row" fxFill formArrayName="resources" |
20 | 20 | *ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams"> |
21 | 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 | 25 | </div> |
29 | 26 | <div fxFlex="10"> |
30 | - <b> | |
31 | 27 | <mat-label translate>device-profile.lwm2m.attribute-label</mat-label> |
32 | - </b> | |
33 | 28 | </div> |
34 | 29 | <div fxFlex="10"> |
35 | - <b> | |
36 | 30 | <mat-label translate>device-profile.lwm2m.telemetry-label</mat-label> |
37 | - </b> | |
38 | 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 | 36 | <mat-label translate>device-profile.lwm2m.key-name-label</mat-label> |
42 | - </b> | |
43 | 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 | 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 | 46 | </div> |
56 | - <div fxFlex="10"> | |
47 | + <div fxFlex="10" fxLayoutAlign="center center"> | |
57 | 48 | <mat-checkbox formControlName="attribute" color="warn" |
58 | 49 | [checked]="updateObserve(i)" |
59 | 50 | matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}" |
60 | 51 | matTooltipPosition="above"> |
61 | 52 | </mat-checkbox> |
62 | 53 | </div> |
63 | - <div fxFlex="10"> | |
54 | + <div fxFlex="10" fxLayoutAlign="center center"> | |
64 | 55 | <mat-checkbox formControlName="telemetry" color="primary" |
65 | 56 | [checked]="updateObserve(i)" |
66 | 57 | matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}" |
67 | 58 | matTooltipPosition="above"> |
68 | 59 | </mat-checkbox> |
69 | 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 | 68 | <mat-form-field fxFlex="25"> |
71 | 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 | 72 | matTooltip="{{'device-profile.lwm2m.key-name-tip' | translate}}" |
75 | 73 | (input)="updateValueKeyName($event, i)" |
76 | 74 | matTooltipPosition="above"> |
... | ... | @@ -79,6 +77,16 @@ |
79 | 77 | <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> |
80 | 78 | </mat-error> |
81 | 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 | 90 | </div> |
83 | 91 | </div> |
84 | 92 | </div> | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | |
17 | 17 | import {Component, forwardRef, Input} from '@angular/core'; |
18 | 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 | 20 | import {Store} from '@ngrx/store'; |
21 | 21 | import {AppState} from '@core/core.state'; |
22 | 22 | import _ from 'lodash'; |
... | ... | @@ -25,6 +25,7 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion'; |
25 | 25 | @Component({ |
26 | 26 | selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource', |
27 | 27 | templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html', |
28 | + styleUrls: ['./lwm2m-attributes.component.scss'], | |
28 | 29 | providers: [ |
29 | 30 | { |
30 | 31 | provide: NG_VALUE_ACCESSOR, |
... | ... | @@ -73,7 +74,7 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA |
73 | 74 | } |
74 | 75 | |
75 | 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 | 80 | setDisabledState(isDisabled: boolean): void { |
... | ... | @@ -89,6 +90,14 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA |
89 | 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 | 101 | createResourceLwM2M(resourcesLwM2M: ResourceLwM2M[]): void { |
93 | 102 | if (resourcesLwM2M.length === this.resourceFormArray.length) { |
94 | 103 | this.resourceFormArray.patchValue(resourcesLwM2M, {emitEvent: false}); |
... | ... | @@ -101,7 +110,8 @@ export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueA |
101 | 110 | observe: resourceLwM2M.observe, |
102 | 111 | attribute: resourceLwM2M.attribute, |
103 | 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 | 138 | updateObserve = (index: number): void =>{ |
129 | 139 | if (this.resourceFormArray.at(index).value.attribute === false && this.resourceFormArray.at(index).value.telemetry === false) { |
130 | 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 | 20 | <mat-expansion-panel |
21 | 21 | *ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;" |
22 | 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 | 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 | 38 | <button type="button" |
29 | 39 | [fxShow]="objectLwM2M.get('multiple').value" |
30 | 40 | mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)" |
31 | 41 | matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}" |
32 | 42 | matTooltipPosition="above"> |
33 | - <mat-icon class="material-icons">{{'add'}}</mat-icon> | |
43 | + <mat-icon class="material-icons">{{'note_add'}}</mat-icon> | |
34 | 44 | </button> |
35 | 45 | </mat-panel-description> |
36 | 46 | </mat-expansion-panel-header> |
... | ... | @@ -45,22 +55,10 @@ |
45 | 55 | <mat-panel-title> |
46 | 56 | <div class="tb-panel-title-height" fxFlex="100"> |
47 | 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 | 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 | 62 | <mat-checkbox color="warn" |
65 | 63 | [disabled]="this.disabled" |
66 | 64 | [checked]="getChecked(instances, 'attribute')" |
... | ... | @@ -84,7 +82,29 @@ |
84 | 82 | matTooltipPosition="above"> |
85 | 83 | </mat-checkbox> |
86 | 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 | 108 | </div> |
89 | 109 | </div> |
90 | 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 | 13 | * See the License for the specific language governing permissions and |
14 | 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 | 16 | .tb-panel-title-height { |
25 | 17 | user-select: none; |
26 | 18 | min-height: 32px; |
... | ... | @@ -28,21 +20,5 @@ |
28 | 20 | |
29 | 21 | .checkbox-padding { |
30 | 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 | 23 | text-align:center; |
47 | 24 | } |
48 | - | ... | ... |
... | ... | @@ -14,7 +14,6 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | - | |
18 | 17 | import {Component, forwardRef, Input} from '@angular/core'; |
19 | 18 | import { |
20 | 19 | AbstractControl, |
... | ... | @@ -28,19 +27,29 @@ import { |
28 | 27 | import {Store} from '@ngrx/store'; |
29 | 28 | import {AppState} from '@core/core.state'; |
30 | 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 | 41 | import {deepClone, isDefinedAndNotNull, isEqual, isUndefined} from '@core/utils'; |
33 | 42 | import {MatDialog} from '@angular/material/dialog'; |
34 | 43 | import {TranslateService} from '@ngx-translate/core'; |
35 | 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 | 49 | @Component({ |
41 | 50 | selector: 'tb-profile-lwm2m-observe-attr-telemetry', |
42 | 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 | 53 | providers: [ |
45 | 54 | { |
46 | 55 | provide: NG_VALUE_ACCESSOR, |
... | ... | @@ -56,6 +65,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
56 | 65 | |
57 | 66 | valuePrev = null as any; |
58 | 67 | observeAttrTelemetryFormGroup: FormGroup; |
68 | + resources = RESOURCES; | |
59 | 69 | |
60 | 70 | get required(): boolean { |
61 | 71 | return this.requiredValue; |
... | ... | @@ -143,6 +153,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
143 | 153 | name: objectLwM2M.name, |
144 | 154 | multiple: objectLwM2M.multiple, |
145 | 155 | mandatory: objectLwM2M.mandatory, |
156 | + attributeLwm2m: objectLwM2M.attributeLwm2m, | |
146 | 157 | instances: this.createInstanceLwM2M(objectLwM2M.instances) |
147 | 158 | }); |
148 | 159 | })); |
... | ... | @@ -152,6 +163,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
152 | 163 | return this.fb.array(instancesLwM2M.map((instanceLwM2M) => { |
153 | 164 | return this.fb.group({ |
154 | 165 | id: instanceLwM2M.id, |
166 | + attributeLwm2m: {value: instanceLwM2M.attributeLwm2m, disabled: this.disabled}, | |
155 | 167 | resources: {value: instanceLwM2M.resources, disabled: this.disabled} |
156 | 168 | }); |
157 | 169 | })); |
... | ... | @@ -222,7 +234,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
222 | 234 | $event.stopPropagation(); |
223 | 235 | $event.preventDefault(); |
224 | 236 | } |
225 | - this.dialog.open<Lwm2mObjectAddInstancesComponent, Lwm2mObjectAddInstancesData, object>(Lwm2mObjectAddInstancesComponent, { | |
237 | + this.dialog.open<Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesData, object>(Lwm2mObjectAddInstancesDialogComponent, { | |
226 | 238 | disableClose: true, |
227 | 239 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
228 | 240 | data: { |
... | ... | @@ -240,6 +252,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
240 | 252 | } |
241 | 253 | |
242 | 254 | private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { |
255 | + debugger | |
243 | 256 | const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls |
244 | 257 | .find(e => e.value.keyId === data.objectKeyId) as FormGroup; |
245 | 258 | const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; |
... | ... | @@ -249,6 +262,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
249 | 262 | r.attribute = false; |
250 | 263 | r.telemetry = false; |
251 | 264 | r.observe = false; |
265 | + r.keyName = {}; | |
266 | + r.attributeLwm2m = {}; | |
252 | 267 | }); |
253 | 268 | const valueOld = this.instancesToSetId(instancesArray); |
254 | 269 | if (!isEqual(valueOld, data.instancesIds)) { |
... | ... | @@ -286,6 +301,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
286 | 301 | private pushInstance = (instancesFormArray: FormArray, x: number, instanceNew: Instance): void => { |
287 | 302 | instancesFormArray.push(this.fb.group({ |
288 | 303 | id: x, |
304 | + attributeLwm2m: instanceNew.attributeLwm2m, | |
289 | 305 | resources: {value: instanceNew.resources, disabled: this.disabled} |
290 | 306 | })); |
291 | 307 | } |
... | ... | @@ -297,4 +313,54 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
297 | 313 | private instancesToSetId = (instances: Instance[]): Set<number> => { |
298 | 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 | 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 | 31 | @NgModule({ |
29 | 32 | declarations: |
... | ... | @@ -32,8 +35,11 @@ import { SharedModule } from '@app/shared/shared.module'; |
32 | 35 | Lwm2mObjectListComponent, |
33 | 36 | Lwm2mObserveAttrTelemetryComponent, |
34 | 37 | Lwm2mObserveAttrTelemetryResourceComponent, |
38 | + Lwm2mAttributesDialogComponent, | |
39 | + Lwm2mAttributesComponent, | |
40 | + Lwm2mAttributesKeyListComponent, | |
35 | 41 | Lwm2mDeviceConfigServerComponent, |
36 | - Lwm2mObjectAddInstancesComponent, | |
42 | + Lwm2mObjectAddInstancesDialogComponent, | |
37 | 43 | Lwm2mObjectAddInstancesListComponent |
38 | 44 | ], |
39 | 45 | imports: [ |
... | ... | @@ -45,8 +51,11 @@ import { SharedModule } from '@app/shared/shared.module'; |
45 | 51 | Lwm2mObjectListComponent, |
46 | 52 | Lwm2mObserveAttrTelemetryComponent, |
47 | 53 | Lwm2mObserveAttrTelemetryResourceComponent, |
54 | + Lwm2mAttributesDialogComponent, | |
55 | + Lwm2mAttributesComponent, | |
56 | + Lwm2mAttributesKeyListComponent, | |
48 | 57 | Lwm2mDeviceConfigServerComponent, |
49 | - Lwm2mObjectAddInstancesComponent, | |
58 | + Lwm2mObjectAddInstancesDialogComponent, | |
50 | 59 | Lwm2mObjectAddInstancesListComponent |
51 | 60 | ], |
52 | 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 | 16 | |
17 | 17 | export const PAGE_SIZE_LIMIT = 50; |
18 | 18 | export const INSTANCES = 'instances'; |
19 | +export const INSTANCE = 'instance'; | |
19 | 20 | export const RESOURCES = 'resources'; |
21 | +export const ATTRIBUTE_LWM2M = 'attributeLwm2m'; | |
20 | 22 | export const CLIENT_LWM2M = 'clientLwM2M'; |
21 | 23 | export const CLIENT_LWM2M_SETTINGS = 'clientLwM2mSettings'; |
22 | 24 | export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry'; |
... | ... | @@ -33,7 +35,7 @@ export const DEFAULT_CLIENT_HOLD_OFF_TIME = 1; |
33 | 35 | export const DEFAULT_LIFE_TIME = 300; |
34 | 36 | export const DEFAULT_MIN_PERIOD = 1; |
35 | 37 | export const DEFAULT_NOTIF_IF_DESIBLED = true; |
36 | -export const DEFAULT_BINDING = 'U'; | |
38 | +export const DEFAULT_BINDING = 'UQ'; | |
37 | 39 | export const DEFAULT_BOOTSTRAP_SERVER_ACCOUNT_TIME_OUT = 0; |
38 | 40 | export const LEN_MAX_PUBLIC_KEY_RPK = 182; |
39 | 41 | export const LEN_MAX_PUBLIC_KEY_X509 = 3000; |
... | ... | @@ -42,6 +44,44 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; |
42 | 44 | export const INSTANCES_ID_VALUE_MIN = 0; |
43 | 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 | 85 | export enum SECURITY_CONFIG_MODE { |
46 | 86 | PSK = 'PSK', |
47 | 87 | RPK = 'RPK', |
... | ... | @@ -54,7 +94,7 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( |
54 | 94 | [SECURITY_CONFIG_MODE.PSK, 'Pre-Shared Key'], |
55 | 95 | [SECURITY_CONFIG_MODE.RPK, 'Raw Public Key'], |
56 | 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 | 130 | lwm2mServer: ServerSecurityConfig; |
91 | 131 | } |
92 | 132 | |
93 | -export interface ProfileConfigModels { | |
133 | +export interface Lwm2mProfileConfigModels { | |
94 | 134 | clientLwM2mSettings: ClientLwM2mSettings; |
95 | 135 | observeAttr: ObservableAttributes; |
96 | 136 | bootstrap: BootstrapSecurityConfig; |
... | ... | @@ -100,11 +140,13 @@ export interface ProfileConfigModels { |
100 | 140 | export interface ClientLwM2mSettings { |
101 | 141 | clientOnlyObserveAfterConnect: number; |
102 | 142 | } |
143 | + | |
103 | 144 | export interface ObservableAttributes { |
104 | 145 | observe: string[]; |
105 | 146 | attribute: string[]; |
106 | 147 | telemetry: string[]; |
107 | 148 | keyName: {}; |
149 | + attributeLwm2m: {}; | |
108 | 150 | } |
109 | 151 | |
110 | 152 | export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig { |
... | ... | @@ -151,21 +193,22 @@ function getDefaultProfileObserveAttrConfig(): ObservableAttributes { |
151 | 193 | observe: [], |
152 | 194 | attribute: [], |
153 | 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 | 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 | 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 | 218 | observe: boolean; |
176 | 219 | attribute: boolean; |
177 | 220 | telemetry: boolean; |
178 | - keyName: string; | |
221 | + keyName: {}; | |
222 | + attributeLwm2m?: {}; | |
179 | 223 | } |
180 | 224 | |
181 | 225 | export interface Instance { |
182 | 226 | id: number; |
227 | + attributeLwm2m?: {}; | |
183 | 228 | resources: ResourceLwM2M[]; |
184 | 229 | } |
185 | 230 | |
... | ... | @@ -190,11 +235,12 @@ export interface Instance { |
190 | 235 | * mandatory == false => Optional |
191 | 236 | */ |
192 | 237 | export interface ObjectLwM2M { |
238 | + | |
193 | 239 | id: number; |
194 | 240 | keyId: string; |
195 | 241 | name: string; |
196 | 242 | multiple?: boolean; |
197 | 243 | mandatory?: boolean; |
244 | + attributeLwm2m?: {}; | |
198 | 245 | instances?: Instance []; |
199 | 246 | } |
200 | - | ... | ... |
... | ... | @@ -1171,17 +1171,32 @@ |
1171 | 1171 | "instances-list": "Instances list", |
1172 | 1172 | "instances-input": "Input Instance Id value", |
1173 | 1173 | "instances-input-holder": "Input Instance number...", |
1174 | - "resource-label": "Resource", | |
1174 | + "instance-label": "Instance", | |
1175 | + "resource-label": "<id> Resource name", | |
1175 | 1176 | "observe-label": "Observe", |
1176 | 1177 | "attribute-label": "Attribute", |
1177 | 1178 | "telemetry-label": "Telemetry", |
1178 | 1179 | "key-name-label": "Key Name", |
1180 | + "attribute-lwm2m-label": "AttrLwm2m", | |
1181 | + "resource-tip": "ID & Original Name of the Resource", | |
1179 | 1182 | "is-observe-tip": "Is Observe", |
1183 | + "not-observe-tip": "To observe select telemetry or attributes first", | |
1180 | 1184 | "is-attr-tip": "Is Attribute", |
1181 | 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 | 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 | 1200 | "required": " value is required.", |
1186 | 1201 | "mode": "Security config mode", |
1187 | 1202 | "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", | ... | ... |