[MNT-25635] Search filter autocomplete search for tags when input changes (#11780)

This commit is contained in:
Michal Kinas
2026-04-01 09:29:43 +02:00
committed by GitHub
parent f321b74be0
commit 565db01819
2 changed files with 35 additions and 39 deletions
@@ -18,7 +18,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { SearchFilterAutocompleteChipsComponent } from './search-filter-autocomplete-chips.component';
import { EMPTY, of, ReplaySubject } from 'rxjs';
import { of, ReplaySubject } from 'rxjs';
import { AutocompleteField, AutocompleteOption } from '../../models/autocomplete-option.interface';
import { TagService } from '../../../tag/services/tag.service';
import { SitesService } from '../../../common/services/sites.service';
@@ -33,13 +33,7 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [SearchFilterAutocompleteChipsComponent],
providers: [
{
provide: TagService,
useValue: { getAllTheTags: () => EMPTY }
}
]
imports: [SearchFilterAutocompleteChipsComponent]
});
fixture = TestBed.createComponent(SearchFilterAutocompleteChipsComponent);
@@ -86,23 +80,6 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
});
});
it('should load tags if field = TAG', (done) => {
const tagPagingMock = {
list: {
pagination: {},
entries: [{ entry: { tag: 'tag1', id: 'id1' } }, { entry: { tag: 'tag2', id: 'id2' } }]
}
};
component.settings.field = AutocompleteField.TAG;
spyOn(tagService, 'getAllTheTags').and.returnValue(of(tagPagingMock));
component.ngOnInit();
component.autocompleteOptions$.subscribe((result) => {
expect(result).toEqual([{ value: 'tag1' }, { value: 'tag2' }]);
done();
});
});
it('should update display value when options changes', () => {
const newOption = 'option1';
spyOn(component, 'onOptionsChange').and.callThrough();
@@ -215,13 +192,9 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
it('should use id if present, otherwise value, in LOCATION query fragment', () => {
component.settings.field = AutocompleteField.LOCATION;
component.settings.autocompleteOptions = [];
component.selectedOptions = [
{ id: 'site1', value: 'Marketing' },
{ value: 'custom' }
];
component.selectedOptions = [{ id: 'site1', value: 'Marketing' }, { value: 'custom' }];
component.submitValues();
expect(component.context.queryFragments[component.id])
.toBe('SITE:"site1" OR SITE:"custom"');
expect(component.context.queryFragments[component.id]).toBe('SITE:"site1" OR SITE:"custom"');
});
it('should still call sitesService.getSites when input is empty for LOCATION field', () => {
@@ -251,6 +224,22 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
expect(searchSpy).toHaveBeenCalledWith('', 0, 15);
});
it('should search for tags if field = TAG and input is not empty', () => {
component.settings.field = AutocompleteField.TAG;
const searchSpy = spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
pagination: {},
entries: [{ entry: { tag: 'tag1', id: 'id1' } }, { entry: { tag: 'tag2', id: 'id2' } }]
}
})
);
component.onInputChange('tag');
expect(searchSpy).toHaveBeenCalledWith('tag', { orderBy: 'tag', direction: 'asc' }, false, 0, 15);
});
describe('optionComparator', () => {
it('should return false if either option is undefined', () => {
expect(component.optionComparator(undefined, { value: 'A' })).toBe(false);
@@ -258,7 +247,7 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
});
it('should compare by id if both have id', () => {
expect(component.optionComparator({ id: 'abc', value: 'B' } , { id: 'ABC', value: 'B' })).toBe(true);
expect(component.optionComparator({ id: 'abc', value: 'B' }, { id: 'ABC', value: 'B' })).toBe(true);
expect(component.optionComparator({ id: 'abc', value: 'B' }, { id: 'def', value: 'B' })).toBe(false);
});
@@ -124,6 +124,8 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
onInputChange(value: string) {
if (this.settings.field === AutocompleteField.CATEGORIES) {
this.searchForExistingCategories(value);
} else if (this.settings.field === AutocompleteField.TAG) {
this.searchForExistingTags(value);
} else if (this.settings.field === AutocompleteField.LOCATION) {
this.populateSitesOptions();
}
@@ -166,13 +168,7 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
private setOptions() {
switch (this.settings.field) {
case AutocompleteField.TAG:
this.tagService.getAllTheTags().subscribe((tagPaging) => {
this.autocompleteOptionsSubject$.next(
tagPaging.list.entries.map((tag) => ({
value: tag.entry.tag
}))
);
});
this.autocompleteOptionsSubject$.next([]);
break;
case AutocompleteField.CATEGORIES:
this.autocompleteOptionsSubject$.next([]);
@@ -197,6 +193,17 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
});
}
private searchForExistingTags(searchTerm: string) {
this.tagService.searchTags(searchTerm, { orderBy: 'tag', direction: 'asc' }, false, 0, 15).subscribe((existingTagsResult) => {
this.autocompleteOptionsSubject$.next(
existingTagsResult.list.entries.map((tag) => ({
id: tag.entry.id,
value: tag.entry.tag
}))
);
});
}
private populateSitesOptions(): void {
this.sitesService
.getSites()