-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1154 from ORCID/memberImport
member import
- Loading branch information
Showing
7 changed files
with
228 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<form name="uploadForm" (ngSubmit)="upload()"> | ||
<div class="modal-header"> | ||
<h4 class="modal-title" i18n="@@gatewayApp.msUserServiceMSMember.import.title.string">Import members</h4> | ||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" | ||
(click)="clear()">×</button> | ||
</div> | ||
<div class="modal-body"> | ||
<app-error-alert></app-error-alert> | ||
<div class="alerts top right" role="alert" *ngIf="csvErrors && csvErrors.length > 0"> | ||
<ngb-alert class="alert alert-danger alert-dismissible" role="alert" ng-reflect-type="danger" (close)="csvErrors = null" [dismissible]="false"> | ||
<p i18n="@@gatewayApp.msUserServiceMSMember.import.errors.label.string">Oops! There was a problem processing your data. Pleases fix the errors below and try again</p> | ||
<table> | ||
<thead> | ||
<th>Errors</th> | ||
</thead> | ||
<tbody> | ||
<tr *ngFor="let error of csvErrors"> | ||
<td>Row {{error['index']}}</td> | ||
<td>{{error['message']}}</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</ngb-alert> | ||
</div> | ||
<p id="jhi-delete-msMember-heading" i18n="@@gatewayApp.msUserServiceMSMember.import.label.string">Please select a CSV file to upload</p> | ||
<div class="form-group"> | ||
<label class="form-control-label sr-only" i18n="@@gatewayApp.msUserServiceMSMember.import.filePath" for="field_filePath.string">File Path</label> | ||
<input type="file" class="form-control" name="filePath" id="field_filePath" accept=".csv" | ||
onclick="this.value=null" (change)="selectFile($event)"/> | ||
</div> | ||
</div> | ||
<div *ngIf="loading" class="progress progress-striped"> | ||
<div class="progress-bar indeterminate" role="progressbar"></div> | ||
</div> | ||
<div class="modal-footer"> | ||
<button type="button" class="btn btn-outline-primary" data-dismiss="modal" (click)="clear()"> | ||
<fa-icon [icon]="faBan"></fa-icon> <span i18n="@@entity.action.cancel.string">Cancel</span> | ||
</button> | ||
<button id="jhi-confirm-delete-msUser" type="submit" class="btn btn-primary"> | ||
<fa-icon [icon]="faSave"></fa-icon> <span i18n="@@entity.action.upload.string">Upload</span> | ||
</button> | ||
</div> | ||
</form> |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { ComponentFixture, TestBed } from '@angular/core/testing' | ||
|
||
import { MemberImportDialogComponent } from './member-import-dialog.component' | ||
import { EventService } from '../shared/service/event.service' | ||
import { FileUploadService } from '../shared/service/file-upload.service' | ||
import { FormBuilder } from '@angular/forms' | ||
import { HttpClientTestingModule } from '@angular/common/http/testing' | ||
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap' | ||
import { EMPTY, of } from 'rxjs' | ||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/compiler' | ||
|
||
describe('MemberImportDialogComponent', () => { | ||
let component: MemberImportDialogComponent | ||
let fixture: ComponentFixture<MemberImportDialogComponent> | ||
|
||
let uploadServiceSpy: jasmine.SpyObj<FileUploadService> | ||
|
||
beforeEach(() => { | ||
uploadServiceSpy = jasmine.createSpyObj('FileUploadService', ['uploadFile']) | ||
|
||
TestBed.configureTestingModule({ | ||
declarations: [MemberImportDialogComponent], | ||
imports: [HttpClientTestingModule], | ||
providers: [FormBuilder, NgbModal, NgbActiveModal, { provide: FileUploadService, useValue: uploadServiceSpy }], | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
fixture = TestBed.createComponent(MemberImportDialogComponent) | ||
component = fixture.componentInstance | ||
fixture.detectChanges() | ||
|
||
uploadServiceSpy = TestBed.inject(FileUploadService) as jasmine.SpyObj<FileUploadService> | ||
}) | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy() | ||
}) | ||
|
||
it('should call upload service', () => { | ||
component.currentFile = getFileList() | ||
uploadServiceSpy.uploadFile.and.returnValue(EMPTY) | ||
component.upload() | ||
expect(uploadServiceSpy.uploadFile).toHaveBeenCalled() | ||
}) | ||
|
||
it('errors should be parsed', () => { | ||
component.currentFile = getFileList() | ||
uploadServiceSpy.uploadFile.and.returnValue(of('[{"index":1,"message":"error"}]')) | ||
component.upload() | ||
expect(uploadServiceSpy.uploadFile).toHaveBeenCalled() | ||
expect(component.csvErrors.length).toEqual(1) | ||
}) | ||
|
||
const getFileList = () => { | ||
const blob = new Blob([''], { type: 'text/html' }) | ||
const file = <File>blob | ||
const fileList: FileList = { | ||
0: file, | ||
1: file, | ||
length: 2, | ||
item: (index: number) => file, | ||
} | ||
return fileList | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { Component, OnDestroy, OnInit } from '@angular/core' | ||
import { MemberService } from './service/member.service' | ||
import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' | ||
import { EventService } from '../shared/service/event.service' | ||
import { FileUploadService } from '../shared/service/file-upload.service' | ||
import { ActivatedRoute, Router } from '@angular/router' | ||
import { Event } from '../shared/model/event.model' | ||
import { EventType } from '../app.constants' | ||
import { faBan, faSave } from '@fortawesome/free-solid-svg-icons' | ||
|
||
@Component({ | ||
selector: 'app-member-import-dialog', | ||
templateUrl: './member-import-dialog.component.html', | ||
styleUrls: ['./member-import-dialog.component.scss'], | ||
}) | ||
export class MemberImportDialogComponent { | ||
public resourceUrl | ||
isSaving: boolean | ||
currentFile: FileList | null | ||
csvErrors: any | ||
loading = false | ||
faBan = faBan | ||
faSave = faSave | ||
|
||
constructor( | ||
protected memberService: MemberService, | ||
public activeModal: NgbActiveModal, | ||
protected eventService: EventService, | ||
private uploadService: FileUploadService | ||
) { | ||
this.currentFile = null | ||
this.isSaving = false | ||
this.resourceUrl = this.memberService.resourceUrl + '/members/upload' | ||
} | ||
|
||
clear() { | ||
this.activeModal.dismiss('cancel') | ||
} | ||
|
||
selectFile(event: any) { | ||
this.currentFile = event.target.files | ||
} | ||
|
||
upload() { | ||
if (this.currentFile) { | ||
this.loading = true | ||
const f = this.currentFile.item(0) | ||
this.uploadService.uploadFile(this.resourceUrl, f!, 'text').subscribe((res: any) => { | ||
if (res) { | ||
this.csvErrors = JSON.parse(res) | ||
this.loading = false | ||
if (this.csvErrors.length === 0) { | ||
this.eventService.broadcast(new Event(EventType.MEMBER_LIST_MODIFICATION, 'New member uploaded')) | ||
this.activeModal.dismiss(true) | ||
} | ||
} | ||
}) | ||
} else { | ||
alert( | ||
$localize`:gatewayApp.msUserServiceMSUser.import.emptyFile.string:There is no file to upload. Please select one.` | ||
) | ||
} | ||
} | ||
} | ||
|
||
@Component({ | ||
selector: 'app-member-import-popup', | ||
template: '', | ||
}) | ||
export class MemberImportPopupComponent implements OnInit, OnDestroy { | ||
protected ngbModalRef: NgbModalRef | undefined | null | ||
|
||
constructor( | ||
protected activatedRoute: ActivatedRoute, | ||
protected router: Router, | ||
protected modalService: NgbModal | ||
) {} | ||
|
||
ngOnInit() { | ||
this.activatedRoute.data.subscribe(({ msMember }) => { | ||
setTimeout(() => { | ||
this.ngbModalRef = this.modalService.open(MemberImportDialogComponent as Component, { | ||
size: 'lg', | ||
backdrop: 'static', | ||
}) | ||
this.ngbModalRef.componentInstance.msMember = msMember | ||
this.ngbModalRef.result.then( | ||
(result) => { | ||
this.router.navigate(['/members', { outlets: { popup: null } }]) | ||
this.ngbModalRef = null | ||
}, | ||
(reason) => { | ||
this.router.navigate(['/members', { outlets: { popup: null } }]) | ||
this.ngbModalRef = null | ||
} | ||
) | ||
}, 0) | ||
}) | ||
} | ||
|
||
ngOnDestroy() { | ||
this.ngbModalRef = null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters