fixed file upload, styling, boolean/date/output inputs

This commit is contained in:
lotte
2020-03-24 18:05:22 +01:00
committed by Art Lowel
parent 3e4704af0d
commit e38aec831f
34 changed files with 291 additions and 69 deletions

View File

@@ -1614,6 +1614,24 @@
"process.new.select-parameters": "Parameters",
"process.new.submit": "Submit",
"process.new.select-script": "Script",
"process.new.select-script.placeholder": "Choose a script...",
"process.new.select-script.required": "Script is required",
"process.new.parameter.file.upload-button": "Select file...",
"process.new.parameter.file.required": "Please select a file",
"process.new.parameter.string.required": "Parameter value is required",
"publication.listelement.badge": "Publication", "publication.listelement.badge": "Publication",
"publication.page.description": "Description", "publication.page.description": "Description",

View File

@@ -1,6 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DataService } from '../data.service'; import { DataService } from '../data.service';
import { RequestService } from '../request.service';
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { CoreState } from '../../core.reducers'; import { CoreState } from '../../core.reducers';
@@ -10,6 +9,11 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { DefaultChangeAnalyzer } from '../default-change-analyzer.service'; import { DefaultChangeAnalyzer } from '../default-change-analyzer.service';
import { Script } from '../../../process-page/scripts/script.model'; import { Script } from '../../../process-page/scripts/script.model';
import { ProcessParameter } from '../../../process-page/processes/process-parameter.model';
import { map } from 'rxjs/operators';
import { URLCombiner } from '../../url-combiner/url-combiner';
import { MultipartPostRequest, RestRequest } from '../request.models';
import { RequestService } from '../request.service';
@Injectable() @Injectable()
export class ScriptDataService extends DataService<Script> { export class ScriptDataService extends DataService<Script> {
@@ -26,4 +30,24 @@ export class ScriptDataService extends DataService<Script> {
protected comparator: DefaultChangeAnalyzer<Script>) { protected comparator: DefaultChangeAnalyzer<Script>) {
super(); super();
} }
public invocate(scriptName: string, parameters: ProcessParameter[], files: File[]) {
this.getBrowseEndpoint().pipe(
map((endpoint: string) => new URLCombiner(endpoint, scriptName, 'processes').toString()),
map((endpoint: string) => {
const body = this.getInvocationFormData(parameters, files);
return new MultipartPostRequest(this.requestService.generateRequestId(), endpoint, body)
}),
map((request: RestRequest) => this.requestService.configure(request))
).subscribe();
}
private getInvocationFormData(parameters: ProcessParameter[], files: File[]): FormData {
const form: FormData = new FormData();
form.set('properties', JSON.stringify(parameters));
files.forEach((file: File) => {
form.append('file', file);
});
return form;
}
} }

View File

@@ -12,12 +12,7 @@ import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.
import { DSpaceRESTv2Service } from '../dspace-rest-v2/dspace-rest-v2.service'; import { DSpaceRESTv2Service } from '../dspace-rest-v2/dspace-rest-v2.service';
import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer';
import { import { RequestActionTypes, RequestCompleteAction, RequestExecuteAction, ResetResponseTimestampsAction } from './request.actions';
RequestActionTypes,
RequestCompleteAction,
RequestExecuteAction,
ResetResponseTimestampsAction
} from './request.actions';
import { RequestError, RestRequest } from './request.models'; import { RequestError, RestRequest } from './request.models';
import { RequestEntry } from './request.reducer'; import { RequestEntry } from './request.reducer';
import { RequestService } from './request.service'; import { RequestService } from './request.service';
@@ -43,12 +38,12 @@ export class RequestEffects {
filter((entry: RequestEntry) => hasValue(entry)), filter((entry: RequestEntry) => hasValue(entry)),
map((entry: RequestEntry) => entry.request), map((entry: RequestEntry) => entry.request),
flatMap((request: RestRequest) => { flatMap((request: RestRequest) => {
let body; let body = request.body;
if (isNotEmpty(request.body)) { if (isNotEmpty(request.body) && !request.isMultipart) {
const serializer = new DSpaceSerializer(getClassForType(request.body.type)); const serializer = new DSpaceSerializer(getClassForType(request.body.type));
body = serializer.serialize(request.body); body = serializer.serialize(request.body);
} }
return this.restApi.request(request.method, request.href, body, request.options).pipe( return this.restApi.request(request.method, request.href, body, request.options, request.isMultipart).pipe(
map((data: DSpaceRESTV2Response) => this.injector.get(request.getResponseParser()).parse(request, data)), map((data: DSpaceRESTV2Response) => this.injector.get(request.getResponseParser()).parse(request, data)),
addToResponseCacheAndCompleteAction(request, this.EnvConfig), addToResponseCacheAndCompleteAction(request, this.EnvConfig),
catchError((error: RequestError) => observableOf(new ErrorResponse(error)).pipe( catchError((error: RequestError) => observableOf(new ErrorResponse(error)).pipe(

View File

@@ -32,6 +32,8 @@ export enum IdentifierType {
export abstract class RestRequest { export abstract class RestRequest {
public responseMsToLive = 10 * 1000; public responseMsToLive = 10 * 1000;
public forceBypassCache = false; public forceBypassCache = false;
public isMultipart = false;
constructor( constructor(
public uuid: string, public uuid: string,
public href: string, public href: string,
@@ -74,6 +76,18 @@ export class PostRequest extends RestRequest {
} }
} }
export class MultipartPostRequest extends RestRequest {
public isMultipart = true;
constructor(
public uuid: string,
public href: string,
public body?: any,
public options?: HttpOptions
) {
super(uuid, href, RestRequestMethod.POST, body)
}
}
export class PutRequest extends RestRequest { export class PutRequest extends RestRequest {
constructor( constructor(
public uuid: string, public uuid: string,

View File

@@ -72,7 +72,7 @@ export class DSpaceRESTv2Service {
* @return {Observable<string>} * @return {Observable<string>}
* An Observable<string> containing the response from the server * An Observable<string> containing the response from the server
*/ */
request(method: RestRequestMethod, url: string, body?: any, options?: HttpOptions): Observable<DSpaceRESTV2Response> { request(method: RestRequestMethod, url: string, body?: any, options?: HttpOptions, isMultipart?: boolean): Observable<DSpaceRESTV2Response> {
const requestOptions: HttpOptions = {}; const requestOptions: HttpOptions = {};
requestOptions.body = body; requestOptions.body = body;
if (method === RestRequestMethod.POST && isNotEmpty(body) && isNotEmpty(body.name)) { if (method === RestRequestMethod.POST && isNotEmpty(body) && isNotEmpty(body.name)) {
@@ -98,7 +98,7 @@ export class DSpaceRESTv2Service {
requestOptions.withCredentials = options.withCredentials; requestOptions.withCredentials = options.withCredentials;
} }
if (!requestOptions.headers.has('Content-Type')) { if (!requestOptions.headers.has('Content-Type') && !isMultipart) {
// Because HttpHeaders is immutable, the set method returns a new object instead of updating the existing headers // Because HttpHeaders is immutable, the set method returns a new object instead of updating the existing headers
requestOptions.headers = requestOptions.headers.set('Content-Type', DEFAULT_CONTENT_TYPE); requestOptions.headers = requestOptions.headers.set('Content-Type', DEFAULT_CONTENT_TYPE);
} }

View File

@@ -1,14 +1,16 @@
<script src="process-parameters/parameter-value-input/value-input.component.ts"></script>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<form> <form #form="ngForm" (ngSubmit)="submitForm()">
<ds-scripts-select (select)="selectScript($event)"></ds-scripts-select> <ds-scripts-select (select)="selectedScript = $event"></ds-scripts-select>
<ds-process-parameters [script]="selectedScript"></ds-process-parameters> <ds-process-parameters [script]="selectedScript" (updateParameters)="parameters = $event"></ds-process-parameters>
<button [disabled]="form.invalid" type="submit" class="btn btn-light float-right">{{ 'process.new.submit' | translate }}</button>
</form> </form>
</div> </div>
<div class="col-12 col-md-6"> <div class="col-12 col-md-6">
<ds-script-help [script]="selectedScript"></ds-script-help> <ds-script-help [script]="selectedScript"></ds-script-help>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Script } from '../scripts/script.model'; import { Script } from '../scripts/script.model';
import { Process } from '../processes/process.model'; import { Process } from '../processes/process.model';
import { ProcessParameter } from '../processes/process-parameter.model';
import { ScriptDataService } from '../../core/data/processes/script-data.service';
@Component({ @Component({
selector: 'ds-new-process', selector: 'ds-new-process',
@@ -10,13 +12,32 @@ import { Process } from '../processes/process.model';
export class NewProcessComponent implements OnInit { export class NewProcessComponent implements OnInit {
public selectedScript: Script; public selectedScript: Script;
public process: Process; public process: Process;
public parameters: ProcessParameter[];
public files: File[] = [];
constructor(private scriptService: ScriptDataService) {
}
ngOnInit(): void { ngOnInit(): void {
this.process = new Process(); this.process = new Process();
} }
selectScript(script: Script) { submitForm() {
this.selectedScript = script; const stringParameters: ProcessParameter[] = this.parameters.map((parameter: ProcessParameter) => {
console.log('selected script: ', script); return {
name: parameter.name,
value: this.checkValue(parameter)
};
}
);
this.scriptService.invocate(this.selectedScript.id, stringParameters, this.files)
}
checkValue(processParameter: ProcessParameter): string {
if (typeof processParameter.value === 'object') {
this.files = [...this.files, processParameter.value];
return processParameter.value.name;
}
return processParameter.value;
} }
} }

View File

@@ -9,7 +9,7 @@
{{param.nameLong || param.name}} {{param.nameLong || param.name}}
</option> </option>
</select> </select>
<ds-parameter-value-input [parameter]="selectedScriptParameter" class="d-block col"></ds-parameter-value-input> <ds-parameter-value-input [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" class="d-block col"></ds-parameter-value-input>
<button *ngIf="removable" class="btn btn-light col-1" (click)="removeParameter.emit(parameterValue);"><span class="fas fa-trash"></span></button> <button *ngIf="removable" class="btn btn-light col-1" (click)="removeParameter.emit(parameterValue);"><span class="fas fa-trash"></span></button>
<span *ngIf="!removable" class="col-1"></span> <span *ngIf="!removable" class="col-1"></span>
</div> </div>

View File

@@ -31,6 +31,7 @@ export class ParameterSelectComponent implements OnInit {
set selectedParameter(value: string) { set selectedParameter(value: string) {
this.parameterValue.name = value; this.parameterValue.name = value;
this.selectedParameterValue = undefined;
this.changeParameter.emit(this.parameterValue); this.changeParameter.emit(this.parameterValue);
} }

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BooleanValueInputComponent } from './boolean-value-input.component';
describe('StringValueInputComponent', () => {
let component: BooleanValueInputComponent;
let fixture: ComponentFixture<BooleanValueInputComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BooleanValueInputComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BooleanValueInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,13 @@
import { Component, OnInit } from '@angular/core';
import { ValueInputComponent } from '../value-input.component';
@Component({
selector: 'ds-boolean-value-input',
templateUrl: './boolean-value-input.component.html',
styleUrls: ['./boolean-value-input.component.scss']
})
export class BooleanValueInputComponent extends ValueInputComponent<boolean> implements OnInit {
ngOnInit() {
this.updateValue.emit(true)
}
}

View File

@@ -0,0 +1,7 @@
<input required #string="ngModel" type="date" class="form-control" id="string-value-input" [ngModel]="value" (ngModelChange)="setValue($event)"/>
<div *ngIf="string.invalid && (string.dirty || string.touched)"
class="alert alert-danger">
<div *ngIf="string.errors.required">
{{'process.new.parameter.string.required' | translate}}
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DateValueInputComponent } from './date-value-input.component';
describe('StringValueInputComponent', () => {
let component: DateValueInputComponent;
let fixture: ComponentFixture<DateValueInputComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DateValueInputComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DateValueInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,16 @@
import { Component, OnInit } from '@angular/core';
import { ValueInputComponent } from '../value-input.component';
@Component({
selector: 'ds-date-value-input',
templateUrl: './date-value-input.component.html',
styleUrls: ['./date-value-input.component.scss']
})
export class DateValueInputComponent extends ValueInputComponent<string> {
value: string;
setValue(value) {
this.value = value;
this.updateValue.emit(value)
}
}

View File

@@ -1,6 +1,10 @@
<ds-uploader dropMsg="process.parameter.file-upload" <label for="file-upload" class="btn btn-light">
dropOverDocumentMsg="process.parameter.file-upload" {{'process.new.parameter.file.upload-button' | translate}}
[enableDragOverDocument]="true" </label>
[uploadFilesOptions]="uploadFilesOptions" <input requireFile #file="ngModel" type="file" id="file-upload" class="form-control-file d-none" [ngModel]="file" (ngModelChange)="setFile($event)"/>
(onCompleteItem)="onCompleteItem()" <div *ngIf="file.invalid && (file.dirty || file.touched)"
(onUploadError)="onUploadError()"></ds-uploader> class="alert alert-danger">
<div *ngIf="file.errors.required">
{{'process.new.parameter.file.required' | translate}}
</div>
</div>

View File

@@ -1,33 +1,16 @@
import { Component, OnInit } from '@angular/core'; import { Component } from '@angular/core';
import { FileUploaderOptions } from 'ng2-file-upload'; import { ValueInputComponent } from '../value-input.component';
import { UploaderOptions } from '../../../../../shared/uploader/uploader-options.model';
@Component({ @Component({
selector: 'ds-file-value-input', selector: 'ds-file-value-input',
templateUrl: './file-value-input.component.html', templateUrl: './file-value-input.component.html',
styleUrls: ['./file-value-input.component.scss'] styleUrls: ['./file-value-input.component.scss']
}) })
export class FileValueInputComponent implements OnInit { export class FileValueInputComponent extends ValueInputComponent<File> {
uploadFilesOptions: FileUploaderOptions; file: File;
setFile(files) {
constructor() { this.file = files.length > 0 ? files[0] : undefined;
} console.log(this.file);
this.updateValue.emit(this.file);
ngOnInit() {
this.uploadFilesOptions = new UploaderOptions();
this.uploadFilesOptions.autoUpload = false;
this.uploadFilesOptions.url = 'bladibla';
this.uploadFilesOptions.authToken = 'bladibla';
this.uploadFilesOptions.disableMultipart = true;
this.uploadFilesOptions.formatDataFunctionIsAsync = false;
this.uploadFilesOptions.formatDataFunction((t) => console.log(t));
}
onCompleteItem() {
}
onUploadError() {
} }
} }

View File

@@ -1,4 +1,7 @@
<div [ngSwitch]="parameter?.type"> <div [ngSwitch]="parameter?.type">
<ds-string-value-input *ngSwitchCase="parameterTypes.STRING"></ds-string-value-input> <ds-string-value-input *ngSwitchCase="parameterTypes.STRING" (updateValue)="updateValue.emit($event)"></ds-string-value-input>
<ds-file-value-input *ngSwitchCase="parameterTypes.FILE"></ds-file-value-input> <ds-string-value-input *ngSwitchCase="parameterTypes.OUTPUT" (updateValue)="updateValue.emit($event)"></ds-string-value-input>
<ds-date-value-input *ngSwitchCase="parameterTypes.DATE" (updateValue)="updateValue.emit($event)"></ds-date-value-input>
<ds-file-value-input *ngSwitchCase="parameterTypes.FILE" (updateValue)="updateValue.emit($event)"></ds-file-value-input>
<ds-boolean-value-input *ngSwitchCase="parameterTypes.BOOLEAN" (updateValue)="updateValue.emit($event)"></ds-boolean-value-input>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model'; import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
import { ScriptParameter } from '../../../scripts/script-parameter.model'; import { ScriptParameter } from '../../../scripts/script-parameter.model';
@@ -9,5 +9,6 @@ import { ScriptParameter } from '../../../scripts/script-parameter.model';
}) })
export class ParameterValueInputComponent { export class ParameterValueInputComponent {
@Input() parameter: ScriptParameter; @Input() parameter: ScriptParameter;
@Output() updateValue: EventEmitter<any> = new EventEmitter();
parameterTypes = ScriptParameterType; parameterTypes = ScriptParameterType;
} }

View File

@@ -1 +1,7 @@
<input type="input" class="form-control" id="string-value-input"> <input required #string="ngModel" type="text" class="form-control" id="string-value-input" [ngModel]="value" (ngModelChange)="setValue($event)"/>
<div *ngIf="string.invalid && (string.dirty || string.touched)"
class="alert alert-danger">
<div *ngIf="string.errors.required">
{{'process.new.parameter.string.required' | translate}}
</div>
</div>

View File

@@ -1,15 +1,16 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ValueInputComponent } from '../value-input.component';
@Component({ @Component({
selector: 'ds-string-value-input', selector: 'ds-string-value-input',
templateUrl: './string-value-input.component.html', templateUrl: './string-value-input.component.html',
styleUrls: ['./string-value-input.component.scss'] styleUrls: ['./string-value-input.component.scss']
}) })
export class StringValueInputComponent implements OnInit { export class StringValueInputComponent extends ValueInputComponent<string> {
value: string;
constructor() { } setValue(value) {
this.value = value;
ngOnInit() { this.updateValue.emit(value)
} }
} }

View File

@@ -0,0 +1,5 @@
import { EventEmitter, Output } from '@angular/core';
export abstract class ValueInputComponent<T> {
@Output() updateValue: EventEmitter<T> = new EventEmitter<T>()
}

View File

@@ -1,5 +1,5 @@
<div class="form-group" *ngIf="script"> <div class="form-group" *ngIf="script">
<label>Parameters</label> <label>{{'process.new.select-parameters' | translate}}</label>
<ds-parameter-select <ds-parameter-select
*ngFor="let value of parameterValues; let i = index; let last = last" *ngFor="let value of parameterValues; let i = index; let last = last"
[parameters]="script.parameters" [parameters]="script.parameters"

View File

@@ -1,6 +1,7 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { Script } from '../../scripts/script.model'; import { Script } from '../../scripts/script.model';
import { ProcessParameter } from '../../processes/process-parameter.model'; import { ProcessParameter } from '../../processes/process-parameter.model';
import { hasValue } from '../../../shared/empty.util';
@Component({ @Component({
selector: 'ds-process-parameters', selector: 'ds-process-parameters',
@@ -9,6 +10,7 @@ import { ProcessParameter } from '../../processes/process-parameter.model';
}) })
export class ProcessParametersComponent implements OnChanges { export class ProcessParametersComponent implements OnChanges {
@Input() script: Script; @Input() script: Script;
@Output() updateParameters: EventEmitter<ProcessParameter[]> = new EventEmitter();
parameterValues: ProcessParameter[]; parameterValues: ProcessParameter[];
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
@@ -27,6 +29,7 @@ export class ProcessParametersComponent implements OnChanges {
if (index === this.parameterValues.length - 1) { if (index === this.parameterValues.length - 1) {
this.addParameter(); this.addParameter();
} }
this.updateParameters.emit(this.parameterValues.filter((param: ProcessParameter) => hasValue(param.name)));
} }
removeParameter(index: number) { removeParameter(index: number) {

View File

@@ -1,11 +1,11 @@
<div class="form-group" *ngIf="scripts$ | async"> <div class="form-group" *ngIf="scripts$ | async">
<label for="process-script">Script</label> <label for="process-script"><label>{{'process.new.select-script' | translate}}</label></label>
<select required id="process-script" <select required id="process-script"
class="form-control" class="form-control"
name="script" name="script"
[(ngModel)]="selectedScript" [(ngModel)]="selectedScript"
#script="ngModel"> #script="ngModel">
<option [ngValue]="undefined">Choose a script...</option> <option [ngValue]="undefined">{{'process.new.select-script.placeholder' | translate}}</option>
<option *ngFor="let script of scripts$ | async" [ngValue]="script.id"> <option *ngFor="let script of scripts$ | async" [ngValue]="script.id">
{{script.name}} {{script.name}}
</option> </option>
@@ -14,7 +14,7 @@
<div *ngIf="script.invalid && (script.dirty || script.touched)" <div *ngIf="script.invalid && (script.dirty || script.touched)"
class="alert alert-danger"> class="alert alert-danger">
<div *ngIf="script.errors.required"> <div *ngIf="script.errors.required">
Script is required. {{'process.new.select-script.required' | translate}}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -9,6 +9,8 @@ import { ProcessParametersComponent } from './new/process-parameters/process-par
import { StringValueInputComponent } from './new/process-parameters/parameter-value-input/string-value-input/string-value-input.component'; import { StringValueInputComponent } from './new/process-parameters/parameter-value-input/string-value-input/string-value-input.component';
import { ParameterValueInputComponent } from './new/process-parameters/parameter-value-input/parameter-value-input.component'; import { ParameterValueInputComponent } from './new/process-parameters/parameter-value-input/parameter-value-input.component';
import { FileValueInputComponent } from './new/process-parameters/parameter-value-input/file-value-input/file-value-input.component'; import { FileValueInputComponent } from './new/process-parameters/parameter-value-input/file-value-input/file-value-input.component';
import { BooleanValueInputComponent } from './new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component';
import { DateValueInputComponent } from './new/process-parameters/parameter-value-input/date-value-input/date-value-input.component';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -24,6 +26,8 @@ import { FileValueInputComponent } from './new/process-parameters/parameter-valu
StringValueInputComponent, StringValueInputComponent,
ParameterValueInputComponent, ParameterValueInputComponent,
FileValueInputComponent, FileValueInputComponent,
BooleanValueInputComponent,
DateValueInputComponent,
], ],
entryComponents: [] entryComponents: []
}) })

View File

@@ -6,8 +6,9 @@ export class ProcessParameter {
* The name of the parameter Eg. '-d', '-f' etc. * The name of the parameter Eg. '-d', '-f' etc.
*/ */
name: string; name: string;
/** /**
* The value of the parameter * The value of the parameter
*/ */
value: string; value: any;
} }

View File

@@ -63,10 +63,10 @@ export class EndpointMockingRestService extends DSpaceRESTv2Service {
* @return Observable<DSpaceRESTV2Response> * @return Observable<DSpaceRESTV2Response>
* An Observable<DSpaceRESTV2Response> containing the response from the server * An Observable<DSpaceRESTV2Response> containing the response from the server
*/ */
request(method: RestRequestMethod, url: string, body?: any, options?: HttpOptions): Observable<DSpaceRESTV2Response> { request(method: RestRequestMethod, url: string, body?: any, options?: HttpOptions, isMultipart?: boolean): Observable<DSpaceRESTV2Response> {
const mockData = this.getMockData(url); const mockData = this.getMockData(url);
if (isEmpty(mockData)) { if (isEmpty(mockData)) {
return super.request(method, url, body, options); return super.request(method, url, body, options, isMultipart);
} else { } else {
return this.toMockResponse$(mockData); return this.toMockResponse$(mockData);
} }

View File

@@ -186,6 +186,8 @@ import { LogInPasswordComponent } from './log-in/methods/password/log-in-passwor
import { LogInComponent } from './log-in/log-in.component'; import { LogInComponent } from './log-in/log-in.component';
import { MissingTranslationHelper } from './translate/missing-translation.helper'; import { MissingTranslationHelper } from './translate/missing-translation.helper';
import { ItemVersionsNoticeComponent } from './item/item-versions/notice/item-versions-notice.component'; import { ItemVersionsNoticeComponent } from './item/item-versions/notice/item-versions-notice.component';
import { FileValidator } from './utils/require-file.validator';
import { FileValueAccessorDirective } from './utils/file-value-accessor.directive';
const MODULES = [ const MODULES = [
// Do NOT include UniversalModule, HttpModule, or JsonpModule here // Do NOT include UniversalModule, HttpModule, or JsonpModule here
@@ -452,7 +454,9 @@ const DIRECTIVES = [
AutoFocusDirective, AutoFocusDirective,
RoleDirective, RoleDirective,
MetadataRepresentationDirective, MetadataRepresentationDirective,
ListableObjectDirective ListableObjectDirective,
FileValueAccessorDirective,
FileValidator
]; ];
@NgModule({ @NgModule({

View File

@@ -146,6 +146,8 @@ export class UploaderComponent {
}; };
this.uploader.onProgressAll = () => this.onProgress(); this.uploader.onProgressAll = () => this.onProgress();
this.uploader.onProgressItem = () => this.onProgress(); this.uploader.onProgressItem = () => this.onProgress();
console.log(this.uploader.options.formatDataFunction());
} }
/** /**

View File

@@ -0,0 +1,24 @@
import {Directive} from '@angular/core';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
@Directive({
// tslint:disable-next-line:directive-selector
selector: 'input[type=file]',
// tslint:disable-next-line:no-host-metadata-property
host : {
'(change)' : 'onChange($event.target.files)',
'(blur)': 'onTouched()'
},
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessorDirective, multi: true }
]
})
export class FileValueAccessorDirective implements ControlValueAccessor {
value: any;
onChange = (_) => { /* empty */ };
onTouched = () => { /* empty */};
writeValue(value) { /* empty */}
registerOnChange(fn: any) { this.onChange = fn; }
registerOnTouched(fn: any) { this.onTouched = fn; }
}

View File

@@ -0,0 +1,19 @@
import {Directive} from '@angular/core';
import {NG_VALIDATORS, Validator, FormControl} from '@angular/forms';
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[requireFile]',
providers: [
{ provide: NG_VALIDATORS, useExisting: FileValidator, multi: true },
]
})
export class FileValidator implements Validator {
static validate(c: FormControl): {[key: string]: any} {
return c.value == null || c.value.length === 0 ? { required : true} : null;
}
validate(c: FormControl): {[key: string]: any} {
return FileValidator.validate(c);
}
}