From c3d92e5b3127f38b4591411bccd91ffe5568fee0 Mon Sep 17 00:00:00 2001 From: Philip Prinz Date: Wed, 10 Apr 2024 12:50:42 +0200 Subject: [PATCH] add validation for tasks to scenario wizard --- ...de-with-syntax-highlighting.component.html | 2 +- ...code-with-syntax-highlighting.component.ts | 2 +- .../scenario-wizard.component.html | 21 ++++- .../scenario-wizard.component.ts | 77 +++++++++++++++++-- .../task-form/task-form.component.html | 2 - .../scenario/task-form/task-form.component.ts | 9 +-- .../readonly-task.component.html | 8 -- 7 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.html b/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.html index e310fabe..bd457f7e 100644 --- a/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.html +++ b/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.html @@ -1,5 +1,5 @@
-
\ No newline at end of file diff --git a/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.ts b/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.ts index 815d5ef9..0f7fccf9 100644 --- a/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.ts +++ b/src/app/configuration/code-with-syntax-highlighting/code-with-syntax-highlighting.component.ts @@ -53,7 +53,7 @@ export class CodeWithSyntaxHighlightingComponent resizeable: boolean = false; @Input() - readonly: boolean = false + readonly: boolean = false; @Input() outline: string = 'solid 1px'; diff --git a/src/app/scenario/scenario-wizard/scenario-wizard.component.html b/src/app/scenario/scenario-wizard/scenario-wizard.component.html index a77314f8..ec5aa2d6 100644 --- a/src/app/scenario/scenario-wizard/scenario-wizard.component.html +++ b/src/app/scenario/scenario-wizard/scenario-wizard.component.html @@ -5,12 +5,17 @@ (clrWizardOnFinish)="finishScenario()" (clrWizardOnCancel)="doCancel()" > + + + {{ error.message }} + + {{ wizardTitle }} Cancel Back Next - Finish + Finish - + Tasks @@ -358,7 +363,7 @@ - + Finalize

Confirm the following details before finishing

Scenario

@@ -398,6 +403,16 @@

Scenario

> + + Tasks + + + + {{ vm_task.vm_name }}: {{ task.name }} + + + Categories diff --git a/src/app/scenario/scenario-wizard/scenario-wizard.component.ts b/src/app/scenario/scenario-wizard/scenario-wizard.component.ts index afa432d0..80c75b25 100644 --- a/src/app/scenario/scenario-wizard/scenario-wizard.component.ts +++ b/src/app/scenario/scenario-wizard/scenario-wizard.component.ts @@ -7,7 +7,7 @@ import { ViewChild, } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { ClrModal, ClrWizard } from '@clr/angular'; +import { ClrModal, ClrWizard, ClrWizardPage } from '@clr/angular'; import { RbacService } from 'src/app/data/rbac.service'; import { Scenario } from 'src/app/data/scenario'; import { ScenarioService } from 'src/app/data/scenario.service'; @@ -22,6 +22,9 @@ import { AlertDetails } from 'src/app/alert/alert'; import { ClrAlertType } from 'src/app/clr-alert-type'; import { VMTasks } from 'src/app/data/vm-tasks'; +interface ValidationError { + message: string +} @Component({ selector: 'scenario-wizard', templateUrl: './scenario-wizard.component.html', @@ -53,6 +56,9 @@ export class ScenarioWizardComponent implements OnInit { public selectedscenario: Scenario; + public disableFinalizeButton: boolean = false; + public validationErrors: ValidationError[] = []; + get keepaliveRequired() { const ka = this.scenarioDetails.controls.keepalive_amount; const ku = this.scenarioDetails.controls.keepalive_unit; @@ -71,6 +77,8 @@ export class ScenarioWizardComponent implements OnInit { @ViewChild('createvmmodal', { static: true }) createVMModal: ClrModal; @ViewChild('stepsscenario', { static: true }) stepScenario: StepsScenarioComponent; + @ViewChild('taskPage') taskWizardPage: ClrWizardPage; + @ViewChild('finalizePage') finalizeWizardPage: ClrWizardPage; constructor( public scenarioService: ScenarioService, @@ -147,6 +155,59 @@ export class ScenarioWizardComponent implements OnInit { }); } }); + + this.wizard.currentPageChanged.subscribe(() => { + this.validationErrors = [] + if (this.selectedscenario.vm_tasks.length > 0) { + this.validateTaskDefinitions() + } + this.disableFinalizeButton = !(this.validationErrors.length == 0) + }); + } + + validateTaskDefinitions() { + this.taskWizardPage.hasError = false + this.validateVMsExist(); + this.validateNoDuplicateNames(); + this.validateAllFieldsHaveValues() + } + + + private validateVMsExist() { + const vmNames = this.selectedscenario.virtualmachines.map(vm => Object.keys(vm)).reduce((acc, val) => acc.concat(val), []); + const taskVmNames = this.selectedscenario.vm_tasks.map(vmTask => vmTask.vm_name); + taskVmNames.forEach((name) => { + if (!vmNames.includes(name)) { + this.taskWizardPage.hasError = true; + this.validationErrors.push({ message: "One or more Tasks reference a Virtual Machnine Name, that does not exist" }); + } + }); + } + + private validateNoDuplicateNames() { + this.selectedscenario.vm_tasks.forEach(vmTask => { + let tmpArr = []; + vmTask.tasks.forEach(task => { + const taskName = task.name; + if (tmpArr.indexOf(taskName) < 0) { + tmpArr.push(taskName); + } else { + this.taskWizardPage.hasError = true; + this.validationErrors.push({ message: "Task " + vmTask.vm_name + ": " + taskName + " is a Duplicate" }); + } + }); + }); + } + + private validateAllFieldsHaveValues() { + this.selectedscenario.vm_tasks.forEach(vmTask => { + vmTask.tasks.forEach((task) => { + if (task.name.length == 0 || task.command.length == 0 || task.description.length == 0 || task.return_type.length == 0) { + this.taskWizardPage.hasError = true; + this.validationErrors.push({ message: "Task " + vmTask.vm_name + ": " + task.name + " is missing required information" }); + } + }) + }) } open(wizardMode: 'create' | 'edit', scenario?: Scenario) { @@ -296,7 +357,7 @@ export class ScenarioWizardComponent implements OnInit { } addVMSet() { this.selectedscenario.virtualmachines.push({}); - this.updateSelectedScenarioRef() + this.updateSelectedScenarioRef(); } addVM() { this.selectedScenarioHasVM(); @@ -304,23 +365,23 @@ export class ScenarioWizardComponent implements OnInit { this.vmform.controls.vm_name.value ] = this.vmform.controls.vm_template.value; this.createVMModal.close(); - this.updateSelectedScenarioRef() + this.updateSelectedScenarioRef(); } deleteVMSet(i: number) { this.deletingVMSetIndex = i; this.deleteVMSetModal.open(); - this.updateSelectedScenarioRef() + this.updateSelectedScenarioRef(); } public deleteVM(setIndex: number, key: string) { delete this.selectedscenario.virtualmachines[setIndex][key]; - this.updateSelectedScenarioRef() + this.updateSelectedScenarioRef(); } doDeleteVMSet() { this.selectedscenario.virtualmachines.splice(this.deletingVMSetIndex, 1); this.deleteVMSetModal.close(); - this.updateSelectedScenarioRef() + this.updateSelectedScenarioRef(); } public openCreateVM(i: number) { this.vmform.reset(); @@ -400,10 +461,10 @@ export class ScenarioWizardComponent implements OnInit { } updateSelectedScenarioRef() { - this.selectedscenario = {...this.selectedscenario} // Force an Update on Child Components using the selectedscenario as Input + this.selectedscenario = { ...this.selectedscenario }; // Force an Update on Child Components using the selectedscenario as Input } replaceVmTasks(vmTasks: VMTasks[]) { - this.selectedscenario.vm_tasks = vmTasks + this.selectedscenario.vm_tasks = vmTasks; } } diff --git a/src/app/scenario/task-form/task-form.component.html b/src/app/scenario/task-form/task-form.component.html index f4353129..386d74e1 100644 --- a/src/app/scenario/task-form/task-form.component.html +++ b/src/app/scenario/task-form/task-form.component.html @@ -32,7 +32,6 @@ Regex to match (); supportedLanguages = supportedLanguages; @@ -40,12 +38,10 @@ export class TaskFormComponent implements OnInit { taskCommand: new FormControl(this.editTask.command, [ Validators.required, ]), - taskExpectedOutput: new FormControl(this.editTask.expected_output_value, [ - Validators.required, - ]), + taskExpectedOutput: new FormControl(this.editTask.expected_output_value, []), taskExpectedReurncode: new FormControl( this.editTask.expected_return_code, - [Validators.required] + [] ), taskReturnType: new FormControl(ReturnType[this.editTask.return_type], [ Validators.required, @@ -77,7 +73,6 @@ export class TaskFormComponent implements OnInit { } this.previousReturnType = newValue; }); - if (this.readonly) this.taskForm.disable() } private buildEditTaskFromFormData(): EditTask { diff --git a/src/app/scenario/task/readonly-task/readonly-task.component.html b/src/app/scenario/task/readonly-task/readonly-task.component.html index 9c56a077..0b82718f 100644 --- a/src/app/scenario/task/readonly-task/readonly-task.component.html +++ b/src/app/scenario/task/readonly-task/readonly-task.component.html @@ -1,6 +1,5 @@
-
Node
@@ -10,7 +9,6 @@
Node
-
Name
@@ -20,7 +18,6 @@
Name
-
Description
@@ -30,7 +27,6 @@
Description
-
Command
@@ -48,7 +44,6 @@
Command
-
Return Type
@@ -60,7 +55,6 @@
Return Type
class="clr-row" *ngIf="isOfReturnType(['Return Text', 'Return Code and Text'])" > -
Expected Output
@@ -70,7 +64,6 @@
Expected Output
-
Regex to match
@@ -91,7 +84,6 @@
Regex to match
class="clr-row" *ngIf="isOfReturnType(['Return Code', 'Return Code and Text'])" > -
Return Code