@ -14,7 +14,7 @@
/// limitations under the License.
/// limitations under the License.
///
///
import { Component , Inject , OnInit , SkipSelf } from '@angular/core' ;
import { Component , ElementRef , Inject , OnDestroy , On Init , SkipSelf , ViewChild } from '@angular/core' ;
import { ErrorStateMatcher } from '@angular/material/core' ;
import { ErrorStateMatcher } from '@angular/material/core' ;
import { MAT_DIALOG_DATA , MatDialogRef } from '@angular/material/dialog' ;
import { MAT_DIALOG_DATA , MatDialogRef } from '@angular/material/dialog' ;
import { Store } from '@ngrx/store' ;
import { Store } from '@ngrx/store' ;
@ -32,9 +32,12 @@ import {
} from '@shared/models/query/query.models' ;
} from '@shared/models/query/query.models' ;
import { DialogService } from '@core/services/dialog.service' ;
import { DialogService } from '@core/services/dialog.service' ;
import { TranslateService } from '@ngx-translate/core' ;
import { TranslateService } from '@ngx-translate/core' ;
import { EntityField , entityFields } from '@shared/models/entity.models' ;
import { entityFields } from '@shared/models/entity.models' ;
import { Observable } from 'rxjs' ;
import { Observable , of , Subject } from 'rxjs' ;
import { filter , map , startWith } from 'rxjs/operators' ;
import { filter , map , mergeMap , publishReplay , refCount , startWith , takeUntil } from 'rxjs/operators' ;
import { isDefined } from '@core/utils' ;
import { EntityId } from '@shared/models/id/entity-id' ;
import { DeviceProfileService } from '@core/http/device-profile.service' ;
export interface KeyFilterDialogData {
export interface KeyFilterDialogData {
keyFilter : KeyFilterInfo ;
keyFilter : KeyFilterInfo ;
@ -43,6 +46,7 @@ export interface KeyFilterDialogData {
allowUserDynamicSource : boolean ;
allowUserDynamicSource : boolean ;
readonly : boolean ;
readonly : boolean ;
telemetryKeysOnly : boolean ;
telemetryKeysOnly : boolean ;
entityId? : EntityId ;
}
}
@Component ( {
@Component ( {
@ -53,7 +57,13 @@ export interface KeyFilterDialogData {
} )
} )
export class KeyFilterDialogComponent extends
export class KeyFilterDialogComponent extends
DialogComponent < KeyFilterDialogComponent , KeyFilterInfo >
DialogComponent < KeyFilterDialogComponent , KeyFilterInfo >
implements OnInit , ErrorStateMatcher {
implements OnInit , OnDestroy , ErrorStateMatcher {
@ViewChild ( 'keyNameInput' , { static : true } ) private keyNameInput : ElementRef ;
private dirty = false ;
private entityKeysName : Observable < Array < string > > ;
private destroy $ = new Subject ( ) ;
keyFilterFormGroup : FormGroup ;
keyFilterFormGroup : FormGroup ;
@ -72,19 +82,18 @@ export class KeyFilterDialogComponent extends
submitted = false ;
submitted = false ;
entityFields : { [ fieldName : string ] : EntityField } ;
showAutocomplete = false ;
entityFieldsList : string [ ] ;
readonly entityField = EntityKeyType . ENTITY_FIELD ;
filteredKeysName : Observable < Array < string > > ;
filteredEntityFields : Observable < string [ ] > ;
searchText = '' ;
constructor ( protected store : Store < AppState > ,
constructor ( protected store : Store < AppState > ,
protected router : Router ,
protected router : Router ,
@Inject ( MAT_DIALOG_DATA ) public data : KeyFilterDialogData ,
@Inject ( MAT_DIALOG_DATA ) public data : KeyFilterDialogData ,
@SkipSelf ( ) private errorStateMatcher : ErrorStateMatcher ,
@SkipSelf ( ) private errorStateMatcher : ErrorStateMatcher ,
public dialogRef : MatDialogRef < KeyFilterDialogComponent , KeyFilterInfo > ,
public dialogRef : MatDialogRef < KeyFilterDialogComponent , KeyFilterInfo > ,
private deviceProfileService : DeviceProfileService ,
private dialogs : DialogService ,
private dialogs : DialogService ,
private translate : TranslateService ,
private translate : TranslateService ,
private fb : FormBuilder ) {
private fb : FormBuilder ) {
@ -104,7 +113,9 @@ export class KeyFilterDialogComponent extends
) ;
) ;
if ( ! this . data . readonly ) {
if ( ! this . data . readonly ) {
this . keyFilterFormGroup . get ( 'valueType' ) . valueChanges . subscribe ( ( valueType : EntityKeyValueType ) = > {
this . keyFilterFormGroup . get ( 'valueType' ) . valueChanges . pipe (
takeUntil ( this . destroy $ )
) . subscribe ( ( valueType : EntityKeyValueType ) = > {
const prevValue : EntityKeyValueType = this . keyFilterFormGroup . value . valueType ;
const prevValue : EntityKeyValueType = this . keyFilterFormGroup . value . valueType ;
const predicates : KeyFilterPredicate [ ] = this . keyFilterFormGroup . get ( 'predicates' ) . value ;
const predicates : KeyFilterPredicate [ ] = this . keyFilterFormGroup . get ( 'predicates' ) . value ;
if ( prevValue && prevValue !== valueType && predicates && predicates . length ) {
if ( prevValue && prevValue !== valueType && predicates && predicates . length ) {
@ -121,11 +132,26 @@ export class KeyFilterDialogComponent extends
}
}
} ) ;
} ) ;
this . keyFilterFormGroup . get ( 'key.type' ) . valueChanges . pipe (
startWith ( this . data . keyFilter . key . type ) ,
takeUntil ( this . destroy $ )
) . subscribe ( ( type : EntityKeyType ) = > {
if ( type === EntityKeyType . ENTITY_FIELD || isDefined ( this . data . entityId ) ) {
this . entityKeysName = null ;
this . dirty = false ;
this . showAutocomplete = true ;
} else {
this . showAutocomplete = false ;
}
} ) ;
this . keyFilterFormGroup . get ( 'key.key' ) . valueChanges . pipe (
this . keyFilterFormGroup . get ( 'key.key' ) . valueChanges . pipe (
filter ( ( keyName ) = > this . keyFilterFormGroup . get ( 'key.type' ) . value === this . entityField && this . entityFields . hasOwnProperty ( keyName ) )
filter ( ( keyName ) = >
this . keyFilterFormGroup . get ( 'key.type' ) . value === EntityKeyType . ENTITY_FIELD && entityFields . hasOwnProperty ( keyName ) ) ,
takeUntil ( this . destroy $ )
) . subscribe ( ( keyName : string ) = > {
) . subscribe ( ( keyName : string ) = > {
const prevValueType : EntityKeyValueType = this . keyFilterFormGroup . value . valueType ;
const prevValueType : EntityKeyValueType = this . keyFilterFormGroup . value . valueType ;
const newValueType = this . entityFields [ keyName ] ? . time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING ;
const newValueType = entityFields [ keyName ] ? . time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING ;
if ( prevValueType !== newValueType ) {
if ( prevValueType !== newValueType ) {
this . keyFilterFormGroup . get ( 'valueType' ) . patchValue ( newValueType , { emitEvent : false } ) ;
this . keyFilterFormGroup . get ( 'valueType' ) . patchValue ( newValueType , { emitEvent : false } ) ;
}
}
@ -133,18 +159,20 @@ export class KeyFilterDialogComponent extends
} else {
} else {
this . keyFilterFormGroup . disable ( { emitEvent : false } ) ;
this . keyFilterFormGroup . disable ( { emitEvent : false } ) ;
}
}
}
this . entityFields = entityFields ;
ngOnInit() {
this . entityFieldsList = Object . values ( entityFields ) . map ( entityField = > entityField . keyName ) . sort ( ) ;
this . filteredKeysName = this . keyFilterFormGroup . get ( 'key.key' ) . valueChanges
. pipe (
map ( value = > value ? value : '' ) ,
mergeMap ( name = > this . fetchEntityName ( name ) )
) ;
}
}
ngOnInit ( ) : void {
ngOnDestroy() {
this . filteredEntityFields = this . keyFilterFormGroup . get ( 'key.key' ) . valueChanges . pipe (
super . ngOnDestroy ( ) ;
startWith ( '' ) ,
this . destroy $ . next ( ) ;
map ( value = > {
this . destroy $ . complete ( ) ;
return this . entityFieldsList . filter ( option = > option . startsWith ( value ) ) ;
} )
) ;
}
}
isErrorState ( control : FormControl | null , form : FormGroupDirective | NgForm | null ) : boolean {
isErrorState ( control : FormControl | null , form : FormGroupDirective | NgForm | null ) : boolean {
@ -157,6 +185,21 @@ export class KeyFilterDialogComponent extends
this . dialogRef . close ( null ) ;
this . dialogRef . close ( null ) ;
}
}
clear() {
this . keyFilterFormGroup . get ( 'key.key' ) . patchValue ( '' , { emitEvent : true } ) ;
setTimeout ( ( ) = > {
this . keyNameInput . nativeElement . blur ( ) ;
this . keyNameInput . nativeElement . focus ( ) ;
} , 0 ) ;
}
onFocus() {
if ( ! this . dirty && this . showAutocomplete ) {
this . keyFilterFormGroup . get ( 'key.key' ) . updateValueAndValidity ( { onlySelf : true , emitEvent : true } ) ;
this . dirty = true ;
}
}
save ( ) : void {
save ( ) : void {
this . submitted = true ;
this . submitted = true ;
if ( this . keyFilterFormGroup . valid ) {
if ( this . keyFilterFormGroup . valid ) {
@ -164,4 +207,41 @@ export class KeyFilterDialogComponent extends
this . dialogRef . close ( keyFilter ) ;
this . dialogRef . close ( keyFilter ) ;
}
}
}
}
private fetchEntityName ( searchText? : string ) : Observable < Array < string > > {
this . searchText = searchText ;
return this . getEntityKeys ( ) . pipe (
map ( keys = > searchText ? keys . filter ( key = > key . toUpperCase ( ) . startsWith ( searchText . toUpperCase ( ) ) ) : keys )
) ;
}
private getEntityKeys ( ) : Observable < Array < string > > {
if ( ! this . entityKeysName ) {
let keyNameObservable : Observable < Array < string > > ;
switch ( this . keyFilterFormGroup . get ( 'key.type' ) . value ) {
case EntityKeyType . ENTITY_FIELD :
keyNameObservable = of ( Object . values ( entityFields ) . map ( entityField = > entityField . keyName ) . sort ( ) ) ;
break ;
case EntityKeyType . ATTRIBUTE :
keyNameObservable = this . deviceProfileService . getDeviceProfileDevicesAttributesKeys (
this . data . entityId ? . id ,
{ ignoreLoading : true }
) ;
break ;
case EntityKeyType . TIME_SERIES :
keyNameObservable = this . deviceProfileService . getDeviceProfileDevicesTimeseriesKeys (
this . data . entityId ? . id ,
{ ignoreLoading : true }
) ;
break ;
default :
keyNameObservable = of ( [ ] ) ;
}
this . entityKeysName = keyNameObservable . pipe (
publishReplay ( 1 ) ,
refCount ( )
) ;
}
return this . entityKeysName ;
}
}
}