Browse Source

Refactoring lwm2m device profile transport, configuration observe attributes/telemetry

pull/4822/head
Vladyslav_Prykhodko 5 years ago
committed by Andrew Shvayka
parent
commit
09b6b06abb
  1. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component.ts
  2. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.html
  3. 48
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.ts
  4. 38
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  5. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component.html
  6. 11
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component.ts
  7. 70
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.html
  8. 25
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.scss
  9. 219
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.ts
  10. 91
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.html
  11. 145
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resource.component.ts
  12. 75
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component.html
  13. 56
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component.scss
  14. 193
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component.ts
  15. 111
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html
  16. 18
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss
  17. 327
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts
  18. 13
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts
  19. 14
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
  20. 17
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes-dialog.component.ts

@ -34,7 +34,7 @@ export interface Lwm2mAttributesDialogData {
@Component({
selector: 'tb-lwm2m-attributes-dialog',
templateUrl: './lwm2m-attributes-dialog.component.html',
styleUrls: ['./lwm2m-attributes.component.scss'],
styleUrls: [],
providers: [{provide: ErrorStateMatcher, useExisting: Lwm2mAttributesDialogComponent}],
})
export class Lwm2mAttributesDialogComponent

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

@ -15,7 +15,7 @@
limitations under the License.
-->
<div fxLayout="row" [fxHide]="disabled && isEmpty()" fxLayoutAlign="end center" matTooltip="{{ tooltipSetAttributesTelemetry | translate }}" matTooltipPosition="above">
<div [fxHide]="disabled && isEmpty()" matTooltip="{{ tooltipSetAttributesTelemetry | translate }}" matTooltipPosition="above">
<button type="button"
[disabled]="isDisableBtn()"
mat-button mat-icon-button

48
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.ts

@ -14,29 +14,31 @@
/// limitations under the License.
///
import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core';
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { isEmpty, isUndefinedOrNull } from '@core/utils';
import { Lwm2mAttributesDialogComponent, Lwm2mAttributesDialogData } from './lwm2m-attributes-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { AttributesNameValueMap } from './lwm2m-profile-config.models';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-profile-lwm2m-attributes',
templateUrl: './lwm2m-attributes.component.html',
styleUrls: ['./lwm2m-attributes.component.scss'],
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mAttributesComponent),
multi: true
}]
})
export class Lwm2mAttributesComponent implements ControlValueAccessor {
attributeLwm2mFormGroup: FormGroup;
export class Lwm2mAttributesComponent implements ControlValueAccessor, OnDestroy {
attributesFormGroup: FormGroup;
private requiredValue: boolean;
private destroy$ = new Subject();
@Input()
isAttributeTelemetry: boolean;
@ -50,9 +52,6 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
@Input()
isResource = false;
@Output()
updateAttributeLwm2m = new EventEmitter<any>();
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
@ -62,7 +61,21 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
}
constructor(private dialog: MatDialog,
private fb: FormBuilder) {}
private fb: FormBuilder) {
this.attributesFormGroup = this.fb.group({
attributes: [{}]
});
this.attributesFormGroup.get('attributes').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(attributes => {
this.propagateChange(attributes);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
@ -74,24 +87,18 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.attributeLwm2mFormGroup.disable({emitEvent: false});
this.attributesFormGroup.disable({emitEvent: false});
} else {
this.attributeLwm2mFormGroup.enable({emitEvent: false});
this.attributesFormGroup.enable({emitEvent: false});
}
}
ngOnInit() {
this.attributeLwm2mFormGroup = this.fb.group({
attributes: [{}]
});
}
writeValue(value: AttributesNameValueMap | null) {
this.attributeLwm2mFormGroup.patchValue({attributes: value}, {emitEvent: false});
this.attributesFormGroup.patchValue({attributes: value}, {emitEvent: false});
}
get attributesValueMap(): AttributesNameValueMap {
return this.attributeLwm2mFormGroup.get('attributes').value;
return this.attributesFormGroup.get('attributes').value;
}
isDisableBtn(): boolean {
@ -140,8 +147,7 @@ export class Lwm2mAttributesComponent implements ControlValueAccessor {
}
}).afterClosed().subscribe((result) => {
if (result) {
this.attributeLwm2mFormGroup.patchValue({attributeLwm2m: result});
this.updateAttributeLwm2m.next(result);
this.attributesFormGroup.patchValue({attributes: result});
}
});
}

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

@ -287,7 +287,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private updateDeviceProfileValue(config): void {
if (this.lwm2mDeviceProfileFormGroup.valid) {
this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M);
this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry);
}
this.configurationValue.bootstrap.bootstrapServer = config.bootstrap.bootstrapServer;
this.configurationValue.bootstrap.lwm2mServer = config.bootstrap.lwm2mServer;
@ -297,7 +297,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.updateModel();
}
private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => {
private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): ObjectLwM2M[] => {
const objectLwM2MS = deepClone(objectList);
if (this.configurationValue.observeAttr && objectLwM2MS.length > 0) {
const attributeArray = this.configurationValue.observeAttr.attribute;
@ -317,7 +317,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.updateObserveAttrTelemetryObjects(telemetryArray, objectLwM2MS, TELEMETRY);
}
if (isDefinedAndNotNull(this.configurationValue.observeAttr.attributeLwm2m)) {
this.updateAttributeLwm2m(objectLwM2MS);
this.updateAttributes(objectLwM2MS);
}
if (isDefinedAndNotNull(keyNameJson)) {
this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray);
@ -325,7 +325,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.updateKeyNameObjects(objectLwM2MS);
}
}
return {clientLwM2M: objectLwM2MS};
return objectLwM2MS;
}
private includesNotZeroInstance = (attribute: string[], telemetry: string[]): boolean => {
@ -369,7 +369,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
});
}
private updateAttributeLwm2m = (objectLwM2MS: ObjectLwM2M[]): void => {
private updateAttributes = (objectLwM2MS: ObjectLwM2M[]): void => {
Object.keys(this.configurationValue.observeAttr.attributeLwm2m).forEach(key => {
const [objectKeyId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), String);
const objectLwM2M = objectLwM2MS.find(objectLwm2m => objectLwm2m.keyId === objectKeyId);
@ -377,12 +377,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
const instance = objectLwM2M.instances.find(obj => obj.id === +instanceId);
if (instance && resourceId) {
instance.resources.find(resource => resource.id === +resourceId)
.attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key];
.attributes = this.configurationValue.observeAttr.attributeLwm2m[key];
} else if (instance) {
instance.attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key];
instance.attributes = this.configurationValue.observeAttr.attributeLwm2m[key];
}
} else if (objectLwM2M) {
objectLwM2M.attributeLwm2m = this.configurationValue.observeAttr.attributeLwm2m[key];
objectLwM2M.attributes = this.configurationValue.observeAttr.attributeLwm2m[key];
}
});
}
@ -415,19 +415,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
const observeArray: Array<string> = [];
const attributeArray: Array<string> = [];
const telemetryArray: Array<string> = [];
const attributeLwm2m: any = {};
const attributes: any = {};
const keyNameNew = {};
const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val));
observeJson.forEach(obj => {
if (isDefinedAndNotNull(obj.attributeLwm2m) && !isEmpty(obj.attributeLwm2m)) {
if (isDefinedAndNotNull(obj.attributes) && !isEmpty(obj.attributes)) {
const pathObject = `/${obj.keyId}`;
attributeLwm2m[pathObject] = obj.attributeLwm2m;
attributes[pathObject] = obj.attributes;
}
if (obj.hasOwnProperty(INSTANCES) && Array.isArray(obj.instances)) {
obj.instances.forEach(instance => {
if (isDefinedAndNotNull(instance.attributeLwm2m) && !isEmpty(instance.attributeLwm2m)) {
if (isDefinedAndNotNull(instance.attributes) && !isEmpty(instance.attributes)) {
const pathInstance = `/${obj.keyId}/${instance.id}`;
attributeLwm2m[pathInstance] = instance.attributeLwm2m;
attributes[pathInstance] = instance.attributes;
}
if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) {
instance.resources.forEach(resource => {
@ -443,8 +443,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
telemetryArray.push(pathRes);
}
keyNameNew[pathRes] = resource.keyName;
if (isDefinedAndNotNull(resource.attributeLwm2m) && !isEmpty(resource.attributeLwm2m)) {
attributeLwm2m[pathRes] = resource.attributeLwm2m;
if (isDefinedAndNotNull(resource.attributes) && !isEmpty(resource.attributes)) {
attributes[pathRes] = resource.attributes;
}
}
});
@ -458,14 +458,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
attribute: attributeArray,
telemetry: telemetryArray,
keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew),
attributeLwm2m
attributeLwm2m: attributes
};
} else {
this.configurationValue.observeAttr.observe = observeArray;
this.configurationValue.observeAttr.attribute = attributeArray;
this.configurationValue.observeAttr.telemetry = telemetryArray;
this.configurationValue.observeAttr.keyName = this.sortObjectKeyPathJson(KEY_NAME, keyNameNew);
this.configurationValue.observeAttr.attributeLwm2m = attributeLwm2m;
this.configurationValue.observeAttr.attributeLwm2m = attributes;
}
}
@ -535,7 +535,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.keyId);
this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.keyId);
this.removeKeyNameFromJson(value.keyId);
this.removeAttributeLwm2mFromJson(value.keyId);
this.removeAttributesFromJson(value.keyId);
this.updateObserveAttrTelemetryObjectFormGroup(objectsOld);
this.upDateJsonAllConfig();
}
@ -558,7 +558,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
});
}
private removeAttributeLwm2mFromJson = (keyId: string): void => {
private removeAttributesFromJson = (keyId: string): void => {
const keyNameJson = this.configurationValue.observeAttr.attributeLwm2m;
Object.keys(keyNameJson).forEach(key => {
if (key.startsWith(`/${keyId}`)) {

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

@ -17,7 +17,7 @@
-->
<form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;">
<mat-toolbar fxLayout="row" color="primary">
<b><i>{{data.objectName}}</i></b> (object <<b>{{data.objectKeyId}}</b>>)
<b><i>{{data.objectName}}</i></b> (object <<b>{{data.objectId}}</b>>)
<span fxFlex></span>
<button mat-button mat-icon-button
(click)="cancel()"

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

@ -23,9 +23,9 @@ import { Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
export interface Lwm2mObjectAddInstancesData {
instancesIds: Set<number>;
instancesId: Set<number>;
objectName?: string;
objectKeyId?: string;
objectId?: number;
}
@Component({
@ -48,16 +48,15 @@ export class Lwm2mObjectAddInstancesDialogComponent extends DialogComponent<Lwm2
ngOnInit(): void {
this.instancesFormGroup = this.fb.group({
instancesIds: this.data.instancesIds
instancesIds: [this.data.instancesId]
});
}
cancel(): void {
this.dialogRef.close(undefined);
this.dialogRef.close(null);
}
add(): void {
this.data.instancesIds = this.instancesFormGroup.get('instancesIds').value;
this.dialogRef.close(this.data);
this.dialogRef.close(this.instancesFormGroup.get('instancesIds').value);
}
}

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

@ -0,0 +1,70 @@
<!--
Copyright © 2016-2021 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section [formGroup]="instancesFormGroup">
<mat-accordion multi="true" formArrayName="instances">
<mat-expansion-panel
class="instance-row"
*ngFor="let instances of instancesFormArray.controls; let $index = index; trackBy: trackByParams"
[formGroupName]="$index"
[expanded]="isExpend"
[disabled]="isExpend">
<mat-expansion-panel-header>
<mat-panel-title class="tb-panel-title-height" fxLayout="row">
<div fxFlex="30" fxLayoutAlign="start center">
{{ 'device-profile.lwm2m.instance' | translate }} <<b>{{instances.get('id').value}}</b>>
</div>
<div fxLayoutAlign="center center" fxFlex="10">
<mat-checkbox color="warn"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'attribute')"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'attribute')"
[indeterminate]="getIndeterminate(instances, 'attribute')">
</mat-checkbox>
</div>
<div fxLayoutAlign="center center" fxFlex="10">
<mat-checkbox color="primary"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'telemetry')"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'telemetry')"
[indeterminate]="getIndeterminate(instances, 'telemetry')">
</mat-checkbox>
</div>
<div fxLayoutAlign="center center" fxFlex="10">
<mat-checkbox color="primary"
[disabled]="this.disabled || !(getIndeterminate(instances, 'telemetry') || getIndeterminate(instances, 'attribute'))"
[checked]="getChecked(instances, 'observe')"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'observe')"
[indeterminate]="getIndeterminate(instances, 'observe')">
</mat-checkbox>
</div>
<span fxFlex></span>
<tb-profile-lwm2m-attributes
formControlName="attributes"
[isAttributeTelemetry]="disableObserveInstance(instances)"
[modelName]="getNameInstance(instances.value)">
</tb-profile-lwm2m-attributes>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-profile-lwm2m-observe-attr-telemetry-resource
formControlName="resources">
</tb-profile-lwm2m-observe-attr-telemetry-resource>
</ng-template>
</mat-expansion-panel>
</mat-accordion>
</section>

25
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-attributes.component.scss → ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.scss

@ -13,21 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.resource-name-lw-end{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align:end;
//width: 80px;
cursor: pointer;
:host{
.tb-panel-title-height {
min-height: 42px;
}
.resource-name-lw{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
.instance-row {
mat-expansion-panel-header {
color: inherit;
}
}
}
.mat-expansion-panel-header-title {
margin-right: 0;
}
}

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

@ -0,0 +1,219 @@
///
/// Copyright © 2016-2021 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Instance, ResourceLwM2M, ResourceSettingTelemetry, } from './lwm2m-profile-config.models';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
@Component({
selector: 'tb-profile-lwm2m-observe-attr-telemetry-instances',
templateUrl: './lwm2m-observe-attr-telemetry-instances.component.html',
styleUrls: [ './lwm2m-observe-attr-telemetry-instances.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryInstancesComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryInstancesComponent),
multi: true
}
]
})
export class Lwm2mObserveAttrTelemetryInstancesComponent implements ControlValueAccessor, Validator, OnDestroy {
instancesFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
const newVal = coerceBooleanProperty(value);
if (this.requiredValue !== newVal) {
this.requiredValue = newVal;
this.updateValidators();
}
}
@Input()
disabled: boolean;
private valueChange$: Subscription = null;
private propagateChange = (v: any) => { };
constructor(private fb: FormBuilder,
public translate: TranslateService) {
this.instancesFormGroup = this.fb.group({
instances: this.fb.array([])
});
}
ngOnDestroy() {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.instancesFormGroup.disable({emitEvent: false});
} else {
this.instancesFormGroup.enable({emitEvent: false});
}
}
writeValue(value: Instance[]): void {
this.updateInstances(value);
}
validate(control: AbstractControl): ValidationErrors | null {
return this.instancesFormGroup.valid ? null : {
instancesForm: false
};
}
get instancesFormArray(): FormArray {
return this.instancesFormGroup.get('instances') as FormArray;
}
private updateInstances(instances: Instance[]): void {
if (instances.length === this.instancesFormArray.length) {
this.instancesFormArray.patchValue(instances, {emitEvent: false});
} else {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
const instancesControl: Array<AbstractControl> = [];
if (instances) {
instances.forEach((instance) => {
instancesControl.push(this.createInstanceFormGroup(instance));
});
}
this.instancesFormGroup.setControl('instances', this.fb.array(instancesControl));
if (this.disabled) {
this.instancesFormGroup.disable({emitEvent: false});
}
this.valueChange$ = this.instancesFormGroup.valueChanges.subscribe(value => {
this.updateModel(value.instances);
});
}
}
private createInstanceFormGroup(instance: Instance): FormGroup {
return this.fb.group({
id: [instance.id],
attributes: [instance.attributes],
resources: [instance.resources]
});
}
private updateModel(instances: Instance[]) {
if (instances && this.instancesFormGroup.valid) {
this.propagateChange(instances);
} else {
this.propagateChange(null);
}
}
changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: ResourceSettingTelemetry): void => {
const resources = deepClone(instance.get('resources').value as ResourceLwM2M[]);
if (value && type === 'observe') {
resources.forEach(resource => resource[type] = resource.telemetry || resource.attribute);
} else {
resources.forEach(resource => resource[type] = value);
}
instance.get('resources').patchValue(resources);
}
private updateValidators(): void {
this.instancesFormArray.setValidators(this.required ? Validators.required : []);
this.instancesFormArray.updateValueAndValidity();
}
trackByParams = (index: number, instance: Instance): number => {
return instance.id;
}
getIndeterminate = (instance: AbstractControl, type: ResourceSettingTelemetry): boolean => {
const resources = instance.get('resources').value as ResourceLwM2M[];
if (isDefinedAndNotNull(resources)) {
const checkedResource = resources.filter(resource => resource[type]);
return checkedResource.length !== 0 && checkedResource.length !== resources.length;
}
return false;
}
getChecked = (instance: AbstractControl, type: ResourceSettingTelemetry): boolean => {
const resources = instance.get('resources').value as ResourceLwM2M[];
return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]);
}
get isExpend(): boolean {
return this.instancesFormArray.length === 1;
}
getNameInstance(instance: Instance): string {
return `${this.translate.instant('device-profile.lwm2m.instance')} <${instance.id}>`;
}
disableObserveInstance = (instance: AbstractControl): boolean => {
const checkedAttrTelemetry = this.observeInstance(instance);
if (checkedAttrTelemetry) {
instance.get('attributes').patchValue(null, {emitEvent: false});
}
return checkedAttrTelemetry;
}
observeInstance = (instance: AbstractControl): boolean => {
const resources = instance.get('resources').value as ResourceLwM2M[];
if (isDefinedAndNotNull(resources)) {
const checkedAttribute = resources.filter(resource => resource.attribute);
const checkedTelemetry = resources.filter(resource => resource.telemetry);
return checkedAttribute.length === 0 && checkedTelemetry.length === 0;
}
return false;
}
}

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

@ -1,91 +0,0 @@
<!--
Copyright © 2016-2021 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section [formGroup]="resourceFormGroup">
<div fxLayout="row" fxFill formArrayName="resources"
*ngFor="let resourceLwM2M of resourceFormArray.controls; let i = index; trackBy: trackByParams">
<div class="vertical-padding" fxLayout="column" fxFill [formGroupName]="i">
<div fxLayout="row" fxFill fxLayoutAlign="start center" [fxShow]="!i">
<div fxFlex="30">
<mat-label translate>device-profile.lwm2m.resource-label</mat-label>
</div>
<div fxFlex="10" style="text-align: center">
<mat-label translate>device-profile.lwm2m.attribute-label</mat-label>
</div>
<div fxFlex="10" style="text-align: center">
<mat-label translate>device-profile.lwm2m.telemetry-label</mat-label>
</div>
<div fxFlex="10" style="text-align: center">
<mat-label translate>device-profile.lwm2m.observe-label</mat-label>
</div>
<div fxFlex>
<mat-label translate>device-profile.lwm2m.key-name-label</mat-label>
</div>
</div>
<div fxLayout="row" fxFill fxLayoutAlign="start center">
<div class="resource-name-lw" fxFlex="30"
matTooltip="{{'device-profile.lwm2m.resource-tip' | translate}}" matTooltipPosition="above">
<<b>{{resourceLwM2M.get('id').value}}</b>> <b><i>{{resourceLwM2M.get('name').value}}</i></b>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="attribute" color="warn"
(change)="updateObserve(i)"
matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="telemetry" color="primary"
(change)="updateObserve(i)"
matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="observe" color="primary"
[disabled]="disableObserve(i)"
matTooltip="{{(disableObserve(i) ? 'device-profile.lwm2m.not-observe-tip' : 'device-profile.lwm2m.is-observe-tip') | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<mat-form-field fxFlex="33">
<mat-label *ngIf="resourceLwM2M.get('keyName').hasError('required')">
{{ 'device-profile.lwm2m.key-name-label' | translate }}</mat-label>
<input class="resource-name-lw" matInput type="text" formControlName="keyName" required
matTooltip="{{'device-profile.lwm2m.key-name-tip' | translate}}"
(input)="updateValueKeyName($event, i)"
matTooltipPosition="above">
<mat-error *ngIf="resourceLwM2M.get('keyName').hasError('required')">
{{ 'device-profile.lwm2m.key-name' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<span fxFlex></span>
<div class="resource-name-lw-end">
<tb-profile-lwm2m-attributes
formControlName="attributeLwm2m"
[isAttributeTelemetry]="disableObserve(i)"
isResource="true"
[modelName]="getNameResourceLwm2m(resourceLwM2M.value)"
[disabled]="this.disabled"
(updateAttributeLwm2m)="updateAttributeLwm2m($event, i)">
</tb-profile-lwm2m-attributes>
</div>
</div>
</div>
</div>
</section>

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

@ -1,145 +0,0 @@
///
/// Copyright © 2016-2021 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, FormArray, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { ResourceLwM2M, RESOURCES } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
import _ from 'lodash';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource',
templateUrl: './lwm2m-observe-attr-telemetry-resource.component.html',
styleUrls: ['./lwm2m-attributes.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryResourceComponent),
multi: true
}
]
})
export class Lwm2mObserveAttrTelemetryResourceComponent implements ControlValueAccessor {
private requiredValue: boolean;
resourceFormGroup: FormGroup;
disabled = false;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
const newVal = coerceBooleanProperty(value);
if (this.requiredValue !== newVal) {
this.requiredValue = newVal;
}
}
constructor(private fb: FormBuilder) {
this.resourceFormGroup = this.fb.group({
resources: this.fb.array([])
});
this.resourceFormGroup.valueChanges.subscribe(value => {
if (!this.disabled) {
this.propagateChangeState(value.resources);
}
});
}
registerOnTouched(fn: any): void {
}
writeValue(value: ResourceLwM2M[]): void {
this.createResourceLwM2M(value);
}
get resourceFormArray(): FormArray{
return this.resourceFormGroup.get(RESOURCES) as FormArray;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.resourceFormGroup.disable();
} else {
this.resourceFormGroup.enable();
}
}
updateValueKeyName = (event: Event, index: number): void => {
this.resourceFormArray.at(index).patchValue({keyName: _.camelCase((event.target as HTMLInputElement).value)});
}
updateAttributeLwm2m = (event: Event, index: number): void => {
this.resourceFormArray.at(index).patchValue({attributeLwm2m: event});
}
getNameResourceLwm2m = (resourceLwM2M: ResourceLwM2M): string => {
return `<${resourceLwM2M.id}> ${resourceLwM2M.name}`;
}
createResourceLwM2M(resourcesLwM2M: ResourceLwM2M[]): void {
if (resourcesLwM2M.length === this.resourceFormArray.length) {
this.resourceFormArray.patchValue(resourcesLwM2M, {emitEvent: false});
} else {
this.resourceFormArray.clear();
resourcesLwM2M.forEach(resourceLwM2M => {
this.resourceFormArray.push(this.fb.group( {
id: resourceLwM2M.id,
name: resourceLwM2M.name,
observe: resourceLwM2M.observe,
attribute: resourceLwM2M.attribute,
telemetry: resourceLwM2M.telemetry,
keyName: [resourceLwM2M.keyName, Validators.required],
attributeLwm2m: [resourceLwM2M.attributeLwm2m]
}));
});
}
}
private propagateChange = (v: any) => { };
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
private propagateChangeState = (value: any): void => {
if (value && this.resourceFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
}
trackByParams = (index: number): number => {
return index;
}
updateObserve = (index: number): void => {
if (this.resourceFormArray.at(index).value.attribute === false && this.resourceFormArray.at(index).value.telemetry === false) {
this.resourceFormArray.at(index).patchValue({observe: false});
this.resourceFormArray.at(index).patchValue({attributeLwm2m: {}});
}
}
disableObserve = (index: number): boolean => {
return !this.resourceFormArray.at(index).value.telemetry && !this.resourceFormArray.at(index).value.attribute;
}
}

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

@ -0,0 +1,75 @@
<!--
Copyright © 2016-2021 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section [formGroup]="resourcesFormGroup">
<div fxLayout="row" fxLayoutAlign="start center">
<div fxFlex="30">
<mat-label translate>device-profile.lwm2m.resource-label</mat-label>
</div>
<div fxFlex="10" class="checkbox-column-title">
<mat-label translate>device-profile.lwm2m.attribute-label</mat-label>
</div>
<div fxFlex="10" class="checkbox-column-title">
<mat-label translate>device-profile.lwm2m.telemetry-label</mat-label>
</div>
<div fxFlex="10" class="checkbox-column-title">
<mat-label translate>device-profile.lwm2m.observe-label</mat-label>
</div>
<div fxFlex>
<mat-label translate>device-profile.lwm2m.key-name</mat-label>
</div>
</div>
<mat-divider></mat-divider>
<div formArrayName="resources"
*ngFor="let resourceLwM2M of resourcesFormArray.controls; let $index = index; trackBy: trackByParams">
<div [formGroupName]="$index" fxLayout="row" fxLayoutAlign="start center" class="resource-list">
<div class="resource-name" fxFlex="30">
<<b>{{resourceLwM2M.get('id').value}}</b>> <b>{{resourceLwM2M.get('name').value}}</b>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="attribute" color="warn">
</mat-checkbox>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox formControlName="telemetry" color="primary">
</mat-checkbox>
</div>
<div fxFlex="10" fxLayoutAlign="center center">
<mat-checkbox fxFlex="10" formControlName="observe" color="primary"
matTooltip="{{ 'device-profile.lwm2m.edit-observe-select' | translate }}"
[matTooltipDisabled]="disabled || !isDisabledObserve($index)"
matTooltipPosition="above">
</mat-checkbox>
</div>
<mat-form-field fxFlex="33" hideRequiredMarker>
<mat-label></mat-label>
<input matInput type="text" formControlName="keyName" required>
<mat-error *ngIf="resourceLwM2M.get('keyName').hasError('required') ||
resourceLwM2M.get('keyName').hasError('pattern')">
{{ 'device-profile.lwm2m.key-name-required' | translate }}
</mat-error>
</mat-form-field>
<span fxFlex></span>
<tb-profile-lwm2m-attributes
formControlName="attributes"
[isAttributeTelemetry]="isDisabledObserve($index)"
isResource="true"
[modelName]="getNameResourceLwm2m(resourceLwM2M.value)">
</tb-profile-lwm2m-attributes>
</div>
</div>
</section>

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

@ -0,0 +1,56 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.resource-name{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.checkbox-column-title {
text-align: center;
}
.mat-divider {
margin-bottom: 4px;
}
.resource-list {
padding-bottom: 8px;
height: 42px;
}
}
:host ::ng-deep {
.resource-list {
mat-form-field {
.mat-form-field-wrapper {
padding-bottom: 0;
.mat-form-field-infix {
border-top-width: 0.2em;
width: auto;
min-width: auto;
}
.mat-form-field-underline {
bottom: 0;
}
.mat-form-field-subscript-wrapper{
margin-top: 1.8em;
}
}
}
}
}

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

@ -0,0 +1,193 @@
///
/// Copyright © 2016-2021 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import { ResourceLwM2M } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { startWith, takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-profile-lwm2m-observe-attr-telemetry-resource',
templateUrl: './lwm2m-observe-attr-telemetry-resources.component.html',
styleUrls: ['./lwm2m-observe-attr-telemetry-resources.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryResourcesComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryResourcesComponent),
multi: true
}
]
})
export class Lwm2mObserveAttrTelemetryResourcesComponent implements ControlValueAccessor, OnDestroy, Validator {
resourcesFormGroup: FormGroup;
@Input()
disabled = false;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
const newVal = coerceBooleanProperty(value);
if (this.requiredValue !== newVal) {
this.requiredValue = newVal;
}
}
private destroy$ = new Subject();
private valueChange$: Subscription = null;
private propagateChange = (v: any) => { };
constructor(private fb: FormBuilder) {
this.resourcesFormGroup = this.fb.group({
resources: this.fb.array([])
});
}
ngOnDestroy() {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
this.destroy$.next();
this.destroy$.complete();
}
registerOnTouched(fn: any): void {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
writeValue(value: ResourceLwM2M[]): void {
this.updatedResources(value);
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.resourcesFormGroup.disable({emitEvent: false});
} else {
this.resourcesFormArray.controls.forEach(resource => {
resource.get('keyName').enable({emitEvent: false});
resource.get('attribute').enable({emitEvent: false});
resource.get('telemetry').enable({onlySelf: true});
resource.get('attributes').enable({emitEvent: false});
});
}
}
validate(): ValidationErrors | null {
return this.resourcesFormGroup.valid ? null : {
resources: false
};
}
get resourcesFormArray(): FormArray {
return this.resourcesFormGroup.get('resources') as FormArray;
}
getNameResourceLwm2m(resourceLwM2M: ResourceLwM2M): string {
return `<${resourceLwM2M.id}> ${resourceLwM2M.name}`;
}
private updatedResources(resources: ResourceLwM2M[]): void {
if (resources.length === this.resourcesFormArray.length) {
this.resourcesFormArray.patchValue(resources, {emitEvent: false});
} else {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
const resourcesControl: Array<AbstractControl> = [];
if (resources) {
resources.forEach((resource) => {
resourcesControl.push(this.createdResourceFormGroup(resource));
});
}
this.resourcesFormGroup.setControl('resources', this.fb.array(resourcesControl));
if (this.disabled) {
this.resourcesFormGroup.disable({emitEvent: false});
}
this.valueChange$ = this.resourcesFormGroup.valueChanges.subscribe(value => {
this.updateModel(this.resourcesFormGroup.getRawValue().resources);
});
}
}
private createdResourceFormGroup(resource: ResourceLwM2M): FormGroup {
const form = this.fb.group( {
id: [resource.id],
name: [resource.name],
attribute: [resource.attribute],
telemetry: [resource.telemetry],
observe: [resource.observe],
keyName: [resource.keyName, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
attributes: [resource.attributes]
});
combineLatest([
form.get('attribute').valueChanges.pipe(startWith(resource.attribute), takeUntil(this.destroy$)),
form.get('telemetry').valueChanges.pipe(startWith(resource.telemetry), takeUntil(this.destroy$))
]).subscribe(([attribute, telemetry]) => {
if (attribute || telemetry) {
form.get('observe').enable({emitEvent: false});
} else {
form.get('observe').disable({emitEvent: false});
form.get('observe').patchValue(false, {emitEvent: false});
form.get('attributes').patchValue({}, {emitEvent: false});
}
});
return form;
}
private updateModel(value: ResourceLwM2M[]) {
if (value && this.resourcesFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
}
trackByParams(index: number, resource: ResourceLwM2M): number {
return resource.id;
}
isDisabledObserve(index: number): boolean{
return this.resourcesFormArray.at(index).get('observe').disabled;
}
}

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

@ -15,107 +15,32 @@
limitations under the License.
-->
<section [formGroup]="observeAttrTelemetryFormGroup">
<mat-accordion multi="true" formArrayName="clientLwM2M">
<section [formGroup]="modelsFormGroup">
<mat-accordion multi="true" formArrayName="models">
<mat-expansion-panel
*ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;"
[formGroupName]="i">
*ngFor="let objectLwM2M of modelsFormArray.controls; let $index = index; trackBy: trackByParams"
[formGroupName]="$index">
<mat-expansion-panel-header >
<mat-panel-title fxLayoutAlign="start center" >
<b><i>{{ objectLwM2M.get('name').value}}</i></b>&nbsp;&lt;{{ objectLwM2M.get('keyId').value}}>
<div fxFlex class="resource-name-lw-end">
<tb-profile-lwm2m-attributes
formControlName="attributeLwm2m"
[isAttributeTelemetry]="disableObserveObject(i)"
[modelName]="getNameObjectLwm2m( objectLwM2M.get('name').value, objectLwM2M.get('keyId').value)"
[disabled]="this.disabled"
(updateAttributeLwm2m)="updateAttributeLwm2mObject($event, objectLwM2M.get('keyId').value)">
</tb-profile-lwm2m-attributes>
</div>
</mat-panel-title>
<mat-panel-description fxFlex="5" fxLayoutAlign="end center" *ngIf="!disabled && objectLwM2M.get('multiple').value">
<b><i>{{ objectLwM2M.get('name').value}}</i></b>&nbsp;&lt;{{ objectLwM2M.get('id').value}}>
<span fxFlex></span>
<tb-profile-lwm2m-attributes
formControlName="attributes"
[modelName]="getNameObject(objectLwM2M.value)">
</tb-profile-lwm2m-attributes>
<button type="button"
mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)"
matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}"
*ngIf="!disabled && objectLwM2M.get('multiple').value"
mat-button mat-icon-button (click)="addInstances($event, objectLwM2M)"
matTooltip="{{'device-profile.lwm2m.add-new-instances' | translate}}"
matTooltipPosition="above">
<mat-icon class="material-icons">{{'note_add'}}</mat-icon>
<mat-icon class="material-icons">note_add</mat-icon>
</button>
</mat-panel-description>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="8px" formArrayName="instances">
<mat-expansion-panel
class="instance-list"
*ngFor="let instances of instancesLwm2mFormArray(objectLwM2M).controls; let y = index;"
[formGroupName]="y"
[expanded]="getExpended(objectLwM2M)"
[disabled]="getExpended(objectLwM2M)">
<mat-expansion-panel-header>
<mat-panel-title>
<div class="tb-panel-title-height" fxFlex="100">
<div fxLayout="row" fxFill>
<div fxFlex="30">
{{'device-profile.lwm2m.instance-label' | translate}} <<b>{{instances.get('id').value}}</b>>
</div>
<div class="checkbox-padding" fxFlex="10">
<mat-checkbox color="warn"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'attribute')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'attribute')"
(keydown)="$event.stopPropagation()"
[indeterminate]="getIndeterminate(instances, 'attribute')"
matTooltip="{{'device-profile.lwm2m.is-attr-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div class="checkbox-padding" fxFlex="10">
<mat-checkbox color="primary"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'telemetry')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'telemetry')"
(keydown)="$event.stopPropagation()"
[indeterminate]="getIndeterminate(instances, 'telemetry')"
matTooltip="{{'device-profile.lwm2m.is-telemetry-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div class="checkbox-padding" fxFlex="10">
<mat-checkbox color="primary"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'observe')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'observe')"
(keydown)="$event.stopPropagation()"
[indeterminate]="getIndeterminate(instances, 'observe')"
matTooltip="{{'device-profile.lwm2m.is-observe-tip' | translate}}"
matTooltipPosition="above">
</mat-checkbox>
</div>
<div fxFlex="7">
</div>
<div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5">
<tb-profile-lwm2m-attributes
formControlName="attributeLwm2m"
[isAttributeTelemetry]="disableObserveInstance(instances)"
[modelName]="getNameInstanceLwm2m(instances.value, objectLwM2M.get('keyId').value)"
[disabled]="this.disabled"
(updateAttributeLwm2m)="updateAttributeLwm2mInstance($event, y, objectLwM2M.get('keyId').value)">
</tb-profile-lwm2m-attributes>
</div>
</div>
</div>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-profile-lwm2m-observe-attr-telemetry-resource
formControlName="resources"
[required]="required">
</tb-profile-lwm2m-observe-attr-telemetry-resource>
</ng-template>
</mat-expansion-panel>
</div>
<tb-profile-lwm2m-observe-attr-telemetry-instances
formControlName="instances">
</tb-profile-lwm2m-observe-attr-telemetry-instances>
</ng-template>
</mat-expansion-panel>
</mat-accordion>

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

@ -13,23 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.tb-panel-title-height {
user-select: none;
min-height: 32px;
}
.checkbox-padding {
padding-left: 22px;
text-align:center;
}
:host{
section {
padding: 2px;
}
.instance-list {
mat-expansion-panel-header {
color: inherit;
}
.tb-panel-title-height {
user-select: none;
min-height: 32px;
}
}

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

@ -14,38 +14,29 @@
/// limitations under the License.
///
import { Component, forwardRef, Input } from '@angular/core';
import { ChangeDetectorRef, Component, forwardRef, Input, OnDestroy } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
FormArray,
FormBuilder,
FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator,
Validators
} from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
ATTRIBUTE,
ATTRIBUTE_LWM2M,
CLIENT_LWM2M,
Instance,
INSTANCES,
ObjectLwM2M,
ResourceLwM2M,
RESOURCES,
TELEMETRY
} from './lwm2m-profile-config.models';
import { deepClone, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils';
import { Instance, ObjectLwM2M } from './lwm2m-profile-config.models';
import { deepClone, isDefinedAndNotNull, isEqual } from '@core/utils';
import { MatDialog } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
import {
Lwm2mObjectAddInstancesData,
Lwm2mObjectAddInstancesDialogComponent
} from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component';
import _ from 'lodash';
import { Subscription } from 'rxjs';
@Component({
selector: 'tb-profile-lwm2m-observe-attr-telemetry',
@ -56,18 +47,20 @@ import _ from 'lodash';
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => Lwm2mObserveAttrTelemetryComponent),
multi: true
}
]
})
export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor {
export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor, OnDestroy, Validator {
private requiredValue: boolean;
valuePrev = null as any;
observeAttrTelemetryFormGroup: FormGroup;
resources = RESOURCES;
modelsFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@ -84,132 +77,103 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor
@Input()
disabled: boolean;
constructor(private store: Store<AppState>,
private fb: FormBuilder,
private valueChange$: Subscription = null;
private propagateChange = (v: any) => { };
constructor(private fb: FormBuilder,
private dialog: MatDialog,
public translate: TranslateService) {
this.observeAttrTelemetryFormGroup = this.fb.group({
[CLIENT_LWM2M]: this.fb.array([])
});
this.observeAttrTelemetryFormGroup.valueChanges.subscribe(value => {
if (isUndefined(this.disabled) || !this.disabled) {
this.propagateChangeState(value);
}
private cd: ChangeDetectorRef) {
this.modelsFormGroup = this.fb.group({
models: this.fb.array([])
});
}
private propagateChange = (v: any) => {
};
ngOnDestroy() {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
private propagateChangeState = (value: any): void => {
if (value) {
if (this.valuePrev === null) {
this.valuePrev = 'init';
} else if (this.valuePrev === 'init') {
this.valuePrev = value;
} else if (JSON.stringify(value) !== JSON.stringify(this.valuePrev)) {
this.valuePrev = value;
if (this.observeAttrTelemetryFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
}
}
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
this.valuePrev = null;
if (isDisabled) {
this.observeAttrTelemetryFormGroup.disable();
this.modelsFormGroup.disable({emitEvent: false});
} else {
this.observeAttrTelemetryFormGroup.enable();
this.modelsFormGroup.enable({emitEvent: false});
}
}
writeValue(value: {}): void {
writeValue(value: ObjectLwM2M[]): void {
if (isDefinedAndNotNull(value)) {
this.buildClientObjectsLwM2M(value[CLIENT_LWM2M]);
this.updateModels(value);
}
}
private buildClientObjectsLwM2M = (objectsLwM2M: ObjectLwM2M []): void => {
this.observeAttrTelemetryFormGroup.setControl(CLIENT_LWM2M,
this.createObjectsLwM2M(objectsLwM2M)
);
validate(): ValidationErrors | null {
return this.modelsFormGroup.valid ? null : {
modelsFormGroup: false
};
}
private createObjectsLwM2M = (objectsLwM2M: ObjectLwM2M[]): FormArray => {
return this.fb.array(objectsLwM2M.map((objectLwM2M) => {
return this.fb.group({
keyId: objectLwM2M.keyId,
name: objectLwM2M.name,
multiple: objectLwM2M.multiple,
mandatory: objectLwM2M.mandatory,
attributeLwm2m: objectLwM2M.attributeLwm2m,
instances: this.createInstanceLwM2M(objectLwM2M.instances)
});
}));
get modelsFormArray(): FormArray {
return this.modelsFormGroup.get('models') as FormArray;
}
private createInstanceLwM2M = (instancesLwM2M: Instance[]): FormArray => {
return this.fb.array(instancesLwM2M.map((instanceLwM2M) => {
return this.fb.group({
id: instanceLwM2M.id,
attributeLwm2m: {value: instanceLwM2M.attributeLwm2m, disabled: this.disabled},
resources: {value: instanceLwM2M.resources, disabled: this.disabled}
private updateModels(models: ObjectLwM2M[]) {
if (models.length === this.modelsFormArray.length) {
this.modelsFormArray.patchValue(models, {emitEvent: false});
} else {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
}
const modelControls: Array<AbstractControl> = [];
models.forEach(model => {
modelControls.push(this.createModelFormGroup(model));
});
}));
}
get clientLwM2MFormArray(): FormArray {
return this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray;
}
instancesLwm2mFormArray = (objectLwM2M: AbstractControl): FormArray => {
return objectLwM2M.get(INSTANCES) as FormArray;
}
changeInstanceResourcesCheckBox = (value: boolean, instance: AbstractControl, type: string): void => {
const resources = deepClone(instance.get(RESOURCES).value as ResourceLwM2M[]);
resources.forEach(resource => resource[type] = value);
instance.get(RESOURCES).patchValue(resources);
this.propagateChange(this.observeAttrTelemetryFormGroup.value);
}
private updateValidators = (): void => {
this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M).setValidators(this.required ? Validators.required : []);
this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M).updateValueAndValidity();
this.modelsFormGroup.setControl('models', this.fb.array(modelControls));
if (this.disabled) {
this.modelsFormGroup.disable({emitEvent: false});
}
this.valueChange$ = this.modelsFormGroup.valueChanges.subscribe(value => {
this.updateModel(value.models);
});
}
}
trackByParams = (index: number, element: any): number => {
return index;
private createModelFormGroup(objectLwM2M: ObjectLwM2M): FormGroup {
return this.fb.group({
id: [objectLwM2M.id],
keyId: [objectLwM2M.keyId],
name: [objectLwM2M.name],
multiple: [objectLwM2M.multiple],
mandatory: [objectLwM2M.mandatory],
attributes: [objectLwM2M.attributes],
instances: [objectLwM2M.instances]
});
}
getIndeterminate = (instance: AbstractControl, type: string): boolean => {
const resources = instance.get(RESOURCES).value as ResourceLwM2M[];
if (isDefinedAndNotNull(resources)) {
const checkedResource = resources.filter(resource => resource[type]);
return checkedResource.length !== 0 && checkedResource.length !== resources.length;
private updateModel = (value: ObjectLwM2M[]): void => {
if (value && this.modelsFormGroup.valid) {
this.propagateChange(value);
} else {
this.propagateChange(null);
}
return false;
}
getChecked = (instance: AbstractControl, type: string): boolean => {
const resources = instance.get(RESOURCES).value as ResourceLwM2M[];
return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]);
private updateValidators = (): void => {
this.modelsFormArray.setValidators(this.required ? Validators.required : []);
this.modelsFormArray.updateValueAndValidity();
}
getExpended = (objectLwM2M: AbstractControl): boolean => {
return this.instancesLwm2mFormArray(objectLwM2M).length === 1;
trackByParams = (index: number, objectLwM2M: ObjectLwM2M): number => {
return objectLwM2M.id;
}
/**
@ -230,137 +194,76 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor
* Object Instance ID cnt_max = cnt_min = 1 (всегда есть один)
*/
addInstances = ($event: Event, object: ObjectLwM2M): void => {
addInstances = ($event: Event, control: AbstractControl): void => {
if ($event) {
$event.stopPropagation();
$event.preventDefault();
}
this.dialog.open<Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesData, object>(Lwm2mObjectAddInstancesDialogComponent, {
const object: ObjectLwM2M = control.value;
const instancesId: Set<number> = this.instancesToSetId(object.instances);
this.dialog.open<Lwm2mObjectAddInstancesDialogComponent, Lwm2mObjectAddInstancesData>(Lwm2mObjectAddInstancesDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
instancesIds: this.instancesToSetId(object.instances),
instancesId: new Set(instancesId),
objectName: object.name,
objectKeyId: object.keyId
objectId: object.id
}
}).afterClosed().subscribe(
(res: Lwm2mObjectAddInstancesData | undefined) => {
(res: Set<number> | null) => {
if (isDefinedAndNotNull(res)) {
this.updateInstancesIds(res);
this.updateInstancesIds(res, control, instancesId);
}
}
);
}
private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => {
const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls
.find(e => e.value.keyId === data.objectKeyId) as FormGroup;
const instancesArray = objectLwM2MFormGroup.value.instances as Instance [];
const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray;
const instance0 = deepClone(instancesFormArray.at(0).value as Instance);
instance0.resources.forEach(r => {
r.attribute = false;
r.telemetry = false;
r.observe = false;
r.attributeLwm2m = {};
private updateInstancesIds(instancesId: Set<number>, control: AbstractControl, prevInstancesId: Set<number>) {
let instancesValue: Instance[] = control.get('instances').value;
const instanceTemplate = deepClone(instancesValue[0]);
instanceTemplate.attributes = {};
instanceTemplate.resources.forEach(resource => {
resource.attribute = false;
resource.telemetry = false;
resource.observe = false;
resource.keyName = _.camelCase(resource.name);
resource.attributes = {};
});
const valueOld = this.instancesToSetId(instancesArray);
if (!isEqual(valueOld, data.instancesIds)) {
const idsDel = this.diffBetweenSet(valueOld, data.instancesIds);
const idsAdd = this.diffBetweenSet(data.instancesIds, valueOld);
if (!isEqual(prevInstancesId, instancesId)) {
const idsDel = this.diffBetweenSet(prevInstancesId, instancesId);
const idsAdd = this.diffBetweenSet(instancesId, prevInstancesId);
if (idsAdd.size) {
this.addInstancesNew(idsAdd, objectLwM2MFormGroup, instancesFormArray, instance0);
idsAdd.forEach(id => {
const template = deepClone(instanceTemplate);
template.resources.forEach(resource => resource.keyName += id);
template.id = id;
instancesValue.push(template);
});
}
if (idsDel.size) {
this.deleteInstances(idsDel, objectLwM2MFormGroup, instancesFormArray, instance0);
instancesValue = instancesValue.filter(instance => !idsDel.has(instance.id));
if (instancesValue.length === 0) {
instanceTemplate.id = 0;
instancesValue.push(instanceTemplate);
}
}
if (idsAdd.size || idsDel.size) {
instancesValue.sort((a, b) => a.id - b.id);
control.get('instances').patchValue(instancesValue);
this.cd.markForCheck();
}
}
}
private addInstancesNew = (idsAdd: Set<number>, objectLwM2MFormGroup: FormGroup, instancesFormArray: FormArray,
instanceNew: Instance): void => {
idsAdd.forEach(x => {
instanceNew.resources.forEach(resource => {resource.keyName = _.camelCase(resource.name + x);});
this.pushInstance(instancesFormArray, x, deepClone(instanceNew as Instance));
});
(instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id);
}
private deleteInstances = (idsDel: Set<number>, objectLwM2MFormGroup: FormGroup, instancesFormArray: FormArray,
instance0: Instance): void => {
idsDel.forEach(x => {
const instanceIndex = instancesFormArray.value.findIndex(element => element.id === x);
instancesFormArray.removeAt(instanceIndex);
});
if (instancesFormArray.length === 0) {
this.pushInstance(instancesFormArray, 0, instance0);
}
(instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id);
}
private pushInstance = (instancesFormArray: FormArray, x: number, instanceNew: Instance): void => {
instancesFormArray.push(this.fb.group({
id: x,
attributeLwm2m: instanceNew.attributeLwm2m,
resources: {value: instanceNew.resources, disabled: this.disabled}
}));
}
private diffBetweenSet<T>(firstSet: Set<T>, secondSet: Set<T>): Set<T> {
return new Set([...Array.from(firstSet)].filter(x => !secondSet.has(x)));
}
private instancesToSetId = (instances: Instance[]): Set<number> => {
private instancesToSetId(instances: Instance[]): Set<number> {
return new Set(instances.map(x => x.id));
}
getNameObjectLwm2m = (objectName: string, idVerObj: string): string => {
return objectName + ' <' + idVerObj + '>';
}
getNameInstanceLwm2m = (instance: Instance, idVerObj: string): string => {
return ' instance <' + idVerObj + '/' + instance.id +'>';
}
updateAttributeLwm2mObject = (event: Event, objectKeyId: number): void => {
const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls
.find(e => e.value.keyId === objectKeyId) as FormGroup;
objectLwM2MFormGroup.patchValue({attributeLwm2m: event});
}
updateAttributeLwm2mInstance = (event: Event, indexInstance: number, objectKeyId: number): void => {
const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls
.find(e => e.value.keyId === objectKeyId) as FormGroup;
const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray;
instancesFormArray.at(indexInstance).patchValue({attributeLwm2m: event});
}
disableObserveInstance = (instance: AbstractControl): boolean => {
const checkedAttrTelemetry = this.observeInstance(instance);
if (checkedAttrTelemetry) {
instance.get(ATTRIBUTE_LWM2M).patchValue(null);
}
return checkedAttrTelemetry;
}
disableObserveObject = (index: number): boolean => {
const object = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).at(index) as FormGroup;
const instances = object.controls.instances as FormArray;
const checkedAttrTelemetry = instances.controls.filter(instance => !this.disableObserveInstance(instance));
if (checkedAttrTelemetry.length === 0) {
object.controls.attributeLwm2m.patchValue(null);
}
return checkedAttrTelemetry.length === 0;
}
observeInstance = (instance: AbstractControl): boolean => {
const resources = instance.get(RESOURCES).value as ResourceLwM2M[];
if (isDefinedAndNotNull(resources)) {
const checkedAttribute = resources.filter(resource => resource[ATTRIBUTE]);
const checkedTelemetry = resources.filter(resource => resource[TELEMETRY]);
return checkedAttribute.length === 0 && checkedTelemetry.length === 0;
}
return false;
getNameObject = (objectLwM2M: ObjectLwM2M): string => {
return `${objectLwM2M.name} <${objectLwM2M.id}>`;
}
}

13
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-components.module.ts

@ -18,7 +18,7 @@ import { NgModule } from '@angular/core';
import { Lwm2mDeviceProfileTransportConfigurationComponent } from './lwm2m-device-profile-transport-configuration.component';
import { Lwm2mObjectListComponent } from './lwm2m-object-list.component';
import { Lwm2mObserveAttrTelemetryComponent } from './lwm2m-observe-attr-telemetry.component';
import { Lwm2mObserveAttrTelemetryResourceComponent } from './lwm2m-observe-attr-telemetry-resource.component';
import { Lwm2mObserveAttrTelemetryResourcesComponent } from './lwm2m-observe-attr-telemetry-resources.component';
import { Lwm2mAttributesDialogComponent } from './lwm2m-attributes-dialog.component';
import { Lwm2mAttributesComponent } from './lwm2m-attributes.component';
import { Lwm2mAttributesKeyListComponent } from './lwm2m-attributes-key-list.component';
@ -27,6 +27,7 @@ import { Lwm2mObjectAddInstancesDialogComponent } from './lwm2m-object-add-insta
import { Lwm2mObjectAddInstancesListComponent } from './lwm2m-object-add-instances-list.component';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module';
import { Lwm2mObserveAttrTelemetryInstancesComponent } from './lwm2m-observe-attr-telemetry-instances.component';
@NgModule({
declarations:
@ -34,13 +35,14 @@ import { SharedModule } from '@app/shared/shared.module';
Lwm2mDeviceProfileTransportConfigurationComponent,
Lwm2mObjectListComponent,
Lwm2mObserveAttrTelemetryComponent,
Lwm2mObserveAttrTelemetryResourceComponent,
Lwm2mObserveAttrTelemetryResourcesComponent,
Lwm2mAttributesDialogComponent,
Lwm2mAttributesComponent,
Lwm2mAttributesKeyListComponent,
Lwm2mDeviceConfigServerComponent,
Lwm2mObjectAddInstancesDialogComponent,
Lwm2mObjectAddInstancesListComponent
Lwm2mObjectAddInstancesListComponent,
Lwm2mObserveAttrTelemetryInstancesComponent
],
imports: [
CommonModule,
@ -50,13 +52,14 @@ import { SharedModule } from '@app/shared/shared.module';
Lwm2mDeviceProfileTransportConfigurationComponent,
Lwm2mObjectListComponent,
Lwm2mObserveAttrTelemetryComponent,
Lwm2mObserveAttrTelemetryResourceComponent,
Lwm2mObserveAttrTelemetryResourcesComponent,
Lwm2mAttributesDialogComponent,
Lwm2mAttributesComponent,
Lwm2mAttributesKeyListComponent,
Lwm2mDeviceConfigServerComponent,
Lwm2mObjectAddInstancesDialogComponent,
Lwm2mObjectAddInstancesListComponent
Lwm2mObjectAddInstancesListComponent,
Lwm2mObserveAttrTelemetryInstancesComponent
],
providers: [
]

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

@ -20,8 +20,6 @@ export const PAGE_SIZE_LIMIT = 50;
export const INSTANCES = 'instances';
export const INSTANCE = 'instance';
export const RESOURCES = 'resources';
export const ATTRIBUTE_LWM2M = 'attributeLwm2m';
export const CLIENT_LWM2M = 'clientLwM2M';
export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry';
export const OBSERVE = 'observe';
export const ATTRIBUTE = 'attribute';
@ -184,7 +182,7 @@ export interface ObservableAttributes {
attribute: string[];
telemetry: string[];
keyName: {};
attributeLwm2m?: AttributesNameValueMap;
attributeLwm2m?: AttributesNameValueMap[];
}
export function getDefaultBootstrapServersSecurityConfig(): BootstrapServersSecurityConfig {
@ -222,7 +220,7 @@ export function getDefaultProfileObserveAttrConfig(): ObservableAttributes {
attribute: [],
telemetry: [],
keyName: {},
attributeLwm2m: {}
attributeLwm2m: []
};
}
@ -237,6 +235,8 @@ export function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSetting
};
}
export type ResourceSettingTelemetry = 'observe' | 'attribute' | 'telemetry';
export interface ResourceLwM2M {
id: number;
name: string;
@ -244,12 +244,12 @@ export interface ResourceLwM2M {
attribute: boolean;
telemetry: boolean;
keyName: string;
attributeLwm2m?: AttributesNameValueMap;
attributes?: AttributesNameValueMap;
}
export interface Instance {
id: number;
attributeLwm2m?: AttributesNameValueMap;
attributes?: AttributesNameValueMap;
resources: ResourceLwM2M[];
}
@ -265,7 +265,7 @@ export interface ObjectLwM2M {
name: string;
multiple?: boolean;
mandatory?: boolean;
attributeLwm2m?: AttributesNameValueMap;
attributes?: AttributesNameValueMap;
instances?: Instance [];
}

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

@ -1228,25 +1228,20 @@
"valid-id-instance-no-max": "Instance number '{{instance}}' no validated. Max value='{{max}}'",
"valid-id-instance": "Instance number '{{instance}}' no validated. { count, plural, 1 {Max value='{{max}}'} 2 {Min value='{{min}}'} other {Must be only number} }",
"model-tab": "LWM2M Model",
"add-instances-tip": "Add new instances",
"add-new-instances": "Add new instances",
"instances-list": "Instances list",
"instances-input": "Input Instance Id value",
"instances-input-holder": "Input Instance number...",
"instance-label": "Instance",
"instance": "Instance",
"resource-label": "<id> Resource name",
"observe-label": "Observe",
"attribute-label": "Attribute",
"telemetry-label": "Telemetry",
"key-name-label": "Key Name",
"resource-tip": "ID & Original Name of the Resource (only Operations isReadable)",
"is-observe-tip": "Is Observe",
"not-observe-tip": "To observe select telemetry or attributes first",
"is-attr-tip": "Is Attribute",
"is-telemetry-tip": "Is Telemetry",
"key-name-tip": "Key Name in Camel format",
"edit-attributes-select": "To edit attributes select telemetry or attributes",
"edit-observe-select": "To edit observe select telemetry or attribute",
"edit-attributes-select": "To edit attributes select telemetry or attribute",
"no-attributes-set": "No attributes set",
"key-name": "Key Name",
"key-name": "Key name",
"key-name-required": "Key name is required",
"attribute-name": "Name attribute",
"attribute-name-required": "Name attribute is required.",
"attribute-value": "Attribute value",

Loading…
Cancel
Save