mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-16 18:12:50 +00:00
[MNT-25883] Fix: don't persist sorting key until document list load succeeds (#5389)
This commit is contained in:
@@ -22,7 +22,7 @@
|
|||||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DocumentListDirective } from './document-list.directive';
|
import { DocumentListDirective, SortingChangedEventDetail } from './document-list.directive';
|
||||||
import { BehaviorSubject, Subject } from 'rxjs';
|
import { BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { SetSelectedNodesAction } from '@alfresco/aca-shared/store';
|
import { SetSelectedNodesAction } from '@alfresco/aca-shared/store';
|
||||||
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
@@ -33,6 +33,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { ElementRef } from '@angular/core';
|
import { ElementRef } from '@angular/core';
|
||||||
import { AppHookService } from '@alfresco/aca-shared';
|
import { AppHookService } from '@alfresco/aca-shared';
|
||||||
import { NodeEntry } from '@alfresco/js-api';
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
describe('DocumentListDirective', () => {
|
describe('DocumentListDirective', () => {
|
||||||
let documentListDirective: DocumentListDirective;
|
let documentListDirective: DocumentListDirective;
|
||||||
@@ -52,6 +53,7 @@ describe('DocumentListDirective', () => {
|
|||||||
reload: jasmine.createSpy('reload'),
|
reload: jasmine.createSpy('reload'),
|
||||||
resetSelection: jasmine.createSpy('resetSelection'),
|
resetSelection: jasmine.createSpy('resetSelection'),
|
||||||
ready: new Subject<any>(),
|
ready: new Subject<any>(),
|
||||||
|
error: new Subject<HttpErrorResponse>(),
|
||||||
setColumnsWidths: {},
|
setColumnsWidths: {},
|
||||||
setColumnsVisibility: {},
|
setColumnsVisibility: {},
|
||||||
setColumnsOrder: {}
|
setColumnsOrder: {}
|
||||||
@@ -95,6 +97,10 @@ describe('DocumentListDirective', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
userPreferencesServiceMock.set = jasmine.createSpy('set');
|
||||||
|
userPreferencesServiceMock.get = jasmine.createSpy('get');
|
||||||
|
userPreferencesServiceMock.hasItem = jasmine.createSpy('hasItem');
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [DocumentListDirective],
|
imports: [DocumentListDirective],
|
||||||
providers: [
|
providers: [
|
||||||
@@ -117,6 +123,7 @@ describe('DocumentListDirective', () => {
|
|||||||
nodeToSelect$.next(null);
|
nodeToSelect$.next(null);
|
||||||
documentListMock.preselectNodes = [];
|
documentListMock.preselectNodes = [];
|
||||||
documentListMock.selection = [];
|
documentListMock.selection = [];
|
||||||
|
documentListMock.sortingMode = undefined;
|
||||||
elementRefMock.nativeElement.querySelector.calls.reset();
|
elementRefMock.nativeElement.querySelector.calls.reset();
|
||||||
mockSelectedElement.focus.calls.reset();
|
mockSelectedElement.focus.calls.reset();
|
||||||
});
|
});
|
||||||
@@ -270,6 +277,84 @@ describe('DocumentListDirective', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('onSortingChanged - persisting sorting', () => {
|
||||||
|
const sortingChangedEvent = (detail: SortingChangedEventDetail): CustomEvent<SortingChangedEventDetail> =>
|
||||||
|
new CustomEvent<SortingChangedEventDetail>('sorting-changed', { detail });
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockRoute.snapshot.data.sortingPreferenceKey = preferenceKey;
|
||||||
|
documentListDirective.ngOnInit();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should persist sorting immediately when sortingMode is `client`', () => {
|
||||||
|
documentListMock.sortingMode = 'client';
|
||||||
|
documentListDirective.onSortingChanged(sortingChangedEvent({ key: 'name', sortingKey: 'name', direction: 'asc' }));
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, 'name');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.sortingKey`, 'name');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.direction`, 'asc');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT persist sorting immediately when sortingMode is `server` (deferred until success)', () => {
|
||||||
|
documentListMock.sortingMode = 'server';
|
||||||
|
documentListDirective.onSortingChanged(
|
||||||
|
sortingChangedEvent({ key: 'properties.custom:prop', sortingKey: 'properties.custom:prop', direction: 'asc' })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).not.toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, jasmine.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should persist deferred `server` sorting once the document list emits `ready` (successful load)', () => {
|
||||||
|
documentListMock.sortingMode = 'server';
|
||||||
|
documentListDirective.onSortingChanged(
|
||||||
|
sortingChangedEvent({ key: 'properties.custom:prop', sortingKey: 'properties.custom:prop', direction: 'asc' })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).not.toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, jasmine.anything());
|
||||||
|
|
||||||
|
documentListMock.ready.next({});
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, 'properties.custom:prop');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.sortingKey`, 'properties.custom:prop');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.direction`, 'asc');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should discard deferred `server` sorting and never persist it when the document list emits `error`', () => {
|
||||||
|
documentListMock.sortingMode = 'server';
|
||||||
|
|
||||||
|
documentListDirective.onSortingChanged(
|
||||||
|
sortingChangedEvent({ key: 'properties.custom:unsortable', sortingKey: 'properties.custom:unsortable', direction: 'asc' })
|
||||||
|
);
|
||||||
|
|
||||||
|
documentListMock.error.next(new HttpErrorResponse({ status: 400 }));
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).not.toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, jasmine.anything());
|
||||||
|
|
||||||
|
userPreferencesServiceMock.set.calls.reset();
|
||||||
|
documentListMock.ready.next({});
|
||||||
|
expect(userPreferencesServiceMock.set).not.toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, jasmine.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should persist a subsequent valid sort even if the previous sort attempt failed', () => {
|
||||||
|
documentListMock.sortingMode = 'server';
|
||||||
|
|
||||||
|
documentListDirective.onSortingChanged(
|
||||||
|
sortingChangedEvent({ key: 'properties.custom:unsortable', sortingKey: 'properties.custom:unsortable', direction: 'asc' })
|
||||||
|
);
|
||||||
|
documentListMock.error.next(new HttpErrorResponse({ status: 400 }));
|
||||||
|
userPreferencesServiceMock.set.calls.reset();
|
||||||
|
|
||||||
|
documentListDirective.onSortingChanged(sortingChangedEvent({ key: 'name', sortingKey: 'name', direction: 'asc' }));
|
||||||
|
expect(userPreferencesServiceMock.set).not.toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, jasmine.anything());
|
||||||
|
|
||||||
|
documentListMock.ready.next({});
|
||||||
|
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.key`, 'name');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.sortingKey`, 'name');
|
||||||
|
expect(userPreferencesServiceMock.set).toHaveBeenCalledWith(`${preferenceKey}.sorting.direction`, 'asc');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('onReady', () => {
|
describe('onReady', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockRoute.snapshot.data.sortingPreferenceKey = preferenceKey;
|
mockRoute.snapshot.data.sortingPreferenceKey = preferenceKey;
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ import { AppHookService } from '@alfresco/aca-shared';
|
|||||||
const INCLUDE_FIELDS = ['isFavorite', 'aspectNames', 'definition', 'isLink'];
|
const INCLUDE_FIELDS = ['isFavorite', 'aspectNames', 'definition', 'isLink'];
|
||||||
const SEARCH_INCLUDE_FIELDS = ['aspectNames', 'isLink'];
|
const SEARCH_INCLUDE_FIELDS = ['aspectNames', 'isLink'];
|
||||||
|
|
||||||
|
export interface SortingChangedEventDetail {
|
||||||
|
key: string;
|
||||||
|
sortingKey: string;
|
||||||
|
direction: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
selector: '[acaDocumentList]'
|
selector: '[acaDocumentList]'
|
||||||
@@ -52,6 +58,7 @@ export class DocumentListDirective implements OnInit {
|
|||||||
|
|
||||||
private isLibrary = false;
|
private isLibrary = false;
|
||||||
private pendingNode: NodeEntry | null = null;
|
private pendingNode: NodeEntry | null = null;
|
||||||
|
private pendingSorting: SortingChangedEventDetail | null = null;
|
||||||
|
|
||||||
selectedNode: NodeEntry;
|
selectedNode: NodeEntry;
|
||||||
|
|
||||||
@@ -104,6 +111,10 @@ export class DocumentListDirective implements OnInit {
|
|||||||
)
|
)
|
||||||
.subscribe(() => this.onReady());
|
.subscribe(() => this.onReady());
|
||||||
|
|
||||||
|
this.documentList.error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||||
|
this.pendingSorting = null;
|
||||||
|
});
|
||||||
|
|
||||||
this.documentListService.reload$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
this.documentListService.reload$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||||
this.reload();
|
this.reload();
|
||||||
});
|
});
|
||||||
@@ -124,14 +135,14 @@ export class DocumentListDirective implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('sorting-changed', ['$event'])
|
@HostListener('sorting-changed', ['$event'])
|
||||||
onSortingChanged(event: CustomEvent) {
|
onSortingChanged(event: CustomEvent<SortingChangedEventDetail>) {
|
||||||
if (this.sortingPreferenceKey) {
|
if (this.sortingPreferenceKey) {
|
||||||
if (this.documentList.sortingMode === 'client') {
|
if (this.documentList.sortingMode === 'client') {
|
||||||
this.storePreviousSorting();
|
this.storePreviousSorting();
|
||||||
|
this.persistSorting(event.detail);
|
||||||
|
} else {
|
||||||
|
this.pendingSorting = event.detail;
|
||||||
}
|
}
|
||||||
this.preferences.set(`${this.sortingPreferenceKey}.sorting.key`, event.detail.key);
|
|
||||||
this.preferences.set(`${this.sortingPreferenceKey}.sorting.sortingKey`, event.detail.sortingKey);
|
|
||||||
this.preferences.set(`${this.sortingPreferenceKey}.sorting.direction`, event.detail.direction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +182,10 @@ export class DocumentListDirective implements OnInit {
|
|||||||
|
|
||||||
onReady() {
|
onReady() {
|
||||||
this.updateSelection();
|
this.updateSelection();
|
||||||
|
if (this.pendingSorting) {
|
||||||
|
this.persistSorting(this.pendingSorting);
|
||||||
|
this.pendingSorting = null;
|
||||||
|
}
|
||||||
this.restoreSorting();
|
this.restoreSorting();
|
||||||
if (this.pendingNode) {
|
if (this.pendingNode) {
|
||||||
const wasSelected = this.documentList.selection.some((node) => node.entry?.id === this.pendingNode.entry.id);
|
const wasSelected = this.documentList.selection.some((node) => node.entry?.id === this.pendingNode.entry.id);
|
||||||
@@ -206,6 +221,12 @@ export class DocumentListDirective implements OnInit {
|
|||||||
this.documentList.data.setSorting({ key, direction });
|
this.documentList.data.setSorting({ key, direction });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private persistSorting(detail: SortingChangedEventDetail) {
|
||||||
|
this.preferences.set(`${this.sortingPreferenceKey}.sorting.key`, detail.key);
|
||||||
|
this.preferences.set(`${this.sortingPreferenceKey}.sorting.sortingKey`, detail.sortingKey);
|
||||||
|
this.preferences.set(`${this.sortingPreferenceKey}.sorting.direction`, detail.direction);
|
||||||
|
}
|
||||||
|
|
||||||
private storePreviousSorting() {
|
private storePreviousSorting() {
|
||||||
if (this.preferences.hasItem(`${this.sortingPreferenceKey}.sorting.key`)) {
|
if (this.preferences.hasItem(`${this.sortingPreferenceKey}.sorting.key`)) {
|
||||||
const keyToSave = this.preferences.get(`${this.sortingPreferenceKey}.sorting.key`);
|
const keyToSave = this.preferences.get(`${this.sortingPreferenceKey}.sorting.key`);
|
||||||
|
|||||||
Reference in New Issue
Block a user