+ class="alert alert-danger validation-error">
{{'process.new.parameter.string.required' | translate}}
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.spec.ts
index 11af3a4b23..c6f04ada20 100644
--- a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.spec.ts
+++ b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.spec.ts
@@ -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';
describe('StringValueInputComponent', () => {
@@ -8,9 +12,17 @@ describe('StringValueInputComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ StringValueInputComponent ]
+ imports: [
+ FormsModule,
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: MockTranslateLoader
+ }
+ })],
+ declarations: [StringValueInputComponent]
})
- .compileComponents();
+ .compileComponents();
}));
beforeEach(() => {
@@ -22,4 +34,37 @@ describe('StringValueInputComponent', () => {
it('should create', () => {
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();
+ }));
});
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.ts
index 86db8b87d9..bfcc277b3d 100644
--- a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.ts
+++ b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.ts
@@ -1,12 +1,18 @@
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
import { ValueInputComponent } from '../value-input.component';
+/**
+ * Represents the user inputted value of a string parameter
+ */
@Component({
selector: 'ds-string-value-input',
templateUrl: './string-value-input.component.html',
styleUrls: ['./string-value-input.component.scss']
})
export class StringValueInputComponent extends ValueInputComponent
{
+ /**
+ * The current value of the string
+ */
value: string;
setValue(value) {
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/value-input.component.ts
index 949c48728d..a46e059407 100644
--- a/src/app/process-page/new/process-parameters/parameter-value-input/value-input.component.ts
+++ b/src/app/process-page/new/process-parameters/parameter-value-input/value-input.component.ts
@@ -1,5 +1,11 @@
import { EventEmitter, Output } from '@angular/core';
+/**
+ * Abstract class that represents value input components
+ */
export abstract class ValueInputComponent {
+ /**
+ * Used by the subclasses to emit the value when it's updated
+ */
@Output() updateValue: EventEmitter = new EventEmitter()
}
diff --git a/src/app/process-page/new/process-parameters/process-parameters.component.spec.ts b/src/app/process-page/new/process-parameters/process-parameters.component.spec.ts
index 0eb4edb864..2a95d542f0 100644
--- a/src/app/process-page/new/process-parameters/process-parameters.component.spec.ts
+++ b/src/app/process-page/new/process-parameters/process-parameters.component.spec.ts
@@ -1,25 +1,64 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
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', () => {
let component: ProcessParametersComponent;
let fixture: ComponentFixture;
+ 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(() => {
+ init();
TestBed.configureTestingModule({
- declarations: [ ProcessParametersComponent ]
+ imports: [
+ FormsModule,
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: MockTranslateLoader
+ }
+ })],
+ declarations: [ProcessParametersComponent, ParameterSelectComponent],
+ schemas: [NO_ERRORS_SCHEMA]
})
- .compileComponents();
+ .compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProcessParametersComponent);
component = fixture.componentInstance;
+ component.script = script;
+ component.parameterValues = parameterValues;
fixture.detectChanges();
});
it('should create', () => {
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);
+ });
});
diff --git a/src/app/process-page/new/process-parameters/process-parameters.component.ts b/src/app/process-page/new/process-parameters/process-parameters.component.ts
index 156c5a5ebf..765410dc8d 100644
--- a/src/app/process-page/new/process-parameters/process-parameters.component.ts
+++ b/src/app/process-page/new/process-parameters/process-parameters.component.ts
@@ -3,27 +3,54 @@ import { Script } from '../../scripts/script.model';
import { ProcessParameter } from '../../processes/process-parameter.model';
import { hasValue } from '../../../shared/empty.util';
+/**
+ * Component that represents the selected list of parameters for a script
+ */
@Component({
selector: 'ds-process-parameters',
templateUrl: './process-parameters.component.html',
styleUrls: ['./process-parameters.component.scss']
})
export class ProcessParametersComponent implements OnChanges {
+ /**
+ * The currently selected script
+ */
@Input() script: Script;
+ /**
+ * Emits the parameter values when they're updated
+ */
@Output() updateParameters: EventEmitter = new EventEmitter();
+
+ /**
+ * The current parameter values
+ */
parameterValues: ProcessParameter[];
+ /**
+ * Makes sure the parameters are reset when the script changes
+ * @param changes
+ */
ngOnChanges(changes: SimpleChanges): void {
if (changes.script) {
this.initParameters()
}
}
+ /**
+ * Empties the parameter values
+ * Initializes the first parameter value
+ */
initParameters() {
this.parameterValues = [];
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) {
this.parameterValues[index] = processParameter;
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)));
}
+ /**
+ * Removes a parameter value from the list
+ * @param index The index of the parameter to remove
+ */
removeParameter(index: number) {
this.parameterValues = this.parameterValues.filter((value, i) => i !== index);
}
+ /**
+ * Adds an empty parameter value to the end of the list
+ */
addParameter() {
this.parameterValues = [...this.parameterValues, new ProcessParameter()];
}
diff --git a/src/app/process-page/new/script-help/script-help.component.html b/src/app/process-page/new/script-help/script-help.component.html
index a12fafdf4c..a9bb114f2e 100644
--- a/src/app/process-page/new/script-help/script-help.component.html
+++ b/src/app/process-page/new/script-help/script-help.component.html
@@ -1,7 +1,7 @@
{{script?.name}}
{{script?.description}}
-
+
{{param.name}} {{param.nameLong}} {{param.type !== 'boolean' ? '<' + param.type + '>' : ''}} |
{{param.description}} |
diff --git a/src/app/process-page/new/script-help/script-help.component.spec.ts b/src/app/process-page/new/script-help/script-help.component.spec.ts
index 286afa9922..6ebcb5b6c3 100644
--- a/src/app/process-page/new/script-help/script-help.component.spec.ts
+++ b/src/app/process-page/new/script-help/script-help.component.spec.ts
@@ -1,12 +1,29 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
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', () => {
let component: ScriptHelpComponent;
let fixture: ComponentFixture;
+ 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(() => {
+ init();
TestBed.configureTestingModule({
declarations: [ ScriptHelpComponent ]
})
@@ -16,10 +33,20 @@ describe('ScriptHelpComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ScriptHelpComponent);
component = fixture.componentInstance;
+ component.script = script;
fixture.detectChanges();
});
it('should create', () => {
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);
+ })
+ });
});
diff --git a/src/app/process-page/new/script-help/script-help.component.ts b/src/app/process-page/new/script-help/script-help.component.ts
index 0ff4a90ae4..7061e59730 100644
--- a/src/app/process-page/new/script-help/script-help.component.ts
+++ b/src/app/process-page/new/script-help/script-help.component.ts
@@ -1,11 +1,17 @@
import { Component, Input } from '@angular/core';
import { Script } from '../../scripts/script.model';
+/**
+ * Components that represents a help section for the script use and parameters
+ */
@Component({
selector: 'ds-script-help',
templateUrl: './script-help.component.html',
styleUrls: ['./script-help.component.scss']
})
export class ScriptHelpComponent {
+ /**
+ * The current script to show the help information for
+ */
@Input() script: Script;
}
diff --git a/src/app/process-page/new/scripts-select/scripts-select.component.html b/src/app/process-page/new/scripts-select/scripts-select.component.html
index 44b06079ae..d34947c137 100644
--- a/src/app/process-page/new/scripts-select/scripts-select.component.html
+++ b/src/app/process-page/new/scripts-select/scripts-select.component.html
@@ -12,7 +12,7 @@
+ class="alert alert-danger validation-error">
{{'process.new.select-script.required' | translate}}
diff --git a/src/app/process-page/new/scripts-select/scripts-select.component.spec.ts b/src/app/process-page/new/scripts-select/scripts-select.component.spec.ts
index b433d633f1..f7e1f82735 100644
--- a/src/app/process-page/new/scripts-select/scripts-select.component.spec.ts
+++ b/src/app/process-page/new/scripts-select/scripts-select.component.spec.ts
@@ -1,25 +1,99 @@
-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 { 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', () => {
let component: ScriptsSelectComponent;
let fixture: ComponentFixture
;
+ 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(() => {
+ init();
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();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ScriptsSelectComponent);
component = fixture.componentInstance;
+ (component as any)._selectedScript = new Script();
fixture.detectChanges();
});
it('should create', () => {
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();
+ }));
});
diff --git a/src/app/process-page/new/scripts-select/scripts-select.component.ts b/src/app/process-page/new/scripts-select/scripts-select.component.ts
index c0daa94fb0..a3d3095bf9 100644
--- a/src/app/process-page/new/scripts-select/scripts-select.component.ts
+++ b/src/app/process-page/new/scripts-select/scripts-select.component.ts
@@ -6,10 +6,13 @@ import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shar
import { PaginatedList } from '../../../core/data/paginated-list';
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
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';
+/**
+ * Component used to select a script
+ */
@Component({
selector: 'ds-scripts-select',
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() {
this.scripts$ = this.scriptService.findAll({ elementsPerPage: Number.MAX_SAFE_INTEGER })
.pipe(
@@ -55,10 +62,17 @@ export class ScriptsSelectComponent implements OnInit, OnDestroy {
});
}
+ /**
+ * Returns the identifier of the selected script
+ */
get selectedScript(): string {
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) {
this.router.navigate([],
{
diff --git a/src/app/process-page/processes/process.model.ts b/src/app/process-page/processes/process.model.ts
index 4cf3d507a4..cd2c03d6f7 100644
--- a/src/app/process-page/processes/process.model.ts
+++ b/src/app/process-page/processes/process.model.ts
@@ -8,6 +8,9 @@ import { excludeFromEquals } from '../../core/utilities/equals.decorators';
import { ResourceType } from '../../core/shared/resource-type';
import { typedObject } from '../../core/cache/builders/build-decorators';
+/**
+ * Object representing a process
+ */
@typedObject
export class Process implements CacheableObject {
static type = PROCESS;
diff --git a/src/app/process-page/scripts/script.model.ts b/src/app/process-page/scripts/script.model.ts
index 1cd3136c88..e94d233fc2 100644
--- a/src/app/process-page/scripts/script.model.ts
+++ b/src/app/process-page/scripts/script.model.ts
@@ -7,6 +7,9 @@ import { typedObject } from '../../core/cache/builders/build-decorators';
import { excludeFromEquals } from '../../core/utilities/equals.decorators';
import { ResourceType } from '../../core/shared/resource-type';
+/**
+ * Object representing a script
+ */
@typedObject
export class Script implements CacheableObject {
static type = SCRIPT;
diff --git a/src/app/shared/uploader/uploader.component.ts b/src/app/shared/uploader/uploader.component.ts
index a5fce98ceb..935d196d08 100644
--- a/src/app/shared/uploader/uploader.component.ts
+++ b/src/app/shared/uploader/uploader.component.ts
@@ -113,15 +113,12 @@ export class UploaderComponent {
ngAfterViewInit() {
// Maybe to remove: needed to avoid CORS issue with our temp upload server
this.uploader.onAfterAddingFile = ((item) => {
- console.log(item);
-
item.withCredentials = false;
});
if (isUndefined(this.onBeforeUpload)) {
this.onBeforeUpload = () => {return};
}
this.uploader.onBeforeUploadItem = (item) => {
-
if (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.onProgressItem = () => this.onProgress();
-
- console.log(this.uploader.options.formatDataFunction());
}
/**
diff --git a/src/app/shared/utils/file-value-accessor.directive.ts b/src/app/shared/utils/file-value-accessor.directive.ts
index 8c4f071cbe..bcd3381329 100644
--- a/src/app/shared/utils/file-value-accessor.directive.ts
+++ b/src/app/shared/utils/file-value-accessor.directive.ts
@@ -13,6 +13,9 @@ import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
{ provide: NG_VALUE_ACCESSOR, useExisting: FileValueAccessorDirective, multi: true }
]
})
+/**
+ * Value accessor directive for inputs of type 'file'
+ */
export class FileValueAccessorDirective implements ControlValueAccessor {
value: any;
onChange = (_) => { /* empty */ };
diff --git a/src/app/shared/utils/require-file.validator.ts b/src/app/shared/utils/require-file.validator.ts
index c6480e1715..9fa89c4188 100644
--- a/src/app/shared/utils/require-file.validator.ts
+++ b/src/app/shared/utils/require-file.validator.ts
@@ -8,9 +8,12 @@ import {NG_VALIDATORS, Validator, FormControl} from '@angular/forms';
{ provide: NG_VALIDATORS, useExisting: FileValidator, multi: true },
]
})
+/**
+ * Validator directive to validate if a file is selected
+ */
export class FileValidator implements Validator {
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;
}
validate(c: FormControl): {[key: string]: any} {