ACS-7461 Remove ADF_DOCUMENT_PARENT_COMPONENT token (#11372)

This commit is contained in:
Denys Vuika
2025-12-15 13:42:21 +00:00
committed by GitHub
parent 8da24884ec
commit 062b8060bc
7 changed files with 98 additions and 94 deletions
@@ -35,7 +35,11 @@
<adf-filter-header
[currentFolderId]="currentFolderId"
[value]="filterValue"
(filterSelection)="onFilterSelectionChange($event)" />
[pagination]="pagination | async"
[sorting]="sortingSubject | async"
(filterSelection)="onFilterSelectionChange($event)"
(searchResultsReady)="onFilterSearchResultsReady($event)"
(filtersCleared)="onFiltersCleared()" />
</div>
<adf-no-content-template>
@@ -77,7 +77,6 @@ import { PermissionStyleModel } from '../models/permissions-style.model';
import { presetsDefaultModel } from '../models/preset.model';
import { DocumentListService } from '../services/document-list.service';
import { LockService } from '../services/lock.service';
import { ADF_DOCUMENT_PARENT_COMPONENT } from './document-list.token';
import { FileAutoDownloadComponent } from './file-auto-download/file-auto-download.component';
import { NodeEntityEvent, NodeEntryEvent } from './node.event';
import { CommonModule } from '@angular/common';
@@ -108,13 +107,7 @@ const BYTES_TO_MB_CONVERSION_VALUE = 1048576;
],
templateUrl: './document-list.component.html',
styleUrls: ['./document-list.component.scss'],
providers: [
{
provide: ADF_DOCUMENT_PARENT_COMPONENT,
useExisting: DocumentListComponent
},
DataTableService
],
providers: [DataTableService],
encapsulation: ViewEncapsulation.None,
host: { class: 'adf-document-list' }
})
@@ -1048,6 +1041,16 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
this.filterSelection.emit(activeFilters);
}
onFilterSearchResultsReady(nodePaging: NodePaging) {
this.node = nodePaging;
this.reload();
}
onFiltersCleared() {
this.node = null;
this.reload();
}
resetNewFolderPagination() {
this._pagination.skipCount = 0;
this._pagination.maxItems = this.maxItems;
@@ -1,25 +0,0 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable rxjs/no-subject-value */
/* eslint-disable @typescript-eslint/naming-convention */
import { InjectionToken } from '@angular/core';
export const ADF_DOCUMENT_PARENT_COMPONENT = new InjectionToken(
'ADF_DOCUMENT_PARENT_COMPONENT'
);
@@ -1,9 +1,10 @@
<div *ngIf="isFilterServiceActive">
@if (isFilterServiceActive) {
<adf-header-filter-template>
<ng-template let-col>
<adf-search-filter-container [col]="col"
[value]="value"
(filterChange)="onFilterSelectionChange()" />
<adf-search-filter-container
[col]="col"
[value]="value"
(filterChange)="onFilterSelectionChange()" />
</ng-template>
</adf-header-filter-template>
</div>
}
@@ -15,17 +15,14 @@
* limitations under the License.
*/
import { Subject, BehaviorSubject } from 'rxjs';
import { Subject } from 'rxjs';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DataTableComponent, DataSorting } from '@alfresco/adf-core';
import { DataTableComponent, DataSorting, PaginationModel } from '@alfresco/adf-core';
import { SearchService } from '../../../search/services/search.service';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { SimpleChange } from '@angular/core';
import { SearchHeaderQueryBuilderService } from './../../../search/services/search-header-query-builder.service';
import { DocumentListComponent } from './../document-list.component';
import { FilterHeaderComponent } from './filter-header.component';
import { Pagination } from '@alfresco/js-api';
import { ADF_DOCUMENT_PARENT_COMPONENT } from '../document-list.token';
describe('FilterHeaderComponent', () => {
let fixture: ComponentFixture<FilterHeaderComponent>;
@@ -36,28 +33,16 @@ describe('FilterHeaderComponent', () => {
dataLoaded: new Subject()
};
const paginationMock = { maxItems: 10, skipCount: 0 };
const documentListMock = {
node: 'my-node',
sorting: ['name', 'asc'],
pagination: new BehaviorSubject<Pagination>(paginationMock),
sortingSubject: new BehaviorSubject<DataSorting[]>([]),
reload: () => jasmine.createSpy('reload')
};
const paginationMock: PaginationModel = { maxItems: 10, skipCount: 0, totalItems: 0, hasMoreItems: false };
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ContentTestingModule, FilterHeaderComponent],
providers: [
{ provide: ADF_DOCUMENT_PARENT_COMPONENT, useExisting: DocumentListComponent },
{ provide: SearchService, useValue: searchMock },
{ provide: DocumentListComponent, useValue: documentListMock },
DataTableComponent
]
providers: [{ provide: SearchService, useValue: searchMock }, DataTableComponent]
});
fixture = TestBed.createComponent(FilterHeaderComponent);
component = fixture.componentInstance;
component.currentFolderId = 'test-folder-id';
queryBuilder = fixture.componentInstance['searchFilterQueryBuilder'];
});
@@ -68,23 +53,26 @@ describe('FilterHeaderComponent', () => {
it('should subscribe to changes in document list pagination', async () => {
const setupCurrentPaginationSpy = spyOn(queryBuilder, 'setupCurrentPagination');
const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true);
component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange });
component.pagination = paginationMock;
const paginationChange = new SimpleChange(undefined, paginationMock, true);
component.ngOnChanges({ pagination: paginationChange });
fixture.detectChanges();
await fixture.whenStable();
expect(setupCurrentPaginationSpy).toHaveBeenCalled();
expect(setupCurrentPaginationSpy).toHaveBeenCalledWith(paginationMock.maxItems, paginationMock.skipCount);
});
it('should subscribe to changes in document list sorting', async () => {
const setSortingSpy = spyOn(queryBuilder, 'setSorting');
const sortingMock: DataSorting[] = [new DataSorting('name', 'asc')];
const currentFolderNodeIdChange = new SimpleChange('current-node-id', 'next-node-id', true);
component.ngOnChanges({ currentFolderId: currentFolderNodeIdChange });
component.sorting = sortingMock;
const sortingChange = new SimpleChange(undefined, sortingMock, true);
component.ngOnChanges({ sorting: sortingChange });
fixture.detectChanges();
await fixture.whenStable();
expect(setSortingSpy).toHaveBeenCalled();
expect(setSortingSpy).toHaveBeenCalledWith(sortingMock);
});
it('should reset filters after changing the folder node', async () => {
@@ -143,4 +131,29 @@ describe('FilterHeaderComponent', () => {
fixture.detectChanges();
fixture.whenStable();
});
it('should emit filtersCleared when no filters are active', (done) => {
spyOn(queryBuilder, 'getActiveFilters').and.returnValue([]);
spyOn(queryBuilder, 'isNoFilterActive').and.returnValue(true);
component.filtersCleared.subscribe(() => {
done();
});
component.onFilterSelectionChange();
fixture.detectChanges();
});
it('should emit searchResultsReady when search query builder executes', (done) => {
fixture.detectChanges(); // Initialize component (triggers ngOnInit)
const mockNodePaging: any = { list: { entries: [] } };
component.searchResultsReady.subscribe((nodePaging) => {
expect(nodePaging).toBe(mockNodePaging);
done();
});
queryBuilder.executed.next(mockNodePaging);
});
});
@@ -15,18 +15,17 @@
* limitations under the License.
*/
import { Component, DestroyRef, EventEmitter, Inject, inject, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { DataSorting, HeaderFilterTemplateDirective, PaginationModel } from '@alfresco/adf-core';
import { SearchHeaderQueryBuilderService } from '../../../search/services/search-header-query-builder.service';
import { FilterSearch } from './../../../search/models/filter-search.interface';
import { ADF_DOCUMENT_PARENT_COMPONENT } from '../document-list.token';
import { CommonModule } from '@angular/common';
import { SearchFilterContainerComponent } from '../../../search/components/search-filter-container/search-filter-container.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import type { NodePaging } from '@alfresco/js-api';
@Component({
selector: 'adf-filter-header',
imports: [CommonModule, HeaderFilterTemplateDirective, SearchFilterContainerComponent],
imports: [HeaderFilterTemplateDirective, SearchFilterContainerComponent],
templateUrl: './filter-header.component.html'
})
export class FilterHeaderComponent implements OnInit, OnChanges {
@@ -38,26 +37,37 @@ export class FilterHeaderComponent implements OnInit, OnChanges {
@Input({ required: true })
currentFolderId: string;
/** Pagination model from the document list */
@Input()
pagination: PaginationModel;
/** Sorting configuration from the document list */
@Input()
sorting: DataSorting[];
/** Emitted when a filter value is selected */
@Output()
filterSelection: EventEmitter<FilterSearch[]> = new EventEmitter();
/** Emitted when search results are ready */
@Output()
searchResultsReady: EventEmitter<NodePaging> = new EventEmitter();
/** Emitted when filters are cleared and document list should reload */
@Output()
filtersCleared: EventEmitter<void> = new EventEmitter();
isFilterServiceActive: boolean;
private readonly searchFilterQueryBuilder = inject(SearchHeaderQueryBuilderService);
private readonly destroyRef = inject(DestroyRef);
constructor(@Inject(ADF_DOCUMENT_PARENT_COMPONENT) private documentList: any, private searchFilterQueryBuilder: SearchHeaderQueryBuilderService) {
this.isFilterServiceActive = this.searchFilterQueryBuilder.isFilterServiceActive();
}
ngOnInit() {
this.searchFilterQueryBuilder.executed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((newNodePaging) => {
this.documentList.node = newNodePaging;
this.documentList.reload();
this.searchFilterQueryBuilder.executed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((resultSetPaging) => {
// ResultSetPaging is structurally compatible with NodePaging for the document list
// The data adapter can handle both types
this.searchResultsReady.emit(resultSetPaging as unknown as NodePaging);
});
this.initDataPagination();
this.initDataSorting();
}
ngOnChanges(changes: SimpleChanges) {
@@ -65,13 +75,22 @@ export class FilterHeaderComponent implements OnInit, OnChanges {
this.resetFilterHeader();
this.configureSearchParent(changes['currentFolderId'].currentValue);
}
if (changes['pagination']?.currentValue) {
const pagination = changes['pagination'].currentValue as PaginationModel;
this.searchFilterQueryBuilder.setupCurrentPagination(pagination.maxItems, pagination.skipCount);
}
if (changes['sorting']?.currentValue) {
const sorting = changes['sorting'].currentValue as DataSorting[];
this.searchFilterQueryBuilder.setSorting(sorting);
}
}
onFilterSelectionChange() {
this.filterSelection.emit(this.searchFilterQueryBuilder.getActiveFilters());
if (this.searchFilterQueryBuilder.isNoFilterActive()) {
this.documentList.node = null;
this.documentList.reload();
this.filtersCleared.emit();
}
}
@@ -79,18 +98,6 @@ export class FilterHeaderComponent implements OnInit, OnChanges {
this.searchFilterQueryBuilder.resetActiveFilters();
}
initDataPagination() {
this.documentList.pagination.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((newPagination: PaginationModel) => {
this.searchFilterQueryBuilder.setupCurrentPagination(newPagination.maxItems, newPagination.skipCount);
});
}
initDataSorting() {
this.documentList.sortingSubject.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((sorting: DataSorting[]) => {
this.searchFilterQueryBuilder.setSorting(sorting);
});
}
private configureSearchParent(currentFolderId: string) {
if (this.searchFilterQueryBuilder.isCustomSourceNode(currentFolderId)) {
this.searchFilterQueryBuilder.getNodeIdForCustomSource(currentFolderId).subscribe((node) => {