mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Submission from an external source initial commit
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';
|
||||
|
||||
fdescribe('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, Injector, OnInit } 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 {
|
||||
|
||||
}
|
28
src/app/+import-external-page/import-external-page.module.ts
Normal file
28
src/app/+import-external-page/import-external-page.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
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 { SubmissionImportExternalComponent } from '../submission/import-external/submission-import-external.component';
|
||||
import { SubmissionImportExternalSearchbarComponent } from '../submission/import-external/import-external-searchbar/submission-import-external-searchbar.component';
|
||||
import { SubmissionModule } from '../submission/submission.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
CoreModule.forRoot(),
|
||||
ImportExternalRoutingModule,
|
||||
SubmissionModule,
|
||||
],
|
||||
declarations: [ ],
|
||||
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 {
|
||||
|
||||
}
|
@@ -10,6 +10,9 @@
|
||||
<a class="btn btn-lg btn-primary mt-1 ml-2" [routerLink]="['/submit']" role="button">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> {{'mydspace.new-submission' | translate}}
|
||||
</a>
|
||||
<a class="btn btn-lg btn-primary mt-1 ml-2" [routerLink]="['/import-external']" role="button">
|
||||
<i class="fa fa-file-import" aria-hidden="true"></i> {{'mydspace.new-submission-external' | translate}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@@ -86,6 +86,7 @@ export function getDSOPath(dso: DSpaceObject): string {
|
||||
{ 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'
|
||||
|
@@ -11,7 +11,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FindListOptions, GetRequest } from './request.models';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { distinctUntilChanged, map, switchMap } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, map, switchMap, take, flatMap } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||
import { hasValue, isNotEmptyOperator } from '../../shared/empty.util';
|
||||
import { configureRequest } from '../shared/operators';
|
||||
@@ -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
|
||||
@@ -59,6 +60,20 @@ export class ExternalSourceService extends DataService<ExternalSource> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of external sources.
|
||||
*
|
||||
* @param options
|
||||
* Find list options object.
|
||||
* @param linksToFollow
|
||||
* List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved.
|
||||
* @return Observable<RemoteData<PaginatedList<ExternalSource>>>
|
||||
* The list of the external sources.
|
||||
*/
|
||||
getAllExternalSources(options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<ExternalSource>>): Observable<RemoteData<PaginatedList<ExternalSource>>> {
|
||||
return this.findAll(options, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entries for an external source
|
||||
* @param externalSourceId The id of the external source to fetch entries for
|
||||
|
@@ -0,0 +1,24 @@
|
||||
<div class="input-group mb-5">
|
||||
<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 class="input-group-append">
|
||||
<div class="btn-group" 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-outline-secondary" [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>
|
||||
</div>
|
@@ -0,0 +1,12 @@
|
||||
.input-group-append .btn.btn {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.input-group-append .dropdown-toggle {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.w-fx {
|
||||
min-width: 200px;
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
import { Component, OnInit, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ExternalSourceService } from '../../../core/data/external-source.service';
|
||||
import { catchError, first, tap } from 'rxjs/operators';
|
||||
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';
|
||||
|
||||
/**
|
||||
* Interface for the selected external source element.
|
||||
*/
|
||||
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 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;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
constructor(
|
||||
private externalService: ExternalSourceService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Component intitialization and retireve first page of external sources.
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.searchString = '';
|
||||
this.selectedElement = {id: '', name: 'loading'};
|
||||
this.findListOptions = {
|
||||
elementsPerPage: 5,
|
||||
currentPage: 0,
|
||||
};
|
||||
this.externalService.getAllExternalSources(this.findListOptions).pipe(
|
||||
catchError(() => {
|
||||
const pageInfo = new PageInfo();
|
||||
const paginatedList = new PaginatedList(pageInfo, []);
|
||||
const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList);
|
||||
return observableOf(paginatedListRD);
|
||||
}),
|
||||
first()
|
||||
).subscribe((externalSource: RemoteData<PaginatedList<ExternalSource>>) => {
|
||||
externalSource.payload.page.forEach((element) => {
|
||||
this.sourceList.push({id: element.id, name: element.name});
|
||||
this.selectedElement = this.sourceList[0];
|
||||
});
|
||||
this.pageInfo = externalSource.payload.pageInfo;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected external source.
|
||||
*/
|
||||
makeSourceSelection(source) {
|
||||
this.selectedElement = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the next pages of external sources.
|
||||
*/
|
||||
onScroll() {
|
||||
if (!this.sourceListloading && this.pageInfo.currentPage <= this.pageInfo.totalPages) {
|
||||
this.sourceListloading = true;
|
||||
this.findListOptions.currentPage++;
|
||||
this.externalService.getAllExternalSources(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() {
|
||||
this.externalSourceData.emit({sourceId: this.selectedElement.id, query: this.searchString});
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
<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
|
||||
(externalSourceData) = "getExternalsourceData($event)">
|
||||
</ds-submission-import-external-searchbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
DATA<br>
|
||||
{{(externalSourceData)?externalSourceData.sourceId:''}} : {{(externalSourceData)?externalSourceData.query:''}}
|
||||
</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,35 @@
|
||||
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { ExternalSourceService } from '../../core/data/external-source.service';
|
||||
import { ExternalSourceData } from './import-external-searchbar/submission-import-external-searchbar.component';
|
||||
|
||||
/**
|
||||
* 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'
|
||||
})
|
||||
export class SubmissionImportExternalComponent {
|
||||
/**
|
||||
* The external source search data.
|
||||
*/
|
||||
public externalSourceData: ExternalSourceData;
|
||||
|
||||
/**
|
||||
* Initialize the component variables.
|
||||
* @param {ExternalSourceService} externalService
|
||||
*/
|
||||
constructor(
|
||||
private externalService: ExternalSourceService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Get the data to submit a search.
|
||||
*/
|
||||
public getExternalsourceData(event: ExternalSourceData) {
|
||||
this.externalSourceData = event;
|
||||
}
|
||||
}
|
@@ -28,7 +28,8 @@ 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 { CoreState } from '../core/core.reducers';
|
||||
import { SubmissionImportExternalComponent } from './import-external/submission-import-external.component';
|
||||
import { SubmissionImportExternalSearchbarComponent } from './import-external/import-external-searchbar/submission-import-external-searchbar.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -55,7 +56,9 @@ import { CoreState } from '../core/core.reducers';
|
||||
SubmissionUploadFilesComponent,
|
||||
SubmissionSectionUploadFileComponent,
|
||||
SubmissionSectionUploadFileEditComponent,
|
||||
SubmissionSectionUploadFileViewComponent
|
||||
SubmissionSectionUploadFileViewComponent,
|
||||
SubmissionImportExternalComponent,
|
||||
SubmissionImportExternalSearchbarComponent,
|
||||
],
|
||||
entryComponents: [
|
||||
SubmissionSectionUploadComponent,
|
||||
|
@@ -1767,6 +1767,8 @@
|
||||
|
||||
"mydspace.new-submission": "New submission",
|
||||
|
||||
"mydspace.new-submission-external": "Import from external source",
|
||||
|
||||
"mydspace.results.head": "Your submissions",
|
||||
|
||||
"mydspace.results.no-abstract": "No Abstract",
|
||||
@@ -2396,6 +2398,32 @@
|
||||
"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.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.sections.describe.relationship-lookup.close": "Close",
|
||||
|
||||
|
Reference in New Issue
Block a user