Browse Source

feat: auto-preselect first search result in assistant

pull/5656/head
adityagarud 1 month ago
parent
commit
42198affd6
  1. 71
      libs/ui/src/lib/assistant/assistant.component.ts

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

@ -177,8 +177,11 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
'TAG' 'TAG'
]; ];
private keyManager: FocusKeyManager<GfAssistantListItemComponent>; private keyManager: FocusKeyManager<GfAssistantListItemComponent>;
private preselectionTimeout: any;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
private readonly PRESELECTION_DELAY = 100;
public constructor( public constructor(
private adminService: AdminService, private adminService: AdminService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
@ -345,6 +348,9 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
next: (searchResults) => { next: (searchResults) => {
this.searchResults = searchResults; this.searchResults = searchResults;
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
// Trigger preselection of first item
this.preselectFirstItem();
}, },
error: (error) => { error: (error) => {
console.error('Assistant search stream error:', error); console.error('Assistant search stream error:', error);
@ -585,6 +591,11 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
} }
public ngOnDestroy() { public ngOnDestroy() {
// Clear preselection timeout
if (this.preselectionTimeout) {
clearTimeout(this.preselectionTimeout);
}
this.unsubscribeSubject.next(); this.unsubscribeSubject.next();
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
@ -595,6 +606,66 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
}); });
} }
/**
* Gets the first search result item based on priority order:
* Quick Links Accounts Holdings Asset Profiles
*/
private getFirstSearchResultItem(): ISearchResultItem | null {
// Priority order: Quick Links → Accounts → Holdings → Asset Profiles
if (this.searchResults.quickLinks?.length > 0) {
return this.searchResults.quickLinks[0];
}
if (this.searchResults.accounts?.length > 0) {
return this.searchResults.accounts[0];
}
if (this.searchResults.holdings?.length > 0) {
return this.searchResults.holdings[0];
}
if (this.searchResults.assetProfiles?.length > 0) {
return this.searchResults.assetProfiles[0];
}
return null;
}
/**
* Preselects the first search result item with debouncing
*/
private preselectFirstItem(): void {
// Clear any existing timeout
if (this.preselectionTimeout) {
clearTimeout(this.preselectionTimeout);
}
// Debounce preselection to handle rapid search changes
this.preselectionTimeout = setTimeout(() => {
// Check if we have search results and the assistant is open
if (!this.isOpen || !this.searchFormControl.value) {
return;
}
const firstItem = this.getFirstSearchResultItem();
if (!firstItem) {
return;
}
// Clear any existing focus
for (const item of this.assistantListItems) {
item.removeFocus();
}
// Set the first item as active in the key manager
this.keyManager.setFirstItemActive();
// Get the currently focused item and apply focus styling
const currentFocusedItem = this.getCurrentAssistantListItem();
if (currentFocusedItem) {
currentFocusedItem.focus();
}
this.changeDetectorRef.markForCheck();
}, this.PRESELECTION_DELAY);
}
private searchAccounts(aSearchTerm: string): Observable<ISearchResultItem[]> { private searchAccounts(aSearchTerm: string): Observable<ISearchResultItem[]> {
return this.dataService return this.dataService
.fetchAccounts({ .fetchAccounts({

Loading…
Cancel
Save