Browse Source

feat(ui): extend assistant search with accounts

pull/5356/head
David Requeno 2 weeks ago
committed by Thomas Kaul
parent
commit
4afbc4b885
  1. 7
      libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts
  2. 63
      libs/ui/src/lib/assistant/assistant.component.ts
  3. 28
      libs/ui/src/lib/assistant/assistant.html
  4. 1
      libs/ui/src/lib/assistant/enums/search-mode.ts
  5. 9
      libs/ui/src/lib/assistant/interfaces/interfaces.ts

7
libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts

@ -67,6 +67,13 @@ export class GfAssistantListItemComponent
};
this.routerLink = [];
} else if (this.item?.mode === SearchMode.ACCOUNT) {
this.queryParams = {
accountDetailDialog: true,
accountId: (this.item as any).id
};
this.routerLink = internalRoutes.accounts.routerLink;
} else if (this.item?.mode === SearchMode.QUICK_LINK) {
this.queryParams = {};
this.routerLink = this.item.routerLink;

63
libs/ui/src/lib/assistant/assistant.component.ts

@ -154,14 +154,16 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
public holdings: PortfolioPosition[] = [];
public isLoading = {
assetProfiles: false,
accounts: false,
holdings: false,
quickLinks: false
};
public isOpen = false;
public placeholder = $localize`Find holding or page...`;
public placeholder = $localize`Find account, holding or page...`;
public searchFormControl = new FormControl('');
public searchResults: ISearchResults = {
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
};
@ -200,11 +202,13 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
map((searchTerm) => {
this.isLoading = {
assetProfiles: true,
accounts: true,
holdings: true,
quickLinks: true
};
this.searchResults = {
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
};
@ -218,6 +222,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
switchMap((searchTerm) => {
const results = {
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
} as ISearchResults;
@ -227,6 +232,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
tap(() => {
this.isLoading = {
assetProfiles: false,
accounts: false,
holdings: false,
quickLinks: false
};
@ -263,6 +269,25 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
})
);
// Accounts
const accounts$: Observable<Partial<ISearchResults>> =
this.searchAccounts(searchTerm).pipe(
map((accounts) => ({
accounts: accounts.slice(
0,
GfAssistantComponent.SEARCH_RESULTS_DEFAULT_LIMIT
)
})),
catchError((error) => {
console.error('Error fetching accounts for assistant:', error);
return of({ accounts: [] as ISearchResultItem[] });
}),
tap(() => {
this.isLoading.accounts = false;
this.changeDetectorRef.markForCheck();
})
);
// Holdings
const holdings$: Observable<Partial<ISearchResults>> =
this.searchHoldings(searchTerm).pipe(
@ -299,7 +324,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
);
// Merge all results
return merge(quickLinks$, assetProfiles$, holdings$).pipe(
return merge(quickLinks$, assetProfiles$, accounts$, holdings$).pipe(
scan(
(acc: ISearchResults, curr: Partial<ISearchResults>) => ({
...acc,
@ -307,6 +332,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
}),
{
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
} as ISearchResults
@ -324,6 +350,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
console.error('Assistant search stream error:', error);
this.searchResults = {
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
};
@ -332,6 +359,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
complete: () => {
this.isLoading = {
assetProfiles: false,
accounts: false,
holdings: false,
quickLinks: false
};
@ -452,12 +480,14 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
public initialize() {
this.isLoading = {
assetProfiles: true,
accounts: true,
holdings: true,
quickLinks: true
};
this.keyManager = new FocusKeyManager(this.assistantListItems).withWrap();
this.searchResults = {
assetProfiles: [],
accounts: [],
holdings: [],
quickLinks: []
};
@ -473,6 +503,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
this.isLoading = {
assetProfiles: false,
accounts: false,
holdings: false,
quickLinks: false
};
@ -631,6 +662,34 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
);
}
private searchAccounts(aSearchTerm: string): Observable<ISearchResultItem[]> {
return this.dataService
.fetchAccounts({
filters: [
{
id: aSearchTerm,
type: 'SEARCH_QUERY'
}
]
})
.pipe(
catchError(() => {
return EMPTY;
}),
map(({ accounts }) => {
return accounts.map(({ id, name, platform }) => {
return {
id,
name,
platform,
mode: SearchMode.ACCOUNT as const
};
});
}),
takeUntil(this.unsubscribeSubject)
);
}
private searchQuickLinks(aSearchTerm: string): ISearchResultItem[] {
const searchTerm = aSearchTerm.toLowerCase();

28
libs/ui/src/lib/assistant/assistant.html

@ -40,9 +40,11 @@
<div class="overflow-auto py-2 result-container">
@if (
!isLoading.assetProfiles &&
!isLoading.accounts &&
!isLoading.holdings &&
!isLoading.quickLinks &&
searchResults.assetProfiles?.length === 0 &&
searchResults.accounts?.length === 0 &&
searchResults.holdings?.length === 0 &&
searchResults.quickLinks?.length === 0
) {
@ -76,6 +78,32 @@
}
</div>
}
@if (isLoading.accounts || searchResults?.accounts?.length !== 0) {
<div>
<div class="font-weight-bold px-3 text-muted title" i18n>
Accounts
</div>
@for (
searchResultItem of searchResults.accounts;
track searchResultItem
) {
<gf-assistant-list-item
[item]="searchResultItem"
(clicked)="onCloseAssistant()"
/>
}
@if (isLoading.accounts) {
<ngx-skeleton-loader
animation="pulse"
class="mx-3"
[theme]="{
height: '1.5rem',
width: '100%'
}"
/>
}
</div>
}
@if (isLoading.holdings || searchResults?.holdings?.length !== 0) {
<div>
<div class="font-weight-bold px-3 text-muted title" i18n>

1
libs/ui/src/lib/assistant/enums/search-mode.ts

@ -1,4 +1,5 @@
export enum SearchMode {
ACCOUNT = 'account',
ASSET_PROFILE = 'assetProfile',
HOLDING = 'holding',
QUICK_LINK = 'quickLink'

9
libs/ui/src/lib/assistant/interfaces/interfaces.ts

@ -1,5 +1,5 @@
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types';
import { AccountWithValue, DateRange } from '@ghostfolio/common/types';
import { SearchMode } from '../enums/search-mode';
@ -21,12 +21,19 @@ export interface IQuickLinkSearchResultItem {
routerLink: string[];
}
export interface IAccountSearchResultItem
extends Pick<AccountWithValue, 'id' | 'name' | 'platform'> {
mode: SearchMode.ACCOUNT;
}
export type ISearchResultItem =
| IAssetSearchResultItem
| IAccountSearchResultItem
| IQuickLinkSearchResultItem;
export interface ISearchResults {
assetProfiles: ISearchResultItem[];
accounts: ISearchResultItem[];
holdings: ISearchResultItem[];
quickLinks: ISearchResultItem[];
}

Loading…
Cancel
Save