From 1cb39cef4159f763d1f53a844d653042b30a94e7 Mon Sep 17 00:00:00 2001 From: lotte Date: Thu, 19 Mar 2020 16:20:41 +0100 Subject: [PATCH 01/30] created new process page --- src/app/app-routing.module.ts | 1 + src/app/core/core.module.ts | 4 + .../new/new-process.component.html | 10 +++ .../new/new-process.component.scss | 0 .../process-page/new/new-process.component.ts | 16 ++++ .../script-help/script-help.component.html | 9 +++ .../script-help/script-help.component.scss | 0 .../script-help/script-help.component.spec.ts | 25 +++++++ .../new/script-help/script-help.component.ts | 11 +++ .../scripts-select.component.html | 6 ++ .../scripts-select.component.scss | 0 .../scripts-select.component.spec.ts | 25 +++++++ .../scripts-select.component.ts | 41 ++++++++++ .../process-page-routing.module.ts | 17 +++++ src/app/process-page/process-page.module.ts | 30 ++++++++ .../processes/process-data.service.ts | 29 ++++++++ .../processes/process-parameter.model.ts | 13 ++++ .../processes/process-status.model.ts | 9 +++ .../process-page/processes/process.model.ts | 74 +++++++++++++++++++ .../processes/process.resource-type.ts | 9 +++ .../scripts/script-data.service.ts | 29 ++++++++ .../scripts/script-parameter-type.model.ts | 10 +++ .../scripts/script-parameter.model.ts | 31 ++++++++ src/app/process-page/scripts/script.model.ts | 52 +++++++++++++ .../scripts/script.resource-type.ts | 9 +++ 25 files changed, 460 insertions(+) create mode 100644 src/app/process-page/new/new-process.component.html create mode 100644 src/app/process-page/new/new-process.component.scss create mode 100644 src/app/process-page/new/new-process.component.ts create mode 100644 src/app/process-page/new/script-help/script-help.component.html create mode 100644 src/app/process-page/new/script-help/script-help.component.scss create mode 100644 src/app/process-page/new/script-help/script-help.component.spec.ts create mode 100644 src/app/process-page/new/script-help/script-help.component.ts create mode 100644 src/app/process-page/new/scripts-select/scripts-select.component.html create mode 100644 src/app/process-page/new/scripts-select/scripts-select.component.scss create mode 100644 src/app/process-page/new/scripts-select/scripts-select.component.spec.ts create mode 100644 src/app/process-page/new/scripts-select/scripts-select.component.ts create mode 100644 src/app/process-page/process-page-routing.module.ts create mode 100644 src/app/process-page/process-page.module.ts create mode 100644 src/app/process-page/processes/process-data.service.ts create mode 100644 src/app/process-page/processes/process-parameter.model.ts create mode 100644 src/app/process-page/processes/process-status.model.ts create mode 100644 src/app/process-page/processes/process.model.ts create mode 100644 src/app/process-page/processes/process.resource-type.ts create mode 100644 src/app/process-page/scripts/script-data.service.ts create mode 100644 src/app/process-page/scripts/script-parameter-type.model.ts create mode 100644 src/app/process-page/scripts/script-parameter.model.ts create mode 100644 src/app/process-page/scripts/script.model.ts create mode 100644 src/app/process-page/scripts/script.resource-type.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 2927cd4e65..db018fff9d 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -86,6 +86,7 @@ export function getDSOPath(dso: DSpaceObject): string { path: PROFILE_MODULE_PATH, loadChildren: './profile-page/profile-page.module#ProfilePageModule', canActivate: [AuthenticatedGuard] }, + { path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard] }, { path: '**', pathMatch: 'full', component: PageNotFoundComponent }, ], { diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 76b0e3e76c..4d04a79d73 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -139,6 +139,8 @@ import { VersionDataService } from './data/version-data.service'; import { VersionHistoryDataService } from './data/version-history-data.service'; import { Version } from './shared/version.model'; import { VersionHistory } from './shared/version-history.model'; +import { Script } from '../process-page/scripts/script.model'; +import { Process } from '../process-page/processes/process.model'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -307,6 +309,8 @@ export const models = ItemType, ExternalSource, ExternalSourceEntry, + Script, + Process, Version, VersionHistory ]; diff --git a/src/app/process-page/new/new-process.component.html b/src/app/process-page/new/new-process.component.html new file mode 100644 index 0000000000..9e050c37b5 --- /dev/null +++ b/src/app/process-page/new/new-process.component.html @@ -0,0 +1,10 @@ +
+
+
+ +
+
+ +
+
+
diff --git a/src/app/process-page/new/new-process.component.scss b/src/app/process-page/new/new-process.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/process-page/new/new-process.component.ts b/src/app/process-page/new/new-process.component.ts new file mode 100644 index 0000000000..c5fc786442 --- /dev/null +++ b/src/app/process-page/new/new-process.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { Script } from '../scripts/script.model'; + +@Component({ + selector: 'ds-new-process', + templateUrl: './new-process.component.html', + styleUrls: ['./new-process.component.scss'], +}) +export class NewProcessComponent { + public selectedScript: Script; + + selectScript(script: Script) { + this.selectedScript = script; + console.log('selected script: ', script); + } +} 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 new file mode 100644 index 0000000000..937f7c007f --- /dev/null +++ b/src/app/process-page/new/script-help/script-help.component.html @@ -0,0 +1,9 @@ +

{{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.scss b/src/app/process-page/new/script-help/script-help.component.scss new file mode 100644 index 0000000000..e69de29bb2 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 new file mode 100644 index 0000000000..286afa9922 --- /dev/null +++ b/src/app/process-page/new/script-help/script-help.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ScriptHelpComponent } from './script-help.component'; + +describe('ScriptHelpComponent', () => { + let component: ScriptHelpComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ScriptHelpComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ScriptHelpComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000..0ff4a90ae4 --- /dev/null +++ b/src/app/process-page/new/script-help/script-help.component.ts @@ -0,0 +1,11 @@ +import { Component, Input } from '@angular/core'; +import { Script } from '../../scripts/script.model'; + +@Component({ + selector: 'ds-script-help', + templateUrl: './script-help.component.html', + styleUrls: ['./script-help.component.scss'] +}) +export class ScriptHelpComponent { + @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 new file mode 100644 index 0000000000..69b1830941 --- /dev/null +++ b/src/app/process-page/new/scripts-select/scripts-select.component.html @@ -0,0 +1,6 @@ + diff --git a/src/app/process-page/new/scripts-select/scripts-select.component.scss b/src/app/process-page/new/scripts-select/scripts-select.component.scss new file mode 100644 index 0000000000..e69de29bb2 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 new file mode 100644 index 0000000000..b433d633f1 --- /dev/null +++ b/src/app/process-page/new/scripts-select/scripts-select.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ScriptsSelectComponent } from './scripts-select.component'; + +describe('ScriptsSelectComponent', () => { + let component: ScriptsSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ScriptsSelectComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ScriptsSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000..70b13c2e62 --- /dev/null +++ b/src/app/process-page/new/scripts-select/scripts-select.component.ts @@ -0,0 +1,41 @@ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { ScriptDataService } from '../../scripts/script-data.service'; +import { Script } from '../../scripts/script.model'; +import { Observable } from 'rxjs'; +import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators'; +import { PaginatedList } from '../../../core/data/paginated-list'; +import { map } from 'rxjs/operators'; + +@Component({ + selector: 'ds-scripts-select', + templateUrl: './scripts-select.component.html', + styleUrls: ['./scripts-select.component.scss'] +}) +export class ScriptsSelectComponent implements OnInit { + @Output() select: EventEmitter
-
- - + + + +
-
+ diff --git a/src/app/process-page/new/new-process.component.ts b/src/app/process-page/new/new-process.component.ts index 57da770dd9..0c98d4d8b4 100644 --- a/src/app/process-page/new/new-process.component.ts +++ b/src/app/process-page/new/new-process.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { Script } from '../scripts/script.model'; import { Process } from '../processes/process.model'; +import { ProcessParameter } from '../processes/process-parameter.model'; +import { ScriptDataService } from '../../core/data/processes/script-data.service'; @Component({ selector: 'ds-new-process', @@ -10,13 +12,32 @@ import { Process } from '../processes/process.model'; export class NewProcessComponent implements OnInit { public selectedScript: Script; public process: Process; + public parameters: ProcessParameter[]; + public files: File[] = []; + + constructor(private scriptService: ScriptDataService) { + } ngOnInit(): void { this.process = new Process(); } - selectScript(script: Script) { - this.selectedScript = script; - console.log('selected script: ', script); + submitForm() { + const stringParameters: ProcessParameter[] = this.parameters.map((parameter: ProcessParameter) => { + 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; } } diff --git a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.html b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.html index 63aa5afaf9..204b90dc77 100644 --- a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.html +++ b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.html @@ -9,7 +9,7 @@ {{param.nameLong || param.name}} - + diff --git a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts index 42ae16ca1c..b0145b10a3 100644 --- a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts @@ -31,6 +31,7 @@ export class ParameterSelectComponent implements OnInit { set selectedParameter(value: string) { this.parameterValue.name = value; + this.selectedParameterValue = undefined; this.changeParameter.emit(this.parameterValue); } diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html new file mode 100644 index 0000000000..85b27713d2 --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.html @@ -0,0 +1 @@ + diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.scss b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts new file mode 100644 index 0000000000..824d922236 --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BooleanValueInputComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BooleanValueInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts new file mode 100644 index 0000000000..0c4faf0667 --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts @@ -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 implements OnInit { + ngOnInit() { + this.updateValue.emit(true) + } +} diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html new file mode 100644 index 0000000000..3b349bfd43 --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html @@ -0,0 +1,7 @@ + +
+
+ {{'process.new.parameter.string.required' | translate}} +
+
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts new file mode 100644 index 0000000000..5c4b44c3a3 --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DateValueInputComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DateValueInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts new file mode 100644 index 0000000000..f266bebb9a --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts @@ -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 { + value: string; + + setValue(value) { + this.value = value; + this.updateValue.emit(value) + } +} diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html index cb211e607b..aa58d1ffac 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html @@ -1,6 +1,10 @@ - + + +
+
+ {{'process.new.parameter.file.required' | translate}} +
+
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts index d0fa9793d3..ce54207312 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts @@ -1,33 +1,16 @@ -import { Component, OnInit } from '@angular/core'; -import { FileUploaderOptions } from 'ng2-file-upload'; -import { UploaderOptions } from '../../../../../shared/uploader/uploader-options.model'; +import { Component } from '@angular/core'; +import { ValueInputComponent } from '../value-input.component'; @Component({ selector: 'ds-file-value-input', templateUrl: './file-value-input.component.html', styleUrls: ['./file-value-input.component.scss'] }) -export class FileValueInputComponent implements OnInit { - uploadFilesOptions: FileUploaderOptions; - - constructor() { - } - - 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() { - +export class FileValueInputComponent extends ValueInputComponent { + file: File; + setFile(files) { + this.file = files.length > 0 ? files[0] : undefined; + console.log(this.file); + this.updateValue.emit(this.file); } } diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.html index 22d60c8f7f..15261975b9 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.html @@ -1,4 +1,7 @@
- - + + + + +
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts index 17c627b371..5adb96505d 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts @@ -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 { ScriptParameter } from '../../../scripts/script-parameter.model'; @@ -9,5 +9,6 @@ import { ScriptParameter } from '../../../scripts/script-parameter.model'; }) export class ParameterValueInputComponent { @Input() parameter: ScriptParameter; + @Output() updateValue: EventEmitter = new EventEmitter(); parameterTypes = ScriptParameterType; } diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html index e572624f22..e0693efffa 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html @@ -1 +1,7 @@ - + +
+
+ {{'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.ts b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.ts index 5c88523d8d..86db8b87d9 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,15 +1,16 @@ import { Component, OnInit } from '@angular/core'; +import { ValueInputComponent } from '../value-input.component'; @Component({ selector: 'ds-string-value-input', templateUrl: './string-value-input.component.html', styleUrls: ['./string-value-input.component.scss'] }) -export class StringValueInputComponent implements OnInit { +export class StringValueInputComponent extends ValueInputComponent { + value: string; - constructor() { } - - ngOnInit() { + setValue(value) { + this.value = value; + this.updateValue.emit(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 new file mode 100644 index 0000000000..949c48728d --- /dev/null +++ b/src/app/process-page/new/process-parameters/parameter-value-input/value-input.component.ts @@ -0,0 +1,5 @@ +import { EventEmitter, Output } from '@angular/core'; + +export abstract class ValueInputComponent { + @Output() updateValue: EventEmitter = new EventEmitter() +} diff --git a/src/app/process-page/new/process-parameters/process-parameters.component.html b/src/app/process-page/new/process-parameters/process-parameters.component.html index 98c364cbee..24e9c9b1e3 100644 --- a/src/app/process-page/new/process-parameters/process-parameters.component.html +++ b/src/app/process-page/new/process-parameters/process-parameters.component.html @@ -1,5 +1,5 @@
- + = new EventEmitter(); parameterValues: ProcessParameter[]; ngOnChanges(changes: SimpleChanges): void { @@ -27,6 +29,7 @@ export class ProcessParametersComponent implements OnChanges { if (index === this.parameterValues.length - 1) { this.addParameter(); } + this.updateParameters.emit(this.parameterValues.filter((param: ProcessParameter) => hasValue(param.name))); } removeParameter(index: number) { 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 781566aec8..44b06079ae 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 @@ -1,11 +1,11 @@
- + - +
diff --git a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.spec.ts index 0a435f6e27..97c0d7c3d0 100644 --- a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.spec.ts +++ b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.spec.ts @@ -1,25 +1,71 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 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', () => { let component: ParameterSelectComponent; let fixture: ComponentFixture; + 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(() => { + init(); TestBed.configureTestingModule({ - declarations: [ ParameterSelectComponent ] + imports: [FormsModule], + declarations: [ParameterSelectComponent], + schemas: [NO_ERRORS_SCHEMA] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(ParameterSelectComponent); component = fixture.componentInstance; + + component.parameters = scriptParams; + component.removable = false; fixture.detectChanges(); }); it('should create', () => { 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(); + }); }); diff --git a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts index b0145b10a3..a9d5193b9e 100644 --- a/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-select/parameter-select.component.ts @@ -3,16 +3,37 @@ import { ProcessParameter } from '../../../processes/process-parameter.model'; import { ScriptParameter } from '../../../scripts/script-parameter.model'; import { hasNoValue } from '../../../../shared/empty.util'; +/** + * Component to select a single parameter for a process + */ @Component({ selector: 'ds-parameter-select', templateUrl: './parameter-select.component.html', styleUrls: ['./parameter-select.component.scss'] }) export class ParameterSelectComponent implements OnInit { + /** + * The current parameter value of the selected parameter + */ @Input() parameterValue: ProcessParameter; + /** + * The available script parameters for the script + */ @Input() parameters: ScriptParameter[]; + + /** + * Whether or not this selected parameter can be removed from the list + */ @Input() removable: boolean; + + /** + * Emits the parameter value when it's removed + */ @Output() removeParameter: EventEmitter = new EventEmitter(); + + /** + * Emits the updated parameter value when it changes + */ @Output() changeParameter: EventEmitter = new EventEmitter(); ngOnInit(): void { @@ -21,24 +42,43 @@ export class ParameterSelectComponent implements OnInit { } } + /** + * Returns the script parameter based on the currently selected name + */ get selectedScriptParameter(): ScriptParameter { return this.parameters.find((parameter: ScriptParameter) => parameter.name === this.selectedParameter); } + /** + * Return the currently selected parameter name + */ get selectedParameter(): string { 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) { this.parameterValue.name = value; this.selectedParameterValue = undefined; this.changeParameter.emit(this.parameterValue); } + /** + * Returns the currently selected parameter value + */ get selectedParameterValue(): any { 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) { this.parameterValue.value = value; this.changeParameter.emit(this.parameterValue); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts index 824d922236..15f09d98f0 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.spec.ts @@ -1,25 +1,32 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 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 fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ BooleanValueInputComponent ] + declarations: [BooleanValueInputComponent] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(BooleanValueInputComponent); component = fixture.componentInstance; + spyOn(component.updateValue, 'emit'); fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('should emit true onInit', () => { + expect(component.updateValue.emit).toHaveBeenCalledWith(true); + }); }); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts index 0c4faf0667..c75c5cf240 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { ValueInputComponent } from '../value-input.component'; +/** + * Represents the value of a boolean parameter + */ @Component({ selector: 'ds-boolean-value-input', templateUrl: './boolean-value-input.component.html', diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html index 3b349bfd43..7eeca02974 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.html @@ -1,6 +1,6 @@ - +
+ 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/date-value-input/date-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts index 5c4b44c3a3..ab50efc93c 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.spec.ts @@ -1,16 +1,28 @@ -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 { 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 fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ DateValueInputComponent ] + imports: [ + FormsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + })], + declarations: [DateValueInputComponent] }) - .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/date-value-input/date-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts index f266bebb9a..7476e2ac6b 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/date-value-input/date-value-input.component.ts @@ -1,12 +1,18 @@ import { Component, OnInit } from '@angular/core'; import { ValueInputComponent } from '../value-input.component'; +/** + * Represents the user inputted value of a date parameter + */ @Component({ selector: 'ds-date-value-input', templateUrl: './date-value-input.component.html', styleUrls: ['./date-value-input.component.scss'] }) export class DateValueInputComponent extends ValueInputComponent { + /** + * The current value of the date string + */ value: string; setValue(value) { diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html index aa58d1ffac..9f61141a00 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.html @@ -3,7 +3,7 @@
+ class="alert alert-danger validation-error">
{{'process.new.parameter.file.required' | translate}}
diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.spec.ts index b7de5e5a23..a1d5b0dc43 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.spec.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.spec.ts @@ -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 { 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', () => { let component: FileValueInputComponent; @@ -8,9 +15,19 @@ describe('FileValueInputComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ FileValueInputComponent ] + imports: [ + FormsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + })], + declarations: [FileValueInputComponent, FileValueAccessorDirective, FileValidator], + schemas: [NO_ERRORS_SCHEMA] + }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { @@ -22,4 +39,19 @@ describe('FileValueInputComponent', () => { 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', () => { + 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(); + }); }); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts index ce54207312..da16119d35 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/file-value-input/file-value-input.component.ts @@ -1,16 +1,21 @@ import { Component } from '@angular/core'; import { ValueInputComponent } from '../value-input.component'; +/** + * Represents the user inputted value of a file parameter + */ @Component({ selector: 'ds-file-value-input', templateUrl: './file-value-input.component.html', styleUrls: ['./file-value-input.component.scss'] }) export class FileValueInputComponent extends ValueInputComponent { + /** + * The current value of the file + */ file: File; setFile(files) { this.file = files.length > 0 ? files[0] : undefined; - console.log(this.file); this.updateValue.emit(this.file); } } diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.spec.ts b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.spec.ts index 91045ea0f4..ef315ac981 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.spec.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.spec.ts @@ -1,25 +1,105 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 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', () => { let component: ParameterValueInputComponent; let fixture: ComponentFixture; + 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(() => { + init(); 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(); })); beforeEach(() => { fixture = TestBed.createComponent(ParameterValueInputComponent); component = fixture.componentInstance; + component.parameter = stringParameter; fixture.detectChanges(); }); it('should create', () => { 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(); + }); }); diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts index 5adb96505d..42479f4041 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts +++ b/src/app/process-page/new/process-parameters/parameter-value-input/parameter-value-input.component.ts @@ -2,13 +2,27 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angu import { ScriptParameterType } from '../../../scripts/script-parameter-type.model'; import { ScriptParameter } from '../../../scripts/script-parameter.model'; +/** + * Component that renders the correct parameter value input based the script parameter's type + */ @Component({ selector: 'ds-parameter-value-input', templateUrl: './parameter-value-input.component.html', styleUrls: ['./parameter-value-input.component.scss'] }) export class ParameterValueInputComponent { + /** + * The current script parameter + */ @Input() parameter: ScriptParameter; + + /** + * Emits the value of the input when its updated + */ @Output() updateValue: EventEmitter = new EventEmitter(); + + /** + * The available script parameter types + */ parameterTypes = ScriptParameterType; } diff --git a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html index e0693efffa..7eeca02974 100644 --- a/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html +++ b/src/app/process-page/new/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html @@ -1,6 +1,6 @@
+ 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}} - +
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} { From e7a5daad1895b99a013331eaab683cb5eac04c79 Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 25 Mar 2020 18:22:20 +0100 Subject: [PATCH 08/30] fixed tests and feedback --- resources/i18n/en.json5 | 20 ++++++++ .../data/processes/script-data.service.ts | 17 ++++--- .../new/new-process.component.html | 13 ++++- .../new/new-process.component.spec.ts | 18 ++++++- .../process-page/new/new-process.component.ts | 49 +++++++++++++++++-- .../parameter-select.component.html | 6 +-- .../parameter-select.component.ts | 12 ++++- .../boolean-value-input.component.html | 2 +- .../boolean-value-input.component.ts | 9 +++- .../date-value-input.component.html | 2 +- .../date-value-input.component.ts | 9 +++- .../file-value-input.component.html | 9 ++-- .../file-value-input.component.scss | 6 +++ .../file-value-input.component.spec.ts | 4 +- .../file-value-input.component.ts | 15 ++++-- .../parameter-value-input.component.html | 10 ++-- .../parameter-value-input.component.ts | 11 ++++- .../string-value-input.component.html | 2 +- .../string-value-input.component.spec.ts | 8 +-- .../string-value-input.component.ts | 9 +++- .../value-input.component.ts | 3 +- .../process-parameters.component.html | 1 + .../process-parameters.component.ts | 26 ++++++++-- .../script-help/script-help.component.html | 11 ++++- .../script-help/script-help.component.spec.ts | 15 +++++- .../new/script-help/script-help.component.ts | 6 +++ .../scripts-select.component.html | 2 +- .../scripts-select.component.ts | 9 +++- .../process-page-routing.module.ts | 1 + 29 files changed, 248 insertions(+), 57 deletions(-) diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index 385fefd156..2f6c604bc4 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -1616,6 +1616,8 @@ "process.new.select-parameters": "Parameters", + "process.new.cancel": "Cancel", + "process.new.submit": "Submit", "process.new.select-script": "Script", @@ -1630,6 +1632,24 @@ "process.new.parameter.string.required": "Parameter value is required", + "process.new.parameter.type.value": "value", + + "process.new.parameter.type.file": "file", + + "process.new.parameter.required.missing": "The following parameters are required but still missing:", + + "process.new.notification.success.title": "Success", + + "process.new.notification.success.content": "The process was successfully created", + + "process.new.notification.error.title": "Error", + + "process.new.notification.error.content": "An error occurred while creating this process", + + "process.new.header": "Create a new process", + + "process.new.title": "Create a new process", + "publication.listelement.badge": "Publication", diff --git a/src/app/core/data/processes/script-data.service.ts b/src/app/core/data/processes/script-data.service.ts index 6c7222451e..b18c993a52 100644 --- a/src/app/core/data/processes/script-data.service.ts +++ b/src/app/core/data/processes/script-data.service.ts @@ -10,10 +10,12 @@ import { HttpClient } from '@angular/common/http'; import { DefaultChangeAnalyzer } from '../default-change-analyzer.service'; import { Script } from '../../../process-page/scripts/script.model'; import { ProcessParameter } from '../../../process-page/processes/process-parameter.model'; -import { map } from 'rxjs/operators'; +import { find, map, switchMap, tap } from 'rxjs/operators'; import { URLCombiner } from '../../url-combiner/url-combiner'; import { MultipartPostRequest, RestRequest } from '../request.models'; import { RequestService } from '../request.service'; +import { Observable } from 'rxjs'; +import { RequestEntry } from '../request.reducer'; @Injectable() export class ScriptDataService extends DataService
{{param.name}} {{param.nameLong}} {{param.type !== 'boolean' ? '<' + param.type + '>' : ''}} {{param.description}}