mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Merge branch 'w2p-72699_Hard-redirect-after-log-in' into Hard-redirect-after-log-in
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<ds-submission-import-external></ds-submission-import-external>
|
@@ -0,0 +1,26 @@
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ImportExternalPageComponent } from './import-external-page.component';
|
||||
|
||||
describe('ImportExternalPageComponent', () => {
|
||||
let component: ImportExternalPageComponent;
|
||||
let fixture: ComponentFixture<ImportExternalPageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ImportExternalPageComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ImportExternalPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create ImportExternalPageComponent', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component representing the external import page of the submission.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-import-external-page',
|
||||
templateUrl: './import-external-page.component.html',
|
||||
styleUrls: ['./import-external-page.component.scss']
|
||||
})
|
||||
export class ImportExternalPageComponent {
|
||||
|
||||
}
|
29
src/app/+import-external-page/import-external-page.module.ts
Normal file
29
src/app/+import-external-page/import-external-page.module.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { CoreModule } from '../core/core.module';
|
||||
import { ImportExternalRoutingModule } from './import-external-routing.module';
|
||||
import { SubmissionModule } from '../submission/submission.module';
|
||||
import { ImportExternalPageComponent } from './import-external-page.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
CoreModule.forRoot(),
|
||||
ImportExternalRoutingModule,
|
||||
SubmissionModule,
|
||||
],
|
||||
declarations: [
|
||||
ImportExternalPageComponent
|
||||
],
|
||||
entryComponents: [ ]
|
||||
})
|
||||
|
||||
/**
|
||||
* This module handles all components that are necessary for the submission external import page
|
||||
*/
|
||||
export class ImportExternalPageModule {
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||
import { SubmissionImportExternalComponent } from '../submission/import-external/submission-import-external.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
canActivate: [ AuthenticatedGuard ],
|
||||
path: '',
|
||||
component: SubmissionImportExternalComponent,
|
||||
pathMatch: 'full',
|
||||
data: {
|
||||
title: 'submission.import-external.page.title'
|
||||
}
|
||||
}
|
||||
])
|
||||
],
|
||||
providers: [ ]
|
||||
})
|
||||
export class ImportExternalRoutingModule {
|
||||
|
||||
}
|
@@ -8,9 +8,14 @@
|
||||
|
||||
</div>
|
||||
<div class="add">
|
||||
<button class="btn btn-lg btn-primary mt-1 ml-2" (click)="openDialog()" role="button">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> {{'mydspace.new-submission' | translate}}
|
||||
<button class="btn btn-lg btn-primary mt-1 ml-2" (click)="openDialog()" role="button" title="{{'mydspace.new-submission' | translate}}">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="add">
|
||||
<a class="btn btn-lg btn-primary mt-1 ml-2" [routerLink]="['/import-external']" role="button" title="{{'mydspace.new-submission-external' | translate}}">
|
||||
<i class="fa fa-file-import" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@@ -22,6 +22,8 @@ import { getMockScrollToService } from '../../shared/mocks/scroll-to-service.moc
|
||||
import { UploaderService } from '../../shared/uploader/uploader.service';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { HostWindowService } from '../../shared/host-window.service';
|
||||
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
|
||||
import { UploaderComponent } from 'src/app/shared/uploader/uploader.component';
|
||||
|
||||
describe('MyDSpaceNewSubmissionComponent test', () => {
|
||||
@@ -73,7 +75,8 @@ describe('MyDSpaceNewSubmissionComponent test', () => {
|
||||
{ provide: NgbModal, useValue: modalService },
|
||||
ChangeDetectorRef,
|
||||
MyDSpaceNewSubmissionComponent,
|
||||
UploaderService
|
||||
UploaderService,
|
||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
|
@@ -3,6 +3,8 @@ import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output,
|
||||
import { Subscription } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
@@ -12,11 +14,10 @@ import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
||||
import { NotificationType } from '../../shared/notifications/models/notification-type';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { SearchResult } from '../../shared/search/search-result.model';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { CreateItemParentSelectorComponent } from 'src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component';
|
||||
import { CreateItemParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component';
|
||||
import { CollectionSelectorComponent } from '../collection-selector/collection-selector.component';
|
||||
import { UploaderComponent } from 'src/app/shared/uploader/uploader.component';
|
||||
import { UploaderError } from 'src/app/shared/uploader/uploader-error.model';
|
||||
import { UploaderComponent } from '../../shared/uploader/uploader.component';
|
||||
import { UploaderError } from '../../shared/uploader/uploader-error.model';
|
||||
|
||||
/**
|
||||
* This component represents the whole mydspace page header
|
||||
@@ -56,6 +57,8 @@ export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit {
|
||||
* @param {NotificationsService} notificationsService
|
||||
* @param {Store<SubmissionState>} store
|
||||
* @param {TranslateService} translate
|
||||
* @param {Router} router
|
||||
* @param {NgbModal} modalService
|
||||
*/
|
||||
constructor(private authService: AuthService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
|
@@ -48,6 +48,7 @@ import { ReloadGuard } from './core/reload/reload.guard';
|
||||
{ path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' },
|
||||
{ path: 'logout', loadChildren: './+logout-page/logout-page.module#LogoutPageModule' },
|
||||
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
||||
{ path: 'import-external', loadChildren: './+import-external-page/import-external-page.module#ImportExternalPageModule' },
|
||||
{
|
||||
path: 'workspaceitems',
|
||||
loadChildren: './+workspaceitems-edit-page/workspaceitems-edit-page.module#WorkspaceitemsEditPageModule'
|
||||
|
@@ -19,6 +19,9 @@ export class AuthBlockingGuard implements CanActivate {
|
||||
constructor(private store: Store<AppState>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the authentication isn't blocking everything
|
||||
*/
|
||||
canActivate(): Observable<boolean> {
|
||||
return this.store.pipe(select(isAuthenticationBlocking)).pipe(
|
||||
map((isBlocking: boolean) => isBlocking === false),
|
||||
|
@@ -19,6 +19,7 @@ import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list';
|
||||
import { ExternalSourceEntry } from '../shared/external-source-entry.model';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
|
||||
/**
|
||||
* A service handling all external source requests
|
||||
|
@@ -24,7 +24,7 @@ interface CollectionListEntryItem {
|
||||
/**
|
||||
* An interface to represent an entry in the collection list
|
||||
*/
|
||||
interface CollectionListEntry {
|
||||
export interface CollectionListEntry {
|
||||
communities: CollectionListEntryItem[],
|
||||
collection: CollectionListEntryItem
|
||||
}
|
||||
|
59
src/app/shared/mocks/external-source.service.mock.ts
Normal file
59
src/app/shared/mocks/external-source.service.mock.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { ExternalSourceService } from '../../core/data/external-source.service';
|
||||
import { ExternalSource } from '../../core/shared/external-source.model';
|
||||
import { ResourceType } from '../../core/shared/resource-type';
|
||||
|
||||
export const externalSourceOrcid: ExternalSource = {
|
||||
type: new ResourceType('externalsource'),
|
||||
id: 'orcid',
|
||||
name: 'orcid',
|
||||
hierarchical: false,
|
||||
_links: {
|
||||
entries: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/orcid/entries'
|
||||
},
|
||||
self: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/orcid'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const externalSourceCiencia: ExternalSource = {
|
||||
type: new ResourceType('externalsource'),
|
||||
id: 'ciencia',
|
||||
name: 'ciencia',
|
||||
hierarchical: false,
|
||||
_links: {
|
||||
entries: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia/entries'
|
||||
},
|
||||
self: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const externalSourceMyStaffDb: ExternalSource = {
|
||||
type: new ResourceType('externalsource'),
|
||||
id: 'my_staff_db',
|
||||
name: 'my_staff_db',
|
||||
hierarchical: false,
|
||||
_links: {
|
||||
entries: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entries'
|
||||
},
|
||||
self: {
|
||||
href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock for [[ExternalSourceService]]
|
||||
*/
|
||||
export function getMockExternalSourceService():
|
||||
ExternalSourceService {
|
||||
return jasmine.createSpyObj('ExternalSourceService', {
|
||||
findAll: jasmine.createSpy('findAll'),
|
||||
getExternalSourceEntries: jasmine.createSpy('getExternalSourceEntries'),
|
||||
});
|
||||
}
|
@@ -478,6 +478,7 @@ const ENTRY_COMPONENTS = [
|
||||
ClaimedTaskActionsRejectComponent,
|
||||
ClaimedTaskActionsReturnToPoolComponent,
|
||||
ClaimedTaskActionsEditMetadataComponent,
|
||||
CollectionDropdownComponent,
|
||||
FileDownloadLinkComponent,
|
||||
CurationFormComponent,
|
||||
ExportMetadataSelectorComponent,
|
||||
|
@@ -2,6 +2,7 @@ export class SubmissionServiceStub {
|
||||
|
||||
changeSubmissionCollection = jasmine.createSpy('changeSubmissionCollection');
|
||||
createSubmission = jasmine.createSpy('createSubmission');
|
||||
createSubmissionFromExternalSource = jasmine.createSpy('createSubmissionFromExternalSource');
|
||||
depositSubmission = jasmine.createSpy('depositSubmission');
|
||||
discardSubmission = jasmine.createSpy('discardSubmission');
|
||||
dispatchInit = jasmine.createSpy('dispatchInit');
|
||||
|
@@ -0,0 +1,11 @@
|
||||
<div>
|
||||
<div class="modal-header">{{'dso-selector.create.collection.head' | translate}}
|
||||
<button type="button" class="close" (click)="closeCollectionModal()" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ds-collection-dropdown (selectionChange)="selectObject($event)">
|
||||
</ds-collection-dropdown>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,3 @@
|
||||
.close:focus {
|
||||
outline: none !important;
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
import { Component, NO_ERRORS_SCHEMA, EventEmitter } from '@angular/core';
|
||||
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { createTestComponent } from '../../../shared/testing/utils.test';
|
||||
import { SubmissionImportExternalCollectionComponent } from './submission-import-external-collection.component';
|
||||
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
describe('SubmissionImportExternalCollectionComponent test suite', () => {
|
||||
let comp: SubmissionImportExternalCollectionComponent;
|
||||
let compAsAny: any;
|
||||
let fixture: ComponentFixture<SubmissionImportExternalCollectionComponent>;
|
||||
|
||||
beforeEach(async (() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
declarations: [
|
||||
SubmissionImportExternalCollectionComponent,
|
||||
TestComponent,
|
||||
],
|
||||
providers: [
|
||||
NgbActiveModal,
|
||||
SubmissionImportExternalCollectionComponent
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents().then();
|
||||
}));
|
||||
|
||||
// First test to check the correct component creation
|
||||
describe('', () => {
|
||||
let testComp: TestComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
|
||||
// synchronous beforeEach
|
||||
beforeEach(() => {
|
||||
const html = `
|
||||
<ds-submission-import-external-collection></ds-submission-import-external-collection>`;
|
||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||
testComp = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
testFixture.destroy();
|
||||
});
|
||||
|
||||
it('should create SubmissionImportExternalCollectionComponent', inject([SubmissionImportExternalCollectionComponent], (app: SubmissionImportExternalCollectionComponent) => {
|
||||
expect(app).toBeDefined();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SubmissionImportExternalCollectionComponent);
|
||||
comp = fixture.componentInstance;
|
||||
compAsAny = comp;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
});
|
||||
|
||||
it('The variable \'selectedEvent\' should be assigned', () => {
|
||||
const event = new EventEmitter<CollectionListEntry>();
|
||||
comp.selectObject(event);
|
||||
|
||||
expect(comp.selectedEvent).toEqual(event);
|
||||
});
|
||||
|
||||
it('The variable \'selectedEvent\' should be assigned', () => {
|
||||
spyOn(compAsAny.activeModal, 'dismiss');
|
||||
comp.closeCollectionModal();
|
||||
|
||||
expect(compAsAny.activeModal.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// declare a test component
|
||||
@Component({
|
||||
selector: 'ds-test-cmp',
|
||||
template: ``
|
||||
})
|
||||
class TestComponent {
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
import { Component, Output, EventEmitter } from '@angular/core';
|
||||
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
/**
|
||||
* Wrap component for 'ds-collection-dropdown'.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-import-external-collection',
|
||||
styleUrls: ['./submission-import-external-collection.component.scss'],
|
||||
templateUrl: './submission-import-external-collection.component.html'
|
||||
})
|
||||
export class SubmissionImportExternalCollectionComponent {
|
||||
/**
|
||||
* The event passed by 'ds-collection-dropdown'.
|
||||
*/
|
||||
@Output() public selectedEvent = new EventEmitter<CollectionListEntry>();
|
||||
|
||||
/**
|
||||
* Initialize the component variables.
|
||||
* @param {NgbActiveModal} activeModal
|
||||
*/
|
||||
constructor(
|
||||
private activeModal: NgbActiveModal
|
||||
) { }
|
||||
|
||||
/**
|
||||
* This method populates the 'selectedEvent' variable.
|
||||
*/
|
||||
public selectObject(event): void {
|
||||
this.selectedEvent.emit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method closes the modal.
|
||||
*/
|
||||
public closeCollectionModal(): void {
|
||||
this.activeModal.dismiss(false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<div class="modal-header">
|
||||
<h2>{{'submission.import-external.preview.title' | translate}}</h2>
|
||||
<button type="button" class="close"
|
||||
(click)="closeMetadataModal()" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>{{'submission.import-external.preview.subtitle' | translate}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngFor="let metadata of metadataList" class="row">
|
||||
<div class="col-md-12">
|
||||
<strong>{{'item.preview.' + metadata.key | translate}}</strong>
|
||||
<p>{{metadata.value.value}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button class="btn btn-success" (click)="import()" role="button">
|
||||
<i class="fa fa-file-import" aria-hidden="true"></i> {{'submission.import-external.preview.button.import' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,3 @@
|
||||
.close:focus {
|
||||
outline: none !important;
|
||||
}
|
@@ -0,0 +1,165 @@
|
||||
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { SubmissionImportExternalPreviewComponent } from './submission-import-external-preview.component';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { RouterStub } from '../../../shared/testing/router.stub';
|
||||
import { SubmissionService } from '../../submission.service';
|
||||
import { createTestComponent } from '../../../shared/testing/utils.test';
|
||||
import { SubmissionServiceStub } from '../../../shared/testing/submission-service.stub';
|
||||
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
|
||||
import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model';
|
||||
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||
import { SubmissionImportExternalCollectionComponent } from '../import-external-collection/submission-import-external-collection.component';
|
||||
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
|
||||
|
||||
describe('SubmissionImportExternalPreviewComponent test suite', () => {
|
||||
let comp: SubmissionImportExternalPreviewComponent;
|
||||
let compAsAny: any;
|
||||
let fixture: ComponentFixture<SubmissionImportExternalPreviewComponent>;
|
||||
let submissionServiceStub: SubmissionServiceStub;
|
||||
let scheduler: TestScheduler;
|
||||
const ngbActiveModal = jasmine.createSpyObj('modal', ['close', 'dismiss']);
|
||||
const ngbModal = jasmine.createSpyObj('modal', ['open']);
|
||||
const externalEntry = Object.assign(new ExternalSourceEntry(), {
|
||||
id: '0001-0001-0001-0001',
|
||||
display: 'John Doe',
|
||||
value: 'John, Doe',
|
||||
metadata: {
|
||||
'dc.identifier.uri': [
|
||||
{
|
||||
value: 'https://orcid.org/0001-0001-0001-0001'
|
||||
}
|
||||
]
|
||||
},
|
||||
_links: { self: { href: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004' } }
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
scheduler = getTestScheduler();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
SubmissionImportExternalPreviewComponent,
|
||||
TestComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: Router, useValue: new RouterStub() },
|
||||
{ provide: SubmissionService, useValue: new SubmissionServiceStub() },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
||||
{ provide: NgbModal, useValue: ngbModal },
|
||||
{ provide: NgbActiveModal, useValue: ngbActiveModal },
|
||||
SubmissionImportExternalPreviewComponent
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents().then();
|
||||
}));
|
||||
|
||||
// First test to check the correct component creation
|
||||
describe('', () => {
|
||||
let testComp: TestComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
|
||||
// synchronous beforeEach
|
||||
beforeEach(() => {
|
||||
const html = `
|
||||
<ds-submission-import-external-preview></ds-submission-import-external-preview>`;
|
||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||
testComp = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
testFixture.destroy();
|
||||
});
|
||||
|
||||
it('should create SubmissionImportExternalPreviewComponent', inject([SubmissionImportExternalPreviewComponent], (app: SubmissionImportExternalPreviewComponent) => {
|
||||
expect(app).toBeDefined();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SubmissionImportExternalPreviewComponent);
|
||||
comp = fixture.componentInstance;
|
||||
compAsAny = comp;
|
||||
submissionServiceStub = TestBed.get(SubmissionService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
});
|
||||
|
||||
it('Should init component properly', () => {
|
||||
comp.externalSourceEntry = externalEntry;
|
||||
const expected = [
|
||||
{ key: 'dc.identifier.uri', value: Metadata.first(comp.externalSourceEntry.metadata, 'dc.identifier.uri') }
|
||||
];
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(comp.metadataList).toEqual(expected);
|
||||
});
|
||||
|
||||
it('Should close the modal calling \'activeModal.dismiss\'', () => {
|
||||
comp.modalRef = jasmine.createSpyObj('modal', ['close', 'dismiss']);
|
||||
comp.closeMetadataModal();
|
||||
|
||||
expect(compAsAny.activeModal.dismiss).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should start the import process opening a modal', (done) => {
|
||||
const emittedEvent: CollectionListEntry = {
|
||||
communities: [
|
||||
{
|
||||
id: 'dummy',
|
||||
uuid: 'dummy',
|
||||
name: 'dummy',
|
||||
}
|
||||
],
|
||||
collection: {
|
||||
id: 'ce64f48e-2c9b-411a-ac36-ee429c0e6a88',
|
||||
uuid: 'ce64f48e-2c9b-411a-ac36-ee429c0e6a88',
|
||||
name: 'Collection 1',
|
||||
}
|
||||
};
|
||||
const submissionObjects = [
|
||||
{ id: 'jk11k13o-9v4z-632i-sr88-wq071n0h1d47' }
|
||||
];
|
||||
comp.externalSourceEntry = externalEntry;
|
||||
ngbModal.open.and.returnValue({
|
||||
componentInstance: { selectedEvent: observableOf(emittedEvent) },
|
||||
close: () => {
|
||||
return;
|
||||
}
|
||||
});
|
||||
spyOn(comp, 'closeMetadataModal');
|
||||
submissionServiceStub.createSubmissionFromExternalSource.and.returnValue(observableOf(submissionObjects));
|
||||
spyOn(compAsAny.router, 'navigateByUrl');
|
||||
scheduler.schedule(() => comp.import());
|
||||
scheduler.flush();
|
||||
|
||||
expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalCollectionComponent, { size: 'lg' });
|
||||
expect(comp.closeMetadataModal).toHaveBeenCalled();
|
||||
expect(compAsAny.submissionService.createSubmissionFromExternalSource).toHaveBeenCalledWith(externalEntry._links.self.href, emittedEvent.collection.id);
|
||||
expect(compAsAny.router.navigateByUrl).toHaveBeenCalledWith('/workspaceitems/' + submissionObjects[0].id + '/edit');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// declare a test component
|
||||
@Component({
|
||||
selector: 'ds-test-cmp',
|
||||
template: ``
|
||||
})
|
||||
class TestComponent {
|
||||
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgbActiveModal, NgbModalRef, NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ExternalSourceEntry } from '../../../core/shared/external-source-entry.model';
|
||||
import { MetadataValue } from '../../../core/shared/metadata.models';
|
||||
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||
import { CollectionListEntry } from '../../../shared/collection-dropdown/collection-dropdown.component';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
import { SubmissionService } from '../../submission.service';
|
||||
import { SubmissionObject } from '../../../core/submission/models/submission-object.model';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { SubmissionImportExternalCollectionComponent } from '../import-external-collection/submission-import-external-collection.component';
|
||||
|
||||
/**
|
||||
* This component display a preview of an external source item.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-import-external-preview',
|
||||
styleUrls: ['./submission-import-external-preview.component.scss'],
|
||||
templateUrl: './submission-import-external-preview.component.html'
|
||||
})
|
||||
export class SubmissionImportExternalPreviewComponent implements OnInit {
|
||||
/**
|
||||
* The external source entry
|
||||
*/
|
||||
public externalSourceEntry: ExternalSourceEntry;
|
||||
/**
|
||||
* The entry metadata list
|
||||
*/
|
||||
public metadataList: Array<{ key: string, value: MetadataValue }>;
|
||||
/**
|
||||
* The modal for the entry preview
|
||||
*/
|
||||
modalRef: NgbModalRef;
|
||||
|
||||
/**
|
||||
* Initialize the component variables.
|
||||
* @param {NgbActiveModal} activeModal
|
||||
* @param {SubmissionService} submissionService
|
||||
* @param {NgbModal} modalService
|
||||
* @param {Router} router
|
||||
* @param {NotificationsService} notificationService
|
||||
*/
|
||||
constructor(
|
||||
private activeModal: NgbActiveModal,
|
||||
private submissionService: SubmissionService,
|
||||
private modalService: NgbModal,
|
||||
private router: Router,
|
||||
private notificationService: NotificationsService
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Metadata initialization for HTML display.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.metadataList = [];
|
||||
const metadataKeys = Object.keys(this.externalSourceEntry.metadata);
|
||||
metadataKeys.forEach((key) => {
|
||||
this.metadataList.push({
|
||||
key: key,
|
||||
value: Metadata.first(this.externalSourceEntry.metadata, key)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the modal.
|
||||
*/
|
||||
public closeMetadataModal(): void {
|
||||
this.activeModal.dismiss(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the import of an entry by opening up a collection choice modal window.
|
||||
*/
|
||||
public import(): void {
|
||||
this.modalRef = this.modalService.open(SubmissionImportExternalCollectionComponent, {
|
||||
size: 'lg',
|
||||
});
|
||||
this.closeMetadataModal();
|
||||
|
||||
this.modalRef.componentInstance.selectedEvent.pipe(
|
||||
mergeMap((collectionListEntry: CollectionListEntry) => {
|
||||
return this.submissionService.createSubmissionFromExternalSource(this.externalSourceEntry._links.self.href, collectionListEntry.collection.id);
|
||||
})
|
||||
).subscribe((submissionObjects: SubmissionObject[]) => {
|
||||
let isValid = false
|
||||
if (submissionObjects.length === 1) {
|
||||
if (submissionObjects[0] !== null) {
|
||||
isValid = true;
|
||||
this.router.navigateByUrl('/workspaceitems/' + submissionObjects[0].id + '/edit');
|
||||
}
|
||||
}
|
||||
if (!isValid) {
|
||||
this.notificationService.error('submission.import-external.preview.error.import.title', 'submission.import-external.preview.error.import.body');
|
||||
}
|
||||
this.modalRef.close();
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<div *ngIf="(isXsOrSm$ | async)" class="input-group mb-2">
|
||||
<input type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' |translate}}" aria-label="" aria-describedby="">
|
||||
</div>
|
||||
<div class="input-group mb-5">
|
||||
<input *ngIf="!(isXsOrSm$ | async)" type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' |translate}}" aria-label="" aria-describedby="">
|
||||
<div [ngClass]="{'input-group-append': !(isXsOrSm$ | async)}" ngbDropdown role="group" aria-label="">
|
||||
<button class="btn btn-outline-secondary w-fx" title="{{'submission.import-external.search.source.hint' |translate}}" ngbDropdownToggle>{{'submission.import-external.source.' + selectedElement?.name | translate}}</button>
|
||||
<div ngbDropdownMenu class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
aria-labelledby="scrollableDropdownMenuButton">
|
||||
<div class="scrollable-menu"
|
||||
aria-labelledby="scrollableDropdownMenuButton"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="2"
|
||||
[infiniteScrollThrottle]="50"
|
||||
(scrolled)="onScroll()"
|
||||
[scrollWindow]="false">
|
||||
<button ngbDropdownItem class="dropdown-item text-truncate" title="{{'submission.import-external.source.' + source?.name | translate}}" (click)="makeSourceSelection(source)" *ngFor="let source of sourceList">{{'submission.import-external.source.' + source?.name | translate}}</button>
|
||||
<div ngbDropdownItem class="scrollable-dropdown-loading text-center" *ngIf="sourceListLoading"><p>{{'submission.import-external.source.loading' | translate}}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" [title]="(searchString === '')?('submission.import-external.search.button.hint' | translate):('submission.import-external.search.button' | translate)" [disabled]="searchString === ''" (click)="search()">{{'submission.import-external.search.button' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,27 @@
|
||||
.input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle) {
|
||||
margin-left: -1px;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
}
|
||||
|
||||
.input-group-append .dropdown-toggle {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.w-fx {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.scrollable-menu {
|
||||
height: auto;
|
||||
max-height: $dropdown-menu-max-height;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.scrollable-dropdown-loading {
|
||||
background-color: map-get($theme-colors, primary);
|
||||
color: white;
|
||||
height: $spacer * 2 !important;
|
||||
line-height: $spacer * 2;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
import { Component, NO_ERRORS_SCHEMA, ChangeDetectorRef } from '@angular/core';
|
||||
import { async, TestBed, ComponentFixture, inject, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { SubmissionImportExternalSearchbarComponent, SourceElement } from './submission-import-external-searchbar.component';
|
||||
import { ExternalSourceService } from '../../../core/data/external-source.service';
|
||||
import { createTestComponent } from '../../../shared/testing/utils.test';
|
||||
import { getMockExternalSourceService, externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb } from '../../../shared/mocks/external-source.service.mock';
|
||||
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
|
||||
import { ExternalSource } from '../../../core/shared/external-source.model';
|
||||
import { FindListOptions } from '../../../core/data/request.models';
|
||||
import { HostWindowService } from '../../../shared/host-window.service';
|
||||
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
describe('SubmissionImportExternalSearchbarComponent test suite', () => {
|
||||
let comp: SubmissionImportExternalSearchbarComponent;
|
||||
let compAsAny: any;
|
||||
let fixture: ComponentFixture<SubmissionImportExternalSearchbarComponent>;
|
||||
let scheduler: TestScheduler;
|
||||
|
||||
beforeEach(async (() => {
|
||||
scheduler = getTestScheduler();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
declarations: [
|
||||
SubmissionImportExternalSearchbarComponent,
|
||||
TestComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ExternalSourceService, useClass: getMockExternalSourceService },
|
||||
ChangeDetectorRef,
|
||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
|
||||
SubmissionImportExternalSearchbarComponent
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents().then();
|
||||
}));
|
||||
|
||||
// First test to check the correct component creation
|
||||
describe('', () => {
|
||||
let testComp: TestComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
|
||||
// synchronous beforeEach
|
||||
beforeEach(() => {
|
||||
const html = `
|
||||
<ds-submission-import-external-searchbar></ds-submission-import-external-searchbar>`;
|
||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||
testComp = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
testFixture.destroy();
|
||||
});
|
||||
|
||||
it('should create SubmissionImportExternalSearchbarComponent', inject([SubmissionImportExternalSearchbarComponent], (app: SubmissionImportExternalSearchbarComponent) => {
|
||||
expect(app).toBeDefined();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('', () => {
|
||||
let sourceList: SourceElement[];
|
||||
let paginatedList: PaginatedList<ExternalSource>;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SubmissionImportExternalSearchbarComponent);
|
||||
comp = fixture.componentInstance;
|
||||
compAsAny = comp;
|
||||
const pageInfo = new PageInfo();
|
||||
paginatedList = new PaginatedList(pageInfo, [externalSourceOrcid, externalSourceCiencia, externalSourceMyStaffDb]);
|
||||
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
|
||||
compAsAny.externalService.findAll.and.returnValue(observableOf(paginatedListRD));
|
||||
sourceList = [
|
||||
{id: 'orcid', name: 'orcid'},
|
||||
{id: 'ciencia', name: 'ciencia'},
|
||||
{id: 'my_staff_db', name: 'my_staff_db'},
|
||||
];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
});
|
||||
|
||||
it('Should init component properly (without initExternalSourceData)', () => {
|
||||
comp.initExternalSourceData = { sourceId: '', query: '' };
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.flush();
|
||||
|
||||
expect(comp.selectedElement).toEqual(sourceList[0]);
|
||||
expect(compAsAny.pageInfo).toEqual(paginatedList.pageInfo);
|
||||
expect(comp.sourceList).toEqual(sourceList);
|
||||
});
|
||||
|
||||
it('Should init component properly (with initExternalSourceData populated)', () => {
|
||||
comp.initExternalSourceData = { query: 'dummy', sourceId: 'ciencia' };
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.flush();
|
||||
|
||||
expect(comp.selectedElement).toEqual(sourceList[1]);
|
||||
expect(compAsAny.pageInfo).toEqual(paginatedList.pageInfo);
|
||||
expect(comp.sourceList).toEqual(sourceList);
|
||||
});
|
||||
|
||||
it('Variable \'selectedElement\' should be assigned', () => {
|
||||
const selectedElement = {id: 'orcid', name: 'orcid'};
|
||||
comp.makeSourceSelection(selectedElement);
|
||||
expect(comp.selectedElement).toEqual(selectedElement);
|
||||
});
|
||||
|
||||
it('Should load additional external sources', () => {
|
||||
comp.sourceListLoading = false;
|
||||
compAsAny.pageInfo = new PageInfo({
|
||||
elementsPerPage: 3,
|
||||
totalElements: 6,
|
||||
totalPages: 2,
|
||||
currentPage: 0
|
||||
});
|
||||
compAsAny.findListOptions = Object.assign({}, new FindListOptions(), {
|
||||
elementsPerPage: 3,
|
||||
currentPage: 0,
|
||||
});
|
||||
comp.sourceList = sourceList;
|
||||
const expected = sourceList.concat(sourceList);
|
||||
|
||||
scheduler.schedule(() => comp.onScroll());
|
||||
scheduler.flush();
|
||||
|
||||
expect(comp.sourceList).toEqual(expected);
|
||||
});
|
||||
|
||||
it('The \'search\' method should call \'emit\'', () => {
|
||||
comp.selectedElement = { id: 'orcidV2', name: 'orcidV2' };
|
||||
comp.searchString = 'dummy';
|
||||
const expected = { sourceId: comp.selectedElement.id, query: comp.searchString };
|
||||
spyOn(comp.externalSourceData, 'emit');
|
||||
comp.search();
|
||||
|
||||
expect(comp.externalSourceData.emit).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// declare a test component
|
||||
@Component({
|
||||
selector: 'ds-test-cmp',
|
||||
template: ``
|
||||
})
|
||||
class TestComponent {
|
||||
|
||||
}
|
@@ -0,0 +1,172 @@
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
|
||||
import { of as observableOf, Observable } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
|
||||
import { ExternalSourceService } from '../../../core/data/external-source.service';
|
||||
import { ExternalSource } from '../../../core/shared/external-source.model';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
|
||||
import { FindListOptions } from '../../../core/data/request.models';
|
||||
import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
|
||||
import { HostWindowService } from '../../../shared/host-window.service';
|
||||
|
||||
/**
|
||||
* Interface for the selected external source element.
|
||||
*/
|
||||
export interface SourceElement {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the external source data to export.
|
||||
*/
|
||||
export interface ExternalSourceData {
|
||||
query: string;
|
||||
sourceId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This component builds the searchbar for the submission external import.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-import-external-searchbar',
|
||||
styleUrls: ['./submission-import-external-searchbar.component.scss'],
|
||||
templateUrl: './submission-import-external-searchbar.component.html'
|
||||
})
|
||||
export class SubmissionImportExternalSearchbarComponent implements OnInit {
|
||||
/**
|
||||
* The init external source value.
|
||||
*/
|
||||
@Input() public initExternalSourceData: ExternalSourceData;
|
||||
/**
|
||||
* The selected external sources.
|
||||
*/
|
||||
public selectedElement: SourceElement;
|
||||
/**
|
||||
* The list of external sources.
|
||||
*/
|
||||
public sourceList: SourceElement[];
|
||||
/**
|
||||
* The string used to search items in the external sources.
|
||||
*/
|
||||
public searchString: string;
|
||||
/**
|
||||
* The external sources loading status.
|
||||
*/
|
||||
public sourceListLoading = false;
|
||||
/**
|
||||
* Emits true if were on a small screen
|
||||
*/
|
||||
public isXsOrSm$: Observable<boolean>;
|
||||
/**
|
||||
* The external source data to use to perform the search.
|
||||
*/
|
||||
@Output() public externalSourceData: EventEmitter<ExternalSourceData> = new EventEmitter<ExternalSourceData>();
|
||||
|
||||
/**
|
||||
* The external sources pagination data.
|
||||
*/
|
||||
protected pageInfo: PageInfo;
|
||||
/**
|
||||
* The options for REST data retireval.
|
||||
*/
|
||||
protected findListOptions: FindListOptions;
|
||||
|
||||
/**
|
||||
* Initialize the component variables.
|
||||
* @param {ExternalSourceService} externalService
|
||||
* @param {ChangeDetectorRef} cdr
|
||||
* @param {HostWindowService} windowService
|
||||
*/
|
||||
constructor(
|
||||
private externalService: ExternalSourceService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected windowService: HostWindowService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Component initialization and retrieve first page of external sources.
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.selectedElement = {
|
||||
id: '',
|
||||
name: 'loading'
|
||||
};
|
||||
this.searchString = '';
|
||||
this.sourceList = [];
|
||||
this.findListOptions = Object.assign({}, new FindListOptions(), {
|
||||
elementsPerPage: 5,
|
||||
currentPage: 0,
|
||||
});
|
||||
this.externalService.findAll(this.findListOptions).pipe(
|
||||
catchError(() => {
|
||||
const pageInfo = new PageInfo();
|
||||
const paginatedList = new PaginatedList(pageInfo, []);
|
||||
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
|
||||
return observableOf(paginatedListRD);
|
||||
}),
|
||||
getFirstSucceededRemoteDataPayload()
|
||||
).subscribe((externalSource: PaginatedList<ExternalSource>) => {
|
||||
externalSource.page.forEach((element) => {
|
||||
this.sourceList.push({ id: element.id, name: element.name });
|
||||
if (this.initExternalSourceData.sourceId === element.id) {
|
||||
this.selectedElement = { id: element.id, name: element.name };
|
||||
this.searchString = this.initExternalSourceData.query;
|
||||
}
|
||||
});
|
||||
if (this.selectedElement.id === '') {
|
||||
this.selectedElement = this.sourceList[0];
|
||||
}
|
||||
this.pageInfo = externalSource.pageInfo;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected external source.
|
||||
*/
|
||||
public makeSourceSelection(source): void {
|
||||
this.selectedElement = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the next pages of external sources.
|
||||
*/
|
||||
public onScroll(): void {
|
||||
if (!this.sourceListLoading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
|
||||
this.sourceListLoading = true;
|
||||
this.findListOptions = Object.assign({}, new FindListOptions(), {
|
||||
elementsPerPage: 5,
|
||||
currentPage: this.findListOptions.currentPage + 1,
|
||||
});
|
||||
this.externalService.findAll(this.findListOptions).pipe(
|
||||
catchError(() => {
|
||||
const pageInfo = new PageInfo();
|
||||
const paginatedList = new PaginatedList(pageInfo, []);
|
||||
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
|
||||
return observableOf(paginatedListRD);
|
||||
}),
|
||||
tap(() => this.sourceListLoading = false)
|
||||
).subscribe((externalSource: RemoteData<PaginatedList<ExternalSource>>) => {
|
||||
externalSource.payload.page.forEach((element) => {
|
||||
this.sourceList.push({ id: element.id, name: element.name });
|
||||
})
|
||||
this.pageInfo = externalSource.payload.pageInfo;
|
||||
this.cdr.detectChanges();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes the search parameters to the parent component.
|
||||
*/
|
||||
public search(): void {
|
||||
this.externalSourceData.emit({ sourceId: this.selectedElement.id, query: this.searchString });
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2 id="header" class="pb-2">{{'submission.import-external.title' | translate}}</h2>
|
||||
<ds-submission-import-external-searchbar
|
||||
[initExternalSourceData]="routeData"
|
||||
(externalSourceData) = "getExternalsourceData($event)">
|
||||
</ds-submission-import-external-searchbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div *ngIf="routeData.sourceId !== ''" class="col-md-12">
|
||||
<ng-container *ngVar="(entriesRD$ | async) as entriesRD">
|
||||
<h3 *ngIf="entriesRD?.payload?.page?.length !== 0">{{ 'submission.sections.describe.relationship-lookup.selection-tab.title.' + routeData.sourceId | translate}}</h3>
|
||||
<ds-viewable-collection *ngIf="entriesRD?.hasSucceeded && !(isLoading$ | async) && entriesRD?.payload?.page?.length > 0" @fadeIn
|
||||
[objects]="entriesRD"
|
||||
[selectionConfig]="{ repeatable: repeatable, listId: listId }"
|
||||
[config]="initialPagination"
|
||||
[hideGear]="true"
|
||||
[context]="context"
|
||||
[importable]="true"
|
||||
[importConfig]="importConfig"
|
||||
(importObject)="import($event)">
|
||||
</ds-viewable-collection>
|
||||
<ds-loading *ngIf="(isLoading$ | async)"
|
||||
message="{{'loading.search-results' | translate}}"></ds-loading>
|
||||
<div *ngIf="!(isLoading$ | async) && entriesRD?.payload?.page?.length === 0" id="empty-external-entry-list">
|
||||
{{ 'search.results.empty' | translate }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div *ngIf="routeData.sourceId === ''" class="col-md-12">
|
||||
<ds-alert [type]="'alert-info'">
|
||||
<p class="lead mb-0">{{'submission.import-external.page.hint' | translate}}</p>
|
||||
</ds-alert>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<hr>
|
||||
<a class="btn btn-outline-secondary" [routerLink]="['/mydspace']" role="button">
|
||||
<i class="fa fa-chevron-left" aria-hidden="true"></i> {{'submission.import-external.back-to-my-dspace' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,158 @@
|
||||
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { async, TestBed, ComponentFixture, inject } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { of as observableOf, of } from 'rxjs/internal/observable/of';
|
||||
import { SubmissionImportExternalComponent } from './submission-import-external.component';
|
||||
import { ExternalSourceService } from '../../core/data/external-source.service';
|
||||
import { getMockExternalSourceService } from '../../shared/mocks/external-source.service.mock';
|
||||
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { createTestComponent, createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { RouterStub } from '../../shared/testing/router.stub';
|
||||
import { VarDirective } from '../../shared/utils/var.directive';
|
||||
import { routeServiceStub } from '../../shared/testing/route-service.stub';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||
import { ExternalSourceEntry } from '../../core/shared/external-source-entry.model';
|
||||
import { SubmissionImportExternalPreviewComponent } from './import-external-preview/submission-import-external-preview.component';
|
||||
|
||||
describe('SubmissionImportExternalComponent test suite', () => {
|
||||
let comp: SubmissionImportExternalComponent;
|
||||
let compAsAny: any;
|
||||
let fixture: ComponentFixture<SubmissionImportExternalComponent>;
|
||||
const ngbModal = jasmine.createSpyObj('modal', ['open']);
|
||||
const mockSearchOptions = of(new PaginatedSearchOptions({
|
||||
pagination: Object.assign(new PaginationComponentOptions(), {
|
||||
pageSize: 10,
|
||||
currentPage: 0
|
||||
})
|
||||
}));
|
||||
const searchConfigServiceStub = {
|
||||
paginatedSearchOptions: mockSearchOptions
|
||||
};
|
||||
|
||||
beforeEach(async (() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
SubmissionImportExternalComponent,
|
||||
TestComponent,
|
||||
VarDirective
|
||||
],
|
||||
providers: [
|
||||
{ provide: ExternalSourceService, useClass: getMockExternalSourceService },
|
||||
{ provide: SearchConfigurationService, useValue: searchConfigServiceStub },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{ provide: Router, useValue: new RouterStub() },
|
||||
{ provide: NgbModal, useValue: ngbModal },
|
||||
SubmissionImportExternalComponent
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents().then();
|
||||
}));
|
||||
|
||||
// First test to check the correct component creation
|
||||
describe('', () => {
|
||||
let testComp: TestComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
|
||||
// synchronous beforeEach
|
||||
beforeEach(() => {
|
||||
const html = `
|
||||
<ds-submission-import-external></ds-submission-import-external>`;
|
||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||
testComp = testFixture.componentInstance;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
testFixture.destroy();
|
||||
});
|
||||
|
||||
it('should create SubmissionImportExternalComponent', inject([SubmissionImportExternalComponent], (app: SubmissionImportExternalComponent) => {
|
||||
expect(app).toBeDefined();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SubmissionImportExternalComponent);
|
||||
comp = fixture.componentInstance;
|
||||
compAsAny = comp;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
comp = null;
|
||||
compAsAny = null;
|
||||
});
|
||||
|
||||
it('Should init component properly (without route data)', () => {
|
||||
const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([]));
|
||||
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf(''));
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(comp.routeData).toEqual({ sourceId: '', query: '' });
|
||||
expect(comp.isLoading$.value).toBe(false);
|
||||
expect(comp.entriesRD$.value).toEqual(expectedEntries);
|
||||
});
|
||||
|
||||
it('Should init component properly (with route data)', () => {
|
||||
const expectedEntries = createSuccessfulRemoteDataObject(createPaginatedList([]));
|
||||
const searchOptions = new PaginatedSearchOptions({
|
||||
pagination: Object.assign(new PaginationComponentOptions(), {
|
||||
pageSize: 10,
|
||||
currentPage: 0
|
||||
})
|
||||
});
|
||||
spyOn(compAsAny.routeService, 'getQueryParameterValue').and.returnValue(observableOf('dummy'));
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(comp.routeData).toEqual({ sourceId: 'dummy', query: 'dummy' });
|
||||
expect(comp.isLoading$.value).toBe(true);
|
||||
expect(comp.entriesRD$.value).toEqual(expectedEntries);
|
||||
expect(compAsAny.externalService.getExternalSourceEntries).toHaveBeenCalledWith('dummy', searchOptions);
|
||||
});
|
||||
|
||||
it('Should call \'router.navigate\'', () => {
|
||||
const event = { sourceId: 'orcidV2', query: 'dummy' };
|
||||
comp.getExternalsourceData(event);
|
||||
|
||||
expect(compAsAny.router.navigate).toHaveBeenCalledWith([], { queryParams: { source: event.sourceId, query: event.query }, replaceUrl: true });
|
||||
});
|
||||
|
||||
it('Entry should be passed to the component loaded inside the modal', () => {
|
||||
const entry = Object.assign(new ExternalSourceEntry(), {
|
||||
id: '0001-0001-0001-0001',
|
||||
display: 'John Doe',
|
||||
value: 'John, Doe',
|
||||
metadata: {
|
||||
'dc.identifier.uri': [
|
||||
{
|
||||
value: 'https://orcid.org/0001-0001-0001-0001'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
ngbModal.open.and.returnValue({componentInstance: { externalSourceEntry: null}});
|
||||
comp.import(entry);
|
||||
|
||||
expect(compAsAny.modalService.open).toHaveBeenCalledWith(SubmissionImportExternalPreviewComponent, { size: 'lg' });
|
||||
expect(comp.modalRef.componentInstance.externalSourceEntry).toEqual(entry);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// declare a test component
|
||||
@Component({
|
||||
selector: 'ds-test-cmp',
|
||||
template: ``
|
||||
})
|
||||
class TestComponent {
|
||||
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { combineLatest, BehaviorSubject } from 'rxjs';
|
||||
import { ExternalSourceService } from '../../core/data/external-source.service';
|
||||
import { ExternalSourceData } from './import-external-searchbar/submission-import-external-searchbar.component';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { ExternalSourceEntry } from '../../core/shared/external-source-entry.model';
|
||||
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
|
||||
import { switchMap, filter, take } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { Context } from '../../core/shared/context.model';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { SubmissionImportExternalPreviewComponent } from './import-external-preview/submission-import-external-preview.component';
|
||||
import { fadeIn } from '../../shared/animations/fade';
|
||||
import { PageInfo } from '../../core/shared/page-info.model';
|
||||
|
||||
/**
|
||||
* This component allows to submit a new workspaceitem importing the data from an external source.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-submission-import-external',
|
||||
styleUrls: ['./submission-import-external.component.scss'],
|
||||
templateUrl: './submission-import-external.component.html',
|
||||
animations: [ fadeIn ]
|
||||
})
|
||||
export class SubmissionImportExternalComponent implements OnInit {
|
||||
/**
|
||||
* The external source search data from the routing service.
|
||||
*/
|
||||
public routeData: ExternalSourceData;
|
||||
/**
|
||||
* The displayed list of entries
|
||||
*/
|
||||
public entriesRD$: BehaviorSubject<RemoteData<PaginatedList<ExternalSourceEntry>>>;
|
||||
/**
|
||||
* TRUE if the REST service is called to retrieve the external source items
|
||||
*/
|
||||
public isLoading$: BehaviorSubject<boolean>;
|
||||
/**
|
||||
* Configuration to use for the import buttons
|
||||
*/
|
||||
public importConfig: { buttonLabel: string };
|
||||
/**
|
||||
* Suffix for button label
|
||||
*/
|
||||
public label: string;
|
||||
/**
|
||||
* The ID of the list to add/remove selected items to/from
|
||||
*/
|
||||
public listId: string;
|
||||
/**
|
||||
* TRUE if the selection is repeatable
|
||||
*/
|
||||
public repeatable: boolean;
|
||||
/**
|
||||
* The initial pagination options
|
||||
*/
|
||||
public initialPagination = Object.assign(new PaginationComponentOptions(), {
|
||||
id: 'submission-external-source-relation-list',
|
||||
pageSize: 5
|
||||
});
|
||||
/**
|
||||
* The context to displaying lists for
|
||||
*/
|
||||
public context: Context;
|
||||
/**
|
||||
* The modal for the entry preview
|
||||
*/
|
||||
public modalRef: NgbModalRef;
|
||||
|
||||
/**
|
||||
* Initialize the component variables.
|
||||
* @param {SearchConfigurationService} searchConfigService
|
||||
* @param {ExternalSourceService} externalService
|
||||
* @param {RouteService} routeService
|
||||
* @param {Router} router
|
||||
* @param {NgbModal} modalService
|
||||
*/
|
||||
constructor(
|
||||
public searchConfigService: SearchConfigurationService,
|
||||
private externalService: ExternalSourceService,
|
||||
private routeService: RouteService,
|
||||
private router: Router,
|
||||
private modalService: NgbModal,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the entries for the selected external source and set initial configuration.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.label = 'Journal';
|
||||
this.listId = 'list-submission-external-sources';
|
||||
this.context = Context.EntitySearchModalWithNameVariants;
|
||||
this.repeatable = false;
|
||||
this.routeData = { sourceId: '', query: '' };
|
||||
this.importConfig = {
|
||||
buttonLabel: 'submission.sections.describe.relationship-lookup.external-source.import-button-title.' + this.label
|
||||
};
|
||||
this.entriesRD$ = new BehaviorSubject(createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [])));
|
||||
this.isLoading$ = new BehaviorSubject(false);
|
||||
combineLatest(
|
||||
[
|
||||
this.routeService.getQueryParameterValue('source'),
|
||||
this.routeService.getQueryParameterValue('query')
|
||||
]).pipe(
|
||||
filter(([source, query]) => source && query && source !== '' && query !== ''),
|
||||
filter(([source, query]) => source !== this.routeData.sourceId || query !== this.routeData.query),
|
||||
switchMap(([source, query]) => {
|
||||
this.routeData.sourceId = source;
|
||||
this.routeData.query = query;
|
||||
this.isLoading$.next(true);
|
||||
return this.searchConfigService.paginatedSearchOptions.pipe(
|
||||
switchMap((searchOptions: PaginatedSearchOptions) => {
|
||||
return this.externalService.getExternalSourceEntries(this.routeData.sourceId, searchOptions);
|
||||
}),
|
||||
take(1)
|
||||
)
|
||||
}),
|
||||
).subscribe((rdData) => {
|
||||
this.entriesRD$.next(rdData);
|
||||
this.isLoading$.next(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data from the searchbar and changes the router data.
|
||||
*/
|
||||
public getExternalsourceData(event: ExternalSourceData): void {
|
||||
this.router.navigate(
|
||||
[],
|
||||
{
|
||||
queryParams: { source: event.sourceId, query: event.query },
|
||||
replaceUrl: true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an item preview by opening up an import modal window.
|
||||
* @param entry The entry to import
|
||||
*/
|
||||
public import(entry): void {
|
||||
this.modalRef = this.modalService.open(SubmissionImportExternalPreviewComponent, {
|
||||
size: 'lg',
|
||||
});
|
||||
const modalComp = this.modalRef.componentInstance;
|
||||
modalComp.externalSourceEntry = entry;
|
||||
}
|
||||
}
|
@@ -28,6 +28,10 @@ import { SubmissionSectionUploadFileViewComponent } from './sections/upload/file
|
||||
import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upload/accessConditions/submission-section-upload-access-conditions.component';
|
||||
import { SubmissionSubmitComponent } from './submit/submission-submit.component';
|
||||
import { storeModuleConfig } from '../app.reducer';
|
||||
import { SubmissionImportExternalComponent } from './import-external/submission-import-external.component';
|
||||
import { SubmissionImportExternalSearchbarComponent } from './import-external/import-external-searchbar/submission-import-external-searchbar.component';
|
||||
import { SubmissionImportExternalPreviewComponent } from './import-external/import-external-preview/submission-import-external-preview.component';
|
||||
import { SubmissionImportExternalCollectionComponent } from './import-external/import-external-collection/submission-import-external-collection.component';
|
||||
import { SubmissionSectionCcLicensesComponent } from './sections/cc-license/submission-section-cc-licenses.component';
|
||||
|
||||
@NgModule({
|
||||
@@ -56,19 +60,26 @@ import { SubmissionSectionCcLicensesComponent } from './sections/cc-license/subm
|
||||
SubmissionSectionContainerComponent,
|
||||
SubmissionSectionUploadFileComponent,
|
||||
SubmissionSectionUploadFileEditComponent,
|
||||
SubmissionSectionUploadFileViewComponent
|
||||
SubmissionSectionUploadFileViewComponent,
|
||||
SubmissionImportExternalComponent,
|
||||
SubmissionImportExternalSearchbarComponent,
|
||||
SubmissionImportExternalPreviewComponent,
|
||||
SubmissionImportExternalCollectionComponent
|
||||
],
|
||||
entryComponents: [
|
||||
SubmissionSectionUploadComponent,
|
||||
SubmissionSectionformComponent,
|
||||
SubmissionSectionLicenseComponent,
|
||||
SubmissionSectionContainerComponent,
|
||||
SubmissionSectionCcLicensesComponent,
|
||||
SubmissionImportExternalPreviewComponent,
|
||||
SubmissionImportExternalCollectionComponent,
|
||||
SubmissionSectionCcLicensesComponent
|
||||
],
|
||||
exports: [
|
||||
SubmissionEditComponent,
|
||||
SubmissionFormComponent,
|
||||
SubmissionSubmitComponent
|
||||
SubmissionSubmitComponent,
|
||||
SubmissionImportExternalComponent
|
||||
],
|
||||
providers: [
|
||||
SectionUploadService,
|
||||
|
@@ -411,6 +411,19 @@ describe('SubmissionService test suite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSubmissionFromExternalSource', () => {
|
||||
it('should deposit submission', () => {
|
||||
const options: HttpOptions = Object.create({});
|
||||
let headers = new HttpHeaders();
|
||||
headers = headers.append('Content-Type', 'text/uri-list');
|
||||
options.headers = headers;
|
||||
|
||||
service.createSubmissionFromExternalSource(selfUrl, collectionId);
|
||||
|
||||
expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workspaceitems', selfUrl, null, options, collectionId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('depositSubmission', () => {
|
||||
it('should deposit submission', () => {
|
||||
const options: HttpOptions = Object.create({});
|
||||
|
@@ -114,6 +114,24 @@ export class SubmissionService {
|
||||
catchError(() => observableOf({} as SubmissionObject)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a REST call to deposit a workspaceitem and return response
|
||||
*
|
||||
* @param selfUrl
|
||||
* The workspaceitem self url
|
||||
* @param collectionId
|
||||
* Optional collection id
|
||||
* @return Observable<SubmissionObject>
|
||||
* observable of SubmissionObject
|
||||
*/
|
||||
createSubmissionFromExternalSource(selfUrl: string, collectionId?: string): Observable<SubmissionObject[]> {
|
||||
const options: HttpOptions = Object.create({});
|
||||
let headers = new HttpHeaders();
|
||||
headers = headers.append('Content-Type', 'text/uri-list');
|
||||
options.headers = headers;
|
||||
return this.restService.postToEndpoint(this.workspaceLinkPath, selfUrl, null, options, collectionId) as Observable<SubmissionObject[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a REST call to deposit a workspaceitem and return response
|
||||
*
|
||||
|
@@ -1606,6 +1606,28 @@
|
||||
|
||||
"item.page.filesection.license.bundle" : "License bundle",
|
||||
|
||||
"item.preview.dc.identifier.uri": "Identifier:",
|
||||
|
||||
"item.preview.dc.contributor.author": "Authors:",
|
||||
|
||||
"item.preview.dc.date.issued": "Published date:",
|
||||
|
||||
"item.preview.dc.description.abstract": "Abstract:",
|
||||
|
||||
"item.preview.dc.identifier.other": "Other identifier:",
|
||||
|
||||
"item.preview.dc.language.iso": "Language:",
|
||||
|
||||
"item.preview.dc.subject": "Subjects:",
|
||||
|
||||
"item.preview.dc.title": "Title:",
|
||||
|
||||
"item.preview.person.familyName": "Surname:",
|
||||
|
||||
"item.preview.person.givenName": "Name:",
|
||||
|
||||
"item.preview.person.identifier.orcid": "ORCID:",
|
||||
|
||||
|
||||
"item.select.confirm": "Confirm selected",
|
||||
|
||||
@@ -1960,6 +1982,10 @@
|
||||
|
||||
"mydspace.new-submission": "New submission",
|
||||
|
||||
"mydspace.new-submission-external": "Import metadata from external source",
|
||||
|
||||
"mydspace.new-submission-external-short": "Import metadata",
|
||||
|
||||
"mydspace.results.head": "Your submissions",
|
||||
|
||||
"mydspace.results.no-abstract": "No Abstract",
|
||||
@@ -2748,6 +2774,43 @@
|
||||
"submission.general.save-later": "Save for later",
|
||||
|
||||
|
||||
"submission.import-external.page.title": "Import metadata from an external source",
|
||||
|
||||
"submission.import-external.title": "Import metadata 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.back-to-my-dspace": "Back to MyDSpace",
|
||||
|
||||
"submission.import-external.search.placeholder": "Search the external source",
|
||||
|
||||
"submission.import-external.search.button": "Search",
|
||||
|
||||
"submission.import-external.search.button.hint": "Write some words to search",
|
||||
|
||||
"submission.import-external.search.source.hint": "Pick an external source",
|
||||
|
||||
"submission.import-external.source.loading": "Loading ...",
|
||||
|
||||
"submission.import-external.source.sherpaJournal": "SHERPA Journals",
|
||||
|
||||
"submission.import-external.source.sherpaPublisher": "SHERPA Publishers",
|
||||
|
||||
"submission.import-external.source.orcidV2": "ORCID",
|
||||
|
||||
"submission.import-external.source.pubmed": "Pubmed",
|
||||
|
||||
"submission.import-external.source.lcname": "Library of Congress Names",
|
||||
|
||||
"submission.import-external.preview.title": "Item Preview",
|
||||
|
||||
"submission.import-external.preview.subtitle": "The metadata below was imported from an external source. It will be pre-filled when you start the submission.",
|
||||
|
||||
"submission.import-external.preview.button.import": "Start submission",
|
||||
|
||||
"submission.import-external.preview.error.import.title": "Submission error",
|
||||
|
||||
"submission.import-external.preview.error.import.body": "An error occurs during the external source entry import process.",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.close": "Close",
|
||||
|
||||
@@ -2889,8 +2952,12 @@
|
||||
|
||||
"submission.sections.describe.relationship-lookup.selection-tab.title.orcidV2": "Search Results",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Search Results",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Search Results",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Search Results",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.name-variant.notification.content": "Would you like to save \"{{ value }}\" as a name variant for this person so you and others can reuse it for future submissions? If you don\'t you can still use it for this submission.",
|
||||
|
||||
"submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Save a new name variant",
|
||||
|
Reference in New Issue
Block a user