mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[MNT-25681] Content node selector panel filtering fixed (#12032)
* [MNT-25681] Content node selector panel filtering fixed * [MNT-25681] Small cleanup * [MNT-25681] CR fix
This commit is contained in:
@@ -206,5 +206,9 @@ describe('ContentNodeDialogService', () => {
|
|||||||
expect(testContentNodeSelectorComponentData.isSelectionValid(testData.node)).toBe(testData.expected);
|
expect(testContentNodeSelectorComponentData.isSelectionValid(testData.node)).toBe(testData.expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should scope the search to folders by disabling files in the result', () => {
|
||||||
|
expect(testContentNodeSelectorComponentData.showFilesInResult).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ export class ContentNodeDialogService {
|
|||||||
where: '(isFolder=true)',
|
where: '(isFolder=true)',
|
||||||
isSelectionValid: this.isCopyMoveSelectionValid.bind(this),
|
isSelectionValid: this.isCopyMoveSelectionValid.bind(this),
|
||||||
excludeSiteContent: excludeSiteContent || ContentNodeDialogService.nonDocumentSiteContent,
|
excludeSiteContent: excludeSiteContent || ContentNodeDialogService.nonDocumentSiteContent,
|
||||||
select
|
select,
|
||||||
|
showFilesInResult: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const dialogRef = this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px');
|
const dialogRef = this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px');
|
||||||
@@ -196,7 +197,8 @@ export class ContentNodeDialogService {
|
|||||||
imageResolver: this.imageResolver.bind(this),
|
imageResolver: this.imageResolver.bind(this),
|
||||||
isSelectionValid: this.hasAllowableOperationsOnNodeFolder.bind(this),
|
isSelectionValid: this.hasAllowableOperationsOnNodeFolder.bind(this),
|
||||||
where: '(isFolder=true)',
|
where: '(isFolder=true)',
|
||||||
select
|
select,
|
||||||
|
showFilesInResult: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const dialogRef = this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px');
|
const dialogRef = this.openContentNodeDialog(data, 'adf-content-node-selector-dialog', '630px');
|
||||||
|
|||||||
+51
-1
@@ -19,7 +19,7 @@ import { DebugElement } from '@angular/core';
|
|||||||
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Node, NodeEntry, NodePaging, RequestScope, ResultSetPaging, SiteEntry, SitePaging, SitePagingList } from '@alfresco/js-api';
|
import { Node, NodeEntry, NodePaging, RequestScope, ResultSetPaging, SiteEntry, SitePaging, SitePagingList } from '@alfresco/js-api';
|
||||||
import { of } from 'rxjs';
|
import { of, Subject } from 'rxjs';
|
||||||
import { ContentNodeSelectorPanelComponent } from './content-node-selector-panel.component';
|
import { ContentNodeSelectorPanelComponent } from './content-node-selector-panel.component';
|
||||||
import { DocumentListService } from '../../document-list/services/document-list.service';
|
import { DocumentListService } from '../../document-list/services/document-list.service';
|
||||||
import { DocumentListComponent } from '../../document-list/components/document-list.component';
|
import { DocumentListComponent } from '../../document-list/components/document-list.component';
|
||||||
@@ -294,6 +294,32 @@ describe('ContentNodeSelectorPanelComponent', () => {
|
|||||||
expect(searchQueryBuilderService.addFilterQuery).toHaveBeenCalledWith(expectedRequest);
|
expect(searchQueryBuilderService.addFilterQuery).toHaveBeenCalledWith(expectedRequest);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should remove the previous site filter query when changing the selected site', fakeAsync(() => {
|
||||||
|
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
||||||
|
spyOn(searchQueryBuilderService, 'removeFilterQuery').and.callThrough();
|
||||||
|
typeToSearchBox('search-term');
|
||||||
|
tick(debounceSearch);
|
||||||
|
|
||||||
|
component.siteChanged({ entry: { guid: 'namek' } } as SiteEntry);
|
||||||
|
component.siteChanged({ entry: { guid: 'vegeta' } } as SiteEntry);
|
||||||
|
|
||||||
|
expect(searchQueryBuilderService.removeFilterQuery).toHaveBeenCalledWith(`ANCESTOR:'workspace://SpacesStore/namek'`);
|
||||||
|
expect(searchQueryBuilderService.addFilterQuery).toHaveBeenCalledWith(`ANCESTOR:'workspace://SpacesStore/vegeta'`);
|
||||||
|
expect(searchQueryBuilderService.filterQueries).toEqual([{ query: `ANCESTOR:'workspace://SpacesStore/vegeta'` }]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should browse the selected site folder without searching when no search term is present', fakeAsync(() => {
|
||||||
|
expect(searchSpy.calls.count()).toBe(0);
|
||||||
|
|
||||||
|
component.siteChanged({ entry: { guid: 'namek' } } as SiteEntry);
|
||||||
|
tick(debounceSearch);
|
||||||
|
|
||||||
|
expect(searchSpy).not.toHaveBeenCalled();
|
||||||
|
expect(component.searchTerm).toBe('');
|
||||||
|
expect(component.folderIdToShow).toBe('namek');
|
||||||
|
expect(component.showingSearchResults).toBe(false);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should create the query with the right parameters on changing the site selectBox value from a custom dropdown menu', fakeAsync(() => {
|
it('should create the query with the right parameters on changing the site selectBox value from a custom dropdown menu', fakeAsync(() => {
|
||||||
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
||||||
component.dropdownSiteList = { list: { entries: [{ entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } } as SitePaging;
|
component.dropdownSiteList = { list: { entries: [{ entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } } as SitePaging;
|
||||||
@@ -343,6 +369,29 @@ describe('ContentNodeSelectorPanelComponent', () => {
|
|||||||
expect(getCorrespondingNodeIdsSpy.calls.mostRecent().args[0]).toEqual('-sites-');
|
expect(getCorrespondingNodeIdsSpy.calls.mostRecent().args[0]).toEqual('-sites-');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should execute the search only after the corresponding node ids filter query is applied for aliases', fakeAsync(() => {
|
||||||
|
component.documentList.folderNode = { id: 'fakeNodeId', isFolder: true, path: {} } as Node;
|
||||||
|
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
||||||
|
const nodeIds$ = new Subject<string[]>();
|
||||||
|
getCorrespondingNodeIdsSpy.and.returnValue(nodeIds$.asObservable());
|
||||||
|
|
||||||
|
typeToSearchBox('vegeta');
|
||||||
|
tick(debounceSearch);
|
||||||
|
|
||||||
|
searchSpy.calls.reset();
|
||||||
|
|
||||||
|
component.siteChanged({ entry: { guid: '-sites-' } } as SiteEntry);
|
||||||
|
|
||||||
|
expect(searchSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
nodeIds$.next(['123456testId']);
|
||||||
|
nodeIds$.complete();
|
||||||
|
|
||||||
|
const expectedRequest = `ANCESTOR:'workspace://SpacesStore/-sites-' OR ANCESTOR:'workspace://SpacesStore/123456testId'`;
|
||||||
|
expect(searchQueryBuilderService.addFilterQuery).toHaveBeenCalledWith(expectedRequest);
|
||||||
|
expect(searchSpy).toHaveBeenCalledWith(false);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should NOT get the corresponding node ids on search when NOTHING is selected from dropdown', fakeAsync(() => {
|
it('should NOT get the corresponding node ids on search when NOTHING is selected from dropdown', fakeAsync(() => {
|
||||||
component.dropdownSiteList = { list: { entries: [{ entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } } as SitePaging;
|
component.dropdownSiteList = { list: { entries: [{ entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } } as SitePaging;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -508,6 +557,7 @@ describe('ContentNodeSelectorPanelComponent', () => {
|
|||||||
|
|
||||||
it('should the query restrict the search to the site and not to the currentFolderId in case is changed', async () => {
|
it('should the query restrict the search to the site and not to the currentFolderId in case is changed', async () => {
|
||||||
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
spyOn(searchQueryBuilderService, 'addFilterQuery').and.callThrough();
|
||||||
|
component.searchTerm = 'search-term';
|
||||||
searchQueryBuilderService.userQuery = 'search-term*';
|
searchQueryBuilderService.userQuery = 'search-term*';
|
||||||
component.currentFolderId = 'my-root-id';
|
component.currentFolderId = 'my-root-id';
|
||||||
component.restrictRootToCurrentFolderId = true;
|
component.restrictRootToCurrentFolderId = true;
|
||||||
|
|||||||
+39
-21
@@ -40,7 +40,8 @@ import { ImageResolver } from '../../document-list/data/image-resolver.model';
|
|||||||
import { CustomResourcesService } from '../../document-list/services/custom-resources.service';
|
import { CustomResourcesService } from '../../document-list/services/custom-resources.service';
|
||||||
import { ShareDataRow } from '../../document-list/data/share-data-row.model';
|
import { ShareDataRow } from '../../document-list/data/share-data-row.model';
|
||||||
import { NodeEntryEvent } from '../../document-list/components/node.event';
|
import { NodeEntryEvent } from '../../document-list/components/node.event';
|
||||||
import { debounceTime } from 'rxjs/operators';
|
import { debounceTime, map } from 'rxjs/operators';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
import { ContentNodeSelectorPanelService } from './content-node-selector-panel.service';
|
import { ContentNodeSelectorPanelService } from './content-node-selector-panel.service';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
@@ -110,6 +111,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
private showSearchField = true;
|
private showSearchField = true;
|
||||||
private showCounter = false;
|
private showCounter = false;
|
||||||
private _emptyList = true;
|
private _emptyList = true;
|
||||||
|
private lastParentFilterQuery: string | null = null;
|
||||||
|
|
||||||
/** If true will restrict the search and breadcrumbs to the currentFolderId */
|
/** If true will restrict the search and breadcrumbs to the currentFolderId */
|
||||||
@Input()
|
@Input()
|
||||||
@@ -440,7 +442,12 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
this.siteId = chosenSite.entry.guid;
|
this.siteId = chosenSite.entry.guid;
|
||||||
this.setTitleIfCustomSite(chosenSite);
|
this.setTitleIfCustomSite(chosenSite);
|
||||||
this.siteChange.emit(chosenSite.entry.title);
|
this.siteChange.emit(chosenSite.entry.title);
|
||||||
this.executeSearch(this.searchTerm);
|
if (this.searchTerm) {
|
||||||
|
this.executeSearch(this.searchTerm);
|
||||||
|
} else {
|
||||||
|
this.resetFolderToShow();
|
||||||
|
this.clearSearch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -467,7 +474,6 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
this.folderIdToShow = null;
|
this.folderIdToShow = null;
|
||||||
this.preselectedNodes = [];
|
this.preselectedNodes = [];
|
||||||
this.loadingSearchResults = true;
|
this.loadingSearchResults = true;
|
||||||
this.addCorrespondingNodeIdsQuery();
|
|
||||||
this.resetChosenNode();
|
this.resetChosenNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,25 +505,35 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
this.showingSearch.emit(this.showingSearchResults);
|
this.showingSearch.emit(this.showingSearchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addCorrespondingNodeIdsQuery() {
|
private addCorrespondingNodeIdsQuery(): Observable<void> {
|
||||||
let extraParentFiltering = '';
|
|
||||||
|
|
||||||
if (this.customResourcesService.hasCorrespondingNodeIds(this.siteId)) {
|
if (this.customResourcesService.hasCorrespondingNodeIds(this.siteId)) {
|
||||||
this.customResourcesService.getCorrespondingNodeIds(this.siteId).subscribe((nodeIds) => {
|
return this.customResourcesService.getCorrespondingNodeIds(this.siteId).pipe(
|
||||||
if (nodeIds?.length) {
|
map((nodeIds) => {
|
||||||
nodeIds
|
let extraParentFiltering = '';
|
||||||
.filter((id) => id !== this.siteId)
|
if (nodeIds?.length) {
|
||||||
.forEach((extraId) => {
|
nodeIds
|
||||||
extraParentFiltering += ` OR ANCESTOR:'workspace://SpacesStore/${extraId}'`;
|
.filter((id) => id !== this.siteId)
|
||||||
});
|
.forEach((extraId) => {
|
||||||
}
|
extraParentFiltering += ` OR ANCESTOR:'workspace://SpacesStore/${extraId}'`;
|
||||||
const parentFiltering = this.siteId ? `ANCESTOR:'workspace://SpacesStore/${this.siteId}'${extraParentFiltering}` : '';
|
});
|
||||||
this.queryBuilderService.addFilterQuery(parentFiltering);
|
}
|
||||||
});
|
const parentFiltering = this.siteId ? `ANCESTOR:'workspace://SpacesStore/${this.siteId}'${extraParentFiltering}` : '';
|
||||||
} else {
|
this.setParentFilterQuery(parentFiltering);
|
||||||
const parentFiltering = this.siteId ? `ANCESTOR:'workspace://SpacesStore/${this.siteId}'` : '';
|
})
|
||||||
this.queryBuilderService.addFilterQuery(parentFiltering);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const siteFilter = this.siteId ? `ANCESTOR:'workspace://SpacesStore/${this.siteId}'` : '';
|
||||||
|
this.setParentFilterQuery(siteFilter);
|
||||||
|
return of(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setParentFilterQuery(parentFiltering: string) {
|
||||||
|
if (this.lastParentFilterQuery) {
|
||||||
|
this.queryBuilderService.removeFilterQuery(this.lastParentFilterQuery);
|
||||||
|
}
|
||||||
|
this.lastParentFilterQuery = parentFiltering || null;
|
||||||
|
this.queryBuilderService.addFilterQuery(parentFiltering);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setSearchScopeToNodes() {
|
private setSearchScopeToNodes() {
|
||||||
@@ -685,6 +701,8 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
this.queryBuilderService.searchMode = 'formula';
|
this.queryBuilderService.searchMode = 'formula';
|
||||||
const wildcardSuffix = this.queryBuilderService.wildcardsEnabled ? '*' : '';
|
const wildcardSuffix = this.queryBuilderService.wildcardsEnabled ? '*' : '';
|
||||||
this.queryBuilderService.userQuery = searchValue.length > 0 ? `(${searchValue}${wildcardSuffix})` : searchValue;
|
this.queryBuilderService.userQuery = searchValue.length > 0 ? `(${searchValue}${wildcardSuffix})` : searchValue;
|
||||||
this.queryBuilderService.execute(false);
|
this.addCorrespondingNodeIdsQuery()
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe(() => this.queryBuilderService.execute(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,12 @@ export class InfiniteSelectScrollDirective implements AfterViewInit {
|
|||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.matSelect.openedChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((opened: boolean) => {
|
this.matSelect.openedChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((opened: boolean) => {
|
||||||
if (opened) {
|
if (opened) {
|
||||||
this.itemHeightToWaitBeforeLoadNext = this.getItemHeight() * (InfiniteSelectScrollDirective.MAX_ITEMS / 2);
|
setTimeout(() => {
|
||||||
this.matSelect.panel.nativeElement.addEventListener('scroll', (event: Event) => this.handleScrollEvent(event));
|
if (this.matSelect.panel?.nativeElement) {
|
||||||
|
this.itemHeightToWaitBeforeLoadNext = this.getItemHeight() * (InfiniteSelectScrollDirective.MAX_ITEMS / 2);
|
||||||
|
this.matSelect.panel.nativeElement.addEventListener('scroll', (event: Event) => this.handleScrollEvent(event));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -56,6 +60,7 @@ export class InfiniteSelectScrollDirective implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getItemHeight(): number {
|
private getItemHeight(): number {
|
||||||
return parseFloat(getComputedStyle(this.matSelect.panel.nativeElement).fontSize || '0') * SELECT_ITEM_HEIGHT_EM;
|
const panelElement = this.matSelect.panel?.nativeElement;
|
||||||
|
return panelElement ? parseFloat(getComputedStyle(panelElement).fontSize || '0') * SELECT_ITEM_HEIGHT_EM : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user