mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[ACA-3542] - added sorting for filters (#5932)
* [ACA-3542] - added sorting for filters * [ACA-3542] - removed wrong parameter * [ACA-3542] - fixed test with fixed sorting mode parameter * Update content-node-selector-panel.component.html * fix e2e * fix delete site Co-authored-by: Eugenio Romano <eromano@users.noreply.github.com> Co-authored-by: Eugenio Romano <eugenio.romano@alfresco.com>
This commit is contained in:
parent
bfbb66ea8e
commit
85183ead0d
@ -567,7 +567,7 @@
|
||||
"ascending": true
|
||||
},
|
||||
{
|
||||
"key": "createdByUser",
|
||||
"key": "createdByUser.displayName",
|
||||
"label": "Author",
|
||||
"type": "FIELD",
|
||||
"field": "cm:creator",
|
||||
|
@ -229,7 +229,7 @@
|
||||
[sortingMode]="sortingMode"
|
||||
[showHeader]="showHeader"
|
||||
[thumbnails]="thumbnails"
|
||||
[stickyHeader]="stickyHeader"
|
||||
[stickyHeader]="stickyHeader"
|
||||
(error)="onNavigationError($event)"
|
||||
(success)="resetError()"
|
||||
(ready)="emitReadyEvent($event)"
|
||||
@ -242,6 +242,7 @@
|
||||
<adf-search-header [col]="col"
|
||||
[value]="paramValues? paramValues[col.key] : null"
|
||||
[currentFolderNodeId]="currentFolderId"
|
||||
[sorting]="filterSorting"
|
||||
[maxItems]="pagination?.maxItems"
|
||||
[skipCount]="pagination?.skipCount"
|
||||
(update)="onFilterUpdate($event)"
|
||||
|
@ -88,7 +88,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
processId;
|
||||
|
||||
@Input()
|
||||
sorting = ['nodeType', 'DESC'];
|
||||
sorting = ['name', 'ASC'];
|
||||
|
||||
@Input()
|
||||
sortingMode = 'server';
|
||||
@ -163,7 +163,10 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
enableCustomHeaderFilter = false;
|
||||
|
||||
@Input()
|
||||
paramValues: Map <any, any> = null;
|
||||
paramValues: Map<any, any> = null;
|
||||
|
||||
@Input()
|
||||
filterSorting: string = null;
|
||||
|
||||
@Output()
|
||||
documentListReady: EventEmitter<any> = new EventEmitter();
|
||||
@ -208,7 +211,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
|
||||
enableMediumTimeFormat = false;
|
||||
displayEmptyMetadata = false;
|
||||
hyperlinkNavigation = false;
|
||||
filtersStates: any[] = [];
|
||||
filteredSorting: string[] = null;
|
||||
|
||||
constructor(private notificationService: NotificationService,
|
||||
private uploadService: UploadService,
|
||||
|
@ -4,6 +4,8 @@
|
||||
[showSettingsPanel]="false"
|
||||
[navigationRoute]="navigationRoute"
|
||||
[currentFolderId]="currentFolderId"
|
||||
[filterSorting]="filterSorting"
|
||||
[enableCustomHeaderFilter]="true"
|
||||
[paramValues]="queryParams">
|
||||
[paramValues]="queryParams"
|
||||
(sorting-changed)="onSortingChanged($event)">
|
||||
</app-files-component>
|
||||
|
@ -30,6 +30,7 @@ export class FilteredSearchComponent {
|
||||
currentFolderId = '-my-';
|
||||
|
||||
queryParams = null;
|
||||
filterSorting = null;
|
||||
|
||||
constructor(@Optional() private route: ActivatedRoute) {
|
||||
|
||||
@ -46,4 +47,8 @@ export class FilteredSearchComponent {
|
||||
}
|
||||
}
|
||||
|
||||
onSortingChanged(event) {
|
||||
this.filterSorting = event.detail.column + '-' + event.detail.direction;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ import { by, element, ElementFinder } from 'protractor';
|
||||
import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing';
|
||||
|
||||
export class FolderDialogPage {
|
||||
folderDialog = element(by.css('adf-folder-dialog'));
|
||||
|
||||
folderDialog = element.all(by.css('adf-folder-dialog')).first();
|
||||
folderNameField = this.folderDialog.element(by.id('adf-folder-name-input'));
|
||||
folderDescriptionField = this.folderDialog.element(by.id('adf-folder-description-input'));
|
||||
createUpdateButton = this.folderDialog.element(by.id('adf-folder-create-button'));
|
||||
|
@ -64,6 +64,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
await navigationBarPage.clickLogoutButton();
|
||||
});
|
||||
|
@ -76,6 +76,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
await navigationBarPage.clickLogoutButton();
|
||||
});
|
||||
|
@ -64,6 +64,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
});
|
||||
|
||||
|
@ -70,6 +70,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
});
|
||||
|
||||
|
@ -66,6 +66,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
});
|
||||
|
||||
|
@ -64,6 +64,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
});
|
||||
|
||||
|
@ -66,6 +66,7 @@ describe('Viewer', () => {
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await apiService.getInstance().login(browser.params.testConfig.admin.email, browser.params.testConfig.admin.password);
|
||||
await apiService.getInstance().core.sitesApi.deleteSite(site.entry.id, { permanent: true });
|
||||
await navigationBarPage.clickLogoutButton();
|
||||
});
|
||||
|
@ -14,6 +14,9 @@
|
||||
"paths": {
|
||||
"@alfresco/adf-testing": [
|
||||
"../lib/testing"
|
||||
],
|
||||
"@alfresco/adf-process-services-cloud": [
|
||||
"../lib/process-services-cloud"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -69,7 +69,7 @@
|
||||
[contextMenuActions]="false"
|
||||
[contentActions]="false"
|
||||
[allowDropFiles]="false"
|
||||
[sorting]="'server'"
|
||||
sortingMode="server"
|
||||
[where]="where"
|
||||
(folderChange)="onFolderChange($event)"
|
||||
(ready)="onFolderLoaded()"
|
||||
|
@ -131,7 +131,7 @@ describe('ContentNodeSelectorComponent', () => {
|
||||
});
|
||||
|
||||
it('should the document list use the server ordering', () => {
|
||||
expect(component.documentList.sorting).toBe('server');
|
||||
expect(component.documentList.sortingMode).toBe('server');
|
||||
});
|
||||
|
||||
it('should trigger the select event when selection has been made', (done) => {
|
||||
|
@ -13,7 +13,7 @@
|
||||
[noPermission]="noPermission"
|
||||
[showHeader]="showHeader"
|
||||
[rowMenuCacheEnabled]="false"
|
||||
[stickyHeader]="stickyHeader"
|
||||
[stickyHeader]="stickyHeader"
|
||||
[allowFiltering]="allowFiltering"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
|
@ -1451,7 +1451,7 @@ describe('DocumentList', () => {
|
||||
where: undefined,
|
||||
maxItems: 25,
|
||||
skipCount: 0,
|
||||
orderBy: [ 'name ASC' ],
|
||||
orderBy: ['nodeType DESC', 'name asc' ],
|
||||
rootFolderId: 'fake-id'
|
||||
}, ['test-include']);
|
||||
});
|
||||
@ -1467,14 +1467,14 @@ describe('DocumentList', () => {
|
||||
where: '(isFolder=true)',
|
||||
maxItems: 25,
|
||||
skipCount: 0,
|
||||
orderBy: [ 'name ASC' ],
|
||||
orderBy: ['nodeType DESC', 'name asc' ],
|
||||
rootFolderId: 'fake-id'
|
||||
}, ['test-include']);
|
||||
});
|
||||
|
||||
it('should add orderBy in the server request', () => {
|
||||
documentList.includeFields = ['test-include'];
|
||||
documentList.orderBy = ['size DESC'];
|
||||
documentList.sorting = ['size', 'DESC'];
|
||||
documentList.currentFolderId = 'fake-id';
|
||||
documentList.where = null;
|
||||
|
||||
@ -1484,7 +1484,7 @@ describe('DocumentList', () => {
|
||||
maxItems: 25,
|
||||
skipCount: 0,
|
||||
where: undefined,
|
||||
orderBy: ['size DESC'],
|
||||
orderBy: ['nodeType DESC', 'size DESC'],
|
||||
rootFolderId: 'fake-id'
|
||||
}, ['test-include']);
|
||||
});
|
||||
@ -1502,7 +1502,7 @@ describe('DocumentList', () => {
|
||||
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
|
||||
maxItems: 25,
|
||||
skipCount: 0,
|
||||
orderBy: [ 'name ASC' ],
|
||||
orderBy: ['nodeType DESC', 'name asc' ],
|
||||
rootFolderId: 'folder-id',
|
||||
where: undefined
|
||||
}, undefined);
|
||||
|
@ -183,7 +183,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
* override the default sorting detected by the component based on columns.
|
||||
*/
|
||||
@Input()
|
||||
sorting = ['nodeType', 'DESC'];
|
||||
sorting = ['name', 'asc'];
|
||||
|
||||
/** Defines default sorting. The format is an array of strings `[key direction, otherKey otherDirection]`
|
||||
* i.e. `['name desc', 'nodeType asc']` or `['name asc']`. Set this value if you want a base
|
||||
* rule to be added to the sorting apart from the one driven by the header.
|
||||
*/
|
||||
@Input()
|
||||
additionalSorting = ['nodeType DESC'];
|
||||
|
||||
/** Defines sorting mode. Can be either `client` (items in the list
|
||||
* are sorted client-side) or `server` (the ordering supplied by the
|
||||
@ -255,6 +262,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
set currentFolderId(currentFolderId: string) {
|
||||
if (this._currentFolderId !== currentFolderId) {
|
||||
this._currentFolderId = currentFolderId;
|
||||
if (this.sorting) {
|
||||
const [key, direction] = this.sorting;
|
||||
this.orderBy = this.buildOrderByArray(key, direction);
|
||||
}
|
||||
if (this.data) {
|
||||
this.data.loadPage(null, false);
|
||||
this.resetNewFolderPagination();
|
||||
@ -456,10 +467,16 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.resetSelection();
|
||||
|
||||
if (changes.sorting && changes.sorting.currentValue) {
|
||||
const [key, direction] = changes.sorting.currentValue;
|
||||
this.orderBy = this.buildOrderByArray(key, direction);
|
||||
}
|
||||
|
||||
if (this.data) {
|
||||
this.data.thumbnails = this.thumbnails;
|
||||
|
||||
}
|
||||
|
||||
if (changes.sortingMode && !changes.sortingMode.firstChange && this.data) {
|
||||
this.data.sortingMode = changes.sortingMode.currentValue;
|
||||
}
|
||||
@ -475,7 +492,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
if (this.data) {
|
||||
if (changes.node && changes.node.currentValue) {
|
||||
const merge = this._pagination ? this._pagination.merge : false;
|
||||
|
||||
this.data.loadPage(changes.node.currentValue, merge);
|
||||
this.onDataReady(changes.node.currentValue);
|
||||
} else if (changes.imageResolver) {
|
||||
@ -646,6 +662,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
loadFolder() {
|
||||
|
||||
if (!this._pagination.merge) {
|
||||
this.setLoadingState(true);
|
||||
}
|
||||
@ -685,13 +702,16 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
||||
}
|
||||
|
||||
onSortingChanged(event: CustomEvent) {
|
||||
const flattenExtraSortingOption = this.sorting.join(' ');
|
||||
const orderArray = [flattenExtraSortingOption];
|
||||
orderArray.push(''.concat(event.detail.key, ' ', event.detail.direction));
|
||||
this.orderBy = orderArray;
|
||||
this.orderBy = this.buildOrderByArray(event.detail.key, event.detail.direction);
|
||||
this.reload();
|
||||
}
|
||||
|
||||
private buildOrderByArray(currentKey: string, currentDirection: string ): string[] {
|
||||
const orderArray = [...this.additionalSorting];
|
||||
orderArray.push(''.concat(currentKey, ' ', currentDirection));
|
||||
return orderArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of predefined columns.
|
||||
*/
|
||||
|
@ -51,6 +51,7 @@ export abstract class BaseQueryBuilderService {
|
||||
filterQueries: FilterQuery[] = [];
|
||||
paging: { maxItems?: number; skipCount?: number } = null;
|
||||
sorting: Array<SearchSortingDefinition> = [];
|
||||
sortingOptions: Array<SearchSortingDefinition> = [];
|
||||
|
||||
protected userFacetBuckets: { [key: string]: Array<FacetFieldBucket> } = {};
|
||||
|
||||
@ -93,6 +94,7 @@ export abstract class BaseQueryBuilderService {
|
||||
this.userFacetBuckets = {};
|
||||
if (this.config.sorting) {
|
||||
this.sorting = this.config.sorting.defaults || [];
|
||||
this.sortingOptions = this.config.sorting.options || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,20 @@ describe('SearchHeaderComponent', () => {
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should execute a new query when a new sorting is requested', async (done) => {
|
||||
spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(Promise.resolve(fakeNodePaging));
|
||||
spyOn(queryBuilder, 'buildQuery').and.returnValue({});
|
||||
component.update.subscribe((newNodePaging) => {
|
||||
expect(newNodePaging).toBe(fakeNodePaging);
|
||||
done();
|
||||
});
|
||||
|
||||
const skipCount = new SimpleChange(null, '123-asc', false);
|
||||
component.ngOnChanges({ 'sorting': skipCount });
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should emit the clear event when no filter has been selected', async (done) => {
|
||||
spyOn(queryBuilder, 'isNoFilterActive').and.returnValue(true);
|
||||
spyOn(alfrescoApiService.searchApi, 'search').and.returnValue(Promise.resolve(fakeNodePaging));
|
||||
|
@ -67,6 +67,9 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
skipCount: number;
|
||||
|
||||
@Input()
|
||||
sorting: string = null;
|
||||
|
||||
/** Emitted when the result of the filter is received from the API. */
|
||||
@Output()
|
||||
update: EventEmitter<NodePaging> = new EventEmitter();
|
||||
@ -136,6 +139,14 @@ export class SearchHeaderComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
this.searchHeaderQueryBuilder.setupCurrentPagination(actualMaxItems, actualSkipCount);
|
||||
}
|
||||
|
||||
if (changes['sorting'] && changes['sorting'].currentValue) {
|
||||
const [key, value] = changes['sorting'].currentValue.split('-');
|
||||
if (key === this.col.key) {
|
||||
this.searchHeaderQueryBuilder.setSorting(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -23,6 +23,7 @@ import { SearchCategory } from './search-category.interface';
|
||||
import { MinimalNode, QueryBody } from '@alfresco/js-api';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SearchSortingDefinition } from './search-sorting-definition.interface';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -77,6 +78,22 @@ export class SearchHeaderQueryBuilderService extends BaseQueryBuilderService {
|
||||
}
|
||||
}
|
||||
|
||||
setSorting(column: string, direction: string) {
|
||||
const optionAscending = direction.toLocaleLowerCase() === 'asc' ? true : false;
|
||||
const fieldValue = this.getSortingFieldFromColumnName(column);
|
||||
const currentSort: SearchSortingDefinition = { key: column, label: 'current', type: 'FIELD', field: fieldValue, ascending: optionAscending};
|
||||
this.sorting = [currentSort];
|
||||
this.execute();
|
||||
}
|
||||
|
||||
private getSortingFieldFromColumnName(columnName: string) {
|
||||
if (this.sortingOptions.length > 0) {
|
||||
const sortOption: SearchSortingDefinition = this.sortingOptions.find((option: SearchSortingDefinition) => option.key === columnName);
|
||||
return sortOption.field;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
getCategoryForColumn(columnKey: string): SearchCategory {
|
||||
let foundCategory = null;
|
||||
if (this.categories !== null) {
|
||||
|
@ -543,11 +543,11 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
|
||||
const current = this.data.getSorting();
|
||||
let newDirection = 'asc';
|
||||
if (current && column.key === current.key) {
|
||||
newDirection = current.direction === 'asc' ? 'desc' : 'asc';
|
||||
newDirection = current.direction?.toLowerCase() === 'asc' ? 'desc' : 'asc';
|
||||
}
|
||||
this.sorting = [column.key, newDirection];
|
||||
this.data.setSorting(new DataSorting(column.key, newDirection));
|
||||
this.emitSortingChangedEvent(column.sortingKey, newDirection);
|
||||
this.emitSortingChangedEvent(column.key, column.sortingKey, newDirection);
|
||||
}
|
||||
|
||||
this.keyManager.updateActiveItem(0);
|
||||
@ -639,7 +639,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
|
||||
isColumnSorted(col: DataColumn, direction: string): boolean {
|
||||
if (col && direction) {
|
||||
const sorting = this.data.getSorting();
|
||||
return sorting && sorting.key === col.key && sorting.direction === direction;
|
||||
return sorting && sorting.key === col.key && sorting.direction.toLocaleLowerCase() === direction;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -771,9 +771,10 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
|
||||
this.elementRef.nativeElement.dispatchEvent(domEvent);
|
||||
}
|
||||
|
||||
private emitSortingChangedEvent(key: string, direction: string) {
|
||||
private emitSortingChangedEvent(column: string, key: string, direction: string) {
|
||||
const domEvent = new CustomEvent('sorting-changed', {
|
||||
detail: {
|
||||
column,
|
||||
key,
|
||||
direction
|
||||
},
|
||||
|
@ -51,7 +51,7 @@ export class TaskFiltersCloudComponentPage {
|
||||
}
|
||||
|
||||
getTaskFilterLocatorByFilterName(filterName: string): ElementFinder {
|
||||
return element(by.css(`button[data-automation-id="${filterName}_filter"]`));
|
||||
return element.all(by.css(`button[data-automation-id="${filterName}_filter"]`)).first();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user