From fc33d6430887354de65bbe7cce9d42b821683d66 Mon Sep 17 00:00:00 2001 From: "EUR\\y508925" Date: Tue, 23 Jan 2024 17:34:10 +0530 Subject: [PATCH 01/34] computed device property config implementation. --- .../asset-properties.module.ts | 6 + .../common/asset-property-constant.ts | 137 +++++++++++++++++- ...sset-property-item-selector.component.html | 8 + .../asset-property-selector.component.html | 20 ++- .../asset-property-selector.component.ts | 30 ++++ .../computed-property-config-component.html | 57 ++++++++ .../computed-property-config.component.ts | 47 ++++++ .../last-measurement-config.component.html | 22 +++ .../last-measurement-config.component.ts | 29 ++++ 9 files changed, 353 insertions(+), 3 deletions(-) create mode 100644 asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config-component.html create mode 100644 asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts create mode 100644 asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html create mode 100644 asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts diff --git a/asset-properties-widget/asset-properties.module.ts b/asset-properties-widget/asset-properties.module.ts index 56235ea..2f0ac89 100644 --- a/asset-properties-widget/asset-properties.module.ts +++ b/asset-properties-widget/asset-properties.module.ts @@ -15,6 +15,9 @@ import { AssetPropertiesItemComponent } from './component/asset-properties-view/ import { assetPropertyItemSelectorCtrlComponent } from './component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component'; import { AssetPropertiesSelectorComponent } from './component/asset-properties-config/asset-property-selector/asset-property-selector.component'; import { SubAssetsModule } from '@c8y/ngx-components/sub-assets'; +import { ComputedPropertyConfigComponent } from './component/asset-properties-config/computed-asset-property/computed-property-config.component'; +import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector'; +import { ComputedPropertyLastMeasurementConfigComponent } from './component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component'; @NgModule({ declarations: [ @@ -24,6 +27,8 @@ import { SubAssetsModule } from '@c8y/ngx-components/sub-assets'; AssetPropertiesViewComponent, AssetPropertiesComponent, AssetPropertiesItemComponent, + ComputedPropertyConfigComponent, + ComputedPropertyLastMeasurementConfigComponent ], imports: [ CoreModule, @@ -32,6 +37,7 @@ import { SubAssetsModule } from '@c8y/ngx-components/sub-assets'; DragDropModule, RealtimeModule, SubAssetsModule, + DatapointSelectorModule, ], providers: [ { diff --git a/asset-properties-widget/common/asset-property-constant.ts b/asset-properties-widget/common/asset-property-constant.ts index 1dbbd0c..dddb2f3 100644 --- a/asset-properties-widget/common/asset-property-constant.ts +++ b/asset-properties-widget/common/asset-property-constant.ts @@ -51,4 +51,139 @@ export const property = [ isEditable: false, isExistingProperty: true, }, -]; + { + c8y_JsonSchema: { + properties: { alarmCountToday: { + title: 'Alarm count today', + type: 'number', + },}, + }, + name: 'alarmCountToday', + label: 'Alarm count today', + title: 'Alarm type', + type: 'string', + config:{type:''}, + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { alarmCount3Months: { + title: 'Alarm count 3 months', + type: 'number', + },}, + }, + name: 'alarmCount3Months', + label: 'Alarm count 3 months', + title: 'Alarm type', + type: 'string', + config:{type:''}, + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { eventCountToday: { + title: 'Event count today', + type: 'number', + },}, + }, + name: 'eventCountToday', + label: 'Event count today', + title: 'Event type', + type: 'string', + config:{type:''}, + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { eventCount3Months: { + title: 'Event count 3 months', + type: 'number', + },}, + }, + name: 'eventCount3Months', + label: 'Event count 3 months', + title: 'Event type', + type: 'string', + config:{type:''}, + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { lastDeviceMessage: { + title: 'Last device message', + type: 'string', + },}, + }, + name: 'lastDeviceMessage', + label: 'Last device message', + printFormat: 'datetime', + type: 'string', + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: {properties: { lastMeasurement: { + title: 'Last measurement', + type: 'string', + },},}, + name: 'lastMeasurement', + label: 'Last measurement', + type: 'string', + config:{dp:[],isValid:null}, + computed: true, + isEditable: false, + isExistingProperty: true, + description: 'sdjfvsdjfvsdfvksdfvsdhfvskdh' + }, + { + c8y_JsonSchema: { + properties: { childDevicesCount: { + title: 'Number of child devices', + type: 'number', + },}, + }, + name: 'childDevicesCount', + label: 'Number of child devices', + type: 'number', + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { childAssetsCount: { + title: 'Number of child assets', + type: 'number', + },}, + }, + name: 'childAssetsCount', + label: 'Number of child assets', + type: 'number', + computed: true, + isEditable: false, + isExistingProperty: true, + }, + { + c8y_JsonSchema: { + properties: { configurationSnapshot: { + title: 'Configuration snapshot', + type: 'number', + },}, + }, + name: 'configurationSnapshot', + label: 'Configuration snapshot', + type: 'number', + computed: true, + isEditable: false, + isExistingProperty: true, + } +]; \ No newline at end of file diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html index 8e6f4c4..ad04f48 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html @@ -91,6 +91,14 @@ > + {{ property.label ? property.label : (property.title | translate) }} diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html index 4f21cea..7106c6b 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html @@ -45,7 +45,7 @@ cdkDrag cdkDragLockAxis="y" class="property" - *ngFor="let property of properties" + *ngFor="let property of properties; index as i" class="table-row-not-expanded" > @@ -131,7 +131,23 @@ /> - {{ + + {{ (property.name | translate) || (property.keyPath?.join(".") | translate) }} diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts index ea7f27a..775ad25 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts @@ -12,6 +12,7 @@ import { property, } from '../../../common/asset-property-constant'; import { some } from 'lodash-es'; +import { ComputedPropertyConfigComponent } from '../computed-asset-property/computed-property-config.component'; type ModalInitialState = { title: string; @@ -29,12 +30,14 @@ export class AssetPropertiesSelectorComponent implements OnChanges { isLoading: boolean = false; assetType: IManagedObject; assetPropertySelectorModalRef: BsModalRef; + computedPropertyConfigModalRef: BsModalRef; properties = cloneDeep(defaultProperty); customProperties: IManagedObject[] = cloneDeep(defaultProperty).concat( cloneDeep(property) ); ExpandedComplexProperty: any; isAtleastOnePropertySelected: boolean = true; + selectedComputedPropertyIndex: number; constructor( private assetTypes: AssetTypesService, @@ -129,6 +132,12 @@ export class AssetPropertiesSelectorComponent implements OnChanges { ); this.isAtleastOnePropertySelected = true; this.config.properties = this.properties; + this.properties.forEach((property, idx, arr) => { + console.log(property); + if(property.computed && (!property.config.dp || !property.config.type)){ + this.configComputeProperty(idx); + } + }); this.assetPropertySelectorModalRef.hide(); } ); @@ -208,4 +217,25 @@ export class AssetPropertiesSelectorComponent implements OnChanges { drop(event: CdkDragDrop) { moveItemInArray(this.properties, event.previousIndex, event.currentIndex); } + + configComputeProperty(index){ + this.selectedComputedPropertyIndex = index; + this.computedPropertyConfigModalRef = this.modalService.show( + ComputedPropertyConfigComponent, + { + backdrop: 'static', + initialState: { + title: gettext('Computed property configuration'), + property: this.properties[index], + index: index + }, + } + ); + this.computedPropertyConfigModalRef.content.savePropertySelection.subscribe( + (object: any) => { + this.config.properties[object.index] = object.property; + // this.computedPropertyConfigModalRef.hide(); + } + ); + } } diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config-component.html b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config-component.html new file mode 100644 index 0000000..71d080c --- /dev/null +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config-component.html @@ -0,0 +1,57 @@ +
+ + + +
diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts new file mode 100644 index 0000000..89877d6 --- /dev/null +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts @@ -0,0 +1,47 @@ +import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; +import * as cloneDeep from 'lodash/cloneDeep'; +import { BsModalRef } from 'ngx-bootstrap/modal'; +import { IManagedObject } from '@c8y/client'; + +@Component({ + selector: 'c8y-computed-property-config-component', + templateUrl: './computed-property-config-component.html', +}) + +export class ComputedPropertyConfigComponent implements OnInit { + @Input() title?: string; + @Input() property?: IManagedObject; + @Input() index?:number; + + @Output() savePropertySelection = new EventEmitter(); + @Output() cancelPropertySelection = new EventEmitter(); + + tempProperty: IManagedObject; + config2: object = {type: 's7aRealTime_47773',_id: '5140160262811182'}; + configSchema: object = {properties:{type:{title: 'Event type',type: 'string'}},type: 'string'}; + constructor(private bsModal: BsModalRef) {} + ngOnInit(): void { + this.tempProperty = cloneDeep(this.property); + // this.configSchema = this.property.c8y_JsonSchema; + console.log('hii',this.configSchema); + // this.customProperties = cloneDeep(this.constructCustomProperties()); + } + + onSaveButtonClicked(): void { + this.property = this.tempProperty; + this.savePropertySelection.emit({property:this.property,index:this.index}); + this.bsModal.hide(); + } + + onCancelButtonClicked(): void { + this.bsModal.hide(); + } + isSaveButtonDisabled(): boolean{ + if(this.tempProperty.name == 'lastMeasurement'){ + return !this.tempProperty.config?.isValid; + }else{ + return !this.tempProperty.config?.type; + } + } + +} diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html new file mode 100644 index 0000000..69263f5 --- /dev/null +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html @@ -0,0 +1,22 @@ +
+ + +
+ +
+ +
+ +
+
diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts new file mode 100644 index 0000000..cbb29a7 --- /dev/null +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts @@ -0,0 +1,29 @@ +import { Component, Input, Output, OnInit } from '@angular/core'; +import { IManagedObject } from '@c8y/client'; +import * as cloneDeep from 'lodash/cloneDeep'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'c8y-last-measurement-config', + templateUrl: './last-measurement-config.component.html', +}) +export class ComputedPropertyLastMeasurementConfigComponent implements OnInit { + @Input() property?: any; + + @Output() measurmentChange: Observable; + + selectedProperty: IManagedObject[] = []; + dataPoints: Array = []; + minSelectCount: number = 1; + maxSelectCount: number = 1; + configSchema: object = {properties:{type:{title: 'Event type',type: 'string'}},type: 'string'}; + + ngOnInit(): void { + this.dataPoints = this.property.config?.dp; + console.log('datapoint',this.dataPoints); + } + + validationChanged(isValid){ + this.property.config.isValid= isValid; + } +} From bf297eeeee1764a420f5577281c690754e89faef Mon Sep 17 00:00:00 2001 From: "EUR\\y508925" Date: Tue, 30 Jan 2024 01:01:23 +0530 Subject: [PATCH 02/34] device property: last measurement implemantation added. --- .../common/asset-property-constant.ts | 14 ++- .../asset-property-selector.component.ts | 20 ++-- .../computed-property-config.component.ts | 12 +-- .../last-measurement-config.component.html | 13 ++- .../last-measurement-config.component.ts | 11 +-- .../asset-properties-view.component.html | 4 + .../asset-properties-view.component.ts | 60 +++++++++++- .../asset-properties.component.ts | 94 ++++++++++++++++--- 8 files changed, 184 insertions(+), 44 deletions(-) diff --git a/asset-properties-widget/common/asset-property-constant.ts b/asset-properties-widget/common/asset-property-constant.ts index dddb2f3..8b223ea 100644 --- a/asset-properties-widget/common/asset-property-constant.ts +++ b/asset-properties-widget/common/asset-property-constant.ts @@ -1,3 +1,5 @@ +import { gettext } from "@c8y/ngx-components"; + export const defaultProperty = [ { c8y_JsonSchema: { properties: { name: { type: 'string', label: 'Name' } } }, @@ -138,11 +140,10 @@ export const property = [ name: 'lastMeasurement', label: 'Last measurement', type: 'string', - config:{dp:[],isValid:null}, + config:{dp:[],isValid:null, resultTypes:1}, computed: true, isEditable: false, isExistingProperty: true, - description: 'sdjfvsdjfvsdfvksdfvsdhfvskdh' }, { c8y_JsonSchema: { @@ -186,4 +187,11 @@ export const property = [ isEditable: false, isExistingProperty: true, } -]; \ No newline at end of file +]; + +export const RESULT_TYPES = { + VALUE: { name: 'VALUE', value: 1, label: gettext('Only value') }, + VALUE_UNIT: { name: 'VALUE_UNIT', value: 2, label: gettext('Value and unit') }, + VALUE_UNIT_TIME: { name: 'VALUE_UNIT_TIME', value: 3, label: gettext('Value, unit and time') }, + // OBJECT: { name: 'OBJECT', value: 4, label: gettext('Complete object') } +}; \ No newline at end of file diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts index 775ad25..5daeaf0 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts @@ -132,10 +132,10 @@ export class AssetPropertiesSelectorComponent implements OnChanges { ); this.isAtleastOnePropertySelected = true; this.config.properties = this.properties; - this.properties.forEach((property, idx, arr) => { - console.log(property); - if(property.computed && (!property.config.dp || !property.config.type)){ - this.configComputeProperty(idx); + this.properties.forEach((property, index) => { + if(property.computed && property.config && !(property.config.dp?.length>0 || property.config.type)){ + this.config.properties[index].config = {...this.config.properties[index].config, ...{id:String(Math.random()).substr(2)}}; + this.configComputeProperty(index); } }); this.assetPropertySelectorModalRef.hide(); @@ -183,7 +183,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { return item.name || item.title; }) .indexOf(property.name || property.title); - if (removeIndex >= 0) { + if (removeIndex >= 0 && !property.config) { this.properties[removeIndex] = property; properties.splice(index, 1); this.removeSelectedProperties(properties); @@ -231,10 +231,16 @@ export class AssetPropertiesSelectorComponent implements OnChanges { }, } ); - this.computedPropertyConfigModalRef.content.savePropertySelection.subscribe( + this.computedPropertyConfigModalRef.content.savePropertyConfiguration.subscribe( (object: any) => { this.config.properties[object.index] = object.property; - // this.computedPropertyConfigModalRef.hide(); + } + ); + this.computedPropertyConfigModalRef.content.cancelPropertyConfiguration.subscribe( + (index: number) => { + if(!(this.config.properties[index].config.dp?.length>0 || this.config.properties[index].config.type)){ + this.config.properties.splice(index, 1); + } } ); } diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts index 89877d6..85017d3 100644 --- a/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/computed-property-config.component.ts @@ -13,27 +13,23 @@ export class ComputedPropertyConfigComponent implements OnInit { @Input() property?: IManagedObject; @Input() index?:number; - @Output() savePropertySelection = new EventEmitter(); - @Output() cancelPropertySelection = new EventEmitter(); + @Output() savePropertyConfiguration = new EventEmitter(); + @Output() cancelPropertyConfiguration = new EventEmitter(); tempProperty: IManagedObject; - config2: object = {type: 's7aRealTime_47773',_id: '5140160262811182'}; - configSchema: object = {properties:{type:{title: 'Event type',type: 'string'}},type: 'string'}; constructor(private bsModal: BsModalRef) {} ngOnInit(): void { this.tempProperty = cloneDeep(this.property); - // this.configSchema = this.property.c8y_JsonSchema; - console.log('hii',this.configSchema); - // this.customProperties = cloneDeep(this.constructCustomProperties()); } onSaveButtonClicked(): void { this.property = this.tempProperty; - this.savePropertySelection.emit({property:this.property,index:this.index}); + this.savePropertyConfiguration.emit({property:this.property,index:this.index}); this.bsModal.hide(); } onCancelButtonClicked(): void { + this.cancelPropertyConfiguration.emit(this.index); this.bsModal.hide(); } isSaveButtonDisabled(): boolean{ diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html index 69263f5..14ae0da 100644 --- a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html @@ -15,8 +15,17 @@
- +
diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts index cbb29a7..4fa92c3 100644 --- a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.ts @@ -2,26 +2,21 @@ import { Component, Input, Output, OnInit } from '@angular/core'; import { IManagedObject } from '@c8y/client'; import * as cloneDeep from 'lodash/cloneDeep'; import { Observable } from 'rxjs'; +import { RESULT_TYPES } from '../../../../common/asset-property-constant'; @Component({ selector: 'c8y-last-measurement-config', templateUrl: './last-measurement-config.component.html', }) -export class ComputedPropertyLastMeasurementConfigComponent implements OnInit { +export class ComputedPropertyLastMeasurementConfigComponent { @Input() property?: any; @Output() measurmentChange: Observable; selectedProperty: IManagedObject[] = []; - dataPoints: Array = []; minSelectCount: number = 1; maxSelectCount: number = 1; - configSchema: object = {properties:{type:{title: 'Event type',type: 'string'}},type: 'string'}; - - ngOnInit(): void { - this.dataPoints = this.property.config?.dp; - console.log('datapoint',this.dataPoints); - } + resultTypes = RESULT_TYPES; validationChanged(isValid){ this.property.config.isValid= isValid; diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.html b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.html index 1fa2785..fd8c532 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.html +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.html @@ -1,5 +1,6 @@ {{ "No Data" | translate }} +
+ +
diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts index bb6d4e6..8a3d48f 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts @@ -1,13 +1,23 @@ import { Component, OnInit, Input } from '@angular/core'; import { IManagedObject, InventoryService } from '@c8y/client'; -import { ManagedObjectRealtimeService } from '@c8y/ngx-components'; +import { ManagedObjectRealtimeService, MeasurementRealtimeService } from '@c8y/ngx-components'; import { AssetPropertiesService } from '../asset-properties-config/asset-properties.service'; import { some, cloneDeep } from 'lodash-es'; +import { KPIDetails } from '@c8y/ngx-components/datapoint-selector'; +import { Observable } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; + +interface MeasurementValue { + unit?: string; + value: number; + date: string; + id: string; +} @Component({ selector: 'c8y-asset-properties-view', templateUrl: './asset-properties-view.component.html', - providers: [ManagedObjectRealtimeService], + providers: [ManagedObjectRealtimeService, MeasurementRealtimeService], }) export class AssetPropertiesViewComponent implements OnInit { selected = { id: 'asset-properties-widget' }; @@ -16,11 +26,18 @@ export class AssetPropertiesViewComponent implements OnInit { customProperties: IManagedObject[]; properties: IManagedObject[]; @Input() config: any; + computedPropertyObject:object; + isLoading = true; + + state$: Observable<{ + latestMeasurement: MeasurementValue; + }>; constructor( protected inventoryService: InventoryService, protected moRealtimeService: ManagedObjectRealtimeService, - private assetPropertiesService: AssetPropertiesService + private assetPropertiesService: AssetPropertiesService, + private measurementRealtime: MeasurementRealtimeService ) {} async ngOnInit(): Promise { @@ -45,7 +62,20 @@ export class AssetPropertiesViewComponent implements OnInit { }); this.config.properties = cloneDeep(this.properties); this.constructComplexPropertyKeys(); + this.config.properties.forEach(property =>{ + if(property.computed && property.name ==='lastMeasurement' && property.config.dp.length>0){ + // eslint-disable-next-line no-underscore-dangle + let datapoint = property.config.dp.find((dp) =>dp.__active); + datapoint = {...datapoint, ...{uniqId:property.config.id}}; + this.getLatestMeasurement$(datapoint).subscribe( + (lastMeasurement) => { + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`lastMeasurement_${lastMeasurement.id}`]: lastMeasurement}}; + } + ); + } + }); this.handleRealtime(); + this.isLoading = false; }, 1000); } catch (error) { this.isEmptyWidget = true; @@ -69,7 +99,7 @@ export class AssetPropertiesViewComponent implements OnInit { if(!customizedProperty.find((prop) => prop.id === property.id)){ customizedProperty.push(property); } - }else if (element.active && !customizedProperty.find((prop) => prop.name === element.name)){ + }else if (element.active && (!customizedProperty.find((prop) => prop.name === element.name) || element.computed)){ customizedProperty.push(element); } }); @@ -102,4 +132,26 @@ export class AssetPropertiesViewComponent implements OnInit { this.selectedAsset = asset; }); } + + getLatestMeasurement$(datapoint: KPIDetails): Observable { + return this.measurementRealtime + .latestValueOfSpecificMeasurement$( + datapoint.fragment, + datapoint.series, + datapoint.__target.id, + // we only need the last two values in case we want to show a trend + 1 + ) + .pipe( + filter(measurement => !!measurement), + map(measurement => { + return { + unit: measurement[datapoint.fragment][datapoint.series].unit, + value: measurement[datapoint.fragment][datapoint.series].value, + date: measurement.time as string, + id: datapoint.uniqId + }; + }) + ); + } } diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts index 8dcca14..67d9c4e 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts @@ -3,6 +3,7 @@ import { EventEmitter, Input, OnChanges, + OnInit, Output, SimpleChanges, ViewChild, @@ -17,6 +18,7 @@ import { AlertService, AssetTypesService, DashboardChildComponent, + DatePipe, gettext, } from '@c8y/ngx-components'; import { AssetPropertiesItem } from './asset-properties.model'; @@ -25,12 +27,14 @@ import { Permissions } from '@c8y/ngx-components'; import { filter, takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; import { AssetLocationComponent } from '@c8y/ngx-components/sub-assets'; +import { RESULT_TYPES } from '../../../common/asset-property-constant'; @Component({ selector: 'c8y-asset-properties', templateUrl: './asset-properties.component.html', }) -export class AssetPropertiesComponent implements OnChanges { +export class AssetPropertiesComponent implements OnChanges, OnInit { + @Input() computedPropertyObject: IManagedObject; @Input() asset: IManagedObject; @Output() assetChange = new EventEmitter(); @Input() @@ -51,7 +55,8 @@ export class AssetPropertiesComponent implements OnChanges { private inventoryBinary: InventoryBinaryService, private alert: AlertService, private permissionsService: Permissions, - public dashboardChild: DashboardChildComponent + public dashboardChild: DashboardChildComponent, + private pipe: DatePipe ) {} async ngOnInit() { @@ -63,7 +68,7 @@ export class AssetPropertiesComponent implements OnChanges { } async ngOnChanges(changes: SimpleChanges): Promise { - if (changes.asset?.currentValue || changes.properties?.currentValue) { + if (changes.asset?.currentValue || changes.properties?.currentValue || changes.computedPropertyObject?.currentValue) { this.assetType = undefined; this.customProperties = []; this.loadAsset(); @@ -108,6 +113,9 @@ export class AssetPropertiesComponent implements OnChanges { for (const key of keys) { if (properties[key]) { let value = asset[key]; + if(mo.computed){ + value = this.getComputedPropertyValue(mo,asset); + } const {type} = properties[key]; const {title} = properties[key]; let file; @@ -237,14 +245,76 @@ export class AssetPropertiesComponent implements OnChanges { item.jsonSchema.required = [mo.c8y_JsonSchema.key]; } } - private async listenToWidgetResizeEvent(dashboardChild: DashboardChildComponent) { - dashboardChild.changeEnd - .pipe( - filter(child => child.lastChange === 'resize'), - takeUntil(this.destroy$) - ) - .subscribe(async () => { - this.clusterMap.mapView.map.invalidateSize(); - }); + + private async listenToWidgetResizeEvent(dashboardChild: DashboardChildComponent) { + dashboardChild.changeEnd + .pipe( + filter(child => child.lastChange === 'resize'), + takeUntil(this.destroy$) + ) + .subscribe(async () => { + this.clusterMap.mapView.map.invalidateSize(); + }); + } + + getComputedPropertyValue(mo,asset){ + let value = ''; + + switch (mo.name) { + case 'alarmCountToday': + value = asset.childDevices.references.length; + break; + case 'alarmCount3Months': + value = asset.childDevices.references.length; + break; + case 'eventCountToday': + value = asset.childDevices.references.length; + break; + case 'eventCount3Months': + value = asset.childDevices.references.length; + break; + case 'lastDeviceMessage': + value = asset.childDevices.references.length; + break; + case 'lastMeasurement': + value = this.computedPropertyObject ? this.getLastMeasurementWithFormat(this.computedPropertyObject[`${mo.name}_${mo.config.id}`],mo.config.resultTypes) : undefined; + break; + case 'childDevicesCount': + value = asset.childDevices.references.length; + break; + case 'childAssetsCount': + value = asset.childAssets.references.length; + break; + case 'configurationSnapshot': + value = asset.childDevices.references.length; + break; + default: + value = ''; + break; + } + return value; + } + + getLastMeasurementWithFormat ( measurementObj ,resultType) { + let out = ''; + if(measurementObj){ + const { date,value, unit } = measurementObj; + const type = resultType || RESULT_TYPES.VALUE.value; + switch (type) { + case RESULT_TYPES.VALUE.value: + out = value; + break; + case RESULT_TYPES.VALUE_UNIT.value: + out = `${value } ${ unit || ''}`; + break; + case RESULT_TYPES.VALUE_UNIT_TIME.value: + out = ` ${this.pipe.transform(date, 'short')} | ${`${value } ${ unit || ''}`}`; + break; + default: + out = ''; + break; } + } + return out; + } } From 949305aa60775e5bca1f145ee35e101bea4c7405 Mon Sep 17 00:00:00 2001 From: "EUR\\y508925" Date: Wed, 7 Feb 2024 15:09:07 +0530 Subject: [PATCH 03/34] coputed property alarms and events intigration added. --- .../asset-properties.module.ts | 6 + .../common/asset-property-constant.ts | 36 ++++- .../asset-property-item-selector.component.ts | 6 +- .../asset-property-selector.component.html | 5 +- .../asset-property-selector.component.ts | 8 +- .../last-measurement-config.component.html | 52 ++++---- .../asset-properties-view.component.spec.ts | 12 +- .../asset-properties-view.component.ts | 123 ++++++++++++++---- .../asset-properties-view.service.ts | 30 +++++ .../asset-properties.component.spec.ts | 4 +- .../asset-properties.component.ts | 16 +-- 11 files changed, 217 insertions(+), 81 deletions(-) create mode 100644 asset-properties-widget/component/asset-properties-view/asset-properties-view.service.ts diff --git a/asset-properties-widget/asset-properties.module.ts b/asset-properties-widget/asset-properties.module.ts index 2f0ac89..4123d78 100644 --- a/asset-properties-widget/asset-properties.module.ts +++ b/asset-properties-widget/asset-properties.module.ts @@ -1,6 +1,8 @@ import { NgModule } from '@angular/core'; import { + AlarmRealtimeService, CoreModule, + EventRealtimeService, HOOK_COMPONENTS, RealtimeModule, } from '@c8y/ngx-components'; @@ -18,6 +20,7 @@ import { SubAssetsModule } from '@c8y/ngx-components/sub-assets'; import { ComputedPropertyConfigComponent } from './component/asset-properties-config/computed-asset-property/computed-property-config.component'; import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector'; import { ComputedPropertyLastMeasurementConfigComponent } from './component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component'; +import { DatePipe } from '@angular/common'; @NgModule({ declarations: [ @@ -40,6 +43,9 @@ import { ComputedPropertyLastMeasurementConfigComponent } from './component/asse DatapointSelectorModule, ], providers: [ + AlarmRealtimeService, + DatePipe, + EventRealtimeService, { provide: HOOK_COMPONENTS, multi: true, diff --git a/asset-properties-widget/common/asset-property-constant.ts b/asset-properties-widget/common/asset-property-constant.ts index 8b223ea..90b71a5 100644 --- a/asset-properties-widget/common/asset-property-constant.ts +++ b/asset-properties-widget/common/asset-property-constant.ts @@ -53,6 +53,36 @@ export const property = [ isEditable: false, isExistingProperty: true, }, + { + label: 'Active alarms status', + type: 'object', + isEditable: false, + name: 'c8y_ActiveAlarmsStatus', + c8y_JsonSchema: { + properties: { c8y_ActiveAlarmsStatus: {key:'c8y_ActiveAlarmsStatus', type: 'object', label: 'Active alarms status',properties: { + critical: { + title: 'Critical', + type: 'number', + isEditable: false + }, + major: { + title: 'Major', + type: 'number', + isEditable: false + }, + minor: { + title: 'Minor', + type: 'number', + isEditable: false + }, + warning: { + title: 'Warning', + type: 'number', + isEditable: false + } + } } }, + }, + }, { c8y_JsonSchema: { properties: { alarmCountToday: { @@ -64,7 +94,7 @@ export const property = [ label: 'Alarm count today', title: 'Alarm type', type: 'string', - config:{type:''}, + config:{ type:'' }, computed: true, isEditable: false, isExistingProperty: true, @@ -80,7 +110,7 @@ export const property = [ label: 'Alarm count 3 months', title: 'Alarm type', type: 'string', - config:{type:''}, + config:{ type:'' }, computed: true, isEditable: false, isExistingProperty: true, @@ -112,7 +142,7 @@ export const property = [ label: 'Event count 3 months', title: 'Event type', type: 'string', - config:{type:''}, + config:{ type:'' }, computed: true, isEditable: false, isExistingProperty: true, diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.ts b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.ts index af96621..154b156 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.ts @@ -28,8 +28,8 @@ export class assetPropertyItemSelectorCtrlComponent implements OnInit { this.customProperties.forEach((property) => { if (this.isComplexProperty(property)) { complexProperties.push(property); - Object.keys(property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key].properties).forEach((key)=>{ - const object = property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key].properties[key]; + Object.keys(property.c8y_JsonSchema.properties[property.name].properties).forEach((key)=>{ + const object = property.c8y_JsonSchema.properties[property.name].properties[key]; object['keyPath'] = [property.name]; object.keyPath.push(key); complexProperties.push(object); @@ -93,7 +93,7 @@ export class assetPropertyItemSelectorCtrlComponent implements OnInit { return false; } return ( - prop.c8y_JsonSchema.properties[prop.c8y_JsonSchema.key]?.type === 'object' + prop.c8y_JsonSchema.properties[prop.name]?.type === 'object' ); } } diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html index 7106c6b..583a44b 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html @@ -83,9 +83,8 @@ diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts index 5daeaf0..0f25a89 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts @@ -79,7 +79,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { const constructCustomProperties: IManagedObject[] = []; customProperties.forEach((property) => { const object = - property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key]; + property.c8y_JsonSchema.properties[property.name]; if (object.type === 'object') { constructCustomProperties.push(property); } else { @@ -146,7 +146,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { this.properties.forEach((property) => { if (this.isComplexProperty(property)) { const customProperties = - property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key] + property.c8y_JsonSchema.properties[property.name] ?.properties; const tempCustomProperties = {}; for (const key in customProperties) { @@ -160,7 +160,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { } if (!isEmpty(tempCustomProperties)) { property.c8y_JsonSchema.properties[ - property.c8y_JsonSchema.key + property.name ].properties = tempCustomProperties; } } @@ -172,7 +172,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { return false; } return ( - prop.c8y_JsonSchema.properties[prop.c8y_JsonSchema.key]?.type === 'object' + prop.c8y_JsonSchema.properties[prop.name]?.type === 'object' ); } diff --git a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html index 14ae0da..550afc7 100644 --- a/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html +++ b/asset-properties-widget/component/asset-properties-config/computed-asset-property/properties/last-measurement-config.component.html @@ -1,31 +1,27 @@ -
- - -
+ + -
- -
- + - -
+ {{ item.value.label }} + +
diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.spec.ts b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.spec.ts index 52868ae..2c1b684 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.spec.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.spec.ts @@ -11,6 +11,11 @@ describe('AssetPropertiesViewComponent', () => { let asset: any; let customPropertyObjects: any; let configCustomPropertyObjects: any; + let measurementRealtime:any; + let assetPropertiesViewService: any; + let datePipe: any; + let alarmRealtimeService: any; + let eventRealtimeService: any; beforeEach(() => { inventoryMock = { detail: jest.fn() }; @@ -21,7 +26,12 @@ describe('AssetPropertiesViewComponent', () => { component = new AssetPropertiesViewComponent( inventoryMock, moRealtimeServiceMock, - assetPropertiesServiceMock + assetPropertiesServiceMock, + measurementRealtime, + assetPropertiesViewService, + datePipe, + alarmRealtimeService, + eventRealtimeService ); asset = { diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts index 8a3d48f..2bb6e03 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts @@ -1,11 +1,13 @@ import { Component, OnInit, Input } from '@angular/core'; -import { IManagedObject, InventoryService } from '@c8y/client'; -import { ManagedObjectRealtimeService, MeasurementRealtimeService } from '@c8y/ngx-components'; +import { IAlarm, IEvent, IManagedObject, InventoryService } from '@c8y/client'; +import { AlarmRealtimeService, EventRealtimeService, ManagedObjectRealtimeService, MeasurementRealtimeService } from '@c8y/ngx-components'; import { AssetPropertiesService } from '../asset-properties-config/asset-properties.service'; import { some, cloneDeep } from 'lodash-es'; import { KPIDetails } from '@c8y/ngx-components/datapoint-selector'; import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; +import { AssetPropertiesViewService } from './asset-properties-view.service'; +import { DatePipe } from '@angular/common'; interface MeasurementValue { unit?: string; @@ -37,7 +39,11 @@ export class AssetPropertiesViewComponent implements OnInit { protected inventoryService: InventoryService, protected moRealtimeService: ManagedObjectRealtimeService, private assetPropertiesService: AssetPropertiesService, - private measurementRealtime: MeasurementRealtimeService + private measurementRealtime: MeasurementRealtimeService, + private assetPropertiesViewService: AssetPropertiesViewService, + private datePipe: DatePipe, + private alarmRealtimeService: AlarmRealtimeService, + private eventRealtimeService: EventRealtimeService ) {} async ngOnInit(): Promise { @@ -47,31 +53,47 @@ export class AssetPropertiesViewComponent implements OnInit { await this.inventoryService.detail(this.config.device.id) ).data; setTimeout(async () => { - this.customProperties = + // eslint-disable-next-line no-prototype-builtins + if(this.selectedAsset.hasOwnProperty('c8y_IsAsset')){ + this.customProperties = await this.assetPropertiesService.getCustomProperties( this.selectedAsset ); - this.properties = this.config.properties.filter((property) => { - if ( - property.isExistingProperty || - ((this.customProperties.length != 0 && - this.customProperties.find((prop) => prop.id === property.id)) || this.validateComplexProperty(property)) - ) { - return property; - } - }); - this.config.properties = cloneDeep(this.properties); + this.properties = this.config.properties.filter((property) => { + if ( + property.isExistingProperty || + ((this.customProperties.length != 0 && + this.customProperties.find((prop) => prop.id === property.id)) || this.validateComplexProperty(property)) + ) { + return property; + } + }); + this.config.properties = cloneDeep(this.properties); + }else{ + this.properties = cloneDeep(this.config.properties); + } this.constructComplexPropertyKeys(); this.config.properties.forEach(property =>{ - if(property.computed && property.name ==='lastMeasurement' && property.config.dp.length>0){ - // eslint-disable-next-line no-underscore-dangle - let datapoint = property.config.dp.find((dp) =>dp.__active); - datapoint = {...datapoint, ...{uniqId:property.config.id}}; - this.getLatestMeasurement$(datapoint).subscribe( - (lastMeasurement) => { - this.computedPropertyObject = {...this.computedPropertyObject, ...{[`lastMeasurement_${lastMeasurement.id}`]: lastMeasurement}}; - } - ); + if(property.computed && property.active){ + switch (property.name) { + case 'alarmCountToday': + this.getAlarmCount(this.config.device, property,this.datePipe.transform(new Date(), 'yyyy-MM-dd')); + break; + case 'alarmCount3Months': + this.getAlarmCount(this.config.device, property, this.datePipe.transform(new Date().setMonth(new Date().getMonth() - 3), 'yyyy-MM-dd')); + break; + case 'eventCountToday': + this.getEventCount(this.config.device, property,this.datePipe.transform(new Date(), 'yyyy-MM-dd')); + break; + case 'eventCount3Months': + this.getEventCount(this.config.device, property, this.datePipe.transform(new Date().setMonth(new Date().getMonth() - 3), 'yyyy-MM-dd')); + break; + case 'lastMeasurement': + this.getLastMeasurement(property); + break; + default: + break; + } } }); this.handleRealtime(); @@ -83,6 +105,53 @@ export class AssetPropertiesViewComponent implements OnInit { } } + async getAlarmCount(device:IManagedObject, property:IManagedObject, dateFrom:string){ + const filters = { + dateFrom: dateFrom, + dateTo: this.datePipe.transform(new Date().setDate( new Date().getDate() + 1), 'yyyy-MM-ddThh:mm:ssZZZZZ'), + source: device.id, + pageSize: 2000, + type: property.config.type, + }; + const alarms = (await this.assetPropertiesViewService.getAlarms(filters)); + this.alarmRealtimeService.onCreate$(this.selectedAsset.id) + .subscribe((alarm: IAlarm) => { + if(alarm.type === property.config.type){ + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`${property.name}_${property.config.id}`]: ++ this.computedPropertyObject[`${property.name}_${property.config.id}`]}}; + } + }); + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`${property.name}_${property.config.id}`]: alarms.length}}; + } + + async getEventCount(device:IManagedObject, property:IManagedObject, dateFrom:string){ + const filters = { + dateFrom: dateFrom, + dateTo: this.datePipe.transform(new Date().setDate( new Date().getDate() + 1), 'yyyy-MM-ddThh:mm:ssZZZZZ'), + source: device.id, + pageSize: 2000, + type: property.config.type, + }; + const events = (await this.assetPropertiesViewService.getEvents(filters)); + this.eventRealtimeService.onCreate$(this.selectedAsset.id) + .subscribe((event: IEvent ) => { + if(event.type === property.config.type){ + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`${property.name}_${property.config.id}`]: ++ this.computedPropertyObject[`${property.name}_${property.config.id}`]}}; + } + }); + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`${property.name}_${property.config.id}`]: events.length}}; + } + + getLastMeasurement(property){ + // eslint-disable-next-line no-underscore-dangle + let datapoint = property.config.dp.find((dp) =>dp.__active); + datapoint = {...datapoint, ...{uniqId:property.config.id}}; + this.getLatestMeasurement$(datapoint).subscribe( + (lastMeasurement) => { + this.computedPropertyObject = {...this.computedPropertyObject, ...{[`lastMeasurement_${lastMeasurement.id}`]: lastMeasurement}}; + } + ); + } + constructComplexPropertyKeys(){ const customizedProperty =[]; this.properties.forEach(element => { @@ -92,9 +161,9 @@ export class AssetPropertiesViewComponent implements OnInit { if(!property.isParentKeySelected){ property.isParentKeySelected = true; property.active = true; - property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key].properties = {}; + property.c8y_JsonSchema.properties[property.name].properties = {}; } - property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key].properties[element.keyPath?.[1]] = {...element}; + property.c8y_JsonSchema.properties[property.name].properties[element.keyPath?.[1]] = {...element}; } if(!customizedProperty.find((prop) => prop.id === property.id)){ customizedProperty.push(property); @@ -109,7 +178,7 @@ export class AssetPropertiesViewComponent implements OnInit { validateComplexProperty(item): boolean{ if(item.keyPath){ const property = this.customProperties.find((prop) => prop.name === item.keyPath?.[0]); - return some(Object.keys(property.c8y_JsonSchema.properties[property.c8y_JsonSchema.key].properties), function(key) { + return some(Object.keys(property.c8y_JsonSchema.properties[property.name].properties), function(key) { return (key === item.keyPath?.[1]); }); } @@ -121,7 +190,7 @@ export class AssetPropertiesViewComponent implements OnInit { return false; } return ( - prop.c8y_JsonSchema.properties[prop.c8y_JsonSchema.key]?.type === 'object' + prop.c8y_JsonSchema.properties[prop.name]?.type === 'object' ); } diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.service.ts b/asset-properties-widget/component/asset-properties-view/asset-properties-view.service.ts new file mode 100644 index 0000000..0b72b49 --- /dev/null +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { AlarmService, EventService, IManagedObject } from '@c8y/client'; + +@Injectable({ + providedIn: 'root', +}) +export class AssetPropertiesViewService { + constructor( + private c8yAlarms: AlarmService, + private c8yEvents: EventService + ) {} + + async getAlarms(filters): Promise { + let data = []; + await this.c8yAlarms.list(filters) + .then(function (alarms) { + data = alarms.data; + }); + return data; + } + + async getEvents(filters) { + let data = []; + await this.c8yEvents.list(filters) + .then(events => { + data = events.data; + }); + return data; + } +} diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.spec.ts b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.spec.ts index 673b91b..8b9e849 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.spec.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.spec.ts @@ -11,6 +11,7 @@ describe('AssetPropertiesComponent', () => { let assetTypesMock: any; let permissionsServiceMock: any; let dashboardChildMock:any; + let datePipe:any; beforeEach(() => { permissionsServiceMock = { canEdit: jest.fn() }; @@ -31,7 +32,8 @@ describe('AssetPropertiesComponent', () => { inventoryBinaryMock, alertMock, permissionsServiceMock, - dashboardChildMock + dashboardChildMock, + datePipe ); }); diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts index 67d9c4e..263d8fa 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts @@ -56,7 +56,7 @@ export class AssetPropertiesComponent implements OnChanges, OnInit { private alert: AlertService, private permissionsService: Permissions, public dashboardChild: DashboardChildComponent, - private pipe: DatePipe + private datePipe: DatePipe ) {} async ngOnInit() { @@ -239,10 +239,10 @@ export class AssetPropertiesComponent implements OnChanges, OnInit { } const isComplexProperty = !!item?.complex?.length; if (isComplexProperty) { - const complexProperty = item.jsonSchema?.properties?.[mo.c8y_JsonSchema.key] as JSONSchema7; + const complexProperty = item.jsonSchema?.properties?.[mo.name] as JSONSchema7; complexProperty.required = item.complex.map(({ key }) => key); } else { - item.jsonSchema.required = [mo.c8y_JsonSchema.key]; + item.jsonSchema.required = [mo.name]; } } @@ -262,16 +262,10 @@ export class AssetPropertiesComponent implements OnChanges, OnInit { switch (mo.name) { case 'alarmCountToday': - value = asset.childDevices.references.length; - break; case 'alarmCount3Months': - value = asset.childDevices.references.length; - break; case 'eventCountToday': - value = asset.childDevices.references.length; - break; case 'eventCount3Months': - value = asset.childDevices.references.length; + value = this.computedPropertyObject? this.computedPropertyObject[`${mo.name}_${mo.config.id}`] : 0; break; case 'lastDeviceMessage': value = asset.childDevices.references.length; @@ -308,7 +302,7 @@ export class AssetPropertiesComponent implements OnChanges, OnInit { out = `${value } ${ unit || ''}`; break; case RESULT_TYPES.VALUE_UNIT_TIME.value: - out = ` ${this.pipe.transform(date, 'short')} | ${`${value } ${ unit || ''}`}`; + out = ` ${this.datePipe.transform(date, 'short')} | ${`${value } ${ unit || ''}`}`; break; default: out = ''; From 58e71da8762ed5856bfce471f36c9b7080c66d45 Mon Sep 17 00:00:00 2001 From: "EUR\\y508925" Date: Sun, 11 Feb 2024 05:36:42 +0530 Subject: [PATCH 04/34] device property changes updated and property filter added. --- .../common/asset-property-constant.ts | 422 ++++++++++++++++-- .../asset-properties-config.component.ts | 4 +- ...sset-property-item-selector.component.html | 8 +- .../asset-property-selector.component.ts | 34 +- .../asset-properties-view.component.ts | 10 +- .../asset-properties.component.ts | 2 +- 6 files changed, 403 insertions(+), 77 deletions(-) diff --git a/asset-properties-widget/common/asset-property-constant.ts b/asset-properties-widget/common/asset-property-constant.ts index 90b71a5..67072dc 100644 --- a/asset-properties-widget/common/asset-property-constant.ts +++ b/asset-properties-widget/common/asset-property-constant.ts @@ -1,4 +1,4 @@ -import { gettext } from "@c8y/ngx-components"; +import { gettext } from '@c8y/ngx-components'; export const defaultProperty = [ { @@ -32,7 +32,7 @@ export const defaultProperty = [ }, ]; -export const property = [ +export const commonProperty = [ { c8y_JsonSchema: { properties: { owner: { type: 'string', label: 'Owner' } }, @@ -53,36 +53,6 @@ export const property = [ isEditable: false, isExistingProperty: true, }, - { - label: 'Active alarms status', - type: 'object', - isEditable: false, - name: 'c8y_ActiveAlarmsStatus', - c8y_JsonSchema: { - properties: { c8y_ActiveAlarmsStatus: {key:'c8y_ActiveAlarmsStatus', type: 'object', label: 'Active alarms status',properties: { - critical: { - title: 'Critical', - type: 'number', - isEditable: false - }, - major: { - title: 'Major', - type: 'number', - isEditable: false - }, - minor: { - title: 'Minor', - type: 'number', - isEditable: false - }, - warning: { - title: 'Warning', - type: 'number', - isEditable: false - } - } } }, - }, - }, { c8y_JsonSchema: { properties: { alarmCountToday: { @@ -147,21 +117,6 @@ export const property = [ isEditable: false, isExistingProperty: true, }, - { - c8y_JsonSchema: { - properties: { lastDeviceMessage: { - title: 'Last device message', - type: 'string', - },}, - }, - name: 'lastDeviceMessage', - label: 'Last device message', - printFormat: 'datetime', - type: 'string', - computed: true, - isEditable: false, - isExistingProperty: true, - }, { c8y_JsonSchema: {properties: { lastMeasurement: { title: 'Last measurement', @@ -203,6 +158,21 @@ export const property = [ isEditable: false, isExistingProperty: true, }, + { + c8y_JsonSchema: { + properties: { lastDeviceMessage: { + title: 'Last device message', + type: 'string', + },}, + }, + name: 'lastDeviceMessage', + label: 'Last device message', + printFormat: 'datetime', + type: 'string', + computed: true, + isEditable: false, + isExistingProperty: true, + }, { c8y_JsonSchema: { properties: { configurationSnapshot: { @@ -217,6 +187,364 @@ export const property = [ isEditable: false, isExistingProperty: true, } + +]; +export const deviceProperty = [ + { + label: 'Active alarms status', + type: 'object', + isEditable: false, + name: 'c8y_ActiveAlarmsStatus', + c8y_JsonSchema: { + properties: { c8y_ActiveAlarmsStatus: {key:'c8y_ActiveAlarmsStatus', type: 'object', label: 'Active alarms status',properties: { + critical: { + title: 'Critical', + type: 'number', + }, + major: { + title: 'Major', + type: 'number', + }, + minor: { + title: 'Minor', + type: 'number', + }, + warning: { + title: 'Warning', + type: 'number', + } + } } }, + }, + }, + { + label: 'Address', + type: 'object', + isEditable: true, + name: 'c8y_Address', + c8y_JsonSchema: { + properties: { c8y_Address: {key:'c8y_Address', type: 'object', label: 'Address',properties: { + street: { + title: 'Street', + type: 'string' + }, + city: { + title: 'City', + type: 'string' + }, + cityCode: { + title: 'City code', + type: 'string' + }, + territory: { + title: 'Territory', + type: 'string' + }, + region: { + title: 'Region', + type: 'string' + }, + country: { + title: 'Country', + type: 'string' + } + }}} + }, + }, + { + label: 'Agent', + type: 'object', + isEditable: true, + name: 'c8y_Agent', + c8y_JsonSchema: { + properties: { c8y_Agent: {key:'c8y_Agent', type: 'object', label: 'Agent',properties : { + name: { + title: 'Name', + type: 'string' + }, + version: { + title: 'Version', + type: 'string' + }, + url: { + title: 'URL', + type: 'string' + }, + maintainer: { + title: 'Maintainer', + type: 'string' + } + }}} + } + }, + { + label: 'Availability', + type: 'object', + isEditable: false, + name: 'c8y_Availability', + c8y_JsonSchema: { + properties: { c8y_Availability: {key:'c8y_Availability', type: 'object', label: 'Availability',properties : { + status: { + title: 'Status', + type: 'string', + }, + lastMessage: { + title: 'Last message', + type: 'string', + printFormat: 'datetime', + } + }}} + }, + }, + { + label: 'Connection', + type: 'object', + isEditable: false, + name: 'c8y_Connection', + c8y_JsonSchema: { + properties: { c8y_Connection: {key:'c8y_Connection', type: 'object', label: 'Connection',properties : { + status: { + title: 'Status', + type: 'string', + } + }}} + }, + }, + { + label: 'Communication mode', + type: 'object', + isEditable: true, + name: 'c8y_CommunicationMode', + c8y_JsonSchema: { + properties: { c8y_CommunicationMode: {key:'c8y_CommunicationMode', type: 'object', label: 'Communication mode',properties : { + mode: { + title: 'Mode', + type: 'string' + } + }}} + } + }, + { + label: 'Firmware', + type: 'object', + isEditable: false, + name: 'c8y_Firmware', + c8y_JsonSchema: { + properties: { c8y_Firmware: {key:'c8y_Firmware', type: 'object', label: 'Firmware',properties : { + moduleVersion: { + title: 'Module version', + type: 'string' + }, + name: { + title: 'Name', + type: 'string' + }, + version: { + title: 'Version', + type: 'string' + }, + url: { + title: 'URL', + type: ['string', 'null'] + } + }}} + }, + }, + { + label: 'Hardware', + type: 'object', + isEditable: true, + name: 'c8y_Hardware', + c8y_JsonSchema: { + properties: { c8y_Hardware: {key:'c8y_Hardware', type: 'object', label: 'Hardware',properties : { + model: { + title: 'Model', + type: 'string' + }, + serialNumber: { + title: 'Serial number', + type: 'string' + }, + revision: { + title: 'Revision', + type: 'string' + } + }}} + }, + }, + { + label: 'LPWAN device', + type: 'object', + isEditable: false, + name: 'c8y_LpwanDevice', + c8y_JsonSchema: { + properties: { c8y_LpwanDevice: {key:'c8y_LpwanDevice', type: 'object', label: 'LPWAN device',properties : { + provisioned: { + title: 'Provisioned', + type: 'boolean', + } + }}} + }, + }, + { + label: 'Mobile', + type: 'object', + isEditable: true, + name: 'c8y_Mobile', + c8y_JsonSchema: { + properties: { c8y_Mobile: {key:'c8y_Mobile', type: 'object', label: 'Mobile',properties : { + cellId: { + title: 'Cell ID', + type: ['string', 'null'], + readonly: true, + templateOptions: { + label: 'Test 2', + description: 'Field always read-only', + readonly: true + } + }, + connType: { + title: 'Connection type', + type: 'string', + isEditable: false, + }, + currentOperator: { + title: 'Current operator', + type: 'string', + }, + currentBand: { + title: 'Current band', + type: 'string', + }, + ecn0: { + title: 'ECN0', + type: 'string', + }, + iccid: { + title: 'ICCID', + type: ['string', 'null'] + }, + imei: { + title: 'IMEI', + type: ['string', 'null'] + }, + imsi: { + title: 'IMSI', + type: ['string', 'null'] + }, + lac: { + title: 'LAC', + type: ['string', 'null'] + }, + mcc: { + title: 'MCC', + type: ['string', 'null'] + }, + mnc: { + title: 'MNC', + type: ['string', 'null'] + }, + msisdn: { + title: 'MSISDN', + type: 'string' + }, + rcsp: { + title: 'RCSP', + type: 'string', + isEditable: false + }, + rscp: { + title: 'RSCP', + type: 'string', + isEditable: false + }, + rsrp: { + title: 'RSRP', + type: 'string', + isEditable: false + }, + rsrq: { + title: 'RSRQ', + type: 'string', + isEditable: false + }, + rssi: { + title: 'RSSI', + type: 'string', + isEditable: false + } + }}} + }, + }, + { + c8y_JsonSchema: { properties: { c8y_Notes: { type: 'string', label: 'Notes','x-schema-form': { + type: 'textarea' + } } } }, + name: 'c8y_Notes', + label: 'Notes', + type: 'string', + isEditable: true + }, + { + label: 'Position', + type: 'object', + isEditable: true, + name: 'c8y_Position', + c8y_JsonSchema: { + properties: { c8y_Position: {key:'c8y_Position', type: 'object', label: 'Position',properties : { + lat: { + title: 'Latitude', + type: 'number' + }, + lng: { + title: 'Longitude', + type: 'number' + }, + alt: { + title: 'Altitude', + type: 'number' + } + }}} + } + }, + { + label: 'Required availability', + type: 'object', + isEditable: true, + name: 'c8y_RequiredAvailability', + c8y_JsonSchema: { + properties: { c8y_RequiredAvailability: {key:'c8y_RequiredAvailability', type: 'object', label: 'Required availability',properties : { + responseInterval: { + title: 'Response interval', + description: 'Takes a value between -32768 and 32767 minutes (a negative value indicates that the device is under maintenance).', + type: 'integer', + minimum: -32768, + maximum: 32767 + } + }}} + }, + }, + { + label: 'Software', + type: 'object', + isEditable: false, + name: 'c8y_Software', + c8y_JsonSchema: { + properties: { c8y_Software: {key:'c8y_Software', type: 'object', label: 'Software',properties : { + name: { + title: 'Name', + type: 'string' + }, + version: { + title: 'Version', + type: 'string' + }, + url: { + title: 'URL', + type: ['string', 'null'] + } + }}} + } + } ]; export const RESULT_TYPES = { diff --git a/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.ts b/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.ts index dc4ff47..bc65fda 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.ts @@ -17,7 +17,7 @@ export class AssetPropertiesConfigComponent constructor(private inventoryService: InventoryService) {} async ngOnChanges(){ - if (this.config.device) { + if (this.config.device && !this.config.device.hasOwnProperty('c8y_IsDevice')) { try { this.selectedAsset = ( await this.inventoryService.detail(this.config.device.id) @@ -25,6 +25,8 @@ export class AssetPropertiesConfigComponent } catch (er) { // intended empty } + }else if(this.config.device){ + this.selectedAsset = this.config.device; } } diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html index ad04f48..7bde7d1 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-property-item-selector/asset-property-item-selector.component.html @@ -106,13 +106,13 @@ data-cy="asset-property-item-property-name" class="col-xs-5 text-truncate" title="{{ - (property.name | translate) || - (property.keyPath.join('.') | translate) + (property.keyPath?.join('.') | translate) || + (property.name | translate) }}" > {{ - (property.name | translate) || - (property.keyPath.join(".") | translate) + (property.keyPath?.join(".") | translate) || + (property.name | translate) }} diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts index 0f25a89..2149d38 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.ts @@ -9,7 +9,8 @@ import { assetPropertyItemSelectorCtrlComponent } from '../asset-property-item-s import { AssetPropertiesService } from '../asset-properties.service'; import { defaultProperty, - property, + deviceProperty, + commonProperty, } from '../../../common/asset-property-constant'; import { some } from 'lodash-es'; import { ComputedPropertyConfigComponent } from '../computed-asset-property/computed-property-config.component'; @@ -32,9 +33,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { assetPropertySelectorModalRef: BsModalRef; computedPropertyConfigModalRef: BsModalRef; properties = cloneDeep(defaultProperty); - customProperties: IManagedObject[] = cloneDeep(defaultProperty).concat( - cloneDeep(property) - ); + customProperties: Array = [...cloneDeep(defaultProperty), ...cloneDeep(commonProperty)]; ExpandedComplexProperty: any; isAtleastOnePropertySelected: boolean = true; selectedComputedPropertyIndex: number; @@ -47,7 +46,15 @@ export class AssetPropertiesSelectorComponent implements OnChanges { ) {} async ngOnChanges(changes: IManagedObject): Promise { - if ((changes.asset.firstChange || !changes.asset.previousValue) && this.config?.properties) { + if(changes.asset.currentValue?.hasOwnProperty('c8y_IsDevice') && this.config?.properties){ + this.properties = this.config.properties; + if(changes.asset.previousValue?.hasOwnProperty('c8y_IsAsset')){ + this.properties = cloneDeep(defaultProperty); + this.config.properties = this.properties; + } + this.customProperties = [...cloneDeep(defaultProperty), ...cloneDeep(commonProperty), ...cloneDeep(deviceProperty)]; + } + else if (!changes.asset.previousValue && this.config?.properties) { this.properties = this.config.properties; this.customProperties = this.customProperties.concat( this.getConstructCustomProperties( @@ -60,20 +67,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { } this.isAtleastOnePropertySelected = true; } - addDefaultAndSelectedProperties() { - this.properties.forEach((property) => { - const existingPropertyIndex = this.customProperties - .map(function (item) { - return item.name; - }) - .indexOf(property.name); - if (existingPropertyIndex > 0) { - this.customProperties[existingPropertyIndex] = cloneDeep(property); - } else { - this.customProperties.push(cloneDeep(property)); - } - }); - } + getConstructCustomProperties(customProperties): IManagedObject[] { const simpleProperties: IManagedObject[] = []; const constructCustomProperties: IManagedObject[] = []; @@ -94,7 +88,7 @@ export class AssetPropertiesSelectorComponent implements OnChanges { this.assetType = this.assetTypes.getAssetTypeByName(this.asset.type); this.config.properties = this.properties; this.customProperties = cloneDeep(this.properties) - .concat(property) + .concat(commonProperty) .concat( this.getConstructCustomProperties( await this.assetPropertyService.getCustomProperties(this.asset) diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts index 2bb6e03..404a099 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties-view.component.ts @@ -8,6 +8,7 @@ import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; import { AssetPropertiesViewService } from './asset-properties-view.service'; import { DatePipe } from '@angular/common'; +import { deviceProperty } from '../../common/asset-property-constant'; interface MeasurementValue { unit?: string; @@ -25,7 +26,7 @@ export class AssetPropertiesViewComponent implements OnInit { selected = { id: 'asset-properties-widget' }; selectedAsset: IManagedObject; isEmptyWidget: boolean = false; - customProperties: IManagedObject[]; + customProperties: Array; properties: IManagedObject[]; @Input() config: any; computedPropertyObject:object; @@ -71,6 +72,7 @@ export class AssetPropertiesViewComponent implements OnInit { this.config.properties = cloneDeep(this.properties); }else{ this.properties = cloneDeep(this.config.properties); + this.customProperties = cloneDeep(deviceProperty); } this.constructComplexPropertyKeys(); this.config.properties.forEach(property =>{ @@ -108,7 +110,7 @@ export class AssetPropertiesViewComponent implements OnInit { async getAlarmCount(device:IManagedObject, property:IManagedObject, dateFrom:string){ const filters = { dateFrom: dateFrom, - dateTo: this.datePipe.transform(new Date().setDate( new Date().getDate() + 1), 'yyyy-MM-ddThh:mm:ssZZZZZ'), + dateTo: this.datePipe.transform(new Date(), 'yyyy-MM-ddThh:mm:ssZZZZZ'), source: device.id, pageSize: 2000, type: property.config.type, @@ -126,7 +128,7 @@ export class AssetPropertiesViewComponent implements OnInit { async getEventCount(device:IManagedObject, property:IManagedObject, dateFrom:string){ const filters = { dateFrom: dateFrom, - dateTo: this.datePipe.transform(new Date().setDate( new Date().getDate() + 1), 'yyyy-MM-ddThh:mm:ssZZZZZ'), + dateTo: this.datePipe.transform(new Date(), 'yyyy-MM-ddThh:mm:ssZZZZZ'), source: device.id, pageSize: 2000, type: property.config.type, @@ -165,7 +167,7 @@ export class AssetPropertiesViewComponent implements OnInit { } property.c8y_JsonSchema.properties[property.name].properties[element.keyPath?.[1]] = {...element}; } - if(!customizedProperty.find((prop) => prop.id === property.id)){ + if(!customizedProperty.find((prop) => prop.name === property.name)){ customizedProperty.push(property); } }else if (element.active && (!customizedProperty.find((prop) => prop.name === element.name) || element.computed)){ diff --git a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts index 263d8fa..eb9a63c 100644 --- a/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts +++ b/asset-properties-widget/component/asset-properties-view/asset-properties/asset-properties.component.ts @@ -253,7 +253,7 @@ export class AssetPropertiesComponent implements OnChanges, OnInit { takeUntil(this.destroy$) ) .subscribe(async () => { - this.clusterMap.mapView.map.invalidateSize(); + this.clusterMap?.mapView.map.invalidateSize(); }); } From 140dddac6d372f0f35852b0035e835de7992cbb6 Mon Sep 17 00:00:00 2001 From: "EUR\\y508925" Date: Thu, 22 Feb 2024 17:37:05 +0530 Subject: [PATCH 05/34] Device property implementation added. --- .../common/asset-property-constant.ts | 146 +++++++++++++++--- .../asset-properties-config.component.html | 1 - ...sset-property-item-selector.component.html | 62 ++++---- .../asset-property-item-selector.component.ts | 50 +++--- .../asset-property-selector.component.html | 48 +++--- .../asset-property-selector.component.ts | 10 +- .../asset-properties-view.component.html | 2 +- .../asset-properties-view.component.spec.ts | 1 + .../asset-properties-view.component.ts | 48 ++++-- .../asset-properties-item.component.html | 60 ++++--- .../asset-properties.component.ts | 4 +- 11 files changed, 292 insertions(+), 140 deletions(-) diff --git a/asset-properties-widget/common/asset-property-constant.ts b/asset-properties-widget/common/asset-property-constant.ts index 67072dc..a686523 100644 --- a/asset-properties-widget/common/asset-property-constant.ts +++ b/asset-properties-widget/common/asset-property-constant.ts @@ -56,7 +56,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { alarmCountToday: { - title: 'Alarm count today', + label: 'Alarm count today', type: 'number', },}, }, @@ -72,7 +72,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { alarmCount3Months: { - title: 'Alarm count 3 months', + label: 'Alarm count 3 months', type: 'number', },}, }, @@ -88,7 +88,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { eventCountToday: { - title: 'Event count today', + label: 'Event count today', type: 'number', },}, }, @@ -104,7 +104,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { eventCount3Months: { - title: 'Event count 3 months', + label: 'Event count 3 months', type: 'number', },}, }, @@ -119,7 +119,7 @@ export const commonProperty = [ }, { c8y_JsonSchema: {properties: { lastMeasurement: { - title: 'Last measurement', + label: 'Last measurement', type: 'string', },},}, name: 'lastMeasurement', @@ -133,7 +133,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { childDevicesCount: { - title: 'Number of child devices', + label: 'Number of child devices', type: 'number', },}, }, @@ -147,7 +147,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { childAssetsCount: { - title: 'Number of child assets', + label: 'Number of child assets', type: 'number', },}, }, @@ -161,7 +161,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { lastDeviceMessage: { - title: 'Last device message', + label: 'Last device message', type: 'string', },}, }, @@ -176,7 +176,7 @@ export const commonProperty = [ { c8y_JsonSchema: { properties: { configurationSnapshot: { - title: 'Configuration snapshot', + label: 'Configuration snapshot', type: 'number', },}, }, @@ -187,7 +187,6 @@ export const commonProperty = [ isEditable: false, isExistingProperty: true, } - ]; export const deviceProperty = [ { @@ -395,29 +394,26 @@ export const deviceProperty = [ cellId: { title: 'Cell ID', type: ['string', 'null'], - readonly: true, - templateOptions: { - label: 'Test 2', - description: 'Field always read-only', - readonly: true - } }, connType: { title: 'Connection type', type: 'string', - isEditable: false, + readOnly: true }, currentOperator: { title: 'Current operator', type: 'string', + readOnly: true }, currentBand: { title: 'Current band', type: 'string', + readOnly: true }, ecn0: { title: 'ECN0', type: 'string', + readOnly: true }, iccid: { title: 'ICCID', @@ -450,27 +446,27 @@ export const deviceProperty = [ rcsp: { title: 'RCSP', type: 'string', - isEditable: false + readOnly: true }, rscp: { title: 'RSCP', type: 'string', - isEditable: false + readOnly: true }, rsrp: { title: 'RSRP', type: 'string', - isEditable: false + readOnly: true }, rsrq: { title: 'RSRQ', type: 'string', - isEditable: false + readOnly: true }, rssi: { title: 'RSSI', type: 'string', - isEditable: false + readOnly: true } }}} }, @@ -544,6 +540,112 @@ export const deviceProperty = [ } }}} } + }, + { + label: 'Network', + type: 'object', + isEditable: true, + name: 'c8y_Network', + c8y_JsonSchema: { + properties: { c8y_Network: {key:'c8y_Network', type: 'object', label: 'Network',properties : { + c8y_DHCP: { + title: 'DHCP', + type: 'object', + printFormat: 'hidden', + name: 'c8y_DHCP', + properties: { + addressRange: { + title: 'Address range', + type: 'object', + name: 'addressRange', + printFormat: 'hidden', + properties: { + start: { + title: 'Start', + type: 'string' + }, + end: { + title: 'End', + type: 'string' + } + } + }, + dns1: { + title: 'DNS 1', + type: 'string' + }, + dns2: { + title: 'DNS 2', + type: 'string' + }, + enabled: { + title: 'Enabled', + type: 'integer' + } + } + }, + c8y_LAN: { + title: 'LAN', + type: 'object', + name: 'c8y_LAN', + printFormat: 'hidden', + properties: { + enabled: { + title: 'Enabled', + type: 'integer' + }, + ip: { + title: 'IP', + type: 'string' + }, + mac: { + title: 'MAC', + type: 'string' + }, + name: { + title: 'Name', + type: 'string' + }, + netmask: { + title: 'Netmask', + type: 'string' + } + } + }, + c8y_WAN: { + title: 'WAN', + type: 'object', + name: 'c8y_WAN', + printFormat: 'hidden', + properties: { + apn: { + title: 'APN', + type: 'string' + }, + authType: { + title: 'Auth type', + type: 'string' + }, + ip: { + title: 'IP', + type: 'string' + }, + password: { + title: 'Password', + type: 'string' + }, + simStatus: { + title: 'SIM status', + type: 'string' + }, + username: { + title: 'Username', + type: 'string' + } + } + } + }}} + }, } ]; diff --git a/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.html b/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.html index 47bf455..1538b5c 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-properties-config.component.html @@ -1,5 +1,4 @@ {{ title | translate }} *ngFor="let property of customProperties | filter : search" >
- - - - +
{ if (this.isComplexProperty(property)) { complexProperties.push(property); - Object.keys(property.c8y_JsonSchema.properties[property.name].properties).forEach((key)=>{ - const object = property.c8y_JsonSchema.properties[property.name].properties[key]; - object['keyPath'] = [property.name]; - object.keyPath.push(key); - complexProperties.push(object); - }); - + this.parseItem(property.c8y_JsonSchema.properties[property.name], complexProperties, property.name); } else { simpleProperties.push(property); } @@ -42,6 +36,18 @@ export class assetPropertyItemSelectorCtrlComponent implements OnInit { return simpleProperties.concat(complexProperties); } + parseItem(property, complexProperties, parentName?){ + Object.keys(property.properties).forEach((key)=>{ + const object = property.properties[key]; + object['keyPath'] = property.keyPath? cloneDeep(property.keyPath) : [property.name || parentName]; + object.keyPath.push(key); + complexProperties.push(object); + if(Object.prototype.hasOwnProperty.call(object, 'properties')){ + this.parseItem(object,complexProperties); + } + }); + } + onSelectProperty(property) { if (property.active) { this.selectedProperty.push(cloneDeep(property)); @@ -53,19 +59,20 @@ export class assetPropertyItemSelectorCtrlComponent implements OnInit { } selectOrUnselectChildren(selectedProperty, active){ - if(this.isComplexProperty(selectedProperty)){ - this.customProperties.forEach((property) => { - if(property.keyPath?.[0] === selectedProperty.name){ - property.active = active; - if(active){ + if (!this.isComplexProperty(selectedProperty)) return; + this.customProperties.forEach((property) => { + if(property.keyPath?.some(name => name === selectedProperty.name)){ + property.active = active; + if(active){ + if(!some(this.selectedProperty, obj => isEqual(obj, property))){ this.selectedProperty.push(cloneDeep(property)); - }else{ - property.active = active; - this.removeUnselectedProperties(property); } + }else{ + property.active = active; + this.removeUnselectedProperties(property); } - }); - } + } + }); } removeUnselectedProperties(property){ const removeIndex = this.selectedProperty @@ -89,11 +96,6 @@ export class assetPropertyItemSelectorCtrlComponent implements OnInit { } isComplexProperty(prop) { - if (!prop.c8y_JsonSchema) { - return false; - } - return ( - prop.c8y_JsonSchema.properties[prop.name]?.type === 'object' - ); + return prop.c8y_JsonSchema?.properties[prop.name]?.type === 'object' || prop.properties !== undefined; } } diff --git a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html index 583a44b..9b9bfa9 100644 --- a/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html +++ b/asset-properties-widget/component/asset-properties-config/asset-property-selector/asset-property-selector.component.html @@ -1,19 +1,19 @@
-
-
- -
+
+
+
+
@@ -121,13 +121,21 @@
- - +
+ +
+
+ +