From 73c25998e37139618c6ab3f5e52fb7db140cb6a5 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 25 Jun 2020 11:09:37 +0200 Subject: [PATCH] 71380: Fix loading/cache issue with dropping objects on page --- .../item-bitstreams.component.ts | 8 +++--- ...-and-drop-bitstream-list.component.spec.ts | 12 +++++++-- ...-drag-and-drop-bitstream-list.component.ts | 20 +++++++++----- src/app/core/data/bundle-data.service.ts | 11 ++++---- ...-paginated-drag-and-drop-list.component.ts | 27 +++++++++++++++---- 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts index 35da302961..115e8489d4 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-bitstreams.component.ts @@ -196,9 +196,11 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme path: `/_links/bitstreams/${event.toIndex}/href` }); this.bundleService.patch(bundle, [moveOperation]).pipe(take(1)).subscribe((response: RestResponse) => { - this.displayNotifications('item.edit.bitstreams.notifications.move', [response]); - this.requestService.removeByHrefSubstring(bundle.self); - this.zone.run(() => event.finish()); + this.zone.run(() => { + this.displayNotifications('item.edit.bitstreams.notifications.move', [response]); + this.requestService.removeByHrefSubstring(bundle.self); + event.finish(); + }); }); } }); diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.spec.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.spec.ts index 54171ed8af..118f2b1619 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.spec.ts @@ -16,6 +16,7 @@ import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-siz import { ResponsiveColumnSizes } from '../../../../../shared/responsive-table-sizes/responsive-column-sizes'; import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils'; import { createPaginatedList } from '../../../../../shared/testing/utils.test'; +import { RequestService } from '../../../../../core/data/request.service'; describe('PaginatedDragAndDropBitstreamListComponent', () => { let comp: PaginatedDragAndDropBitstreamListComponent; @@ -23,6 +24,7 @@ describe('PaginatedDragAndDropBitstreamListComponent', () => { let objectUpdatesService: ObjectUpdatesService; let bundleService: BundleDataService; let objectValuesPipe: ObjectValuesPipe; + let requestService: RequestService; const columnSizes = new ResponsiveTableSizes([ new ResponsiveColumnSizes(2, 2, 3, 4, 4), @@ -98,18 +100,24 @@ describe('PaginatedDragAndDropBitstreamListComponent', () => { ); bundleService = jasmine.createSpyObj('bundleService', { - getBitstreams: createSuccessfulRemoteDataObject$(createPaginatedList([bitstream1, bitstream2])) + getBitstreams: createSuccessfulRemoteDataObject$(createPaginatedList([bitstream1, bitstream2])), + getBitstreamsEndpoint: observableOf('') }); objectValuesPipe = new ObjectValuesPipe(); + requestService = jasmine.createSpyObj('requestService', { + hasByHrefObservable: observableOf(true) + }); + TestBed.configureTestingModule({ imports: [TranslateModule.forRoot()], declarations: [PaginatedDragAndDropBitstreamListComponent, VarDirective], providers: [ { provide: ObjectUpdatesService, useValue: objectUpdatesService }, { provide: BundleDataService, useValue: bundleService }, - { provide: ObjectValuesPipe, useValue: objectValuesPipe } + { provide: ObjectValuesPipe, useValue: objectValuesPipe }, + { provide: RequestService, useValue: requestService } ], schemas: [ NO_ERRORS_SCHEMA ] diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts index 19cf3b27e4..a288e9993a 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts @@ -9,6 +9,7 @@ import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-s import { ResponsiveTableSizes } from '../../../../../shared/responsive-table-sizes/responsive-table-sizes'; import { followLink } from '../../../../../shared/utils/follow-link-config.model'; import { ObjectValuesPipe } from '../../../../../shared/utils/object-values-pipe'; +import { RequestService } from '../../../../../core/data/request.service'; @Component({ selector: 'ds-paginated-drag-and-drop-bitstream-list', @@ -35,7 +36,8 @@ export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginate constructor(protected objectUpdatesService: ObjectUpdatesService, protected elRef: ElementRef, protected objectValuesPipe: ObjectValuesPipe, - protected bundleService: BundleDataService) { + protected bundleService: BundleDataService, + protected requestService: RequestService) { super(objectUpdatesService, elRef, objectValuesPipe); } @@ -48,11 +50,17 @@ export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginate */ initializeObjectsRD(): void { this.objectsRD$ = this.currentPage$.pipe( - switchMap((page: number) => this.bundleService.getBitstreams( - this.bundle.id, - new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })}), - followLink('format') - )) + switchMap((page: number) => { + const paginatedOptions = new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })}); + return this.bundleService.getBitstreamsEndpoint(this.bundle.id, paginatedOptions).pipe( + switchMap((href) => this.requestService.hasByHrefObservable(href)), + switchMap(() => this.bundleService.getBitstreams( + this.bundle.id, + paginatedOptions, + followLink('format') + )) + ); + }) ); } diff --git a/src/app/core/data/bundle-data.service.ts b/src/app/core/data/bundle-data.service.ts index 160ea0ff0d..de0e8a4337 100644 --- a/src/app/core/data/bundle-data.service.ts +++ b/src/app/core/data/bundle-data.service.ts @@ -88,10 +88,12 @@ export class BundleDataService extends DataService { /** * Get the bitstreams endpoint for a bundle * @param bundleId + * @param searchOptions */ - getBitstreamsEndpoint(bundleId: string): Observable { + getBitstreamsEndpoint(bundleId: string, searchOptions?: PaginatedSearchOptions): Observable { return this.getBrowseEndpoint().pipe( - switchMap((href: string) => this.halService.getEndpoint(this.bitstreamsEndpoint, `${href}/${bundleId}`)) + switchMap((href: string) => this.halService.getEndpoint(this.bitstreamsEndpoint, `${href}/${bundleId}`)), + map((href) => searchOptions ? searchOptions.toRestUrl(href) : href) ); } @@ -102,9 +104,8 @@ export class BundleDataService extends DataService { * @param linksToFollow The {@link FollowLinkConfig}s for the request */ getBitstreams(bundleId: string, searchOptions?: PaginatedSearchOptions, ...linksToFollow: Array>): Observable>> { - const hrefObs = this.getBitstreamsEndpoint(bundleId).pipe( - map((href) => searchOptions ? searchOptions.toRestUrl(href) : href) - ); + const hrefObs = this.getBitstreamsEndpoint(bundleId, searchOptions); + hrefObs.pipe( take(1) ).subscribe((href) => { diff --git a/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts index 3d249b7393..9c46a70b5e 100644 --- a/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts +++ b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts @@ -1,4 +1,4 @@ -import { FieldUpdate, FieldUpdates, Identifiable } from '../../core/data/object-updates/object-updates.reducer'; +import { FieldUpdate, FieldUpdates } from '../../core/data/object-updates/object-updates.reducer'; import { Observable } from 'rxjs/internal/Observable'; import { RemoteData } from '../../core/data/remote-data'; import { PaginatedList } from '../../core/data/paginated-list'; @@ -6,7 +6,7 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service'; import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators'; -import { hasValue } from '../empty.util'; +import { hasValue, isNotEmpty } from '../empty.util'; import { paginatedListToArray } from '../../core/shared/operators'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; @@ -95,10 +95,19 @@ export abstract class AbstractPaginatedDragAndDropListComponent = new BehaviorSubject(false); + /** + * ID of the object the page's first element needs to match in order to stop the loading animation. + * This is to ensure the new page is fully loaded containing the latest data from the REST API whenever an object is + * dropped on a new page. This allows the component to expect the dropped object to be present on top of the new page, + * while displaying a loading animation until this is the case. + */ + stopLoadingWhenFirstIs: string; + /** * List of subscriptions */ @@ -148,7 +157,15 @@ export abstract class AbstractPaginatedDragAndDropListComponent { this.customOrder = updateValues.map((fieldUpdate) => fieldUpdate.field.uuid); - }) + // Check if stopLoadingWhenFirstIs contains a value. If it does and it equals the first value in customOrder, stop the loading animation. + // This is to ensure the page is updated to contain the new values first, before displaying it. + if (hasValue(this.stopLoadingWhenFirstIs) && isNotEmpty(this.customOrder) && this.customOrder[0] === this.stopLoadingWhenFirstIs) { + this.stopLoadingWhenFirstIs = undefined; + this.loading$.next(false); + } + }), + // Disable the pagination when objects are loading + this.loading$.subscribe((loading) => this.options.disabled = loading) ); } @@ -197,6 +214,7 @@ export abstract class AbstractPaginatedDragAndDropListComponent { if (isNewPage) { this.currentPage$.next(redirectPage); - this.loading$.next(false); } } }));