diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 7789b682783..88525eb18bf 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -27,7 +27,7 @@ -
+
+ + diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss index 985516ab121..7fd1f4b31e7 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.scss @@ -43,3 +43,13 @@ .scrollable-table { overflow-x: auto; } + +.disabled-overlay { + opacity: 0.6; +} + +.loading-overlay { + position: fixed; + top: 50%; + left: 50%; +} 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 6ee5dcb545f..72f85675c93 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 @@ -59,6 +59,11 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme */ itemUpdateSubscription: Subscription; + /** + * An observable which emits a boolean which represents whether the service is currently handling a 'move' request + */ + isProcessingMoveRequest: Observable; + constructor( public itemService: ItemDataService, public objectUpdatesService: ObjectUpdatesService, @@ -84,6 +89,7 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme */ postItemInit(): void { const bundlesOptions = this.itemBitstreamsService.getInitialBundlesPaginationOptions(); + this.isProcessingMoveRequest = this.itemBitstreamsService.getPerformingMoveRequest$(); this.bundles$ = this.itemService.getBundles(this.item.id, new PaginatedSearchOptions({pagination: bundlesOptions})).pipe( getFirstSucceededRemoteData(), diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.spec.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.spec.ts index f2af25f22f7..a0277ef064b 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.spec.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.spec.ts @@ -573,8 +573,6 @@ describe('ItemBitstreamsService', () => { const to = 7; const callback = createSpy('callbackFunction'); - console.log('bundle:', bundle); - it('should correctly create the Move request', () => { const expectedOperation: MoveOperation = { op: 'move', @@ -601,6 +599,22 @@ describe('ItemBitstreamsService', () => { service.performBitstreamMoveRequest(bundle, from, to, callback); expect(callback).toHaveBeenCalled(); }); + + it('should emit at the start and end of the request', fakeAsync(() => { + const emittedActions = []; + + service.getPerformingMoveRequest$().subscribe(selected => emittedActions.push(selected)); + + expect(emittedActions.length).toBe(1); + expect(emittedActions[0]).toBeFalse(); + + service.performBitstreamMoveRequest(bundle, from, to, callback); + tick(); + + expect(emittedActions.length).toBe(3); + expect(emittedActions[1]).toBeTrue(); + expect(emittedActions[2]).toBeFalse(); + })); }); describe('displayNotifications', () => { diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.stub.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.stub.ts index 7aac79fe695..f60693f7263 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.stub.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.stub.ts @@ -30,6 +30,10 @@ export class ItemBitstreamsServiceStub { performBitstreamMoveRequest = jasmine.createSpy('performBitstreamMoveRequest'); + getPerformingMoveRequest = jasmine.createSpy('getPerformingMoveRequest').and.returnValue(false); + + getPerformingMoveRequest$ = jasmine.createSpy('getPerformingMoveRequest$').and.returnValue(of(false)); + getInitialBundlesPaginationOptions = jasmine.createSpy('getInitialBundlesPaginationOptions').and .returnValue(new PaginationComponentOptions()); diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.ts index 2329107c29d..9bbf3804873 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.service.ts @@ -119,7 +119,7 @@ export class ItemBitstreamsService { */ protected selectionAction$: BehaviorSubject = new BehaviorSubject(null); - protected isPerformingMoveRequest = false; + protected isPerformingMoveRequest: BehaviorSubject = new BehaviorSubject(false); constructor( protected notificationsService: NotificationsService, @@ -221,7 +221,7 @@ export class ItemBitstreamsService { cancelSelection() { const selected = this.getSelectedBitstream(); - if (hasNoValue(selected) || this.isPerformingMoveRequest) { + if (hasNoValue(selected) || this.getPerformingMoveRequest()) { return; } @@ -247,7 +247,7 @@ export class ItemBitstreamsService { moveSelectedBitstreamUp() { const selected = this.getSelectedBitstream(); - if (hasNoValue(selected) || this.isPerformingMoveRequest) { + if (hasNoValue(selected) || this.getPerformingMoveRequest()) { return; } @@ -272,7 +272,7 @@ export class ItemBitstreamsService { moveSelectedBitstreamDown() { const selected = this.getSelectedBitstream(); - if (hasNoValue(selected) || this.isPerformingMoveRequest) { + if (hasNoValue(selected) || this.getPerformingMoveRequest()) { return; } @@ -299,7 +299,7 @@ export class ItemBitstreamsService { * @param finish Optional: Function to execute once the response has been received */ performBitstreamMoveRequest(bundle: Bundle, fromIndex: number, toIndex: number, finish?: () => void) { - if (this.isPerformingMoveRequest) { + if (this.getPerformingMoveRequest()) { console.warn('Attempted to perform move request while previous request has not completed yet'); return; } @@ -310,18 +310,34 @@ export class ItemBitstreamsService { path: `/_links/bitstreams/${toIndex}/href`, }; - this.isPerformingMoveRequest = true; + this.announceLoading(); + this.isPerformingMoveRequest.next(true); this.bundleService.patch(bundle, [moveOperation]).pipe( getFirstCompletedRemoteData(), tap((response: RemoteData) => this.displayFailedResponseNotifications(MOVE_KEY, [response])), switchMap(() => this.requestService.setStaleByHrefSubstring(bundle.self)), take(1), ).subscribe(() => { - this.isPerformingMoveRequest = false; + console.log('got here!'); + this.isPerformingMoveRequest.next(false); finish?.(); }); } + /** + * Whether the service currently is processing a 'move' request + */ + getPerformingMoveRequest(): boolean { + return this.isPerformingMoveRequest.value; + } + + /** + * Returns an observable which emits when the service starts, or ends, processing a 'move' request + */ + getPerformingMoveRequest$(): Observable { + return this.isPerformingMoveRequest; + } + /** * Returns the pagination options to use when fetching the bundles */ @@ -526,4 +542,12 @@ export class ItemBitstreamsService { { bitstream: bitstreamName }); this.liveRegionService.addMessage(message); } + + /** + * Adds a message to the live region mentioning that the + */ + announceLoading() { + const message = this.translateService.instant('item.edit.bitstreams.edit.live.loading'); + this.liveRegionService.addMessage(message); + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 519189ed691..9007982a728 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1954,6 +1954,8 @@ "item.edit.bitstreams.edit.live.clear": "{{ bitstream }} is no longer selected.", + "item.edit.bitstreams.edit.live.loading": "Waiting for move to complete.", + "item.edit.bitstreams.edit.live.select": "{{ bitstream }} is selected.", "item.edit.bitstreams.edit.live.move": "{{ bitstream }} is now in position {{ toIndex }}.",