[MNT-25408]: updates changing search config logic; exposes stream for active filters (#11386)

* [MNT-25408]: fixes execution sequence

* [MNT-25408]: adds getter

* [MNT-25408]: reverts getter for property access proxy

* [MNT-25408]: adds tests

* [MNT-25408]: minor fixes

* [MNT-25408]: minor fixes
This commit is contained in:
Anton Ramanovich
2025-12-09 09:57:55 +01:00
committed by GitHub
parent 6567c02220
commit 8fa3e6acdf
2 changed files with 97 additions and 2 deletions
@@ -73,20 +73,44 @@ export abstract class BaseQueryBuilderService {
/* Stream that emits the initial value for some or all search filters */ /* Stream that emits the initial value for some or all search filters */
populateFilters = new BehaviorSubject<{ [key: string]: any }>({}); populateFilters = new BehaviorSubject<{ [key: string]: any }>({});
/* Stream that emits every time queryFragments change */
queryFragmentsUpdate = new BehaviorSubject<{ [key: string]: any }>({});
/* Stream that emits every time userFacetBuckets change */
userFacetBucketsUpdate = new BehaviorSubject<{ [key: string]: FacetFieldBucket[] }>({});
categories: SearchCategory[] = []; categories: SearchCategory[] = [];
queryFragments: { [id: string]: string } = {};
filterQueries: FilterQuery[] = []; filterQueries: FilterQuery[] = [];
filterRawParams: { [key: string]: any } = {}; filterRawParams: { [key: string]: any } = {};
paging: { maxItems?: number; skipCount?: number } = null; paging: { maxItems?: number; skipCount?: number } = null;
sorting: SearchSortingDefinition[] = []; sorting: SearchSortingDefinition[] = [];
sortingOptions: SearchSortingDefinition[] = []; sortingOptions: SearchSortingDefinition[] = [];
private encodedQuery: string; private encodedQuery: string;
private scope: RequestScope; private scope: RequestScope;
private selectedConfiguration: number; private selectedConfiguration: number;
private _userQuery = ''; private _userQuery = '';
private _queryFragments: { [id: string]: string } = {};
private readonly queryFragmentsHandler: ProxyHandler<{ [key: string]: any }> = {
set: (target: { [key: string]: any }, property: string, value: any) => {
target[property as keyof typeof target] = value;
this.queryFragmentsUpdate.next(this._queryFragments);
return true;
}
};
protected userFacetBuckets: { [key: string]: FacetFieldBucket[] } = {}; protected userFacetBuckets: { [key: string]: FacetFieldBucket[] } = {};
get queryFragments(): { [key: string]: any } {
return this._queryFragments;
}
set queryFragments(value: { [key: string]: any }) {
this._queryFragments = this.createQueryFragmentsProxy(value);
this.queryFragmentsUpdate.next(this._queryFragments);
}
get userQuery(): string { get userQuery(): string {
return this._userQuery; return this._userQuery;
} }
@@ -108,6 +132,7 @@ export abstract class BaseQueryBuilderService {
protected readonly alfrescoApiService: AlfrescoApiService protected readonly alfrescoApiService: AlfrescoApiService
) { ) {
this.resetToDefaults(); this.resetToDefaults();
this._queryFragments = this.createQueryFragmentsProxy({});
} }
public abstract loadConfiguration(): SearchConfiguration | SearchConfiguration[]; public abstract loadConfiguration(): SearchConfiguration | SearchConfiguration[];
@@ -146,10 +171,10 @@ export abstract class BaseQueryBuilderService {
const currentConfig = this.loadConfiguration(); const currentConfig = this.loadConfiguration();
if (Array.isArray(currentConfig) && currentConfig[index] !== undefined) { if (Array.isArray(currentConfig) && currentConfig[index] !== undefined) {
this.selectedConfiguration = index; this.selectedConfiguration = index;
this.configUpdated.next(currentConfig[index]);
this.searchForms.next(this.getSearchFormDetails()); this.searchForms.next(this.getSearchFormDetails());
this.resetSearchOptions(); this.resetSearchOptions();
this.setUpSearchConfiguration(currentConfig[index]); this.setUpSearchConfiguration(currentConfig[index]);
this.configUpdated.next(currentConfig[index]);
this.update(); this.update();
} }
} }
@@ -216,6 +241,7 @@ export abstract class BaseQueryBuilderService {
buckets.push(bucket); buckets.push(bucket);
} }
this.userFacetBuckets[field] = buckets; this.userFacetBuckets[field] = buckets;
this.userFacetBucketsUpdate.next(this.userFacetBuckets);
} }
} }
@@ -239,6 +265,7 @@ export abstract class BaseQueryBuilderService {
if (field && bucket) { if (field && bucket) {
const buckets = this.userFacetBuckets[field] || []; const buckets = this.userFacetBuckets[field] || [];
this.userFacetBuckets[field] = buckets.filter((facetBucket) => facetBucket.label !== bucket.label); this.userFacetBuckets[field] = buckets.filter((facetBucket) => facetBucket.label !== bucket.label);
this.userFacetBucketsUpdate.next(this.userFacetBuckets);
} }
} }
@@ -615,4 +642,8 @@ export abstract class BaseQueryBuilderService {
queryParamsHandling: 'merge' queryParamsHandling: 'merge'
}); });
} }
private createQueryFragmentsProxy(target: { [key: string]: any }): { [key: string]: any } {
return new Proxy(target, this.queryFragmentsHandler);
}
} }
@@ -24,6 +24,7 @@ import { TestBed } from '@angular/core/testing';
import { ContentTestingModule } from '../../testing/content.testing.module'; import { ContentTestingModule } from '../../testing/content.testing.module';
import { ADF_SEARCH_CONFIGURATION } from '../search-configuration.token'; import { ADF_SEARCH_CONFIGURATION } from '../search-configuration.token';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { skip } from 'rxjs/operators';
const buildConfig = (searchSettings = {}): AppConfigService => { const buildConfig = (searchSettings = {}): AppConfigService => {
let config: AppConfigService; let config: AppConfigService;
@@ -840,4 +841,67 @@ describe('SearchQueryBuilder', () => {
}); });
}); });
}); });
describe('userFacetBucketsUpdate', () => {
it('should emit updated list of UserFacetBuckets on adding the bucket', (done) => {
const service = TestBed.inject(SearchQueryBuilderService);
service.userFacetBucketsUpdate.pipe(skip(1)).subscribe((buckets) => {
expect(buckets).toEqual({ test: [{ checked: true, filterQuery: 'f1-q1', label: 'f1-q1', count: 1 }] });
done();
});
const currentBuckets = service.getUserFacetBuckets('test');
expect(currentBuckets).toEqual([]);
service.addUserFacetBucket('test', { checked: true, filterQuery: 'f1-q1', label: 'f1-q1', count: 1 });
});
it('should emit updated list of UserFacetBuckets on removing the bucket', (done) => {
const service = TestBed.inject(SearchQueryBuilderService);
service.addUserFacetBucket('test', { checked: true, filterQuery: 'f1-q1', label: 'toStay', count: 1 });
service.addUserFacetBucket('test', { checked: true, filterQuery: 'f1-q1', label: 'toLeave', count: 1 });
service.userFacetBucketsUpdate.pipe(skip(1)).subscribe((buckets) => {
expect(buckets).toEqual({ test: [{ checked: true, filterQuery: 'f1-q1', label: 'toStay', count: 1 }] });
done();
});
const currentBuckets = service.getUserFacetBuckets('test');
expect(currentBuckets).toEqual([
{ checked: true, filterQuery: 'f1-q1', label: 'toStay', count: 1 },
{ checked: true, filterQuery: 'f1-q1', label: 'toLeave', count: 1 }
]);
service.removeUserFacetBucket('test', { checked: true, filterQuery: 'f1-q1', label: 'toLeave', count: 1 });
});
});
describe('queryFragments proxy set up', () => {
it('should emit queryFragmentsUpdate when proxy property is set', (done) => {
const service = TestBed.inject(SearchQueryBuilderService);
service.queryFragmentsUpdate.pipe(skip(1)).subscribe((fragments) => {
expect(fragments).toEqual({ test: 'test_fragment' });
done();
});
const currentFragments = service.queryFragments;
expect(currentFragments).toEqual({});
service.queryFragments['test'] = 'test_fragment';
});
it('should emit queryFragmentsUpdate when setter replaces the proxy', (done) => {
const service = TestBed.inject(SearchQueryBuilderService);
service.queryFragments['test'] = 'test_fragment';
const currentFragments = service.queryFragments;
expect(currentFragments).toEqual({ test: 'test_fragment' });
service.queryFragmentsUpdate.pipe(skip(1)).subscribe((fragments) => {
expect(fragments).toEqual({});
done();
});
service.queryFragments = {};
});
});
}); });