| 
						
						
						
					 | 
				
				 | 
				
					@ -1,7 +1,9 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { GfAssetProfileIconComponent } from '@ghostfolio/client/components/asset-profile-icon/asset-profile-icon.component'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { AdminService } from '@ghostfolio/client/services/admin.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DataService } from '@ghostfolio/client/services/data.service'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Filter, User } from '@ghostfolio/common/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Filter, PortfolioPosition, User } from '@ghostfolio/common/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DateRange } from '@ghostfolio/common/types'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { translate } from '@ghostfolio/ui/i18n'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -35,7 +37,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { MatMenuTrigger } from '@angular/material/menu'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { MatSelectModule } from '@angular/material/select'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { RouterModule } from '@angular/router'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Account, AssetClass } from '@prisma/client'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Account, AssetClass, DataSource } from '@prisma/client'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -61,6 +63,7 @@ import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    FormsModule, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    GfAssetProfileIconComponent, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    GfAssistantListItemComponent, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    GfSymbolModule, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    MatButtonModule, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    MatFormFieldModule, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    MatSelectModule, | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -132,8 +135,10 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public filterForm = this.formBuilder.group({ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    account: new FormControl<string>(undefined), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    assetClass: new FormControl<string>(undefined), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    holding: new FormControl<PortfolioPosition>(undefined), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    tag: new FormControl<string>(undefined) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public holdings: PortfolioPosition[] = []; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public isLoading = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public isOpen = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public placeholder = $localize`Find holding...`; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -144,7 +149,13 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public tags: Filter[] = []; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private filterTypes: Filter['type'][] = ['ACCOUNT', 'ASSET_CLASS', 'TAG']; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private filterTypes: Filter['type'][] = [ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    'ACCOUNT', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    'ASSET_CLASS', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    'DATA_SOURCE', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    'SYMBOL', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    'TAG' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private keyManager: FocusKeyManager<GfAssistantListItemComponent>; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private unsubscribeSubject = new Subject<void>(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -156,6 +167,8 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ) {} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public ngOnInit() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.initializeFilterForm(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.assetClasses = Object.keys(AssetClass).map((assetClass) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        id: assetClass, | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -263,16 +276,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.filterForm.enable({ emitEvent: false }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.filterForm.setValue( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        account: this.user?.settings?.['filters.accounts']?.[0] ?? null, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        tag: this.user?.settings?.['filters.tags']?.[0] ?? null | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        emitEvent: false | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.initializeFilterForm(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.tags = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.user?.tags | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -298,6 +302,19 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public holdingComparisonFunction( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    option: PortfolioPosition, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    value: PortfolioPosition | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): boolean { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if (value === null) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      getAssetProfileIdentifier(option) === getAssetProfileIdentifier(value) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async initialize() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.isLoading = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.keyManager = new FocusKeyManager(this.assistantListItems).withWrap(); | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -331,6 +348,14 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        id: this.filterForm.get('assetClass').value, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        type: 'ASSET_CLASS' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        id: this.filterForm.get('holding').value?.dataSource, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        type: 'DATA_SOURCE' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        id: this.filterForm.get('holding').value?.symbol, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        type: 'SYMBOL' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        id: this.filterForm.get('tag').value, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        type: 'TAG' | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -473,4 +498,47 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        takeUntil(this.unsubscribeSubject) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private initializeFilterForm() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.dataService | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      .fetchPortfolioHoldings() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      .pipe(takeUntil(this.unsubscribeSubject)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      .subscribe(({ holdings }) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.holdings = holdings | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          .filter(({ assetSubClass }) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return !['CASH'].includes(assetSubClass); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          }) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          .sort((a, b) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return a.name?.localeCompare(b.name); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.setFilterFormValues(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private setFilterFormValues() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const dataSource = this.user?.settings?.[ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      'filters.dataSource' | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ] as DataSource; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const symbol = this.user?.settings?.['filters.symbol']; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const selectedHolding = this.holdings.find((holding) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        getAssetProfileIdentifier({ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          dataSource: holding.dataSource, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          symbol: holding.symbol | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        }) === getAssetProfileIdentifier({ dataSource, symbol }) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.filterForm.setValue( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        account: this.user?.settings?.['filters.accounts']?.[0] ?? null, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        holding: selectedHolding ?? null, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        tag: this.user?.settings?.['filters.tags']?.[0] ?? null | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        emitEvent: false | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
					 | 
				
				 | 
				
					
  |