From e190a67ca64962381171eee2111d6384e437548b Mon Sep 17 00:00:00 2001 From: PhPrinz <48761034+PhPrinz@users.noreply.github.com> Date: Mon, 13 May 2024 10:44:15 +0200 Subject: [PATCH] Verification checks against vm (#171) * add verification service and ui element * combine ui elements to one interactive element improve service to handle multiple shell clients for multiple vms keep order of verification tasks provided by scenario * combine ui elements to one interactive element improve service to handle multiple shell clients for multiple vms keep order of verification tasks provided by scenario * only show task progress if scenario has tasks * fix keeping old Task information when switching to new scenario * add markdown component to verify single Task * adapt to support darkmode variables * fix linting errors and warnings * fix formatting issues * add animation to Button * adapt to new angular version * adapt to new /verify response * Display only relevant expected and actual Output/Returncode * fix infinite loading spinner if not all nodes have at least 1 Task * Run prettier & Dark mode fixes * prettier * Change verify endpoint to https to avoid browser stopping request * Improve design * Improve design for tasklist * Display checkmark if all tasks are successful * Green circle if all tasks complete * Show VM Name and fix icon position on task progress modal --------- Co-authored-by: Philip Prinz Co-authored-by: Jan-Gerrit Goebel --- angular.json | 3 +- src/app/app.module.ts | 24 +++- src/app/hf-markdown/hf-markdown.component.ts | 8 ++ ...-task-verification-markdown.component.html | 130 +++++++++++++++++ ...-task-verification-markdown.component.scss | 75 ++++++++++ ...le-task-verification-markdown.component.ts | 65 +++++++++ src/app/scenario/Scenario.ts | 3 + src/app/scenario/step.component.html | 9 +- src/app/scenario/step.component.scss | 7 + src/app/scenario/step.component.ts | 9 ++ .../task-modal/task-modal.component.html | 135 ++++++++++++++++++ .../task-modal/task-modal.component.scss | 36 +++++ .../task-modal/task-modal.component.ts | 103 +++++++++++++ .../task-progress.component.html | 20 +++ .../task-progress.component.scss | 85 +++++++++++ .../task-progress/task-progress.component.ts | 131 +++++++++++++++++ src/app/scenario/taskVerification.type.ts | 32 +++++ src/app/services/gargantua.service.ts | 8 ++ src/app/services/verification.service.ts | 122 ++++++++++++++++ src/dark-theme.css | 25 ++++ 20 files changed, 1027 insertions(+), 3 deletions(-) create mode 100644 src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.html create mode 100644 src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.scss create mode 100644 src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.ts create mode 100644 src/app/scenario/task-modal/task-modal.component.html create mode 100644 src/app/scenario/task-modal/task-modal.component.scss create mode 100644 src/app/scenario/task-modal/task-modal.component.ts create mode 100644 src/app/scenario/task-progress/task-progress.component.html create mode 100644 src/app/scenario/task-progress/task-progress.component.scss create mode 100644 src/app/scenario/task-progress/task-progress.component.ts create mode 100644 src/app/scenario/taskVerification.type.ts create mode 100644 src/app/services/verification.service.ts diff --git a/angular.json b/angular.json index d565b6d7..d8a5e1da 100644 --- a/angular.json +++ b/angular.json @@ -131,7 +131,8 @@ } }, "cli": { - "schematicCollections": ["@angular-eslint/schematics"] + "schematicCollections": ["@angular-eslint/schematics"], + "analytics": false }, "schematics": { "@angular-eslint/schematics:application": { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 727c5801..fa9f7fc9 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -43,6 +43,10 @@ import { GuacTerminalComponent } from './scenario/guacTerminal.component'; import { IdeWindowComponent } from './scenario/ideWindow.component'; import { ContextService } from './services/context.service'; import { TypedSettingsService } from './services/typedSettings.service'; +import { VerificationService } from './services/verification.service'; +import { TaskProgressComponent } from './scenario/task-progress/task-progress.component'; +import { TaskModalComponent } from './scenario/task-modal/task-modal.component'; +import { SingleTaskVerificationMarkdownComponent } from './hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component'; import '@cds/core/icon/register.js'; import { ClarityIcons, @@ -69,6 +73,7 @@ import { windowCloseIcon, arrowIcon, hostIcon, + syncIcon, eyeIcon, eyeHideIcon, clockIcon, @@ -99,6 +104,7 @@ ClarityIcons.addIcons( windowCloseIcon, arrowIcon, hostIcon, + syncIcon, eyeIcon, eyeHideIcon, clockIcon, @@ -114,10 +120,21 @@ const appInitializerFn = (appConfig: AppConfigService) => { }; }; +export const jwtAllowedDomains = [ + environment.server.replace(/(^\w+:|^)\/\//, ''), +]; + +export function addJwtAllowedDomain(domain: string) { + const newDomain = domain.replace(/(^\w+:|^)\/\//, ''); + if (!jwtAllowedDomains.includes(newDomain)) { + jwtAllowedDomains.push(newDomain); + } +} + export function jwtOptionsFactory() { return { tokenGetter: tokenGetter, - allowedDomains: [environment.server.replace(/(^\w+:|^)\/\//, '')], + allowedDomains: jwtAllowedDomains, disallowedRoutes: [ environment.server.replace(/(^\w+:|^)\/\//, '') + '/auth/authenticate', ], @@ -147,6 +164,9 @@ export function jwtOptionsFactory() { HfMarkdownComponent, PrintableComponent, IdeWindowComponent, + TaskProgressComponent, + TaskModalComponent, + SingleTaskVerificationMarkdownComponent, ], imports: [ BrowserModule, @@ -167,6 +187,7 @@ export function jwtOptionsFactory() { }, globalParsers: [ { component: CtrComponent }, + { component: SingleTaskVerificationMarkdownComponent }, { component: QuizComponent }, ], }), @@ -193,6 +214,7 @@ export function jwtOptionsFactory() { ProgressService, ContextService, TypedSettingsService, + VerificationService, { provide: APP_INITIALIZER, useFactory: appInitializerFn, diff --git a/src/app/hf-markdown/hf-markdown.component.ts b/src/app/hf-markdown/hf-markdown.component.ts index 35d61faa..6660c365 100644 --- a/src/app/hf-markdown/hf-markdown.component.ts +++ b/src/app/hf-markdown/hf-markdown.component.ts @@ -148,6 +148,14 @@ ${token}`; >${this.renderHighlightedCode(code, language, filename)}`; }, + verifyTask(code: string, target: string, taskName: string) { + return ``; + }, + mermaid(code: string) { const n = 5; const containerId = `mermaid-${this.uniqueString(n)}`; diff --git a/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.html b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.html new file mode 100644 index 00000000..0176dd62 --- /dev/null +++ b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.html @@ -0,0 +1,130 @@ +
+ +
+ + Verify: {{ taskName }} on {{ target }} +
+
+ +
+ +
+
+ +
+
+
+ +
    +
  • +

    + Description: {{ task.description }} +

    +

    + Command: {{ task.command }} +

    +
  • +
  • +

    + Regular Expression: {{ task.expected_output_value }} +

    +

    + Actual Output: {{ task.actual_output_value }} +

    +
  • +
  • +

    + Expected Output: {{ task.expected_output_value }} +

    +

    + Actual Output: {{ task.actual_output_value }} +

    +
  • +
  • +

    + Expected Returncode: {{ task.expected_return_code }} +

    +

    + Actual Returncode: {{ task.actual_return_code }} +

    +
  • +
  • + + Run the validation checks once to see the result. +
  • +
  • + + + + + + + + The Regex matches the output string. + The Regex does not match the output string. + + + Returned Code matches the expected Code + + Returned Code does not match the expected Code + + + + Returned Text matches the expected Text + + Returned Text does not match the expected Text + + + + + Returned Text and Code match the expected Text and Code + + + Either returned Text, Returned Code or both do not match the expected + Text and Code + + +
  • +
+
diff --git a/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.scss b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.scss new file mode 100644 index 00000000..ca47ddec --- /dev/null +++ b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.scss @@ -0,0 +1,75 @@ +.task-verification-box { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-left: 3px solid; + border-radius: 5px; +} + +.down { + transform: rotate(180deg); +} + +.sideways { + transform: rotate(90deg); +} + +.flex-container { + display: flex !important; + flex-direction: row; + justify-content: space-between; +} + +.label-container { + display: flex !important; + flex-direction: row; + justify-content: space-between; + width: fit-content; +} + +.label-status { + margin: auto; + margin-left: 4px; + margin-bottom: 7%; +} + +.label:hover { + cursor: default; +} + +#refreshButton:hover { + cursor: pointer !important; +} + +.list-group { + width: 100%; +} + +.greenBorder { + border-left-color: var(--clr-color-success-500, green) !important; +} + +.redBorder { + border-left-color: #f0ad4e !important; +} + +details { + border: 1px solid var(--clr-color-neutral-400, #cccccc); + border-left: 3px solid; + border-radius: 4px; + padding: 0.5em 0.5em 0; + &[open] { + padding: 0.5em; + summary { + margin-bottom: 0.5em; + } + } +} + +summary { + font-weight: bold; + margin: -0.5em -0.5em 0; + padding: 0.5em; + display: list-item; + cursor: pointer; +} diff --git a/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.ts b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.ts new file mode 100644 index 00000000..fde54f24 --- /dev/null +++ b/src/app/hf-markdown/single-task-verification-markdown/single-task-verification-markdown.component.ts @@ -0,0 +1,65 @@ +import { + animate, + state, + style, + transition, + trigger, +} from '@angular/animations'; +import { Component, Input, OnInit } from '@angular/core'; +import { Task } from 'src/app/scenario/taskVerification.type'; +import { VerificationService } from 'src/app/services/verification.service'; + +@Component({ + selector: 'app-single-task-verification-markdown', + templateUrl: './single-task-verification-markdown.component.html', + animations: [ + trigger('rotatedState', [ + state('default', style({ transform: 'rotate(0)' })), + state('rotating', style({ transform: 'rotate(360deg)' })), + transition('default => rotating', animate('1500ms')), + ]), + ], + styleUrls: ['./single-task-verification-markdown.component.scss'], +}) +export class SingleTaskVerificationMarkdownComponent implements OnInit { + @Input() target: string; + @Input() message: string; + @Input() taskName: string; + + detailsOpen = false; + + rotationState = 'default'; + + task?: Task; + + constructor(private verificationService: VerificationService) {} + + ngOnInit(): void { + this.verificationService.currentVerifications.subscribe( + (verificationMap) => { + const temp = verificationMap.get(this.target); + this.task = temp?.tasks?.filter( + (task) => task.name == this.taskName, + )[0]; + }, + ); + } + + isOfReturnType(task: Task, returnTypes: string[]): boolean { + return returnTypes.includes(task.return_type); + } + + elementClicked() { + this.rotationState = 'rotating'; + setTimeout(() => { + this.rotationState = 'default'; + }, 1500); + this.verificationService + .verifyTask(this.target, this.taskName) + ?.subscribe(); + } + + taskUnset(): boolean { + return this.task == undefined || this.task.success == undefined; + } +} diff --git a/src/app/scenario/Scenario.ts b/src/app/scenario/Scenario.ts index 2569d43a..d491f520 100644 --- a/src/app/scenario/Scenario.ts +++ b/src/app/scenario/Scenario.ts @@ -1,3 +1,5 @@ +import { TaskVerification } from './taskVerification.type'; + export class Scenario { id: string; name: string; @@ -6,4 +8,5 @@ export class Scenario { virtualmachines: Map[]; pauseable: boolean; printable: boolean; + vm_tasks: TaskVerification[]; } diff --git a/src/app/scenario/step.component.html b/src/app/scenario/step.component.html index ab8c449c..b4aa16e6 100644 --- a/src/app/scenario/step.component.html +++ b/src/app/scenario/step.component.html @@ -8,7 +8,14 @@