[ACS-12041] Add debounce timer for saved searches to limit API calls on every keystroke (#5267)

This commit is contained in:
Michal Kinas
2026-07-02 17:48:45 +02:00
committed by GitHub
parent a389048aa5
commit a52a71a254
2 changed files with 20 additions and 2 deletions
@@ -89,9 +89,24 @@ describe('SaveSearchDialogComponent', () => {
expect(notificationService.showError).toHaveBeenCalledWith('APP.BROWSE.SEARCH.SAVE_SEARCH.SAVE_ERROR');
}));
it('should call getSavedSearches only once when user types multiple times within the debounce window', fakeAsync(() => {
const getSavedSearchesSpy = spyOn(savedSearchesService, 'getSavedSearches').and.callThrough();
const nameControl = component.form.controls['name'];
nameControl.setValue('a');
tick(100);
nameControl.setValue('ab');
tick(100);
nameControl.setValue('abc');
tick(300);
expect(getSavedSearchesSpy).toHaveBeenCalledTimes(1);
}));
function setFormValuesAndSubmit() {
component.form.controls['name'].setValue('ABCDEF');
component.form.controls['description'].setValue('TEST');
tick(300);
submitButton.click();
tick();
expect(savedSearchesService.saveSearch).toHaveBeenCalledWith({
@@ -24,15 +24,18 @@
import { Injectable, inject } from '@angular/core';
import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
import { catchError, map, Observable, of } from 'rxjs';
import { catchError, map, Observable, of, switchMap, timer } from 'rxjs';
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
const VALIDATION_DEBOUNCE_TIME = 300;
@Injectable({ providedIn: 'root' })
export class UniqueSearchNameValidator implements AsyncValidator {
private readonly savedSearchesService = inject(SavedSearchesContextService);
validate(control: AbstractControl): Observable<ValidationErrors | null> {
return this.savedSearchesService.getSavedSearches().pipe(
return timer(VALIDATION_DEBOUNCE_TIME).pipe(
switchMap(() => this.savedSearchesService.getSavedSearches()),
map((searches) =>
searches.some((search) => search.name === control.value && control.dirty)
? { message: 'APP.BROWSE.SEARCH.SAVE_SEARCH.SEARCH_NAME_NOT_UNIQUE_ERROR' }