added tests and typedoc

This commit is contained in:
lotte
2020-03-25 13:18:46 +01:00
committed by Art Lowel
parent e38aec831f
commit ef3a235178
36 changed files with 701 additions and 46 deletions

View File

@@ -31,7 +31,7 @@ export class ScriptDataService extends DataService<Script> {
super(); super();
} }
public invocate(scriptName: string, parameters: ProcessParameter[], files: File[]) { public invoke(scriptName: string, parameters: ProcessParameter[], files: File[]) {
this.getBrowseEndpoint().pipe( this.getBrowseEndpoint().pipe(
map((endpoint: string) => new URLCombiner(endpoint, scriptName, 'processes').toString()), map((endpoint: string) => new URLCombiner(endpoint, scriptName, 'processes').toString()),
map((endpoint: string) => { map((endpoint: string) => {

View File

@@ -76,6 +76,9 @@ export class PostRequest extends RestRequest {
} }
} }
/**
* Request representing a multipart post request
*/
export class MultipartPostRequest extends RestRequest { export class MultipartPostRequest extends RestRequest {
public isMultipart = true; public isMultipart = true;
constructor( constructor(

View File

@@ -69,6 +69,8 @@ export class DSpaceRESTv2Service {
* an optional body for the request * an optional body for the request
* @param options * @param options
* the HttpOptions object * the HttpOptions object
* @param isMultipart
* true when this concerns a multipart request
* @return {Observable<string>} * @return {Observable<string>}
* An Observable<string> containing the response from the server * An Observable<string> containing the response from the server
*/ */

View File

@@ -1,8 +1,7 @@
<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="ngForm" (ngSubmit)="submitForm()"> <form #form="ngForm" (ngSubmit)="submitForm(form)">
<ds-scripts-select (select)="selectedScript = $event"></ds-scripts-select> <ds-scripts-select (select)="selectedScript = $event"></ds-scripts-select>
<ds-process-parameters [script]="selectedScript" (updateParameters)="parameters = $event"></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> <button [disabled]="form.invalid" type="submit" class="btn btn-light float-right">{{ 'process.new.submit' | translate }}</button>
@@ -13,4 +12,3 @@
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,68 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NewProcessComponent } from './new-process.component';
import { ScriptDataService } from '../../core/data/processes/script-data.service';
import { MockTranslateLoader } from '../../shared/testing/mock-translate-loader';
import { ScriptParameter } from '../scripts/script-parameter.model';
import { Script } from '../scripts/script.model';
import { ProcessParameter } from '../processes/process-parameter.model';
describe('NewProcessComponent', () => {
let component: NewProcessComponent;
let fixture: ComponentFixture<NewProcessComponent>;
let scriptService;
let parameterValues;
let script;
function init() {
const param1 = new ScriptParameter();
const param2 = new ScriptParameter();
script = Object.assign(new Script(), { parameters: [param1, param2] });
parameterValues = [
Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }),
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
];
scriptService = jasmine.createSpyObj('scriptService', ['invoke'])
}
beforeEach(async(() => {
init();
TestBed.configureTestingModule({
imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [NewProcessComponent],
providers: [
{ provide: ScriptDataService, useValue: scriptService },
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NewProcessComponent);
component = fixture.componentInstance;
component.parameters = parameterValues;
component.selectedScript = script;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call invoke on the scriptService on submit', () => {
component.submitForm({ invalid: false });
expect(scriptService.invoke).toHaveBeenCalled();
});
});

View File

@@ -3,16 +3,35 @@ 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 { ProcessParameter } from '../processes/process-parameter.model';
import { ScriptDataService } from '../../core/data/processes/script-data.service'; import { ScriptDataService } from '../../core/data/processes/script-data.service';
import { NgForm } from '@angular/forms';
/**
* Component to create a new script
*/
@Component({ @Component({
selector: 'ds-new-process', selector: 'ds-new-process',
templateUrl: './new-process.component.html', templateUrl: './new-process.component.html',
styleUrls: ['./new-process.component.scss'], styleUrls: ['./new-process.component.scss'],
}) })
export class NewProcessComponent implements OnInit { export class NewProcessComponent implements OnInit {
/**
* The currently selected script
*/
public selectedScript: Script; public selectedScript: Script;
/**
* The process to create
*/
public process: Process; public process: Process;
/**
* The parameter values to use to start the process
*/
public parameters: ProcessParameter[]; public parameters: ProcessParameter[];
/**
* Optional files that are used as parameter values
*/
public files: File[] = []; public files: File[] = [];
constructor(private scriptService: ScriptDataService) { constructor(private scriptService: ScriptDataService) {
@@ -22,7 +41,15 @@ export class NewProcessComponent implements OnInit {
this.process = new Process(); this.process = new Process();
} }
submitForm() { /**
* Validates the form, sets the parameters to correct values and invokes the script with the correct parameters
* @param form
*/
submitForm(form: NgForm) {
if (!this.validateForm(form)) {
return;
}
const stringParameters: ProcessParameter[] = this.parameters.map((parameter: ProcessParameter) => { const stringParameters: ProcessParameter[] = this.parameters.map((parameter: ProcessParameter) => {
return { return {
name: parameter.name, name: parameter.name,
@@ -30,14 +57,35 @@ export class NewProcessComponent implements OnInit {
}; };
} }
); );
this.scriptService.invocate(this.selectedScript.id, stringParameters, this.files) this.scriptService.invoke(this.selectedScript.id, stringParameters, this.files)
} }
checkValue(processParameter: ProcessParameter): string { /**
* Checks whether the parameter values are files
* Replaces file parameters by strings and stores the files in a separate list
* @param processParameter The parameter value to check
*/
private checkValue(processParameter: ProcessParameter): string {
if (typeof processParameter.value === 'object') { if (typeof processParameter.value === 'object') {
this.files = [...this.files, processParameter.value]; this.files = [...this.files, processParameter.value];
return processParameter.value.name; return processParameter.value.name;
} }
return processParameter.value; return processParameter.value;
} }
/**
* Validates the form
* Returns false if the form is invalid
* Returns true if the form is valid
* @param form The NgForm object to validate
*/
private validateForm(form: NgForm) {
if (form.invalid) {
Object.keys(form.controls).forEach((key) => {
form.controls[key].markAsDirty();
});
return false;
}
return true;
}
} }

View File

@@ -10,7 +10,7 @@
</option> </option>
</select> </select>
<ds-parameter-value-input [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" 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 remove-button" (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

@@ -1,14 +1,41 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ParameterSelectComponent } from './parameter-select.component'; import { ParameterSelectComponent } from './parameter-select.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ScriptParameter } from '../../../scripts/script-parameter.model';
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
import { By } from '@angular/platform-browser';
describe('ParameterSelectComponent', () => { describe('ParameterSelectComponent', () => {
let component: ParameterSelectComponent; let component: ParameterSelectComponent;
let fixture: ComponentFixture<ParameterSelectComponent>; let fixture: ComponentFixture<ParameterSelectComponent>;
let scriptParams: ScriptParameter[];
function init() {
scriptParams = [
Object.assign(
new ScriptParameter(),
{
name: '-a',
type: ScriptParameterType.BOOLEAN
}
),
Object.assign(
new ScriptParameter(),
{
name: '-f',
type: ScriptParameterType.FILE
}
),
]
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ParameterSelectComponent ] imports: [FormsModule],
declarations: [ParameterSelectComponent],
schemas: [NO_ERRORS_SCHEMA]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -16,10 +43,29 @@ describe('ParameterSelectComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ParameterSelectComponent); fixture = TestBed.createComponent(ParameterSelectComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.parameters = scriptParams;
component.removable = false;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should show the remove button when removable', () => {
component.removable = true;
fixture.detectChanges();
const button = fixture.debugElement.query(By.css('button.remove-button'));
expect(button).not.toBeNull();
});
it('should hide the remove button when not removable', () => {
component.removable = false;
fixture.detectChanges();
const button = fixture.debugElement.query(By.css('button.remove-button'));
expect(button).toBeNull();
});
}); });

View File

@@ -3,16 +3,37 @@ import { ProcessParameter } from '../../../processes/process-parameter.model';
import { ScriptParameter } from '../../../scripts/script-parameter.model'; import { ScriptParameter } from '../../../scripts/script-parameter.model';
import { hasNoValue } from '../../../../shared/empty.util'; import { hasNoValue } from '../../../../shared/empty.util';
/**
* Component to select a single parameter for a process
*/
@Component({ @Component({
selector: 'ds-parameter-select', selector: 'ds-parameter-select',
templateUrl: './parameter-select.component.html', templateUrl: './parameter-select.component.html',
styleUrls: ['./parameter-select.component.scss'] styleUrls: ['./parameter-select.component.scss']
}) })
export class ParameterSelectComponent implements OnInit { export class ParameterSelectComponent implements OnInit {
/**
* The current parameter value of the selected parameter
*/
@Input() parameterValue: ProcessParameter; @Input() parameterValue: ProcessParameter;
/**
* The available script parameters for the script
*/
@Input() parameters: ScriptParameter[]; @Input() parameters: ScriptParameter[];
/**
* Whether or not this selected parameter can be removed from the list
*/
@Input() removable: boolean; @Input() removable: boolean;
/**
* Emits the parameter value when it's removed
*/
@Output() removeParameter: EventEmitter<ProcessParameter> = new EventEmitter<ProcessParameter>(); @Output() removeParameter: EventEmitter<ProcessParameter> = new EventEmitter<ProcessParameter>();
/**
* Emits the updated parameter value when it changes
*/
@Output() changeParameter: EventEmitter<ProcessParameter> = new EventEmitter<ProcessParameter>(); @Output() changeParameter: EventEmitter<ProcessParameter> = new EventEmitter<ProcessParameter>();
ngOnInit(): void { ngOnInit(): void {
@@ -21,24 +42,43 @@ export class ParameterSelectComponent implements OnInit {
} }
} }
/**
* Returns the script parameter based on the currently selected name
*/
get selectedScriptParameter(): ScriptParameter { get selectedScriptParameter(): ScriptParameter {
return this.parameters.find((parameter: ScriptParameter) => parameter.name === this.selectedParameter); return this.parameters.find((parameter: ScriptParameter) => parameter.name === this.selectedParameter);
} }
/**
* Return the currently selected parameter name
*/
get selectedParameter(): string { get selectedParameter(): string {
return this.parameterValue ? this.parameterValue.name : undefined; return this.parameterValue ? this.parameterValue.name : undefined;
} }
/**
* Sets the currently selected parameter based on the provided parameter name
* Emits the new value from the changeParameter output
* @param value The parameter name to set
*/
set selectedParameter(value: string) { set selectedParameter(value: string) {
this.parameterValue.name = value; this.parameterValue.name = value;
this.selectedParameterValue = undefined; this.selectedParameterValue = undefined;
this.changeParameter.emit(this.parameterValue); this.changeParameter.emit(this.parameterValue);
} }
/**
* Returns the currently selected parameter value
*/
get selectedParameterValue(): any { get selectedParameterValue(): any {
return this.parameterValue ? this.parameterValue.value : undefined; return this.parameterValue ? this.parameterValue.value : undefined;
} }
/**
* Sets the currently selected value for the parameter
* Emits the new value from the changeParameter output
* @param value The parameter value to set
*/
set selectedParameterValue(value: any) { set selectedParameterValue(value: any) {
this.parameterValue.value = value; this.parameterValue.value = value;
this.changeParameter.emit(this.parameterValue); this.changeParameter.emit(this.parameterValue);

View File

@@ -1,8 +1,10 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BooleanValueInputComponent } from './boolean-value-input.component'; import { BooleanValueInputComponent } from './boolean-value-input.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
describe('StringValueInputComponent', () => { describe('BooleanValueInputComponent', () => {
let component: BooleanValueInputComponent; let component: BooleanValueInputComponent;
let fixture: ComponentFixture<BooleanValueInputComponent>; let fixture: ComponentFixture<BooleanValueInputComponent>;
@@ -16,10 +18,15 @@ describe('StringValueInputComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(BooleanValueInputComponent); fixture = TestBed.createComponent(BooleanValueInputComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
spyOn(component.updateValue, 'emit');
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should emit true onInit', () => {
expect(component.updateValue.emit).toHaveBeenCalledWith(true);
});
}); });

View File

@@ -1,6 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ValueInputComponent } from '../value-input.component'; import { ValueInputComponent } from '../value-input.component';
/**
* Represents the value of a boolean parameter
*/
@Component({ @Component({
selector: 'ds-boolean-value-input', selector: 'ds-boolean-value-input',
templateUrl: './boolean-value-input.component.html', templateUrl: './boolean-value-input.component.html',

View File

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

View File

@@ -1,13 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { DateValueInputComponent } from './date-value-input.component'; import { DateValueInputComponent } from './date-value-input.component';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
import { By } from '@angular/platform-browser';
describe('StringValueInputComponent', () => { describe('DateValueInputComponent', () => {
let component: DateValueInputComponent; let component: DateValueInputComponent;
let fixture: ComponentFixture<DateValueInputComponent>; let fixture: ComponentFixture<DateValueInputComponent>;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [DateValueInputComponent] declarations: [DateValueInputComponent]
}) })
.compileComponents(); .compileComponents();
@@ -22,4 +34,37 @@ describe('StringValueInputComponent', () => {
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should not show a validation error if the input field was left untouched but left empty', () => {
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
});
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
component.value = '';
fixture.detectChanges();
tick();
const input = fixture.debugElement.query(By.css('input'));
input.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeTruthy();
}));
it('should not show a validation error if the input field was touched but not left empty', fakeAsync(() => {
component.value = 'testValue';
fixture.detectChanges();
tick();
const input = fixture.debugElement.query(By.css('input'));
input.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
}));
}); });

View File

@@ -1,12 +1,18 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ValueInputComponent } from '../value-input.component'; import { ValueInputComponent } from '../value-input.component';
/**
* Represents the user inputted value of a date parameter
*/
@Component({ @Component({
selector: 'ds-date-value-input', selector: 'ds-date-value-input',
templateUrl: './date-value-input.component.html', templateUrl: './date-value-input.component.html',
styleUrls: ['./date-value-input.component.scss'] styleUrls: ['./date-value-input.component.scss']
}) })
export class DateValueInputComponent extends ValueInputComponent<string> { export class DateValueInputComponent extends ValueInputComponent<string> {
/**
* The current value of the date string
*/
value: string; value: string;
setValue(value) { setValue(value) {

View File

@@ -3,7 +3,7 @@
</label> </label>
<input requireFile #file="ngModel" type="file" id="file-upload" class="form-control-file d-none" [ngModel]="file" (ngModelChange)="setFile($event)"/> <input requireFile #file="ngModel" type="file" id="file-upload" class="form-control-file d-none" [ngModel]="file" (ngModelChange)="setFile($event)"/>
<div *ngIf="file.invalid && (file.dirty || file.touched)" <div *ngIf="file.invalid && (file.dirty || file.touched)"
class="alert alert-danger"> class="alert alert-danger validation-error">
<div *ngIf="file.errors.required"> <div *ngIf="file.errors.required">
{{'process.new.parameter.file.required' | translate}} {{'process.new.parameter.file.required' | translate}}
</div> </div>

View File

@@ -1,6 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
import { By } from '@angular/platform-browser';
import { FileValueInputComponent } from './file-value-input.component'; import { FileValueInputComponent } from './file-value-input.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { FileValueAccessorDirective } from '../../../../../shared/utils/file-value-accessor.directive';
import { FileValidator } from '../../../../../shared/utils/require-file.validator';
describe('FileValueInputComponent', () => { describe('FileValueInputComponent', () => {
let component: FileValueInputComponent; let component: FileValueInputComponent;
@@ -8,7 +15,17 @@ describe('FileValueInputComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ FileValueInputComponent ] imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [FileValueInputComponent, FileValueAccessorDirective, FileValidator],
schemas: [NO_ERRORS_SCHEMA]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -22,4 +39,19 @@ describe('FileValueInputComponent', () => {
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should not show a validation error if the input field was left untouched but left empty', () => {
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
});
it('should show a validation error if the input field was touched but left empty', () => {
const input = fixture.debugElement.query(By.css('input'));
input.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeTruthy();
});
}); });

View File

@@ -1,16 +1,21 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ValueInputComponent } from '../value-input.component'; import { ValueInputComponent } from '../value-input.component';
/**
* Represents the user inputted value of a file parameter
*/
@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 extends ValueInputComponent<File> { export class FileValueInputComponent extends ValueInputComponent<File> {
/**
* The current value of the file
*/
file: File; file: File;
setFile(files) { setFile(files) {
this.file = files.length > 0 ? files[0] : undefined; this.file = files.length > 0 ? files[0] : undefined;
console.log(this.file);
this.updateValue.emit(this.file); this.updateValue.emit(this.file);
} }
} }

View File

@@ -1,14 +1,58 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ParameterValueInputComponent } from './parameter-value-input.component'; import { ParameterValueInputComponent } from './parameter-value-input.component';
import { ScriptParameter } from '../../../scripts/script-parameter.model';
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
import { By } from '@angular/platform-browser';
import { BooleanValueInputComponent } from './boolean-value-input/boolean-value-input.component';
import { StringValueInputComponent } from './string-value-input/string-value-input.component';
import { FileValueInputComponent } from './file-value-input/file-value-input.component';
import { DateValueInputComponent } from './date-value-input/date-value-input.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../shared/testing/mock-translate-loader';
import { FileValueAccessorDirective } from '../../../../shared/utils/file-value-accessor.directive';
import { FileValidator } from '../../../../shared/utils/require-file.validator';
describe('ParameterValueInputComponent', () => { describe('ParameterValueInputComponent', () => {
let component: ParameterValueInputComponent; let component: ParameterValueInputComponent;
let fixture: ComponentFixture<ParameterValueInputComponent>; let fixture: ComponentFixture<ParameterValueInputComponent>;
let booleanParameter;
let stringParameter;
let fileParameter;
let dateParameter;
let outputParameter;
function init() {
booleanParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.BOOLEAN });
stringParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.STRING });
fileParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.FILE });
dateParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.DATE });
outputParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.OUTPUT });
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ParameterValueInputComponent ] imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [
ParameterValueInputComponent,
BooleanValueInputComponent,
StringValueInputComponent,
FileValueInputComponent,
DateValueInputComponent,
FileValueAccessorDirective,
FileValidator
],
schemas: [NO_ERRORS_SCHEMA]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -16,10 +60,46 @@ describe('ParameterValueInputComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ParameterValueInputComponent); fixture = TestBed.createComponent(ParameterValueInputComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.parameter = stringParameter;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should show a BooleanValueInputComponent when the parameter type is boolean', () => {
component.parameter = booleanParameter;
fixture.detectChanges();
const valueInput = fixture.debugElement.query(By.directive(BooleanValueInputComponent));
expect(valueInput).toBeTruthy();
});
it('should show a StringValueInputComponent when the parameter type is string', () => {
component.parameter = stringParameter;
fixture.detectChanges();
const valueInput = fixture.debugElement.query(By.directive(StringValueInputComponent));
expect(valueInput).toBeTruthy();
});
it('should show a FileValueInputComponent when the parameter type is file', () => {
component.parameter = fileParameter;
fixture.detectChanges();
const valueInput = fixture.debugElement.query(By.directive(FileValueInputComponent));
expect(valueInput).toBeTruthy();
});
it('should show a DateValueInputComponent when the parameter type is date', () => {
component.parameter = dateParameter;
fixture.detectChanges();
const valueInput = fixture.debugElement.query(By.directive(DateValueInputComponent));
expect(valueInput).toBeTruthy();
});
it('should show a StringValueInputComponent when the parameter type is output', () => {
component.parameter = outputParameter;
fixture.detectChanges();
const valueInput = fixture.debugElement.query(By.directive(StringValueInputComponent));
expect(valueInput).toBeTruthy();
});
}); });

View File

@@ -2,13 +2,27 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angu
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';
/**
* Component that renders the correct parameter value input based the script parameter's type
*/
@Component({ @Component({
selector: 'ds-parameter-value-input', selector: 'ds-parameter-value-input',
templateUrl: './parameter-value-input.component.html', templateUrl: './parameter-value-input.component.html',
styleUrls: ['./parameter-value-input.component.scss'] styleUrls: ['./parameter-value-input.component.scss']
}) })
export class ParameterValueInputComponent { export class ParameterValueInputComponent {
/**
* The current script parameter
*/
@Input() parameter: ScriptParameter; @Input() parameter: ScriptParameter;
/**
* Emits the value of the input when its updated
*/
@Output() updateValue: EventEmitter<any> = new EventEmitter(); @Output() updateValue: EventEmitter<any> = new EventEmitter();
/**
* The available script parameter types
*/
parameterTypes = ScriptParameterType; parameterTypes = ScriptParameterType;
} }

View File

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

View File

@@ -1,5 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
import { By } from '@angular/platform-browser';
import { StringValueInputComponent } from './string-value-input.component'; import { StringValueInputComponent } from './string-value-input.component';
describe('StringValueInputComponent', () => { describe('StringValueInputComponent', () => {
@@ -8,6 +12,14 @@ describe('StringValueInputComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [StringValueInputComponent] declarations: [StringValueInputComponent]
}) })
.compileComponents(); .compileComponents();
@@ -22,4 +34,37 @@ describe('StringValueInputComponent', () => {
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should not show a validation error if the input field was left untouched but left empty', () => {
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
});
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
component.value = '';
fixture.detectChanges();
tick();
const input = fixture.debugElement.query(By.css('input'));
input.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeTruthy();
}));
it('should not show a validation error if the input field was touched but not left empty', fakeAsync(() => {
component.value = 'testValue';
fixture.detectChanges();
tick();
const input = fixture.debugElement.query(By.css('input'));
input.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
}));
}); });

View File

@@ -1,12 +1,18 @@
import { Component, OnInit } from '@angular/core'; import { Component } from '@angular/core';
import { ValueInputComponent } from '../value-input.component'; import { ValueInputComponent } from '../value-input.component';
/**
* Represents the user inputted value of a string parameter
*/
@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 extends ValueInputComponent<string> { export class StringValueInputComponent extends ValueInputComponent<string> {
/**
* The current value of the string
*/
value: string; value: string;
setValue(value) { setValue(value) {

View File

@@ -1,5 +1,11 @@
import { EventEmitter, Output } from '@angular/core'; import { EventEmitter, Output } from '@angular/core';
/**
* Abstract class that represents value input components
*/
export abstract class ValueInputComponent<T> { export abstract class ValueInputComponent<T> {
/**
* Used by the subclasses to emit the value when it's updated
*/
@Output() updateValue: EventEmitter<T> = new EventEmitter<T>() @Output() updateValue: EventEmitter<T> = new EventEmitter<T>()
} }

View File

@@ -1,14 +1,46 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProcessParametersComponent } from './process-parameters.component'; import { ProcessParametersComponent } from './process-parameters.component';
import { ProcessParameter } from '../../processes/process-parameter.model';
import { By } from '@angular/platform-browser';
import { ParameterSelectComponent } from './parameter-select/parameter-select.component';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { MockTranslateLoader } from '../../../shared/testing/mock-translate-loader';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Script } from '../../scripts/script.model';
import { ScriptParameter } from '../../scripts/script-parameter.model';
describe('ProcessParametersComponent', () => { describe('ProcessParametersComponent', () => {
let component: ProcessParametersComponent; let component: ProcessParametersComponent;
let fixture: ComponentFixture<ProcessParametersComponent>; let fixture: ComponentFixture<ProcessParametersComponent>;
let parameterValues;
let script;
function init() {
const param1 = new ScriptParameter();
const param2 = new ScriptParameter();
script = Object.assign(new Script(), { parameters: [param1, param2] });
parameterValues = [
Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }),
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
]
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ProcessParametersComponent ] imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [ProcessParametersComponent, ParameterSelectComponent],
schemas: [NO_ERRORS_SCHEMA]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -16,10 +48,17 @@ describe('ProcessParametersComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ProcessParametersComponent); fixture = TestBed.createComponent(ProcessParametersComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.script = script;
component.parameterValues = parameterValues;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should render a ParameterSelectComponent for each parameter value of the component', () => {
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
expect(selectComponents.length).toBe(parameterValues.length);
});
}); });

View File

@@ -3,27 +3,54 @@ 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'; import { hasValue } from '../../../shared/empty.util';
/**
* Component that represents the selected list of parameters for a script
*/
@Component({ @Component({
selector: 'ds-process-parameters', selector: 'ds-process-parameters',
templateUrl: './process-parameters.component.html', templateUrl: './process-parameters.component.html',
styleUrls: ['./process-parameters.component.scss'] styleUrls: ['./process-parameters.component.scss']
}) })
export class ProcessParametersComponent implements OnChanges { export class ProcessParametersComponent implements OnChanges {
/**
* The currently selected script
*/
@Input() script: Script; @Input() script: Script;
/**
* Emits the parameter values when they're updated
*/
@Output() updateParameters: EventEmitter<ProcessParameter[]> = new EventEmitter(); @Output() updateParameters: EventEmitter<ProcessParameter[]> = new EventEmitter();
/**
* The current parameter values
*/
parameterValues: ProcessParameter[]; parameterValues: ProcessParameter[];
/**
* Makes sure the parameters are reset when the script changes
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
if (changes.script) { if (changes.script) {
this.initParameters() this.initParameters()
} }
} }
/**
* Empties the parameter values
* Initializes the first parameter value
*/
initParameters() { initParameters() {
this.parameterValues = []; this.parameterValues = [];
this.addParameter(); this.addParameter();
} }
/**
* Updates a single parameter value using its new value and index
* Adds a new parameter when the last of the parameter values is changed
* @param processParameter The new value of the parameter
* @param index The index of the parameter
*/
updateParameter(processParameter: ProcessParameter, index: number) { updateParameter(processParameter: ProcessParameter, index: number) {
this.parameterValues[index] = processParameter; this.parameterValues[index] = processParameter;
if (index === this.parameterValues.length - 1) { if (index === this.parameterValues.length - 1) {
@@ -32,10 +59,17 @@ export class ProcessParametersComponent implements OnChanges {
this.updateParameters.emit(this.parameterValues.filter((param: ProcessParameter) => hasValue(param.name))); this.updateParameters.emit(this.parameterValues.filter((param: ProcessParameter) => hasValue(param.name)));
} }
/**
* Removes a parameter value from the list
* @param index The index of the parameter to remove
*/
removeParameter(index: number) { removeParameter(index: number) {
this.parameterValues = this.parameterValues.filter((value, i) => i !== index); this.parameterValues = this.parameterValues.filter((value, i) => i !== index);
} }
/**
* Adds an empty parameter value to the end of the list
*/
addParameter() { addParameter() {
this.parameterValues = [...this.parameterValues, new ProcessParameter()]; this.parameterValues = [...this.parameterValues, new ProcessParameter()];
} }

View File

@@ -1,7 +1,7 @@
<h3>{{script?.name}}</h3> <h3>{{script?.name}}</h3>
<span>{{script?.description}}</span> <span>{{script?.description}}</span>
<table class="table-border less mt-3"> <table class="table-borderless mt-3 text-secondary">
<tr *ngFor="let param of script?.parameters"> <tr *ngFor="let param of script?.parameters">
<td>{{param.name}} {{param.nameLong}} {{param.type !== 'boolean' ? '<' + param.type + '>' : ''}}</td> <td>{{param.name}} {{param.nameLong}} {{param.type !== 'boolean' ? '<' + param.type + '>' : ''}}</td>
<td>{{param.description}}</td> <td>{{param.description}}</td>

View File

@@ -1,12 +1,29 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ScriptHelpComponent } from './script-help.component'; import { ScriptHelpComponent } from './script-help.component';
import { ScriptParameter } from '../../scripts/script-parameter.model';
import { Script } from '../../scripts/script.model';
import { ScriptParameterType } from '../../scripts/script-parameter-type.model';
import { By } from '@angular/platform-browser';
describe('ScriptHelpComponent', () => { describe('ScriptHelpComponent', () => {
let component: ScriptHelpComponent; let component: ScriptHelpComponent;
let fixture: ComponentFixture<ScriptHelpComponent>; let fixture: ComponentFixture<ScriptHelpComponent>;
let script;
function init() {
const param1 = Object.assign(
new ScriptParameter(),
{name: '-d', description: 'Lorem ipsum dolor sit amet,', type: ScriptParameterType.DATE}
);
const param2 = Object.assign(
new ScriptParameter(),
{name: '-f', description: 'consetetur sadipscing elitr', type: ScriptParameterType.BOOLEAN}
);
script = Object.assign(new Script(), { parameters: [param1, param2] });
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ScriptHelpComponent ] declarations: [ ScriptHelpComponent ]
}) })
@@ -16,10 +33,20 @@ describe('ScriptHelpComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ScriptHelpComponent); fixture = TestBed.createComponent(ScriptHelpComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.script = script;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should show the name and description for each parameter of the script', () => {
const rows = fixture.debugElement.queryAll(By.css('tr'));
expect(rows.length).toBe(script.parameters.length);
script.parameters.forEach((parameter, index) => {
expect(rows[index].queryAll(By.css('td'))[0].nativeElement.textContent).toContain(parameter.name);
expect(rows[index].queryAll(By.css('td'))[1].nativeElement.textContent.trim()).toEqual(parameter.description);
})
});
}); });

View File

@@ -1,11 +1,17 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { Script } from '../../scripts/script.model'; import { Script } from '../../scripts/script.model';
/**
* Components that represents a help section for the script use and parameters
*/
@Component({ @Component({
selector: 'ds-script-help', selector: 'ds-script-help',
templateUrl: './script-help.component.html', templateUrl: './script-help.component.html',
styleUrls: ['./script-help.component.scss'] styleUrls: ['./script-help.component.scss']
}) })
export class ScriptHelpComponent { export class ScriptHelpComponent {
/**
* The current script to show the help information for
*/
@Input() script: Script; @Input() script: Script;
} }

View File

@@ -12,7 +12,7 @@
</select> </select>
<div *ngIf="script.invalid && (script.dirty || script.touched)" <div *ngIf="script.invalid && (script.dirty || script.touched)"
class="alert alert-danger"> class="alert alert-danger validation-error">
<div *ngIf="script.errors.required"> <div *ngIf="script.errors.required">
{{'process.new.select-script.required' | translate}} {{'process.new.select-script.required' | translate}}
</div> </div>

View File

@@ -1,14 +1,54 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { ScriptsSelectComponent } from './scripts-select.component'; import { ScriptsSelectComponent } from './scripts-select.component';
import { MockTranslateLoader } from '../../../shared/testing/mock-translate-loader';
import { Script } from '../../scripts/script.model';
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router-stub';
import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
import { PaginatedList } from '../../../core/data/paginated-list';
import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('ScriptsSelectComponent', () => { describe('ScriptsSelectComponent', () => {
let component: ScriptsSelectComponent; let component: ScriptsSelectComponent;
let fixture: ComponentFixture<ScriptsSelectComponent>; let fixture: ComponentFixture<ScriptsSelectComponent>;
let scriptService;
let script1;
let script2;
function init() {
script1 = new Script();
script2 = new Script();
scriptService = jasmine.createSpyObj('scriptService',
{
findAll: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [script1, script2]))
}
)
}
beforeEach(async(() => { beforeEach(async(() => {
init();
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ScriptsSelectComponent ] imports: [
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})],
declarations: [ScriptsSelectComponent],
providers: [
{ provide: ScriptDataService, useValue: scriptService },
{ provide: Router, useClass: RouterStub },
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
],
schemas: [NO_ERRORS_SCHEMA]
}) })
.compileComponents(); .compileComponents();
})); }));
@@ -16,10 +56,44 @@ describe('ScriptsSelectComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ScriptsSelectComponent); fixture = TestBed.createComponent(ScriptsSelectComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
(component as any)._selectedScript = new Script();
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should not show a validation error if the input field was left untouched but left empty', () => {
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
});
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
(component as any)._selectedScript.id = '';
fixture.detectChanges();
tick();
const select = fixture.debugElement.query(By.css('select'));
select.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeTruthy();
}));
it('should not show a validation error if the input field was touched but not left empty', fakeAsync(() => {
(component as any)._selectedScript.id = 'testValue';
fixture.detectChanges();
tick();
const select = fixture.debugElement.query(By.css('select'));
select.triggerEventHandler('blur', null);
fixture.detectChanges();
const validationError = fixture.debugElement.query(By.css('.validation-error'));
expect(validationError).toBeFalsy();
}));
}); });

View File

@@ -6,10 +6,13 @@ import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shar
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators'; import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { hasValue, hasValueOperator } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
const SCRIPT_QUERY_PARAMETER = 'script'; const SCRIPT_QUERY_PARAMETER = 'script';
/**
* Component used to select a script
*/
@Component({ @Component({
selector: 'ds-scripts-select', selector: 'ds-scripts-select',
templateUrl: './scripts-select.component.html', templateUrl: './scripts-select.component.html',
@@ -28,6 +31,10 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
) { ) {
} }
/**
* Sets all available scripts
* Checks if the route contains a script ID and auto selects this scripts
*/
ngOnInit() { ngOnInit() {
this.scripts$ = this.scriptService.findAll({ elementsPerPage: Number.MAX_SAFE_INTEGER }) this.scripts$ = this.scriptService.findAll({ elementsPerPage: Number.MAX_SAFE_INTEGER })
.pipe( .pipe(
@@ -55,10 +62,17 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
}); });
} }
/**
* Returns the identifier of the selected script
*/
get selectedScript(): string { get selectedScript(): string {
return this._selectedScript ? this._selectedScript.id : undefined; return this._selectedScript ? this._selectedScript.id : undefined;
} }
/**
* Sets the currently selected script by navigating to the correct route using the scripts ID
* @param value The identifier of the script
*/
set selectedScript(value: string) { set selectedScript(value: string) {
this.router.navigate([], this.router.navigate([],
{ {

View File

@@ -8,6 +8,9 @@ import { excludeFromEquals } from '../../core/utilities/equals.decorators';
import { ResourceType } from '../../core/shared/resource-type'; import { ResourceType } from '../../core/shared/resource-type';
import { typedObject } from '../../core/cache/builders/build-decorators'; import { typedObject } from '../../core/cache/builders/build-decorators';
/**
* Object representing a process
*/
@typedObject @typedObject
export class Process implements CacheableObject { export class Process implements CacheableObject {
static type = PROCESS; static type = PROCESS;

View File

@@ -7,6 +7,9 @@ import { typedObject } from '../../core/cache/builders/build-decorators';
import { excludeFromEquals } from '../../core/utilities/equals.decorators'; import { excludeFromEquals } from '../../core/utilities/equals.decorators';
import { ResourceType } from '../../core/shared/resource-type'; import { ResourceType } from '../../core/shared/resource-type';
/**
* Object representing a script
*/
@typedObject @typedObject
export class Script implements CacheableObject { export class Script implements CacheableObject {
static type = SCRIPT; static type = SCRIPT;

View File

@@ -113,15 +113,12 @@ export class UploaderComponent {
ngAfterViewInit() { ngAfterViewInit() {
// Maybe to remove: needed to avoid CORS issue with our temp upload server // Maybe to remove: needed to avoid CORS issue with our temp upload server
this.uploader.onAfterAddingFile = ((item) => { this.uploader.onAfterAddingFile = ((item) => {
console.log(item);
item.withCredentials = false; item.withCredentials = false;
}); });
if (isUndefined(this.onBeforeUpload)) { if (isUndefined(this.onBeforeUpload)) {
this.onBeforeUpload = () => {return}; this.onBeforeUpload = () => {return};
} }
this.uploader.onBeforeUploadItem = (item) => { this.uploader.onBeforeUploadItem = (item) => {
if (item.url !== this.uploader.options.url) { if (item.url !== this.uploader.options.url) {
item.url = this.uploader.options.url; item.url = this.uploader.options.url;
} }
@@ -146,8 +143,6 @@ 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

@@ -13,6 +13,9 @@ import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
{ provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessorDirective, multi: true } { provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessorDirective, multi: true }
] ]
}) })
/**
* Value accessor directive for inputs of type 'file'
*/
export class FileValueAccessorDirective implements ControlValueAccessor { export class FileValueAccessorDirective implements ControlValueAccessor {
value: any; value: any;
onChange = (_) => { /* empty */ }; onChange = (_) => { /* empty */ };

View File

@@ -8,6 +8,9 @@ import {NG_VALIDATORS, Validator, FormControl} from '@angular/forms';
{ provide: NG_VALIDATORS, useExisting: FileValidator, multi: true }, { provide: NG_VALIDATORS, useExisting: FileValidator, multi: true },
] ]
}) })
/**
* Validator directive to validate if a file is selected
*/
export class FileValidator implements Validator { export class FileValidator implements Validator {
static validate(c: FormControl): {[key: string]: any} { static validate(c: FormControl): {[key: string]: any} {
return c.value == null || c.value.length === 0 ? { required : true } : null; return c.value == null || c.value.length === 0 ? { required : true } : null;