diff --git a/ui-ngx/src/app/core/api/entity-data-subscription.ts b/ui-ngx/src/app/core/api/entity-data-subscription.ts index 79c505b07a..8a6c2f54e8 100644 --- a/ui-ngx/src/app/core/api/entity-data-subscription.ts +++ b/ui-ngx/src/app/core/api/entity-data-subscription.ts @@ -155,7 +155,7 @@ export class EntityDataSubscription { clearTimeout(this.timer); this.timer = null; } - if (this.datasourceType === DatasourceType.entity) { + if (this.datasourceType === DatasourceType.entity || this.datasourceType === DatasourceType.entityCount) { if (this.subscriber) { this.subscriber.unsubscribe(); this.subscriber = null; @@ -318,24 +318,30 @@ export class EntityDataSubscription { entityType: null }; - const entityData: EntityData = { - entityId, - timeseries: {}, - latest: {} - }; - entityData.latest[EntityKeyType.ENTITY_FIELD] = { - name: {ts: Date.now(), value: DatasourceType.entityCount}, - }; - const countKey = this.entityDataSubscriptionOptions.dataKeys[0]; + let dataReceived = false; + this.subscriber.entityCount$.subscribe( (entityCountUpdate) => { - if (!entityData.latest[EntityKeyType.COUNT]) { - entityData.latest[EntityKeyType.COUNT] = {}; - entityData.latest[EntityKeyType.COUNT][countKey.name] = { - ts: Date.now(), - value: entityCountUpdate.count + '' + if (!dataReceived) { + const entityData: EntityData = { + entityId, + latest: { + [EntityKeyType.ENTITY_FIELD]: { + name: { + ts: Date.now(), + value: DatasourceType.entityCount + } + }, + [EntityKeyType.COUNT]: { + [countKey.name]: { + ts: Date.now(), + value: entityCountUpdate.count + '' + } + } + }, + timeseries: {} }; const pageData: PageData = { data: [entityData], @@ -344,12 +350,20 @@ export class EntityDataSubscription { totalPages: 1 }; this.onPageData(pageData); + dataReceived = true; } else { - const update = [deepClone(entityData)]; - update[0].latest[EntityKeyType.COUNT][countKey.name] = { - ts: Date.now(), - value: entityCountUpdate.count + '' - }; + const update: EntityData[] = [{ + entityId, + latest: { + [EntityKeyType.COUNT]: { + [countKey.name]: { + ts: Date.now(), + value: entityCountUpdate.count + '' + } + } + }, + timeseries: {} + }]; this.onDataUpdate(update); } } diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 17a35b2305..0862e10a76 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -481,6 +481,8 @@ export class EntityService { return entityTypes.indexOf(filter.entityType) > -1 ? true : false; case AliasFilterType.entityName: return entityTypes.indexOf(filter.entityType) > -1 ? true : false; + case AliasFilterType.entityType: + return entityTypes.indexOf(filter.entityType) > -1 ? true : false; case AliasFilterType.stateEntity: return true; case AliasFilterType.assetType: @@ -540,6 +542,8 @@ export class EntityService { return true; case AliasFilterType.entityName: return true; + case AliasFilterType.entityType: + return true; case AliasFilterType.stateEntity: return true; case AliasFilterType.assetType: @@ -805,6 +809,9 @@ export class EntityService { case AliasFilterType.entityName: result.entityFilter = deepClone(filter); return of(result); + case AliasFilterType.entityType: + result.entityFilter = deepClone(filter); + return of(result); case AliasFilterType.stateEntity: result.stateEntity = true; if (stateEntityId) { diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts index 42fb943ef3..07cee4ffb2 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity-filter-view.component.ts @@ -76,6 +76,10 @@ export class EntityFilterViewComponent implements ControlValueAccessor { this.filterDisplayValue = this.translate.instant(entityTypeTranslations.get(entityType).nameStartsWith, {prefix}); break; + case AliasFilterType.entityType: + entityType = this.filter.entityType; + this.filterDisplayValue = this.translate.instant(entityTypeTranslations.get(entityType).typePlural); + break; case AliasFilterType.stateEntity: this.filterDisplayValue = this.translate.instant('alias.filter-type-state-entity-description'); break; diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html index cfd75d7299..5c5ca5ff59 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html @@ -59,6 +59,13 @@ + + + + alias.state-entity-parameter-name diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts index 992ee75f7b..539d6b3ff8 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts @@ -123,6 +123,11 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit { entityNameFilter: [filter ? filter.entityNameFilter : '', [Validators.required]], }); break; + case AliasFilterType.entityType: + this.filterFormGroup = this.fb.group({ + entityType: [filter ? filter.entityType : null, [Validators.required]] + }); + break; case AliasFilterType.stateEntity: this.filterFormGroup = this.fb.group({ stateEntityParamName: [filter ? filter.stateEntityParamName : null, []], diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts index d3e95cb8a2..6c9c85330a 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.ts @@ -107,12 +107,15 @@ export class KeyFilterDialogComponent extends key: [this.data.keyFilter.key.key, [Validators.required]] } ), - value: [this.data.keyFilter.value], valueType: [this.data.keyFilter.valueType, [Validators.required]], predicates: [this.data.keyFilter.predicates, [Validators.required]] } ); - + if (this.data.telemetryKeysOnly) { + this.keyFilterFormGroup.addControl( + 'value', this.fb.control(this.data.keyFilter.value) + ); + } if (!this.data.readonly) { this.keyFilterFormGroup.get('valueType').valueChanges.pipe( takeUntil(this.destroy$) @@ -144,12 +147,14 @@ export class KeyFilterDialogComponent extends } else { this.showAutocomplete = false; } - if (type === EntityKeyType.CONSTANT) { - this.keyFilterFormGroup.get('value').setValidators(Validators.required); - this.keyFilterFormGroup.get('value').updateValueAndValidity(); - } else { - this.keyFilterFormGroup.get('value').clearValidators(); - this.keyFilterFormGroup.get('value').updateValueAndValidity(); + if (this.data.telemetryKeysOnly) { + if (type === EntityKeyType.CONSTANT) { + this.keyFilterFormGroup.get('value').setValidators(Validators.required); + this.keyFilterFormGroup.get('value').updateValueAndValidity(); + } else { + this.keyFilterFormGroup.get('value').clearValidators(); + this.keyFilterFormGroup.get('value').updateValueAndValidity(); + } } }); diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts index c9bbf02173..43dbfc45f6 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts @@ -24,7 +24,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { AliasEntityType, EntityType } from '@shared/models/entity-type.models'; -import { EntityTypeFilter } from '@shared/models/relation.models'; +import { RelationEntityTypeFilter } from '@shared/models/relation.models'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -80,7 +80,7 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa this.disabled = isDisabled; } - writeValue(filters: Array): void { + writeValue(filters: Array): void { if (this.valueChangeSubscription) { this.valueChangeSubscription.unsubscribe(); } @@ -102,14 +102,14 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa public addFilter() { const relationFiltersFormArray = this.relationFiltersFormGroup.get('relationFilters') as FormArray; - const filter: EntityTypeFilter = { + const filter: RelationEntityTypeFilter = { relationType: null, entityTypes: [] }; relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter)); } - private createRelationFilterFormGroup(filter: EntityTypeFilter): AbstractControl { + private createRelationFilterFormGroup(filter: RelationEntityTypeFilter): AbstractControl { return this.fb.group({ relationType: [filter ? filter.relationType : null], entityTypes: [filter ? filter.entityTypes : []] @@ -117,7 +117,7 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa } private updateModel() { - const filters: Array = this.relationFiltersFormGroup.get('relationFilters').value; + const filters: Array = this.relationFiltersFormGroup.get('relationFilters').value; this.propagateChange(filters); } } diff --git a/ui-ngx/src/app/shared/models/alias.models.ts b/ui-ngx/src/app/shared/models/alias.models.ts index df80125ae4..5c02089b04 100644 --- a/ui-ngx/src/app/shared/models/alias.models.ts +++ b/ui-ngx/src/app/shared/models/alias.models.ts @@ -16,14 +16,14 @@ import { EntityType } from '@shared/models/entity-type.models'; import { EntityId } from '@shared/models/id/entity-id'; -import { EntitySearchDirection, EntityTypeFilter } from '@shared/models/relation.models'; -import { EntityInfo } from './entity.models'; +import { EntitySearchDirection, RelationEntityTypeFilter } from '@shared/models/relation.models'; import { EntityFilter } from '@shared/models/query/query.models'; export enum AliasFilterType { singleEntity = 'singleEntity', entityList = 'entityList', entityName = 'entityName', + entityType = 'entityType', stateEntity = 'stateEntity', assetType = 'assetType', deviceType = 'deviceType', @@ -40,6 +40,7 @@ export const aliasFilterTypeTranslationMap = new Map( [ AliasFilterType.singleEntity, 'alias.filter-type-single-entity' ], [ AliasFilterType.entityList, 'alias.filter-type-entity-list' ], [ AliasFilterType.entityName, 'alias.filter-type-entity-name' ], + [ AliasFilterType.entityType, 'alias.filter-type-entity-type' ], [ AliasFilterType.stateEntity, 'alias.filter-type-state-entity' ], [ AliasFilterType.assetType, 'alias.filter-type-asset-type' ], [ AliasFilterType.deviceType, 'alias.filter-type-device-type' ], @@ -66,6 +67,10 @@ export interface EntityNameFilter { entityNameFilter?: string; } +export interface EntityTypeFilter { + entityType?: EntityType; +} + export interface StateEntityFilter { stateEntityParamName?: string; defaultStateEntity?: EntityId; @@ -92,7 +97,7 @@ export interface RelationsQueryFilter { defaultStateEntity?: EntityId; rootEntity?: EntityId; direction?: EntitySearchDirection; - filters?: Array; + filters?: Array; maxLevel?: number; fetchLastLevelOnly?: boolean; } @@ -129,6 +134,7 @@ export type EntityFilters = SingleEntityFilter & EntityListFilter & EntityNameFilter & + EntityTypeFilter & StateEntityFilter & AssetTypeFilter & DeviceTypeFilter & diff --git a/ui-ngx/src/app/shared/models/query/query.models.ts b/ui-ngx/src/app/shared/models/query/query.models.ts index dc21f70907..25efe437d7 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -351,14 +351,14 @@ export interface KeyFilterPredicateInfo { export interface KeyFilter { key: EntityKey; valueType: EntityKeyValueType; - value: string | number | boolean; + value?: string | number | boolean; predicate: KeyFilterPredicate; } export interface KeyFilterInfo { key: EntityKey; valueType: EntityKeyValueType; - value: string | number | boolean; + value?: string | number | boolean; predicates: Array; } diff --git a/ui-ngx/src/app/shared/models/relation.models.ts b/ui-ngx/src/app/shared/models/relation.models.ts index 2f0f2b456f..c9037a5dab 100644 --- a/ui-ngx/src/app/shared/models/relation.models.ts +++ b/ui-ngx/src/app/shared/models/relation.models.ts @@ -52,7 +52,7 @@ export const directionTypeTranslations = new Map( ] ); -export interface EntityTypeFilter { +export interface RelationEntityTypeFilter { relationType: string; entityTypes: Array; } @@ -68,7 +68,7 @@ export interface RelationsSearchParameters { export interface EntityRelationsQuery { parameters: RelationsSearchParameters; - filters: Array; + filters: Array; } export interface EntitySearchQuery { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 50fbe58583..7b62f680a8 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -299,6 +299,7 @@ "filter-type-single-entity": "Single entity", "filter-type-entity-list": "Entity list", "filter-type-entity-name": "Entity name", + "filter-type-entity-type": "Entity type", "filter-type-state-entity": "Entity from dashboard state", "filter-type-state-entity-description": "Entity taken from dashboard state parameters", "filter-type-asset-type": "Asset type",