[CST-4591] Change import from external source page in order to work with entity type

This commit is contained in:
Giuseppe Digilio
2021-09-22 18:02:52 +02:00
parent afdbf3541b
commit 6bf3b8e7cd
12 changed files with 204 additions and 61 deletions

View File

@@ -53,6 +53,7 @@ export const externalSourceMyStaffDb: ExternalSource = {
export function getMockExternalSourceService(): ExternalSourceService { export function getMockExternalSourceService(): ExternalSourceService {
return jasmine.createSpyObj('ExternalSourceService', { return jasmine.createSpyObj('ExternalSourceService', {
findAll: jasmine.createSpy('findAll'), findAll: jasmine.createSpy('findAll'),
searchBy: jasmine.createSpy('searchBy'),
getExternalSourceEntries: jasmine.createSpy('getExternalSourceEntries'), getExternalSourceEntries: jasmine.createSpy('getExternalSourceEntries'),
}); });
} }

View File

@@ -5,7 +5,12 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<ds-collection-dropdown (selectionChange)="selectObject($event)"> <ds-loading *ngIf="isLoading()"></ds-loading>
<ds-collection-dropdown [ngClass]="{'d-none': isLoading()}"
(selectionChange)="selectObject($event)"
(hasChoice)="onHasChoice($event)"
(theOnlySelectable)="theOnlySelectable($event)"
[entityType]="entityType">
</ds-collection-dropdown> </ds-collection-dropdown>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,11 @@
import { Component, NO_ERRORS_SCHEMA, EventEmitter } from '@angular/core'; import { Component, EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import { waitForAsync, TestBed, ComponentFixture, inject } from '@angular/core/testing'; import { ComponentFixture, fakeAsync, inject, TestBed, waitForAsync } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { createTestComponent } from '../../../shared/testing/utils.test'; import { createTestComponent } from '../../../shared/testing/utils.test';
import { SubmissionImportExternalCollectionComponent } from './submission-import-external-collection.component'; import { SubmissionImportExternalCollectionComponent } from './submission-import-external-collection.component';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component'; import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { By } from '@angular/platform-browser';
describe('SubmissionImportExternalCollectionComponent test suite', () => { describe('SubmissionImportExternalCollectionComponent test suite', () => {
let comp: SubmissionImportExternalCollectionComponent; let comp: SubmissionImportExternalCollectionComponent;
@@ -76,6 +77,48 @@ describe('SubmissionImportExternalCollectionComponent test suite', () => {
expect(compAsAny.activeModal.dismiss).toHaveBeenCalled(); expect(compAsAny.activeModal.dismiss).toHaveBeenCalled();
}); });
it('should be in loading state when hasChoice variable is different to true', () => {
comp.hasChoice = null;
expect(comp.isLoading()).toBeTrue();
comp.hasChoice = false;
expect(comp.isLoading()).toBeTrue();
comp.hasChoice = true;
expect(comp.isLoading()).toBeFalse();
});
it('should set hasChoice variable on hasChoice event', () => {
comp.hasChoice = null;
comp.onHasChoice(true);
expect(comp.hasChoice).toBe(true);
comp.onHasChoice(false);
expect(comp.hasChoice).toBe(false);
});
it('should emit theOnlySelectable', () => {
spyOn(comp.selectedEvent, 'emit').and.callThrough();
const selected: any = {};
comp.theOnlySelectable(selected);
expect(comp.selectedEvent.emit).toHaveBeenCalledWith(selected);
});
it('dropdown should be invisible when the component is loading', fakeAsync(() => {
spyOn(comp, 'isLoading').and.returnValue(true);
fixture.detectChanges();
fixture.whenStable().then(() => {
const dropdownMenu = fixture.debugElement.query(By.css('ds-collection-dropdown')).nativeElement;
expect(dropdownMenu.classList).toContain('d-none');
});
}));
}); });
}); });

View File

@@ -1,4 +1,4 @@
import { Component, Output, EventEmitter } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core';
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component'; import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@@ -16,6 +16,16 @@ export class SubmissionImportExternalCollectionComponent {
*/ */
@Output() public selectedEvent = new EventEmitter<CollectionListEntry>(); @Output() public selectedEvent = new EventEmitter<CollectionListEntry>();
/**
* If present this value is used to filter collection list by entity type
*/
public entityType: string;
/**
* If a collection choice is available
*/
public hasChoice: boolean = null;
/** /**
* Initialize the component variables. * Initialize the component variables.
* @param {NgbActiveModal} activeModal * @param {NgbActiveModal} activeModal
@@ -37,4 +47,27 @@ export class SubmissionImportExternalCollectionComponent {
public closeCollectionModal(): void { public closeCollectionModal(): void {
this.activeModal.dismiss(false); this.activeModal.dismiss(false);
} }
/**
* Propagate the onlySelectable collection
* @param theOnlySelectable
*/
public theOnlySelectable(theOnlySelectable: CollectionListEntry) {
this.selectedEvent.emit(theOnlySelectable);
}
/**
* Set the hasChoice state
* @param hasChoice
*/
public onHasChoice(hasChoice: boolean) {
this.hasChoice = hasChoice;
}
/**
* If the component is in loading state.
*/
public isLoading(): boolean {
return this.hasChoice !== true;
}
} }

View File

@@ -1,5 +1,5 @@
<div class="modal-header"> <div class="modal-header">
<h2>{{'submission.import-external.preview.title' | translate}}</h2> <h2>{{'submission.import-external.preview.title.' + labelPrefix | translate}}</h2>
<button type="button" class="close" <button type="button" class="close"
(click)="closeMetadataModal()" aria-label="Close"> (click)="closeMetadataModal()" aria-label="Close">
<span aria-hidden="true">×</span> <span aria-hidden="true">×</span>

View File

@@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { NgbActiveModal, NgbModalRef, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model'; import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model';
import { MetadataValue } from '../../../core/shared/metadata.models'; import { MetadataValue } from '../../../core/shared/metadata.models';
import { Metadata } from '../../../core/shared/metadata.utils'; import { Metadata } from '../../../core/shared/metadata.utils';
@@ -28,6 +28,10 @@ export class SubmissionImportExternalPreviewComponent implements OnInit {
* The entry metadata list * The entry metadata list
*/ */
public metadataList: { key: string, value: MetadataValue }[]; public metadataList: { key: string, value: MetadataValue }[];
/**
* The label prefix to use to generate the translation label
*/
public labelPrefix: string;
/** /**
* The modal for the entry preview * The modal for the entry preview
*/ */
@@ -77,6 +81,7 @@ export class SubmissionImportExternalPreviewComponent implements OnInit {
this.modalRef = this.modalService.open(SubmissionImportExternalCollectionComponent, { this.modalRef = this.modalService.open(SubmissionImportExternalCollectionComponent, {
size: 'lg', size: 'lg',
}); });
this.modalRef.componentInstance.entityType = this.labelPrefix;
this.closeMetadataModal(); this.closeMetadataModal();
this.modalRef.componentInstance.selectedEvent.pipe( this.modalRef.componentInstance.selectedEvent.pipe(

View File

@@ -15,7 +15,7 @@ import {
getMockExternalSourceService getMockExternalSourceService
} from '../../../shared/mocks/external-source.service.mock'; } from '../../../shared/mocks/external-source.service.mock';
import { PageInfo } from '../../../core/shared/page-info.model'; import { PageInfo } from '../../../core/shared/page-info.model';
import { PaginatedList, buildPaginatedList } from '../../../core/data/paginated-list.model'; import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { ExternalSource } from '../../../core/shared/external-source.model'; import { ExternalSource } from '../../../core/shared/external-source.model';
import { FindListOptions } from '../../../core/data/request.models'; import { FindListOptions } from '../../../core/data/request.models';
@@ -23,6 +23,7 @@ import { HostWindowService } from '../../../shared/host-window.service';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub'; import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing'; import { TestScheduler } from 'rxjs/testing';
import { RequestParam } from '../../../core/cache/models/request-param.model';
describe('SubmissionImportExternalSearchbarComponent test suite', () => { describe('SubmissionImportExternalSearchbarComponent test suite', () => {
let comp: SubmissionImportExternalSearchbarComponent; let comp: SubmissionImportExternalSearchbarComponent;
@@ -63,9 +64,9 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
// synchronous beforeEach // synchronous beforeEach
beforeEach(() => { beforeEach(() => {
mockExternalSourceService.findAll.and.returnValue(observableOf(paginatedListRD)); mockExternalSourceService.searchBy.and.returnValue(observableOf(paginatedListRD));
const html = ` const html = `
<ds-submission-import-external-searchbar></ds-submission-import-external-searchbar>`; <ds-submission-import-external-searchbar [initExternalSourceData]="initExternalSourceData"></ds-submission-import-external-searchbar>`;
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance; testComp = testFixture.componentInstance;
}); });
@@ -88,7 +89,7 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
const pageInfo = new PageInfo(); const pageInfo = new PageInfo();
paginatedList = buildPaginatedList(pageInfo, [externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb]); paginatedList = buildPaginatedList(pageInfo, [externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb]);
paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
compAsAny.externalService.findAll.and.returnValue(observableOf(paginatedListRD)); compAsAny.externalService.searchBy.and.returnValue(observableOf(paginatedListRD));
sourceList = [ sourceList = [
{id: 'orcid', name: 'orcid'}, {id: 'orcid', name: 'orcid'},
{id: 'ciencia', name: 'ciencia'}, {id: 'ciencia', name: 'ciencia'},
@@ -103,7 +104,7 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
}); });
it('Should init component properly (without initExternalSourceData)', () => { it('Should init component properly (without initExternalSourceData)', () => {
comp.initExternalSourceData = { sourceId: '', query: '' }; comp.initExternalSourceData = { entity: 'Publication', sourceId: '', query: '' };
scheduler.schedule(() => fixture.detectChanges()); scheduler.schedule(() => fixture.detectChanges());
scheduler.flush(); scheduler.flush();
@@ -113,7 +114,7 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
}); });
it('Should init component properly (with initExternalSourceData populated)', () => { it('Should init component properly (with initExternalSourceData populated)', () => {
comp.initExternalSourceData = { query: 'dummy', sourceId: 'ciencia' }; comp.initExternalSourceData = { entity: 'Publication', query: 'dummy', sourceId: 'ciencia' };
scheduler.schedule(() => fixture.detectChanges()); scheduler.schedule(() => fixture.detectChanges());
scheduler.flush(); scheduler.flush();
@@ -129,6 +130,7 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
}); });
it('Should load additional external sources', () => { it('Should load additional external sources', () => {
comp.initExternalSourceData = { entity: 'Publication', query: 'dummy', sourceId: 'ciencia' };
comp.sourceListLoading = false; comp.sourceListLoading = false;
compAsAny.pageInfo = new PageInfo({ compAsAny.pageInfo = new PageInfo({
elementsPerPage: 3, elementsPerPage: 3,
@@ -139,6 +141,9 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
compAsAny.findListOptions = Object.assign({}, new FindListOptions(), { compAsAny.findListOptions = Object.assign({}, new FindListOptions(), {
elementsPerPage: 3, elementsPerPage: 3,
currentPage: 0, currentPage: 0,
searchParams: [
new RequestParam('entityType', 'Publication')
]
}); });
comp.sourceList = sourceList; comp.sourceList = sourceList;
const expected = sourceList.concat(sourceList); const expected = sourceList.concat(sourceList);
@@ -150,9 +155,10 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
}); });
it('The \'search\' method should call \'emit\'', () => { it('The \'search\' method should call \'emit\'', () => {
comp.initExternalSourceData = { entity: 'Publication', query: 'dummy', sourceId: 'ciencia' };
comp.selectedElement = { id: 'orcidV2', name: 'orcidV2' }; comp.selectedElement = { id: 'orcidV2', name: 'orcidV2' };
comp.searchString = 'dummy'; comp.searchString = 'dummy';
const expected = { sourceId: comp.selectedElement.id, query: comp.searchString }; const expected = { entity: 'Publication', sourceId: comp.selectedElement.id, query: comp.searchString };
spyOn(comp.externalSourceData, 'emit'); spyOn(comp.externalSourceData, 'emit');
comp.search(); comp.search();
@@ -167,5 +173,5 @@ describe('SubmissionImportExternalSearchbarComponent test suite', () => {
template: `` template: ``
}) })
class TestComponent { class TestComponent {
initExternalSourceData = { entity: 'Publication', query: 'dummy', sourceId: 'ciencia' };
} }

View File

@@ -1,19 +1,12 @@
import { import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output
} from '@angular/core';
import { Observable, of as observableOf, Subscription } from 'rxjs'; import { Observable, of as observableOf, Subscription } from 'rxjs';
import { catchError, tap } from 'rxjs/operators'; import { catchError, tap } from 'rxjs/operators';
import { RequestParam } from '../../../core/cache/models/request-param.model';
import { ExternalSourceService } from '../../../core/data/external-source.service'; import { ExternalSourceService } from '../../../core/data/external-source.service';
import { ExternalSource } from '../../../core/shared/external-source.model'; import { ExternalSource } from '../../../core/shared/external-source.model';
import { PaginatedList, buildPaginatedList } from '../../../core/data/paginated-list.model'; import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PageInfo } from '../../../core/shared/page-info.model'; import { PageInfo } from '../../../core/shared/page-info.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
@@ -34,6 +27,7 @@ export interface SourceElement {
* Interface for the external source data to export. * Interface for the external source data to export.
*/ */
export interface ExternalSourceData { export interface ExternalSourceData {
entity: string;
query: string; query: string;
sourceId: string; sourceId: string;
} }
@@ -116,8 +110,11 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit, OnDes
this.findListOptions = Object.assign({}, new FindListOptions(), { this.findListOptions = Object.assign({}, new FindListOptions(), {
elementsPerPage: 5, elementsPerPage: 5,
currentPage: 1, currentPage: 1,
searchParams: [
new RequestParam('entityType', this.initExternalSourceData.entity)
]
}); });
this.externalService.findAll(this.findListOptions).pipe( this.externalService.searchBy('findByEntityType', this.findListOptions).pipe(
catchError(() => { catchError(() => {
const pageInfo = new PageInfo(); const pageInfo = new PageInfo();
const paginatedList = buildPaginatedList(pageInfo, []); const paginatedList = buildPaginatedList(pageInfo, []);
@@ -158,8 +155,11 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit, OnDes
this.findListOptions = Object.assign({}, new FindListOptions(), { this.findListOptions = Object.assign({}, new FindListOptions(), {
elementsPerPage: 5, elementsPerPage: 5,
currentPage: this.findListOptions.currentPage + 1, currentPage: this.findListOptions.currentPage + 1,
searchParams: [
new RequestParam('entityType', this.initExternalSourceData.entity)
]
}); });
this.sub = this.externalService.findAll(this.findListOptions).pipe( this.externalService.searchBy('findByEntityType', this.findListOptions).pipe(
catchError(() => { catchError(() => {
const pageInfo = new PageInfo(); const pageInfo = new PageInfo();
const paginatedList = buildPaginatedList(pageInfo, []); const paginatedList = buildPaginatedList(pageInfo, []);
@@ -182,7 +182,13 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit, OnDes
* Passes the search parameters to the parent component. * Passes the search parameters to the parent component.
*/ */
public search(): void { public search(): void {
this.externalSourceData.emit({ sourceId: this.selectedElement.id, query: this.searchString }); this.externalSourceData.emit(
{
entity: this.initExternalSourceData.entity,
sourceId: this.selectedElement.id,
query: this.searchString
}
);
} }
/** /**
@@ -193,4 +199,5 @@ export class SubmissionImportExternalSearchbarComponent implements OnInit, OnDes
this.sub.unsubscribe(); this.sub.unsubscribe();
} }
} }
} }

View File

@@ -1,17 +1,18 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2 id="header" class="pb-2">{{'submission.import-external.title' | translate}}</h2> <h2 id="header" class="pb-2">{{'submission.import-external.title' + ((label) ? '.' + label : '') | translate}}</h2>
<ds-submission-import-external-searchbar <ds-submission-import-external-searchbar
[initExternalSourceData]="routeData" *ngIf="reload$.value.entity"
[initExternalSourceData]="reload$.value"
(externalSourceData) = "getExternalSourceData($event)"> (externalSourceData) = "getExternalSourceData($event)">
</ds-submission-import-external-searchbar> </ds-submission-import-external-searchbar>
</div> </div>
</div> </div>
<div class="row"> <div class="row" *ngIf="reload$.value.entity">
<div *ngIf="routeData.sourceId !== ''" class="col-md-12"> <div *ngIf="reload$.value.sourceId !== ''" class="col-md-12">
<ng-container *ngVar="(entriesRD$ | async) as entriesRD"> <ng-container *ngVar="(entriesRD$ | async) as entriesRD">
<h3 *ngIf="entriesRD && entriesRD?.payload?.page?.length !== 0">{{ 'submission.sections.describe.relationship-lookup.selection-tab.title.' + routeData.sourceId | translate}}</h3> <h3 *ngIf="entriesRD && entriesRD?.payload?.page?.length !== 0">{{ 'submission.sections.describe.relationship-lookup.selection-tab.title' | translate}}</h3>
<ds-viewable-collection *ngIf="entriesRD?.hasSucceeded && !(isLoading$ | async) && entriesRD?.payload?.page?.length > 0" @fadeIn <ds-viewable-collection *ngIf="entriesRD?.hasSucceeded && !(isLoading$ | async) && entriesRD?.payload?.page?.length > 0" @fadeIn
[objects]="entriesRD" [objects]="entriesRD"
[selectionConfig]="{ repeatable: repeatable, listId: listId }" [selectionConfig]="{ repeatable: repeatable, listId: listId }"
@@ -29,12 +30,19 @@
</div> </div>
</ng-container> </ng-container>
</div> </div>
<div *ngIf="routeData.sourceId === ''" class="col-md-12"> <div *ngIf="reload$.value.sourceId === ''" class="col-md-12">
<ds-alert [type]="'alert-info'"> <ds-alert [type]="'alert-info'">
<p class="lead mb-0">{{'submission.import-external.page.hint' | translate}}</p> <p class="lead mb-0">{{'submission.import-external.page.hint' | translate}}</p>
</ds-alert> </ds-alert>
</div> </div>
</div> </div>
<div class="row" *ngIf="!reload$.value.entity">
<div class="col-md-12">
<ds-alert [type]="'alert-warning'">
<p class="lead mb-0">{{'submission.import-external.page.noentity' | translate}}</p>
</ds-alert>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<hr> <hr>

View File

@@ -1,5 +1,5 @@
import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { waitForAsync, ComponentFixture, inject, TestBed } from '@angular/core/testing'; import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -102,17 +102,19 @@ describe('SubmissionImportExternalComponent test suite', () => {
it('Should init component properly (without route data)', () => { it('Should init component properly (without route data)', () => {
const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([])); const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([]));
comp.routeData = {entity: '', sourceId: '', query: '' };
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf('')); spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf(''));
fixture.detectChanges(); fixture.detectChanges();
expect(comp.routeData).toEqual({ sourceId: '', query: '' }); expect(comp.routeData).toEqual({entity: '', sourceId: '', query: '' });
expect(comp.isLoading$.value).toBe(false); expect(comp.isLoading$.value).toBe(false);
expect(comp.entriesRD$.value).toEqual(expectedEntries); expect(comp.entriesRD$.value).toEqual(expectedEntries);
}); });
it('Should init component properly (with route data)', () => { it('Should init component properly (with route data)', () => {
comp.routeData = {entity: '', sourceId: '', query: '' };
spyOn(compAsAny, 'retrieveExternalSources'); spyOn(compAsAny, 'retrieveExternalSources');
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValues(observableOf('source'), observableOf('dummy')); spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValues(observableOf('entity'), observableOf('source'), observableOf('dummy'));
fixture.detectChanges(); fixture.detectChanges();
expect(compAsAny.retrieveExternalSources).toHaveBeenCalled(); expect(compAsAny.retrieveExternalSources).toHaveBeenCalled();
@@ -120,7 +122,7 @@ describe('SubmissionImportExternalComponent test suite', () => {
it('Should call \'getExternalSourceEntries\' properly', () => { it('Should call \'getExternalSourceEntries\' properly', () => {
spyOn(routeServiceStub, 'getQueryParameterValue').and.callFake((param) => { spyOn(routeServiceStub, 'getQueryParameterValue').and.callFake((param) => {
if (param === 'source') { if (param === 'sourceId') {
return observableOf('orcidV2'); return observableOf('orcidV2');
} else if (param === 'query') { } else if (param === 'query') {
return observableOf('test'); return observableOf('test');
@@ -136,15 +138,15 @@ describe('SubmissionImportExternalComponent test suite', () => {
}); });
it('Should call \'router.navigate\'', () => { it('Should call \'router.navigate\'', () => {
comp.routeData = { sourceId: '', query: '' }; comp.routeData = {entity: 'Person', sourceId: '', query: '' };
spyOn(compAsAny, 'retrieveExternalSources').and.callFake(() => null); spyOn(compAsAny, 'retrieveExternalSources').and.callFake(() => null);
compAsAny.router.navigate.and.returnValue( new Promise(() => {return;})); compAsAny.router.navigate.and.returnValue( new Promise(() => {return;}));
const event = { sourceId: 'orcidV2', query: 'dummy' }; const event = {entity: 'Person', sourceId: 'orcidV2', query: 'dummy' };
scheduler.schedule(() => comp.getExternalSourceData(event)); scheduler.schedule(() => comp.getExternalSourceData(event));
scheduler.flush(); scheduler.flush();
expect(compAsAny.router.navigate).toHaveBeenCalledWith([], { queryParams: { source: event.sourceId, query: event.query }, replaceUrl: true }); expect(compAsAny.router.navigate).toHaveBeenCalledWith([], { queryParams: { entity: event.entity, sourceId: event.sourceId, query: event.query }, replaceUrl: true });
}); });
it('Entry should be passed to the component loaded inside the modal', () => { it('Entry should be passed to the component loaded inside the modal', () => {
@@ -166,6 +168,13 @@ describe('SubmissionImportExternalComponent test suite', () => {
expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalPreviewComponent, { size: 'lg' }); expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalPreviewComponent, { size: 'lg' });
expect(comp.modalRef.componentInstance.externalSourceEntry).toEqual(entry); expect(comp.modalRef.componentInstance.externalSourceEntry).toEqual(entry);
}); });
it('Should set the correct label', () => {
const label = 'Person';
compAsAny.selectLabel(label);
expect(comp.label).toEqual(label);
});
}); });
}); });

View File

@@ -45,9 +45,10 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
*/ */
public isLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); public isLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public reload$: BehaviorSubject<{ query: string, source: string }> = new BehaviorSubject<{ query: string; source: string }>({ public reload$: BehaviorSubject<ExternalSourceData> = new BehaviorSubject<ExternalSourceData>({
entity: '',
query: '', query: '',
source: '' sourceId: ''
}); });
/** /**
* Configuration to use for the import buttons * Configuration to use for the import buttons
@@ -109,11 +110,10 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
* Get the entries for the selected external source and set initial configuration. * Get the entries for the selected external source and set initial configuration.
*/ */
ngOnInit(): void { ngOnInit(): void {
this.label = 'Journal';
this.listId = 'list-submission-external-sources'; this.listId = 'list-submission-external-sources';
this.context = Context.EntitySearchModalWithNameVariants; this.context = Context.EntitySearchModalWithNameVariants;
this.repeatable = false; this.repeatable = false;
this.routeData = {sourceId: '', query: ''}; this.routeData = {entity: '', sourceId: '', query: ''};
this.importConfig = { this.importConfig = {
buttonLabel: 'submission.sections.describe.relationship-lookup.external-source.import-button-title.' + this.label buttonLabel: 'submission.sections.describe.relationship-lookup.external-source.import-button-title.' + this.label
}; };
@@ -121,12 +121,14 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
this.isLoading$ = new BehaviorSubject(false); this.isLoading$ = new BehaviorSubject(false);
this.subs.push(combineLatest( this.subs.push(combineLatest(
[ [
this.routeService.getQueryParameterValue('source'), this.routeService.getQueryParameterValue('entity'),
this.routeService.getQueryParameterValue('sourceId'),
this.routeService.getQueryParameterValue('query') this.routeService.getQueryParameterValue('query')
]).pipe( ]).pipe(
take(1) take(1)
).subscribe(([source, query]: [string, string]) => { ).subscribe(([entity, sourceId, query]: [string, string, string]) => {
this.reload$.next({query: query, source: source}); this.reload$.next({entity: entity, query: query, sourceId: sourceId});
this.selectLabel(entity);
this.retrieveExternalSources(); this.retrieveExternalSources();
})); }));
} }
@@ -138,11 +140,11 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
this.router.navigate( this.router.navigate(
[], [],
{ {
queryParams: {source: event.sourceId, query: event.query}, queryParams: event,
replaceUrl: true replaceUrl: true
} }
).then(() => { ).then(() => {
this.reload$.next({source: event.sourceId, query: event.query}); this.reload$.next(event);
this.retrieveExternalSources(); this.retrieveExternalSources();
}); });
} }
@@ -157,6 +159,7 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
}); });
const modalComp = this.modalRef.componentInstance; const modalComp = this.modalRef.componentInstance;
modalComp.externalSourceEntry = entry; modalComp.externalSourceEntry = entry;
modalComp.labelPrefix = this.label;
} }
/** /**
@@ -173,22 +176,17 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
} }
/** /**
* Retrieve external source entries * Retrieve external source entries.
*
* @param source The source tupe
* @param query The query string to search
*/ */
private retrieveExternalSources(): void { private retrieveExternalSources(): void {
if (hasValue(this.retrieveExternalSourcesSub)) { /* if (hasValue(this.retrieveExternalSourcesSub)) {
this.retrieveExternalSourcesSub.unsubscribe(); this.retrieveExternalSourcesSub.unsubscribe();
} }*/
this.retrieveExternalSourcesSub = this.reload$.pipe( this.retrieveExternalSourcesSub = this.reload$.pipe(
filter((sourceQueryObject: { source: string, query: string }) => isNotEmpty(sourceQueryObject.source) && isNotEmpty(sourceQueryObject.query)), filter((sourceQueryObject: ExternalSourceData) => isNotEmpty(sourceQueryObject.sourceId) && isNotEmpty(sourceQueryObject.query)),
switchMap((sourceQueryObject: { source: string, query: string }) => { switchMap((sourceQueryObject: ExternalSourceData) => {
const source = sourceQueryObject.source;
const query = sourceQueryObject.query; const query = sourceQueryObject.query;
this.routeData.sourceId = source; this.routeData = sourceQueryObject;
this.routeData.query = query;
return this.searchConfigService.paginatedSearchOptions.pipe( return this.searchConfigService.paginatedSearchOptions.pipe(
tap((v) => this.isLoading$.next(true)), tap((v) => this.isLoading$.next(true)),
filter((searchOptions) => searchOptions.query === query), filter((searchOptions) => searchOptions.query === query),
@@ -204,4 +202,16 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy {
}); });
} }
/**
* Set the correct button label, depending on the entity.
*
* @param entity The entity name
*/
private selectLabel(entity: string): void {
this.label = entity;
this.importConfig = {
buttonLabel: 'submission.sections.describe.relationship-lookup.external-source.import-button-title.' + this.label
};
}
} }

View File

@@ -3211,8 +3211,24 @@
"submission.import-external.title": "Import metadata from an external source", "submission.import-external.title": "Import metadata from an external source",
"submission.import-external.title.Journal": "Import a journal from an external source",
"submission.import-external.title.JournalIssue": "Import a journal issue from an external source",
"submission.import-external.title.JournalVolume": "Import a journal volume from an external source",
"submission.import-external.title.OrgUnit": "Import a publisher from an external source",
"submission.import-external.title.Person": "Import a person from an external source",
"submission.import-external.title.Project": "Import a project from an external source",
"submission.import-external.title.Publication": "Import a publication from an external source",
"submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.",
"submission.import-external.page.noentity": "An entity type must be selected in order to use this page. Select it using the 'Import metadata from an external source' button in 'MyDspace' page.",
"submission.import-external.back-to-my-dspace": "Back to MyDSpace", "submission.import-external.back-to-my-dspace": "Back to MyDSpace",
"submission.import-external.search.placeholder": "Search the external source", "submission.import-external.search.placeholder": "Search the external source",