diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts b/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts index e8f062f47e..859a4d68ea 100644 --- a/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts +++ b/lib/content-services/src/lib/document-list/components/document-list.component.spec.ts @@ -1276,25 +1276,9 @@ describe('DocumentList', () => { documentList.onNodeDblClick(node); }); - it('should load folder by ID on init if no filterValue is provided', async () => { + it('should load folder by ID on init', async () => { spyOn(documentList, 'loadFolder').and.stub(); - documentList.filterValue = {}; - - fixture.detectChanges(); - - documentList.ngOnChanges({ currentFolderId: new SimpleChange(undefined, '1d26e465-dea3-42f3-b415-faa8364b9692', true) }); - - await fixture.whenStable(); - - expect(documentList.loadFolder).not.toHaveBeenCalled(); - }); - - it('should NOT load folder by ID on init if filterValue is provided', async () => { - spyOn(documentList, 'loadFolder').and.stub(); - - documentList.filterValue = undefined; - fixture.detectChanges(); documentList.ngOnChanges({ currentFolderId: new SimpleChange(undefined, '1d26e465-dea3-42f3-b415-faa8364b9692', true) }); diff --git a/lib/content-services/src/lib/document-list/components/document-list.component.ts b/lib/content-services/src/lib/document-list/components/document-list.component.ts index a3c2f49b37..8901fb6d23 100644 --- a/lib/content-services/src/lib/document-list/components/document-list.component.ts +++ b/lib/content-services/src/lib/document-list/components/document-list.component.ts @@ -599,7 +599,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On } if (this.currentFolderId && changes['currentFolderId']?.currentValue !== changes['currentFolderId']?.previousValue) { - !this.filterValue && this.loadFolder(); + this.loadFolder(); } if (this.data) { @@ -816,6 +816,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On this.preserveExistingSelection(); } this.onPreselectNodes(); + this.setLoadingState(false); this.onDataReady(nodePaging); } } @@ -1022,7 +1023,6 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On private onDataReady(nodePaging: NodePaging) { this.ready.emit(nodePaging); this.pagination.next(nodePaging.list.pagination); - this.setLoadingState(false); } updatePagination(requestPaginationModel: RequestPaginationModel) { diff --git a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts index e5c1322bb3..49be25fdc9 100644 --- a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts +++ b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.spec.ts @@ -109,35 +109,7 @@ describe('FilterHeaderComponent', () => { expect(setCurrentRootFolderIdSpy).toHaveBeenCalled(); }); - it('should set filters if initial value is provided', async () => { - spyOn(queryBuilder, 'setCurrentRootFolderId'); - spyOn(queryBuilder, 'isCustomSourceNode').and.returnValue(false); - spyOn(queryBuilder, 'setActiveFilter'); - - component.value = { name: 'pinocchio' }; - const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true); - component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange }); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(queryBuilder.setActiveFilter).toHaveBeenCalledWith('name', 'pinocchio'); - }); - - it('should NOT set filters if initial value is not provided', async () => { - spyOn(queryBuilder, 'setCurrentRootFolderId'); - spyOn(queryBuilder, 'isCustomSourceNode').and.returnValue(false); - spyOn(queryBuilder, 'setActiveFilter'); - - component.value = undefined; - const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true); - component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange }); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(queryBuilder.setActiveFilter).not.toHaveBeenCalled(); - }); - - it('should set active filters correctly', async () => { + it('should set active filters when an initial value is set', async () => { spyOn(queryBuilder, 'setCurrentRootFolderId'); spyOn(queryBuilder, 'isCustomSourceNode').and.returnValue(false); @@ -145,7 +117,8 @@ describe('FilterHeaderComponent', () => { await fixture.whenStable(); expect(queryBuilder.getActiveFilters().length).toBe(0); - component.value = { name: 'pinocchio' }; + const initialFilterValue = { name: 'pinocchio' }; + component.value = initialFilterValue; const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true); component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange }); fixture.detectChanges(); @@ -156,25 +129,6 @@ describe('FilterHeaderComponent', () => { expect(queryBuilder.getActiveFilters()[0].value).toBe('pinocchio'); }); - it('should update queryParams if initial value is provided', async () => { - spyOn(queryBuilder, 'setCurrentRootFolderId'); - spyOn(queryBuilder, 'isCustomSourceNode').and.returnValue(false); - - fixture.detectChanges(); - await fixture.whenStable(); - expect(Object.keys(queryBuilder.filterRawParams).length).toBe(0); - - component.value = { name: 'pinocchio' }; - const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true); - component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange }); - fixture.detectChanges(); - await fixture.whenStable(); - - expect(Object.keys(queryBuilder.filterRawParams).length).toBe(1); - expect(queryBuilder.filterRawParams['name']).toBe('pinocchio'); - expect(queryBuilder.queryFragments['name']).toBe('pinocchio'); - }); - it('should emit filterSelection when a filter is changed', (done) => { spyOn(queryBuilder, 'getActiveFilters').and.returnValue([{ key: 'name', value: 'pinocchio' }]); diff --git a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.ts b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.ts index c118db40a1..c168652882 100644 --- a/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.ts +++ b/lib/content-services/src/lib/document-list/components/filter-header/filter-header.component.ts @@ -46,10 +46,7 @@ export class FilterHeaderComponent implements OnInit, OnChanges { private readonly destroyRef = inject(DestroyRef); - constructor( - @Inject(ADF_DOCUMENT_PARENT_COMPONENT) private readonly documentList: any, - private readonly searchFilterQueryBuilder: SearchHeaderQueryBuilderService - ) { + constructor(@Inject(ADF_DOCUMENT_PARENT_COMPONENT) private documentList: any, private searchFilterQueryBuilder: SearchHeaderQueryBuilderService) { this.isFilterServiceActive = this.searchFilterQueryBuilder.isFilterServiceActive(); } @@ -105,17 +102,11 @@ export class FilterHeaderComponent implements OnInit, OnChanges { } private initSearchHeader(currentFolderId: string) { + this.searchFilterQueryBuilder.setCurrentRootFolderId(currentFolderId); if (this.value) { - Object.keys(this.value).forEach((key) => { - this.searchFilterQueryBuilder.setActiveFilter(key, this.value[key]); - - const operator = this.searchFilterQueryBuilder.getOperatorForFilterId(key) || 'OR'; - this.searchFilterQueryBuilder.filterRawParams[key] = this.value[key]; - this.searchFilterQueryBuilder.queryFragments[key] = Array.isArray(this.value[key]) - ? this.value[key].join(` ${operator} `) - : this.value[key]; + Object.keys(this.value).forEach((columnKey) => { + this.searchFilterQueryBuilder.setActiveFilter(columnKey, this.value[columnKey]); }); } - this.searchFilterQueryBuilder.setCurrentRootFolderId(currentFolderId); } } diff --git a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts index bdc9a461af..950d03d648 100644 --- a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.spec.ts @@ -203,17 +203,18 @@ describe('SearchCheckListComponent', () => { expect(checkedElements.length).toBe(0); }); - it('should check the checkbox with startValue on init, if provided', () => { + it('should update query with startValue on init, if provided', () => { component.id = 'checkList'; component.options = new SearchFilterList([ { name: 'Folder', value: `TYPE:'cm:folder'`, checked: false }, { name: 'Document', value: `TYPE:'cm:content'`, checked: false } ]); - component.startValue = [`TYPE:'cm:folder'`]; + component.startValue = `TYPE:'cm:folder'`; + component.context.queryFragments[component.id] = 'query'; fixture.detectChanges(); - expect(component.options.items[0].checked).toBeTrue(); - expect(component.options.items[1].checked).toBeFalse(); - expect(component.isActive).toBeTrue(); + + expect(component.context.queryFragments[component.id]).toBe(`TYPE:'cm:folder'`); + expect(component.context.update).toHaveBeenCalled(); }); it('should set query context as blank and not call query update, if no start value was provided', () => { @@ -230,25 +231,6 @@ describe('SearchCheckListComponent', () => { expect(component.context.update).not.toHaveBeenCalled(); }); - it('should handle initial populateFilters emission and no filter state properly', () => { - component.id = 'checkList'; - component.options = new SearchFilterList([ - { name: 'Folder', value: `TYPE:'cm:folder'`, checked: false }, - { name: 'Document', value: `TYPE:'cm:content'`, checked: false } - ]); - - component.context.filterLoaded = new ReplaySubject(1); - spyOn(component.context.filterLoaded, 'next').and.stub(); - spyOn(component.displayValue$, 'next').and.stub(); - fixture.detectChanges(); - - component.context.populateFilters.next({}); - component.context.populateFilters.next({ checkList: [`TYPE:'cm:content'`] }); - fixture.detectChanges(); - - expect(component.context.filterLoaded.next).toHaveBeenCalledTimes(1); - }); - it('should populate filter state when populate filters event has been observed', () => { component.id = 'checkList'; component.options = new SearchFilterList([ diff --git a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.ts b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.ts index 1eccfb0e47..43e546d5aa 100644 --- a/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.ts +++ b/lib/content-services/src/lib/search/components/search-check-list/search-check-list.component.ts @@ -23,7 +23,7 @@ import { SearchQueryBuilderService } from '../../services/search-query-builder.s import { SearchFilterList } from '../../models/search-filter-list.model'; import { TranslationService } from '@alfresco/adf-core'; import { ReplaySubject } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { CommonModule } from '@angular/common'; import { TranslatePipe } from '@ngx-translate/core'; import { MatButtonModule } from '@angular/material/button'; @@ -50,7 +50,7 @@ export class SearchCheckListComponent implements SearchWidget, OnInit { context?: SearchQueryBuilderService; options: SearchFilterList; operator: string = 'OR'; - startValue: string | string[]; + startValue: string; pageSize = 5; isActive = false; enableChangeUpdate = true; @@ -81,9 +81,9 @@ export class SearchCheckListComponent implements SearchWidget, OnInit { } } this.context.populateFilters + .asObservable() .pipe( map((filtersQueries) => filtersQueries[this.id]), - filter((filterQuery) => filterQuery !== undefined), takeUntilDestroyed(this.destroyRef) ) .subscribe((filterQuery) => { @@ -160,8 +160,8 @@ export class SearchCheckListComponent implements SearchWidget, OnInit { } setValue(value: any) { - this.options.items.forEach((item) => (item.checked = value.includes(item.value))); - this.isActive = true; + this.options.items.filter((item) => value.includes(item.value)).forEach((item) => (item.checked = true)); + this.submitValues(); } private getCheckedValues() { diff --git a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts index 82e540f36d..ec13684521 100644 --- a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.spec.ts @@ -94,7 +94,7 @@ describe('SearchFilterContainerComponent', () => { await applyButton.click(); expect(queryBuilder.getActiveFilters().length).toBe(1); - expect(queryBuilder.getActiveFilters()[0].key).toBe('queryName'); + expect(queryBuilder.getActiveFilters()[0].key).toBe('name'); expect(queryBuilder.getActiveFilters()[0].value).toBe('searchText'); await menu.open(); @@ -103,12 +103,12 @@ describe('SearchFilterContainerComponent', () => { await applyButton.click(); expect(queryBuilder.getActiveFilters().length).toBe(1); - expect(queryBuilder.getActiveFilters()[0].key).toBe('queryName'); + expect(queryBuilder.getActiveFilters()[0].key).toBe('name'); expect(queryBuilder.getActiveFilters()[0].value).toBe('updated text'); }); it('should remove active filter after the Clear button is clicked', async () => { - queryBuilder.setActiveFilter('queryName', 'searchText'); + queryBuilder.setActiveFilter('name', 'searchText'); const menu = await loader.getHarness(MatMenuHarness); await menu.open(); diff --git a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.ts b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.ts index d9349d98b6..2b01ba350a 100644 --- a/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.ts +++ b/lib/content-services/src/lib/search/components/search-filter-container/search-filter-container.component.ts @@ -76,7 +76,7 @@ export class SearchFilterContainerComponent implements OnInit { ngOnInit() { this.category = this.searchFilterQueryBuilder.getCategoryForColumn(this.col.key); - this.initialValue = this.value?.[this.category?.id]; + this.initialValue = this.value?.[this.col.key] ? this.value[this.col.key] : undefined; } onKeyPressed(event: KeyboardEvent, menuTrigger: MatMenuTrigger) { @@ -88,7 +88,7 @@ export class SearchFilterContainerComponent implements OnInit { onApply() { if (this.widgetContainer.hasValueSelected()) { - this.searchFilterQueryBuilder.setActiveFilter(this.category.id, this.widgetContainer.getCurrentValue()); + this.searchFilterQueryBuilder.setActiveFilter(this.category.columnKey, this.widgetContainer.getCurrentValue()); this.filterChange.emit(); this.widgetContainer.applyInnerWidget(); } else { @@ -103,7 +103,7 @@ export class SearchFilterContainerComponent implements OnInit { resetSearchFilter() { this.widgetContainer.resetInnerWidget(); - this.searchFilterQueryBuilder.removeActiveFilter(this.category.id); + this.searchFilterQueryBuilder.removeActiveFilter(this.category.columnKey); this.filterChange.emit(); } @@ -115,7 +115,7 @@ export class SearchFilterContainerComponent implements OnInit { } isActive(): boolean { - return this.searchFilterQueryBuilder.getActiveFilters().findIndex((f: FilterSearch) => f.key === this.category.id) > -1; + return this.searchFilterQueryBuilder.getActiveFilters().findIndex((f: FilterSearch) => f.key === this.category.columnKey) > -1; } onMenuOpen() { diff --git a/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts b/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts index 326d06f87e..8813c8f65d 100644 --- a/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts +++ b/lib/content-services/src/lib/search/components/search-text/search-text.component.spec.ts @@ -123,7 +123,7 @@ describe('SearchTextComponent', () => { expect(component.value).toBe(''); expect(component.context.queryFragments[component.id]).toBe(''); - expect(component.context.filterRawParams[component.id]).toBeUndefined(); + expect(component.context.filterRawParams[component.id]).toBeNull(); }); it('should update query with startValue on init, if provided', () => { diff --git a/lib/content-services/src/lib/search/components/search-text/search-text.component.ts b/lib/content-services/src/lib/search/components/search-text/search-text.component.ts index 40b05fba20..f8dcb41b83 100644 --- a/lib/content-services/src/lib/search/components/search-text/search-text.component.ts +++ b/lib/content-services/src/lib/search/components/search-text/search-text.component.ts @@ -99,8 +99,6 @@ export class SearchTextComponent implements SearchWidget, OnInit { reset(updateContext = true) { this.value = ''; - this.context.filterRawParams[this.id] = undefined; - this.context.queryFragments[this.id] = ''; this.updateQuery(null, updateContext); } @@ -113,10 +111,7 @@ export class SearchTextComponent implements SearchWidget, OnInit { } private updateQuery(value: string, updateContext = true) { - if (value !== null) { - this.context.filterRawParams[this.id] = value; - } - + this.context.filterRawParams[this.id] = value; this.displayValue$.next(value); if (this.context && this.settings && this.settings.field) { this.context.queryFragments[this.id] = value ? `${this.settings.field}:'${this.getSearchPrefix()}${value}${this.getSearchSuffix()}'` : ''; diff --git a/lib/content-services/src/lib/search/services/search-header-query-builder.service.spec.ts b/lib/content-services/src/lib/search/services/search-header-query-builder.service.spec.ts index 567ccbfeea..49cf94bc8c 100644 --- a/lib/content-services/src/lib/search/services/search-header-query-builder.service.spec.ts +++ b/lib/content-services/src/lib/search/services/search-header-query-builder.service.spec.ts @@ -22,7 +22,6 @@ import { TestBed } from '@angular/core/testing'; import { ContentTestingModule } from '../../testing/content.testing.module'; import { AlfrescoApiService } from '../../services/alfresco-api.service'; import { ActivatedRoute, Router } from '@angular/router'; -import { SearchCategory } from '../models'; describe('SearchHeaderQueryBuilderService', () => { let activatedRoute: ActivatedRoute; @@ -44,13 +43,10 @@ describe('SearchHeaderQueryBuilderService', () => { it('should load the configuration from app config', () => { TestBed.runInInjectionContext(() => { - const config = { - categories: [ - { id: 'cat1', enabled: true }, - { id: 'cat2', enabled: true } - ], + const config: SearchConfiguration = { + categories: [{ id: 'cat1', enabled: true } as any, { id: 'cat2', enabled: true } as any], filterQueries: [{ query: 'query1' }, { query: 'query2' }] - } as SearchConfiguration; + }; const alfrescoApiService = TestBed.inject(AlfrescoApiService); const builder = new SearchHeaderQueryBuilderService(buildConfig(config), alfrescoApiService, null); @@ -70,13 +66,13 @@ describe('SearchHeaderQueryBuilderService', () => { it('should return the category assigned to a column key', () => { TestBed.runInInjectionContext(() => { - const config = { + const config: SearchConfiguration = { categories: [ - { id: 'cat1', columnKey: 'fake-key-1', enabled: true }, - { id: 'cat2', columnKey: 'fake-key-2', enabled: true } + { id: 'cat1', columnKey: 'fake-key-1', enabled: true } as any, + { id: 'cat2', columnKey: 'fake-key-2', enabled: true } as any ], filterQueries: [{ query: 'query1' }, { query: 'query2' }] - } as SearchConfiguration; + }; const alfrescoApiService = TestBed.inject(AlfrescoApiService); const service = new SearchHeaderQueryBuilderService(buildConfig(config), alfrescoApiService, null); @@ -88,25 +84,6 @@ describe('SearchHeaderQueryBuilderService', () => { }); }); - it('should return operator for a category by id', () => { - TestBed.runInInjectionContext(() => { - const config: SearchConfiguration = { - categories: [ - { id: 'cat1', columnKey: 'fake-key-1', enabled: true, component: { settings: { operator: 'operator' } } }, - { id: 'cat2', columnKey: 'fake-key-2', enabled: true } - ] as SearchCategory[] - }; - - const alfrescoApiService = TestBed.inject(AlfrescoApiService); - const service = new SearchHeaderQueryBuilderService(buildConfig(config), alfrescoApiService, null); - - const operator = service.getOperatorForFilterId('cat1'); - expect(operator).toBe('operator'); - const operator1 = service.getOperatorForFilterId('cat2'); - expect(operator1).toBeUndefined(); - }); - }); - it('should have empty user query by default', () => { TestBed.runInInjectionContext(() => { const alfrescoApiService = TestBed.inject(AlfrescoApiService); @@ -117,13 +94,10 @@ describe('SearchHeaderQueryBuilderService', () => { it('should add the extra filter for the parent node', () => { TestBed.runInInjectionContext(() => { - const config = { - categories: [ - { id: 'cat1', enabled: true }, - { id: 'cat2', enabled: true } - ], + const config: SearchConfiguration = { + categories: [{ id: 'cat1', enabled: true } as any, { id: 'cat2', enabled: true } as any], filterQueries: [{ query: 'query1' }, { query: 'query2' }] - } as SearchConfiguration; + }; const expectedResult = [{ query: 'PARENT:"workspace://SpacesStore/fake-node-id"' }]; @@ -140,13 +114,10 @@ describe('SearchHeaderQueryBuilderService', () => { TestBed.runInInjectionContext(() => { const expectedResult = [{ query: 'PARENT:"workspace://SpacesStore/fake-node-id"' }]; - const config = { - categories: [ - { id: 'cat1', enabled: true }, - { id: 'cat2', enabled: true } - ], + const config: SearchConfiguration = { + categories: [{ id: 'cat1', enabled: true } as any, { id: 'cat2', enabled: true } as any], filterQueries: expectedResult - } as SearchConfiguration; + }; const alfrescoApiService = TestBed.inject(AlfrescoApiService); const searchHeaderService = new SearchHeaderQueryBuilderService(buildConfig(config), alfrescoApiService, null); @@ -161,10 +132,10 @@ describe('SearchHeaderQueryBuilderService', () => { TestBed.runInInjectionContext(() => { const activeFilter = 'FakeColumn'; - const config = { - categories: [{ id: 'cat1', enabled: true }], + const config: SearchConfiguration = { + categories: [{ id: 'cat1', enabled: true } as any], filterQueries: [{ query: 'PARENT:"workspace://SpacesStore/fake-node-id' }] - } as SearchConfiguration; + }; const alfrescoApiService = TestBed.inject(AlfrescoApiService); const searchHeaderService = new SearchHeaderQueryBuilderService(buildConfig(config), alfrescoApiService, null); diff --git a/lib/content-services/src/lib/search/services/search-header-query-builder.service.ts b/lib/content-services/src/lib/search/services/search-header-query-builder.service.ts index 406345459d..60ef9f7603 100644 --- a/lib/content-services/src/lib/search/services/search-header-query-builder.service.ts +++ b/lib/content-services/src/lib/search/services/search-header-query-builder.service.ts @@ -36,11 +36,7 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService { activeFilters: FilterSearch[] = []; - constructor( - appConfig: AppConfigService, - alfrescoApiService: AlfrescoApiService, - private readonly nodeApiService: NodesApiService - ) { + constructor(appConfig: AppConfigService, alfrescoApiService: AlfrescoApiService, private nodeApiService: NodesApiService) { super(appConfig, alfrescoApiService); this.updated.pipe(filter((query) => !!query)).subscribe(() => { @@ -131,12 +127,6 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService { return foundCategory; } - getOperatorForFilterId(id: string): string | undefined { - const foundCategory = this.categories?.find((category) => category.id === id); - - return foundCategory?.component?.settings?.operator; - } - setCurrentRootFolderId(currentFolderId: string) { const alreadyAddedFilter = this.filterQueries.find((filterQueries) => filterQueries.query.includes(currentFolderId));