71380: Fix loading/cache issue with dropping objects on page

This commit is contained in:
Kristof De Langhe
2020-06-25 11:09:37 +02:00
parent 28891211e4
commit 73c25998e3
5 changed files with 57 additions and 21 deletions

View File

@@ -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.zone.run(() => {
this.displayNotifications('item.edit.bitstreams.notifications.move', [response]);
this.requestService.removeByHrefSubstring(bundle.self);
this.zone.run(() => event.finish());
event.finish();
});
});
}
});

View File

@@ -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
]

View File

@@ -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,12 +50,18 @@ export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginate
*/
initializeObjectsRD(): void {
this.objectsRD$ = this.currentPage$.pipe(
switchMap((page: number) => this.bundleService.getBitstreams(
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,
new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })}),
paginatedOptions,
followLink('format')
))
);
})
);
}
/**

View File

@@ -88,10 +88,12 @@ export class BundleDataService extends DataService<Bundle> {
/**
* Get the bitstreams endpoint for a bundle
* @param bundleId
* @param searchOptions
*/
getBitstreamsEndpoint(bundleId: string): Observable<string> {
getBitstreamsEndpoint(bundleId: string, searchOptions?: PaginatedSearchOptions): Observable<string> {
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<Bundle> {
* @param linksToFollow The {@link FollowLinkConfig}s for the request
*/
getBitstreams(bundleId: string, searchOptions?: PaginatedSearchOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
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) => {

View File

@@ -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<T extends DSpace
/**
* Whether or not we should display a loading animation
* This is used to display a loading page when the user drops a bitstream onto a new page. The loading animation
* should stop once the bitstream has moved to the new page and the new page's response has loaded
* should stop once the bitstream has moved to the new page and the new page's response has loaded and contains the
* dropped object on top (see this.stopLoadingWhenFirstIs below)
*/
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(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<T extends DSpace
distinctUntilChanged(compareArraysUsingFieldUuids())
).subscribe((updateValues) => {
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<T extends DSpace
// Send out a drop event (and navigate to the new page) when the "from" and "to" indexes are different from each other
if (fromIndex !== toIndex) {
if (isNewPage) {
this.stopLoadingWhenFirstIs = this.customOrder[dragIndex];
this.customOrder = [];
this.paginationComponent.doPageChange(redirectPage);
this.loading$.next(true);
@@ -207,7 +225,6 @@ export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpace
finish: () => {
if (isNewPage) {
this.currentPage$.next(redirectPage);
this.loading$.next(false);
}
}
}));