diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html index e9d9ec035ba..62755287ec7 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.html @@ -3,14 +3,16 @@

{{ 'person.orcid.registry.queue' | translate }}

- {{ 'person.page.orcid.sync-queue.empty-message' | translate}} - + [collectionSize]="listDataRD?.payload?.totalElements" + [retainScrollPosition]="true" + [hideGear]="true" + (paginationChange)="onPaginationChange()">
@@ -22,7 +24,7 @@

{{ 'person.orcid.registry.queue' | translate }}

- +
@@ -51,3 +53,4 @@

{{ 'person.orcid.registry.queue' | translate }}

+ diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts index a32c7ef7a51..be4e73e41f1 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.spec.ts @@ -8,6 +8,7 @@ import { waitForAsync, } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateLoader, @@ -21,10 +22,14 @@ import { OrcidHistoryDataService } from '../../../core/orcid/orcid-history-data. import { OrcidQueueDataService } from '../../../core/orcid/orcid-queue-data.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { Item } from '../../../core/shared/item.model'; +import { RouterMock } from '../../../shared/mocks/router.mock'; import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; -import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils'; +import { + createNoContentRemoteDataObject$, + createSuccessfulRemoteDataObject$, +} from '../../../shared/remote-data.utils'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { createPaginatedList } from '../../../shared/testing/utils.test'; @@ -111,7 +116,7 @@ describe('OrcidQueueComponent test suite', () => { const orcidQueueElements = [orcidQueueElement(1), orcidQueueElement(2)]; - const orcidQueueServiceSpy = jasmine.createSpyObj('orcidQueueService', ['searchByProfileItemId', 'clearFindByProfileItemRequests']); + const orcidQueueServiceSpy = jasmine.createSpyObj('orcidQueueService', ['searchByProfileItemId', 'clearFindByProfileItemRequests', 'deleteById']); orcidQueueServiceSpy.searchByProfileItemId.and.returnValue(createSuccessfulRemoteDataObject$>(createPaginatedList(orcidQueueElements))); beforeEach(waitForAsync(() => { @@ -136,6 +141,7 @@ describe('OrcidQueueComponent test suite', () => { { provide: OrcidHistoryDataService, useValue: {} }, { provide: PaginationService, useValue: new PaginationServiceStub() }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: Router, useValue: new RouterMock() }, ], schemas: [NO_ERRORS_SCHEMA], }) @@ -166,4 +172,18 @@ describe('OrcidQueueComponent test suite', () => { expect(table.length).toBe(2); }); + it('should handle pagination change', () => { + spyOn(component, 'updateList'); + component.onPaginationChange(); + expect(component.updateList).toHaveBeenCalled(); + }); + + it('should discard an entry', waitForAsync(() => { + spyOn(component, 'removeEntryFromList'); + orcidQueueServiceSpy.deleteById.and.returnValue(createNoContentRemoteDataObject$()); + component.discardEntry(orcidQueueElements[0]); + fixture.whenStable().then(() => { + expect(component.removeEntryFromList).toHaveBeenCalledWith(orcidQueueElements[0].id); + }); + })); }); diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index dfc7fac5265..d4b0d657be7 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -1,12 +1,17 @@ -import { CommonModule } from '@angular/common'; +import { + CommonModule, + DOCUMENT, +} from '@angular/common'; import { Component, + Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, } from '@angular/core'; +import { Router } from '@angular/router'; import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule, @@ -40,6 +45,7 @@ import { AlertType } from '../../../shared/alert/alert-type'; import { hasValue } from '../../../shared/empty.util'; import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { ObjectTableComponent } from '../../../shared/object-table/object-table.component'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; @@ -54,6 +60,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio ThemedLoadingComponent, AlertComponent, PaginationComponent, + ObjectTableComponent, ], standalone: true, }) @@ -70,6 +77,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { public paginationOptions: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), { id: 'oqp', pageSize: 5, + currentPage: 1, }); /** @@ -80,7 +88,7 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { /** * A list of orcid queue records */ - private list$: BehaviorSubject>> = new BehaviorSubject>>({} as any); + listDataRD: RemoteData>; /** * The AlertType enumeration @@ -100,6 +108,8 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { private paginationService: PaginationService, private notificationsService: NotificationsService, private orcidHistoryService: OrcidHistoryDataService, + private router: Router, + @Inject(DOCUMENT) private _document: Document, ) { } @@ -119,24 +129,36 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { updateList() { this.subs.push( this.paginationService.getCurrentPagination(this.paginationOptions.id, this.paginationOptions).pipe( - debounceTime(100), + debounceTime(300), distinctUntilChanged(), tap(() => this.processing$.next(true)), - switchMap((config: PaginationComponentOptions) => this.orcidQueueService.searchByProfileItemId(this.item.id, config, false)), + switchMap((currentPaginationOptions) => this.orcidQueueService.searchByProfileItemId(this.item.id, currentPaginationOptions, false)), getFirstCompletedRemoteData(), - ).subscribe((result: RemoteData>) => { - this.processing$.next(false); - this.list$.next(result); - this.orcidQueueService.clearFindByProfileItemRequests(); + ).subscribe({ + next: (result: RemoteData>) => { + this.paginationOptions = Object.assign(this.paginationOptions, { + currentPage: result.payload.pageInfo.currentPage, + }); + this.processing$.next(false); + this.listDataRD = result; + this.orcidQueueService.clearFindByProfileItemRequests(); + }, }), ); } /** - * Return the list of orcid queue records + * Handle pagination change. + * Scroll to the pagination element and update the list with the new page */ - getList(): Observable>> { - return this.list$.asObservable(); + onPaginationChange(){ + const element = this._document.getElementById(`p-${this.paginationOptions.id}`); + if (element) { + setTimeout(() => { + element.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' }); + }, 300); + } + this.updateList(); } /** @@ -222,20 +244,40 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { * @param orcidQueue The OrcidQueue object to discard */ discardEntry(orcidQueue: OrcidQueue) { - this.processing$.next(true); this.subs.push(this.orcidQueueService.deleteById(orcidQueue.id).pipe( getFirstCompletedRemoteData(), ).subscribe((remoteData) => { - this.processing$.next(false); if (remoteData.isSuccess) { + this.removeEntryFromList(orcidQueue.id); this.notificationsService.success(this.translateService.get('person.page.orcid.sync-queue.discard.success')); - this.updateList(); } else { this.notificationsService.error(this.translateService.get('person.page.orcid.sync-queue.discard.error')); } })); } + /** + * Remove an entry from the list. + * If the last element of the page is removed, navigate to the previous page. + * @param id The id of the entry to remove + */ + removeEntryFromList(id: number) { + const index = this.listDataRD?.payload?.page.findIndex((item) => item.id === id); + if (index > -1) { + this.listDataRD.payload.page.splice(index, 1); + if (this.listDataRD.payload.page.length === 0 && this.listDataRD.payload.pageInfo.currentPage > 0) { + this.paginationOptions.currentPage = this.paginationOptions.currentPage - 1; + this.router.navigate([], { + queryParams: { + [`${this.paginationOptions.id}.page`]: this.paginationOptions.currentPage, + }, + fragment: `p-${this.paginationOptions.id}`, + }); + this.updateList(); + } + } + } + /** * Send a queue entry to orcid for the synchronization * @@ -327,7 +369,6 @@ export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges { * Unsubscribe from all subscriptions */ ngOnDestroy(): void { - this.list$ = null; this.subs.filter((subscription) => hasValue(subscription)) .forEach((subscription) => subscription.unsubscribe()); }