mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
fixed tests and feedback
This commit is contained in:
@@ -1616,6 +1616,8 @@
|
|||||||
|
|
||||||
"process.new.select-parameters": "Parameters",
|
"process.new.select-parameters": "Parameters",
|
||||||
|
|
||||||
|
"process.new.cancel": "Cancel",
|
||||||
|
|
||||||
"process.new.submit": "Submit",
|
"process.new.submit": "Submit",
|
||||||
|
|
||||||
"process.new.select-script": "Script",
|
"process.new.select-script": "Script",
|
||||||
@@ -1630,6 +1632,24 @@
|
|||||||
|
|
||||||
"process.new.parameter.string.required": "Parameter value is required",
|
"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",
|
"publication.listelement.badge": "Publication",
|
||||||
|
@@ -10,10 +10,12 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { DefaultChangeAnalyzer } from '../default-change-analyzer.service';
|
import { DefaultChangeAnalyzer } from '../default-change-analyzer.service';
|
||||||
import { Script } from '../../../process-page/scripts/script.model';
|
import { Script } from '../../../process-page/scripts/script.model';
|
||||||
import { ProcessParameter } from '../../../process-page/processes/process-parameter.model';
|
import { 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 { URLCombiner } from '../../url-combiner/url-combiner';
|
||||||
import { MultipartPostRequest, RestRequest } from '../request.models';
|
import { MultipartPostRequest, RestRequest } from '../request.models';
|
||||||
import { RequestService } from '../request.service';
|
import { RequestService } from '../request.service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { RequestEntry } from '../request.reducer';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ScriptDataService extends DataService<Script> {
|
export class ScriptDataService extends DataService<Script> {
|
||||||
@@ -31,15 +33,18 @@ export class ScriptDataService extends DataService<Script> {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public invoke(scriptName: string, parameters: ProcessParameter[], files: File[]) {
|
public invoke(scriptName: string, parameters: ProcessParameter[], files: File[]): Observable<RequestEntry> {
|
||||||
this.getBrowseEndpoint().pipe(
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
return this.getBrowseEndpoint().pipe(
|
||||||
map((endpoint: string) => new URLCombiner(endpoint, scriptName, 'processes').toString()),
|
map((endpoint: string) => new URLCombiner(endpoint, scriptName, 'processes').toString()),
|
||||||
map((endpoint: string) => {
|
map((endpoint: string) => {
|
||||||
const body = this.getInvocationFormData(parameters, files);
|
const body = this.getInvocationFormData(parameters, files);
|
||||||
return new MultipartPostRequest(this.requestService.generateRequestId(), endpoint, body)
|
return new MultipartPostRequest(requestId, endpoint, body)
|
||||||
}),
|
}),
|
||||||
map((request: RestRequest) => this.requestService.configure(request))
|
map((request: RestRequest) => this.requestService.configure(request)),
|
||||||
).subscribe();
|
switchMap(() => this.requestService.getByUUID(requestId)),
|
||||||
|
find((request: RequestEntry) => request.completed)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getInvocationFormData(parameters: ProcessParameter[], files: File[]): FormData {
|
private getInvocationFormData(parameters: ProcessParameter[], files: File[]): FormData {
|
||||||
|
@@ -1,14 +1,25 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<h2 class="col-12">
|
||||||
|
{{'process.new.header' | translate}}
|
||||||
|
</h2>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<form #form="ngForm" (ngSubmit)="submitForm(form)">
|
<form #form="ngForm" (ngSubmit)="submitForm(form)">
|
||||||
<ds-scripts-select (select)="selectedScript = $event"></ds-scripts-select>
|
<ds-scripts-select (select)="selectedScript = $event"></ds-scripts-select>
|
||||||
<ds-process-parameters [script]="selectedScript" (updateParameters)="parameters = $event"></ds-process-parameters>
|
<ds-process-parameters [script]="selectedScript" (updateParameters)="parameters = $event"></ds-process-parameters>
|
||||||
<button [disabled]="form.invalid" type="submit" class="btn btn-light float-right">{{ 'process.new.submit' | translate }}</button>
|
<button [routerLink]="['/processes']" class="btn btn-light float-left">{{ 'process.new.cancel' | translate }}</button>
|
||||||
|
<button type="submit" class="btn btn-light float-right">{{ 'process.new.submit' | translate }}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<ds-script-help [script]="selectedScript"></ds-script-help>
|
<ds-script-help [script]="selectedScript"></ds-script-help>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="missingParameters.length > 0" class="alert alert-danger validation-error">
|
||||||
|
{{'process.new.parameter.required.missing' | translate}}
|
||||||
|
<ul>
|
||||||
|
<li *ngFor="let missing of missingParameters">{{missing}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,6 +9,9 @@ import { MockTranslateLoader } from '../../shared/testing/mock-translate-loader'
|
|||||||
import { ScriptParameter } from '../scripts/script-parameter.model';
|
import { ScriptParameter } from '../scripts/script-parameter.model';
|
||||||
import { Script } from '../scripts/script.model';
|
import { Script } from '../scripts/script.model';
|
||||||
import { ProcessParameter } from '../processes/process-parameter.model';
|
import { ProcessParameter } from '../processes/process-parameter.model';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
describe('NewProcessComponent', () => {
|
describe('NewProcessComponent', () => {
|
||||||
let component: NewProcessComponent;
|
let component: NewProcessComponent;
|
||||||
@@ -26,7 +29,17 @@ describe('NewProcessComponent', () => {
|
|||||||
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
|
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
|
||||||
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
|
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
|
||||||
];
|
];
|
||||||
scriptService = jasmine.createSpyObj('scriptService', ['invoke'])
|
scriptService = jasmine.createSpyObj(
|
||||||
|
'scriptService',
|
||||||
|
{
|
||||||
|
invoke: observableOf({
|
||||||
|
response:
|
||||||
|
{
|
||||||
|
isSuccessful: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
@@ -43,6 +56,7 @@ describe('NewProcessComponent', () => {
|
|||||||
declarations: [NewProcessComponent],
|
declarations: [NewProcessComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ScriptDataService, useValue: scriptService },
|
{ provide: ScriptDataService, useValue: scriptService },
|
||||||
|
{ provide: NotificationsService, useValue: NotificationsServiceStub },
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
})
|
})
|
||||||
@@ -62,7 +76,7 @@ describe('NewProcessComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call invoke on the scriptService on submit', () => {
|
it('should call invoke on the scriptService on submit', () => {
|
||||||
component.submitForm({ invalid: false });
|
component.submitForm({ invalid: false } as any);
|
||||||
expect(scriptService.invoke).toHaveBeenCalled();
|
expect(scriptService.invoke).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -3,7 +3,13 @@ import { Script } from '../scripts/script.model';
|
|||||||
import { Process } from '../processes/process.model';
|
import { Process } from '../processes/process.model';
|
||||||
import { ProcessParameter } from '../processes/process-parameter.model';
|
import { ProcessParameter } from '../processes/process-parameter.model';
|
||||||
import { ScriptDataService } from '../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../core/data/processes/script-data.service';
|
||||||
import { NgForm } from '@angular/forms';
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { ScriptParameter } from '../scripts/script-parameter.model';
|
||||||
|
import { RequestEntry } from '../../core/data/request.reducer';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { pipe } from 'rxjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to create a new script
|
* Component to create a new script
|
||||||
@@ -27,14 +33,19 @@ export class NewProcessComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* The parameter values to use to start the process
|
* The parameter values to use to start the process
|
||||||
*/
|
*/
|
||||||
public parameters: ProcessParameter[];
|
public parameters: ProcessParameter[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional files that are used as parameter values
|
* Optional files that are used as parameter values
|
||||||
*/
|
*/
|
||||||
public files: File[] = [];
|
public files: File[] = [];
|
||||||
|
|
||||||
constructor(private scriptService: ScriptDataService) {
|
/**
|
||||||
|
* Contains the missing parameters on submission
|
||||||
|
*/
|
||||||
|
public missingParameters = [];
|
||||||
|
|
||||||
|
constructor(private scriptService: ScriptDataService, private notificationsService: NotificationsService, private translationService: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -46,7 +57,7 @@ export class NewProcessComponent implements OnInit {
|
|||||||
* @param form
|
* @param form
|
||||||
*/
|
*/
|
||||||
submitForm(form: NgForm) {
|
submitForm(form: NgForm) {
|
||||||
if (!this.validateForm(form)) {
|
if (!this.validateForm(form) || this.isRequiredMissing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +69,18 @@ export class NewProcessComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.scriptService.invoke(this.selectedScript.id, stringParameters, this.files)
|
this.scriptService.invoke(this.selectedScript.id, stringParameters, this.files)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((requestEntry: RequestEntry) => {
|
||||||
|
if (requestEntry.response.isSuccessful) {
|
||||||
|
const title = this.translationService.get('process.new.notification.success.title');
|
||||||
|
const content = this.translationService.get('process.new.notification.success.content');
|
||||||
|
this.notificationsService.success(title, content)
|
||||||
|
} else {
|
||||||
|
const title = this.translationService.get('process.new.notification.error.title');
|
||||||
|
const content = this.translationService.get('process.new.notification.error.content');
|
||||||
|
this.notificationsService.error(title, content)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +92,7 @@ export class NewProcessComponent implements OnInit {
|
|||||||
if (typeof processParameter.value === 'object') {
|
if (typeof processParameter.value === 'object') {
|
||||||
this.files = [...this.files, processParameter.value];
|
this.files = [...this.files, processParameter.value];
|
||||||
return processParameter.value.name;
|
return processParameter.value.name;
|
||||||
}
|
}
|
||||||
return processParameter.value;
|
return processParameter.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,4 +111,20 @@ export class NewProcessComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isRequiredMissing() {
|
||||||
|
const setParams: string[] = this.parameters
|
||||||
|
.map((param) => param.name);
|
||||||
|
const requiredParams: ScriptParameter[] = this.selectedScript.parameters.filter((param) => param.mandatory)
|
||||||
|
for (const rp of requiredParams) {
|
||||||
|
if (!setParams.includes(rp.name)) {
|
||||||
|
this.missingParameters.push(rp.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.missingParameters.length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function controlContainerFactory(controlContainer?: ControlContainer) {
|
||||||
|
return controlContainer;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<div class="form-row mb-2">
|
<div class="form-row mb-2">
|
||||||
<select required id="process-parameters"
|
<select id="process-parameters"
|
||||||
class="form-control col"
|
class="form-control col"
|
||||||
name="script"
|
name="parameter-{{index}}"
|
||||||
[(ngModel)]="selectedParameter"
|
[(ngModel)]="selectedParameter"
|
||||||
#param="ngModel">
|
#param="ngModel">
|
||||||
<option [ngValue]="undefined">Add a parameter...</option>
|
<option [ngValue]="undefined">Add a parameter...</option>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
{{param.nameLong || param.name}}
|
{{param.nameLong || param.name}}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<ds-parameter-value-input [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" class="d-block col"></ds-parameter-value-input>
|
<ds-parameter-value-input [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" class="d-block col" [index]="index"></ds-parameter-value-input>
|
||||||
<button *ngIf="removable" class="btn btn-light col-1 remove-button" (click)="removeParameter.emit(parameterValue);"><span class="fas fa-trash"></span></button>
|
<button *ngIf="removable" class="btn btn-light col-1 remove-button" (click)="removeParameter.emit(parameterValue);"><span class="fas fa-trash"></span></button>
|
||||||
<span *ngIf="!removable" class="col-1"></span>
|
<span *ngIf="!removable" class="col-1"></span>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, Optional } from '@angular/core';
|
||||||
import { ProcessParameter } from '../../../processes/process-parameter.model';
|
import { ProcessParameter } from '../../../processes/process-parameter.model';
|
||||||
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
||||||
import { hasNoValue } from '../../../../shared/empty.util';
|
import { hasNoValue } from '../../../../shared/empty.util';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to select a single parameter for a process
|
* Component to select a single parameter for a process
|
||||||
@@ -9,13 +11,19 @@ import { hasNoValue } from '../../../../shared/empty.util';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-parameter-select',
|
selector: 'ds-parameter-select',
|
||||||
templateUrl: './parameter-select.component.html',
|
templateUrl: './parameter-select.component.html',
|
||||||
styleUrls: ['./parameter-select.component.scss']
|
styleUrls: ['./parameter-select.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class ParameterSelectComponent implements OnInit {
|
export class ParameterSelectComponent implements OnInit {
|
||||||
|
@Input() index: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current parameter value of the selected parameter
|
* The current parameter value of the selected parameter
|
||||||
*/
|
*/
|
||||||
@Input() parameterValue: ProcessParameter;
|
@Input() parameterValue: ProcessParameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The available script parameters for the script
|
* The available script parameters for the script
|
||||||
*/
|
*/
|
||||||
|
@@ -1 +1 @@
|
|||||||
<input type="hidden" value="true"/>
|
<input type="hidden" value="true" name="boolean-value-{{index}}" id="boolean-value-{{index}}"/>
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Optional } from '@angular/core';
|
||||||
import { ValueInputComponent } from '../value-input.component';
|
import { ValueInputComponent } from '../value-input.component';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the value of a boolean parameter
|
* Represents the value of a boolean parameter
|
||||||
@@ -7,7 +9,10 @@ import { ValueInputComponent } from '../value-input.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-boolean-value-input',
|
selector: 'ds-boolean-value-input',
|
||||||
templateUrl: './boolean-value-input.component.html',
|
templateUrl: './boolean-value-input.component.html',
|
||||||
styleUrls: ['./boolean-value-input.component.scss']
|
styleUrls: ['./boolean-value-input.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class BooleanValueInputComponent extends ValueInputComponent<boolean> implements OnInit {
|
export class BooleanValueInputComponent extends ValueInputComponent<boolean> implements OnInit {
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<input required #string="ngModel" type="text" class="form-control" id="string-value-input" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
<input required #string="ngModel" type="text" class="form-control" name="date-value-{{index}}" id="date-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
||||||
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
||||||
class="alert alert-danger validation-error">
|
class="alert alert-danger validation-error">
|
||||||
<div *ngIf="string.errors.required">
|
<div *ngIf="string.errors.required">
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Optional } from '@angular/core';
|
||||||
import { ValueInputComponent } from '../value-input.component';
|
import { ValueInputComponent } from '../value-input.component';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the user inputted value of a date parameter
|
* Represents the user inputted value of a date parameter
|
||||||
@@ -7,7 +9,10 @@ import { ValueInputComponent } from '../value-input.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-date-value-input',
|
selector: 'ds-date-value-input',
|
||||||
templateUrl: './date-value-input.component.html',
|
templateUrl: './date-value-input.component.html',
|
||||||
styleUrls: ['./date-value-input.component.scss']
|
styleUrls: ['./date-value-input.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class DateValueInputComponent extends ValueInputComponent<string> {
|
export class DateValueInputComponent extends ValueInputComponent<string> {
|
||||||
/**
|
/**
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
<label for="file-upload" class="btn btn-light">
|
<label for="file-upload-{{index}}" class="d-flex align-items-center">
|
||||||
{{'process.new.parameter.file.upload-button' | translate}}
|
<span class="btn btn-light">
|
||||||
|
{{'process.new.parameter.file.upload-button' | translate}}
|
||||||
|
</span>
|
||||||
|
<span class="file-name ml-1">{{fileObject?.name}}</span>
|
||||||
</label>
|
</label>
|
||||||
<input requireFile #file="ngModel" type="file" id="file-upload" class="form-control-file d-none" [ngModel]="file" (ngModelChange)="setFile($event)"/>
|
<input requireFile #file="ngModel" type="file" name="file-upload-{{index}}" id="file-upload-{{index}}" class="form-control-file d-none" [ngModel]="fileObject" (ngModelChange)="setFile($event)"/>
|
||||||
<div *ngIf="file.invalid && (file.dirty || file.touched)"
|
<div *ngIf="file.invalid && (file.dirty || file.touched)"
|
||||||
class="alert alert-danger validation-error">
|
class="alert alert-danger validation-error">
|
||||||
<div *ngIf="file.errors.required">
|
<div *ngIf="file.errors.required">
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
.file-name {
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
|
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
@@ -9,7 +9,7 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { FileValueAccessorDirective } from '../../../../../shared/utils/file-value-accessor.directive';
|
import { FileValueAccessorDirective } from '../../../../../shared/utils/file-value-accessor.directive';
|
||||||
import { FileValidator } from '../../../../../shared/utils/require-file.validator';
|
import { FileValidator } from '../../../../../shared/utils/require-file.validator';
|
||||||
|
|
||||||
describe('FileValueInputComponent', () => {
|
‡describe('FileValueInputComponent', () => {
|
||||||
let component: FileValueInputComponent;
|
let component: FileValueInputComponent;
|
||||||
let fixture: ComponentFixture<FileValueInputComponent>;
|
let fixture: ComponentFixture<FileValueInputComponent>;
|
||||||
|
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, Optional } from '@angular/core';
|
||||||
import { ValueInputComponent } from '../value-input.component';
|
import { ValueInputComponent } from '../value-input.component';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the user inputted value of a file parameter
|
* Represents the user inputted value of a file parameter
|
||||||
@@ -7,15 +9,18 @@ import { ValueInputComponent } from '../value-input.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-file-value-input',
|
selector: 'ds-file-value-input',
|
||||||
templateUrl: './file-value-input.component.html',
|
templateUrl: './file-value-input.component.html',
|
||||||
styleUrls: ['./file-value-input.component.scss']
|
styleUrls: ['./file-value-input.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class FileValueInputComponent extends ValueInputComponent<File> {
|
export class FileValueInputComponent extends ValueInputComponent<File> {
|
||||||
/**
|
/**
|
||||||
* The current value of the file
|
* The current value of the file
|
||||||
*/
|
*/
|
||||||
file: File;
|
fileObject: File;
|
||||||
setFile(files) {
|
setFile(files) {
|
||||||
this.file = files.length > 0 ? files[0] : undefined;
|
this.fileObject = files.length > 0 ? files[0] : undefined;
|
||||||
this.updateValue.emit(this.file);
|
this.updateValue.emit(this.fileObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<div [ngSwitch]="parameter?.type">
|
<div [ngSwitch]="parameter?.type">
|
||||||
<ds-string-value-input *ngSwitchCase="parameterTypes.STRING" (updateValue)="updateValue.emit($event)"></ds-string-value-input>
|
<ds-string-value-input *ngSwitchCase="parameterTypes.STRING" (updateValue)="updateValue.emit($event)" [index]="index"></ds-string-value-input>
|
||||||
<ds-string-value-input *ngSwitchCase="parameterTypes.OUTPUT" (updateValue)="updateValue.emit($event)"></ds-string-value-input>
|
<ds-string-value-input *ngSwitchCase="parameterTypes.OUTPUT" (updateValue)="updateValue.emit($event)" [index]="index"></ds-string-value-input>
|
||||||
<ds-date-value-input *ngSwitchCase="parameterTypes.DATE" (updateValue)="updateValue.emit($event)"></ds-date-value-input>
|
<ds-date-value-input *ngSwitchCase="parameterTypes.DATE" (updateValue)="updateValue.emit($event)" [index]="index"></ds-date-value-input>
|
||||||
<ds-file-value-input *ngSwitchCase="parameterTypes.FILE" (updateValue)="updateValue.emit($event)"></ds-file-value-input>
|
<ds-file-value-input *ngSwitchCase="parameterTypes.FILE" (updateValue)="updateValue.emit($event)" [index]="index"></ds-file-value-input>
|
||||||
<ds-boolean-value-input *ngSwitchCase="parameterTypes.BOOLEAN" (updateValue)="updateValue.emit($event)"></ds-boolean-value-input>
|
<ds-boolean-value-input *ngSwitchCase="parameterTypes.BOOLEAN" (updateValue)="updateValue.emit($event)" [index]="index"></ds-boolean-value-input>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, OnInit, Optional, Output } from '@angular/core';
|
||||||
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
|
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
|
||||||
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders the correct parameter value input based the script parameter's type
|
* Component that renders the correct parameter value input based the script parameter's type
|
||||||
@@ -8,9 +10,14 @@ import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-parameter-value-input',
|
selector: 'ds-parameter-value-input',
|
||||||
templateUrl: './parameter-value-input.component.html',
|
templateUrl: './parameter-value-input.component.html',
|
||||||
styleUrls: ['./parameter-value-input.component.scss']
|
styleUrls: ['./parameter-value-input.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class ParameterValueInputComponent {
|
export class ParameterValueInputComponent {
|
||||||
|
@Input() index: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current script parameter
|
* The current script parameter
|
||||||
*/
|
*/
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<input required #string="ngModel" type="text" class="form-control" id="string-value-input" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
<input required #string="ngModel" type="text" name="string-value-{{index}}" class="form-control" id="string-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
||||||
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
||||||
class="alert alert-danger validation-error">
|
class="alert alert-danger validation-error">
|
||||||
<div *ngIf="string.errors.required">
|
<div *ngIf="string.errors.required">
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
|
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
|
import { MockTranslateLoader } from '../../../../../shared/mocks/mock-translate-loader';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
@@ -20,7 +20,9 @@ describe('StringValueInputComponent', () => {
|
|||||||
useClass: MockTranslateLoader
|
useClass: MockTranslateLoader
|
||||||
}
|
}
|
||||||
})],
|
})],
|
||||||
declarations: [StringValueInputComponent]
|
declarations: [StringValueInputComponent],
|
||||||
|
providers: [
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
@@ -40,7 +42,7 @@ describe('StringValueInputComponent', () => {
|
|||||||
expect(validationError).toBeFalsy();
|
expect(validationError).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
|
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
|
||||||
component.value = '';
|
component.value = '';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
tick();
|
tick();
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, Optional } from '@angular/core';
|
||||||
import { ValueInputComponent } from '../value-input.component';
|
import { ValueInputComponent } from '../value-input.component';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../../../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the user inputted value of a string parameter
|
* Represents the user inputted value of a string parameter
|
||||||
@@ -7,7 +9,10 @@ import { ValueInputComponent } from '../value-input.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-string-value-input',
|
selector: 'ds-string-value-input',
|
||||||
templateUrl: './string-value-input.component.html',
|
templateUrl: './string-value-input.component.html',
|
||||||
styleUrls: ['./string-value-input.component.scss']
|
styleUrls: ['./string-value-input.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class StringValueInputComponent extends ValueInputComponent<string> {
|
export class StringValueInputComponent extends ValueInputComponent<string> {
|
||||||
/**
|
/**
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
import { EventEmitter, Output } from '@angular/core';
|
import { EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class that represents value input components
|
* Abstract class that represents value input components
|
||||||
*/
|
*/
|
||||||
export abstract class ValueInputComponent<T> {
|
export abstract class ValueInputComponent<T> {
|
||||||
|
@Input() index: number;
|
||||||
/**
|
/**
|
||||||
* Used by the subclasses to emit the value when it's updated
|
* Used by the subclasses to emit the value when it's updated
|
||||||
*/
|
*/
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
[parameters]="script.parameters"
|
[parameters]="script.parameters"
|
||||||
[parameterValue]="value"
|
[parameterValue]="value"
|
||||||
[removable]="!last"
|
[removable]="!last"
|
||||||
|
[index]="i"
|
||||||
(removeParameter)="removeParameter(i)"
|
(removeParameter)="removeParameter(i)"
|
||||||
(changeParameter)="updateParameter($event, i)"></ds-parameter-select>
|
(changeParameter)="updateParameter($event, i)"></ds-parameter-select>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, Optional, Output, SimpleChanges } from '@angular/core';
|
||||||
import { Script } from '../../scripts/script.model';
|
import { Script } from '../../scripts/script.model';
|
||||||
import { ProcessParameter } from '../../processes/process-parameter.model';
|
import { ProcessParameter } from '../../processes/process-parameter.model';
|
||||||
import { hasValue } from '../../../shared/empty.util';
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
import { ControlContainer, NgForm } from '@angular/forms';
|
||||||
|
import { ScriptParameter } from '../../scripts/script-parameter.model';
|
||||||
|
import { controlContainerFactory } from '../new-process.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that represents the selected list of parameters for a script
|
* Component that represents the selected list of parameters for a script
|
||||||
@@ -9,7 +12,10 @@ import { hasValue } from '../../../shared/empty.util';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-process-parameters',
|
selector: 'ds-process-parameters',
|
||||||
templateUrl: './process-parameters.component.html',
|
templateUrl: './process-parameters.component.html',
|
||||||
styleUrls: ['./process-parameters.component.scss']
|
styleUrls: ['./process-parameters.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class ProcessParametersComponent implements OnChanges {
|
export class ProcessParametersComponent implements OnChanges {
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +48,7 @@ export class ProcessParametersComponent implements OnChanges {
|
|||||||
*/
|
*/
|
||||||
initParameters() {
|
initParameters() {
|
||||||
this.parameterValues = [];
|
this.parameterValues = [];
|
||||||
this.addParameter();
|
this.initializeParameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,6 +73,20 @@ export class ProcessParametersComponent implements OnChanges {
|
|||||||
this.parameterValues = this.parameterValues.filter((value, i) => i !== index);
|
this.parameterValues = this.parameterValues.filter((value, i) => i !== index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes parameter values based on the selected script
|
||||||
|
*/
|
||||||
|
initializeParameter() {
|
||||||
|
if (hasValue(this.script)) {
|
||||||
|
this.parameterValues = this.script.parameters
|
||||||
|
.filter((param) => param.mandatory)
|
||||||
|
.map(
|
||||||
|
(parameter: ScriptParameter) => Object.assign(new ProcessParameter(), { name: parameter.name })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.addParameter();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an empty parameter value to the end of the list
|
* Adds an empty parameter value to the end of the list
|
||||||
*/
|
*/
|
||||||
|
@@ -3,7 +3,16 @@
|
|||||||
|
|
||||||
<table class="table-borderless mt-3 text-secondary">
|
<table class="table-borderless mt-3 text-secondary">
|
||||||
<tr *ngFor="let param of script?.parameters">
|
<tr *ngFor="let param of script?.parameters">
|
||||||
<td>{{param.name}} {{param.nameLong}} {{param.type !== 'boolean' ? '<' + param.type + '>' : ''}}</td>
|
<td class="align-top text-nowrap">{{param.name}} {{param.nameLong}} <ng-container *ngTemplateOutlet="type; context: param"></ng-container></td>
|
||||||
<td>{{param.description}}</td>
|
<td>{{param.description}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template #type let-type="type">
|
||||||
|
<ng-container [ngSwitch]="type">
|
||||||
|
<span *ngSwitchCase="parameterTypes.DATE"><{{'process.new.parameter.type.value' | translate}}></span>
|
||||||
|
<span *ngSwitchCase="parameterTypes.STRING"><{{'process.new.parameter.type.value' | translate}}></span>
|
||||||
|
<span *ngSwitchCase="parameterTypes.OUTPUT"><{{'process.new.parameter.type.value' | translate}}></span>
|
||||||
|
<span *ngSwitchCase="parameterTypes.FILE"><{{'process.new.parameter.type.file' | translate}}></span>
|
||||||
|
</ng-container>
|
||||||
|
</ng-template>
|
||||||
|
@@ -5,6 +5,10 @@ import { ScriptParameter } from '../../scripts/script-parameter.model';
|
|||||||
import { Script } from '../../scripts/script.model';
|
import { Script } from '../../scripts/script.model';
|
||||||
import { ScriptParameterType } from '../../scripts/script-parameter-type.model';
|
import { ScriptParameterType } from '../../scripts/script-parameter-type.model';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { MockTranslateLoader } from '../../../shared/testing/mock-translate-loader';
|
||||||
|
|
||||||
describe('ScriptHelpComponent', () => {
|
describe('ScriptHelpComponent', () => {
|
||||||
let component: ScriptHelpComponent;
|
let component: ScriptHelpComponent;
|
||||||
@@ -25,7 +29,16 @@ describe('ScriptHelpComponent', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
init();
|
init();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ ScriptHelpComponent ]
|
imports: [
|
||||||
|
FormsModule,
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useClass: MockTranslateLoader
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
declarations: [ ScriptHelpComponent ],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { Script } from '../../scripts/script.model';
|
import { Script } from '../../scripts/script.model';
|
||||||
|
import { ScriptParameterType } from '../../scripts/script-parameter-type.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components that represents a help section for the script use and parameters
|
* Components that represents a help section for the script use and parameters
|
||||||
@@ -14,4 +15,9 @@ export class ScriptHelpComponent {
|
|||||||
* The current script to show the help information for
|
* The current script to show the help information for
|
||||||
*/
|
*/
|
||||||
@Input() script: Script;
|
@Input() script: Script;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The available script parameter types
|
||||||
|
*/
|
||||||
|
parameterTypes = ScriptParameterType;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<div class="form-group" *ngIf="scripts$ | async">
|
<div class="form-group" *ngIf="scripts$ | async">
|
||||||
<label for="process-script"><label>{{'process.new.select-script' | translate}}</label></label>
|
<label for="process-script">{{'process.new.select-script' | translate}}</label>
|
||||||
<select required id="process-script"
|
<select required id="process-script"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
name="script"
|
name="script"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, OnDestroy, OnInit, Optional, Output } from '@angular/core';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
import { Script } from '../../scripts/script.model';
|
import { Script } from '../../scripts/script.model';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
@@ -7,6 +7,8 @@ import { PaginatedList } from '../../../core/data/paginated-list';
|
|||||||
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
|
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { hasValue } from '../../../shared/empty.util';
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
import { ControlContainer, FormControl, NgForm } from '@angular/forms';
|
||||||
|
import { controlContainerFactory } from '../new-process.component';
|
||||||
|
|
||||||
const SCRIPT_QUERY_PARAMETER = 'script';
|
const SCRIPT_QUERY_PARAMETER = 'script';
|
||||||
|
|
||||||
@@ -16,7 +18,10 @@ const SCRIPT_QUERY_PARAMETER = 'script';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-scripts-select',
|
selector: 'ds-scripts-select',
|
||||||
templateUrl: './scripts-select.component.html',
|
templateUrl: './scripts-select.component.html',
|
||||||
styleUrls: ['./scripts-select.component.scss']
|
styleUrls: ['./scripts-select.component.scss'],
|
||||||
|
viewProviders: [ { provide: ControlContainer,
|
||||||
|
useFactory: controlContainerFactory,
|
||||||
|
deps: [[new Optional(), NgForm]] } ]
|
||||||
})
|
})
|
||||||
export class ScriptsSelectComponent implements OnInit, OnDestroy {
|
export class ScriptsSelectComponent implements OnInit, OnDestroy {
|
||||||
@Output() select: EventEmitter<Script> = new EventEmitter<Script>();
|
@Output() select: EventEmitter<Script> = new EventEmitter<Script>();
|
||||||
|
@@ -8,6 +8,7 @@ import { NewProcessComponent } from './new/new-process.component';
|
|||||||
{
|
{
|
||||||
path: 'new',
|
path: 'new',
|
||||||
component: NewProcessComponent,
|
component: NewProcessComponent,
|
||||||
|
data: { title: 'process.new.title' }
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user