diff --git a/.gitattributes b/.gitattributes index cba754c34..2e29b0ae7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,13 @@ # Declare files that will always have CRLF line endings on checkout. *.bat text eol=crlf + +# Declare files that will always have CRLF line endings on checkout. +*.sh text eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jks binary +*.db binary +*.db-shm binary +*.db-wal binary diff --git a/chutney/ui/src/app/modules/campaign/components/execution/detail/campaign-execution.component.ts b/chutney/ui/src/app/modules/campaign/components/execution/detail/campaign-execution.component.ts index 93a91e140..343abf4d6 100644 --- a/chutney/ui/src/app/modules/campaign/components/execution/detail/campaign-execution.component.ts +++ b/chutney/ui/src/app/modules/campaign/components/execution/detail/campaign-execution.component.ts @@ -1,223 +1,223 @@ -/* - * SPDX-FileCopyrightText: 2017-2024 Enedis - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -import { Component, Input, OnInit } from '@angular/core'; -import { forkJoin, Observable, of, switchMap, timer } from 'rxjs'; - -import { - Authorization, - CampaignExecutionFullReport, - CampaignReport, - JiraScenario, - JiraTestExecutionScenarios, - ScenarioExecutionReportOutline, - XrayStatus -} from '@core/model'; -import { CampaignService, JiraPluginService } from '@core/services'; -import { Params } from '@angular/router'; -import { ExecutionStatus } from '@core/model/scenario/execution-status'; -import { EventManagerService } from '@shared'; -import { sortByAndOrder } from '@shared/tools'; -import { CampaignReportService } from '@core/services/campaign-report.service'; -import { DatasetUtils } from "@shared/tools/dataset-utils"; -import { map, tap } from "rxjs/operators"; -import { ScenarioExecutionService } from "src/app/core/services/scenario-execution.service"; -import { ExecutionDataset } from "@core/model/scenario/execution.dataset"; - -@Component({ - selector: 'chutney-campaign-execution', - templateUrl: './campaign-execution.component.html', - styleUrls: ['./campaign-execution.component.scss'] -}) -export class CampaignExecutionComponent implements OnInit { - - @Input() campaignId: number; - @Input() report: CampaignReport; - @Input() jiraUrl: string; - - Authorization = Authorization; - ExecutionStatus = ExecutionStatus; - - datasetByScenarioExecutionId: Map = new Map() - - errors: string[] = []; - jiraTestExecutionId: string; - private jiraScenarios: JiraScenario[] = []; - UNSUPPORTED = 'UNSUPPORTED'; - selectedStatusByScenarioId: Map = new Map(); - showMore: boolean[] = []; - - orderBy: string; - reverseOrder: boolean; - - constructor( - private jiraLinkService: JiraPluginService, - private campaignService: CampaignService, - private eventManagerService: EventManagerService, - private campaignReportService: CampaignReportService, - private scenarioExecutionService: ScenarioExecutionService, - private datasetUtils: DatasetUtils - ) { } - - ngOnInit(): void { - this.cleanJiraUrl(); - forkJoin({ - jirjiraTestExecutionScenarios: this.jiraTestExecutionScenarios$() - }).subscribe(result => { - this.jiraScenarios = result.jirjiraTestExecutionScenarios.jiraScenarios; - this.jiraTestExecutionId = result.jirjiraTestExecutionScenarios.id; - }); - this.report.report.scenarioExecutionReports.forEach((_report, index) => this.showMore[index] = false); - this.fetchMissingInlineDatasetsForScenarioExecution() - } - - private fetchMissingInlineDatasetsForScenarioExecution() { - const scenarioExecutionReportWithoutDataset = this.report.report.scenarioExecutionReports.filter(scenarioExecutionReport => !scenarioExecutionReport.dataset); - for (const execution of scenarioExecutionReportWithoutDataset) { - this.scenarioExecutionService.findExecutionReport(execution.scenarioId, execution.executionId).pipe( - map(scenarioExecution => scenarioExecution.dataset), - tap(dataset => this.datasetByScenarioExecutionId.set(String(execution.executionId), dataset)) - ).subscribe() - } - } - - private cleanJiraUrl() { - if (this.jiraUrl && this.jiraUrl.length == 0) { - this.jiraUrl = null; - } - } - - protected getDataset(execution: ScenarioExecutionReportOutline) { - if (!execution.dataset) { - if (this.datasetByScenarioExecutionId && this.datasetByScenarioExecutionId.has(String(execution.executionId))) { - return this.datasetUtils.getExecutionDatasetName(this.datasetByScenarioExecutionId.get(String(execution.executionId))) - } - return '' - } - return this.datasetUtils.getDatasetName(execution.dataset) - } - - private jiraTestExecutionScenarios$(): Observable { - return this.jiraLinkService.findByCampaignId(this.campaignId).pipe( - switchMap((jiraId) => { // TODO - Why this condition ? don't understand it !! - if (jiraId) { - return this.jiraLinkService.findTestExecScenariosByCampaignExecution(this.report.report.executionId); - } else { - return of(new JiraTestExecutionScenarios(null, [])); - } - }) - ); - } - - xrayStatuses(): Array { - const keys = Object.keys(XrayStatus); - return keys.slice(); - } - - selectedUpdateStatus(scenarioId: string, event: any) { - this.selectedStatusByScenarioId.set(scenarioId, event.target.value); - } - - updateStatus(scenarioId: string) { - const newStatus = this.selectedStatusByScenarioId.get(scenarioId); - if (newStatus === XrayStatus.PASS || newStatus === XrayStatus.FAIL) { - this.jiraLinkService.updateScenarioStatus(this.jiraTestExecutionId, scenarioId, newStatus).subscribe( - () => { }, - (error) => { - console.log(error); - } - ); - } - } - - scenarioStatus(scenarioId: String): string { - const jiraScenario = this.jiraScenarios.filter(s => s.chutneyId === scenarioId); - if (jiraScenario.length > 0) { - if (jiraScenario[0].executionStatus === XrayStatus.PASS || jiraScenario[0].executionStatus === XrayStatus.FAIL) { - return jiraScenario[0].executionStatus; - } - } - return this.UNSUPPORTED; - } - - jiraLinkFrom(chutneyId: string) { - const foundScenario = this.jiraScenarios.find(s => s.chutneyId === chutneyId); - if (foundScenario) { - return this.jiraUrl + '/browse/' + foundScenario.id; - } else { - return null; - } - } - - toQueryParams(scenarioExecutionReportOutline: ScenarioExecutionReportOutline): Params { - let execId = scenarioExecutionReportOutline.executionId !== -1 ? scenarioExecutionReportOutline.executionId : 'last'; - return { - active: execId, - open: execId, - } - } - - replay() { - this.campaignService.replayFailedScenario(this.report.report.executionId).subscribe({ - error: (error) => this.eventManagerService.broadcast({ name: 'error', msg: error.error }) - }); - - timer(1000).pipe( - switchMap(() => of(this.eventManagerService.broadcast({ name: 'replay', executionId: this.report.report.executionId }))) - ).subscribe(); - } - - stop() { - this.campaignService.stopExecution(this.campaignId, this.report.report.executionId).subscribe({ - error: (error) => this.eventManagerService.broadcast({ name: 'error', msg: error.error }) - }); - } - - statusClass(scenarioReportOutline: ScenarioExecutionReportOutline): string { - if (scenarioReportOutline.status === ExecutionStatus.SUCCESS) { - return 'fa-solid fa-circle-check text-info'; - } - if (scenarioReportOutline.status === ExecutionStatus.FAILURE) { - return 'fa-solid fa-circle-xmark text-danger'; - } - if (scenarioReportOutline.status === ExecutionStatus.RUNNING || scenarioReportOutline.status === ExecutionStatus.PAUSED) { - return 'fa-solid fa-spinner fa-pulse text-warning'; - } - if (scenarioReportOutline.status === ExecutionStatus.STOPPED) { - return 'fa-solid fa-circle-stop text-warning'; - } - if (scenarioReportOutline.status === ExecutionStatus.NOT_EXECUTED) { - return 'fa-regular fa-circle text-warning'; - } - return null; - } - - sortBy(property) { - if (this.orderBy === property) { - this.reverseOrder = !this.reverseOrder; - } - this.orderBy = property; - - return sortByAndOrder( - this.report.report.scenarioExecutionReports, - (i) => i[property] == null ? '' : i[property], - this.reverseOrder - ); - } - - exportReport() { - this.campaignService.findExecution(this.report.report.executionId) - .subscribe({ - next: (report: CampaignExecutionFullReport) => { - this.campaignReportService.toPDF(report).save('campaignExecutionReport.pdf'); - }, - error: error => { - this.errors.push(error.message); - } - }); - } -} +/* + * SPDX-FileCopyrightText: 2017-2024 Enedis + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { forkJoin, Observable, of, switchMap, timer } from 'rxjs'; + +import { + Authorization, + CampaignExecutionFullReport, + CampaignReport, + JiraScenario, + JiraTestExecutionScenarios, + ScenarioExecutionReportOutline, + XrayStatus +} from '@core/model'; +import { CampaignService, JiraPluginService } from '@core/services'; +import { Params } from '@angular/router'; +import { ExecutionStatus } from '@core/model/scenario/execution-status'; +import { EventManagerService } from '@shared'; +import { sortByAndOrder } from '@shared/tools'; +import { CampaignReportService } from '@core/services/campaign-report.service'; +import { DatasetUtils } from "@shared/tools/dataset-utils"; +import { map, tap } from "rxjs/operators"; +import { ScenarioExecutionService } from "src/app/core/services/scenario-execution.service"; +import { ExecutionDataset } from "@core/model/scenario/execution.dataset"; + +@Component({ + selector: 'chutney-campaign-execution', + templateUrl: './campaign-execution.component.html', + styleUrls: ['./campaign-execution.component.scss'] +}) +export class CampaignExecutionComponent implements OnInit { + + @Input() campaignId: number; + @Input() report: CampaignReport; + @Input() jiraUrl: string; + + Authorization = Authorization; + ExecutionStatus = ExecutionStatus; + + datasetByScenarioExecutionId: Map = new Map() + + errors: string[] = []; + jiraTestExecutionId: string; + private jiraScenarios: JiraScenario[] = []; + UNSUPPORTED = 'UNSUPPORTED'; + selectedStatusByScenarioId: Map = new Map(); + showMore: boolean[] = []; + + orderBy: string; + reverseOrder: boolean; + + constructor( + private jiraLinkService: JiraPluginService, + private campaignService: CampaignService, + private eventManagerService: EventManagerService, + private campaignReportService: CampaignReportService, + private scenarioExecutionService: ScenarioExecutionService, + private datasetUtils: DatasetUtils + ) { } + + ngOnInit(): void { + this.cleanJiraUrl(); + forkJoin({ + jirjiraTestExecutionScenarios: this.jiraTestExecutionScenarios$() + }).subscribe(result => { + this.jiraScenarios = result.jirjiraTestExecutionScenarios.jiraScenarios; + this.jiraTestExecutionId = result.jirjiraTestExecutionScenarios.id; + }); + this.report.report.scenarioExecutionReports.forEach((_report, index) => this.showMore[index] = false); + this.fetchMissingInlineDatasetsForScenarioExecution() + } + + private fetchMissingInlineDatasetsForScenarioExecution() { + const scenarioExecutionReportWithoutDataset = this.report.report.scenarioExecutionReports.filter(scenarioExecutionReport => !scenarioExecutionReport.dataset); + for (const execution of scenarioExecutionReportWithoutDataset) { + this.scenarioExecutionService.findExecutionReport(execution.scenarioId, execution.executionId).pipe( + map(scenarioExecution => scenarioExecution.dataset), + tap(dataset => this.datasetByScenarioExecutionId.set(String(execution.executionId), dataset)) + ).subscribe() + } + } + + private cleanJiraUrl() { + if (this.jiraUrl && this.jiraUrl.length == 0) { + this.jiraUrl = null; + } + } + + protected getDataset(execution: ScenarioExecutionReportOutline) { + if (!execution.dataset) { + if (this.datasetByScenarioExecutionId && this.datasetByScenarioExecutionId.has(String(execution.executionId))) { + return this.datasetUtils.getExecutionDatasetName(this.datasetByScenarioExecutionId.get(String(execution.executionId))) + } + return '' + } + return this.datasetUtils.getDatasetName(execution.dataset) + } + + private jiraTestExecutionScenarios$(): Observable { + return this.jiraLinkService.findByCampaignId(this.campaignId).pipe( + switchMap((jiraId) => { // TODO - Why this condition ? don't understand it !! + if (jiraId) { + return this.jiraLinkService.findTestExecScenariosByCampaignExecution(this.report.report.executionId); + } else { + return of(new JiraTestExecutionScenarios(null, [])); + } + }) + ); + } + + xrayStatuses(): Array { + const keys = Object.keys(XrayStatus); + return keys.slice(); + } + + selectedUpdateStatus(scenarioId: string, event: any) { + this.selectedStatusByScenarioId.set(scenarioId, event.target.value); + } + + updateStatus(scenarioId: string) { + const newStatus = this.selectedStatusByScenarioId.get(scenarioId); + if (newStatus === XrayStatus.PASS || newStatus === XrayStatus.FAIL) { + this.jiraLinkService.updateScenarioStatus(this.jiraTestExecutionId, scenarioId, newStatus).subscribe( + () => { }, + (error) => { + console.log(error); + } + ); + } + } + + scenarioStatus(scenarioId: String): string { + const jiraScenario = this.jiraScenarios.filter(s => s.chutneyId === scenarioId); + if (jiraScenario.length > 0) { + if (jiraScenario[0].executionStatus === XrayStatus.PASS || jiraScenario[0].executionStatus === XrayStatus.FAIL) { + return jiraScenario[0].executionStatus; + } + } + return this.UNSUPPORTED; + } + + jiraLinkFrom(chutneyId: string) { + const foundScenario = this.jiraScenarios.find(s => s.chutneyId === chutneyId); + if (foundScenario) { + return this.jiraUrl + '/browse/' + foundScenario.id; + } else { + return null; + } + } + + toQueryParams(scenarioExecutionReportOutline: ScenarioExecutionReportOutline): Params { + let execId = scenarioExecutionReportOutline.executionId !== -1 ? scenarioExecutionReportOutline.executionId : 'last'; + return { + active: execId, + open: execId, + } + } + + replay() { + this.campaignService.replayFailedScenario(this.report.report.executionId).subscribe({ + error: (error) => this.eventManagerService.broadcast({ name: 'error', msg: error.error }) + }); + + timer(1000).pipe( + switchMap(() => of(this.eventManagerService.broadcast({ name: 'replay', executionId: this.report.report.executionId }))) + ).subscribe(); + } + + stop() { + this.campaignService.stopExecution(this.campaignId, this.report.report.executionId).subscribe({ + error: (error) => this.eventManagerService.broadcast({ name: 'error', msg: error.error }) + }); + } + + statusClass(scenarioReportOutline: ScenarioExecutionReportOutline): string { + if (scenarioReportOutline.status === ExecutionStatus.SUCCESS) { + return 'fa-solid fa-circle-check text-info'; + } + if (scenarioReportOutline.status === ExecutionStatus.FAILURE) { + return 'fa-solid fa-circle-xmark text-danger'; + } + if (scenarioReportOutline.status === ExecutionStatus.RUNNING || scenarioReportOutline.status === ExecutionStatus.PAUSED) { + return 'fa-solid fa-spinner fa-pulse text-warning'; + } + if (scenarioReportOutline.status === ExecutionStatus.STOPPED) { + return 'fa-solid fa-circle-stop text-warning'; + } + if (scenarioReportOutline.status === ExecutionStatus.NOT_EXECUTED) { + return 'fa-regular fa-circle text-warning'; + } + return null; + } + + sortBy(property) { + if (this.orderBy === property) { + this.reverseOrder = !this.reverseOrder; + } + this.orderBy = property; + + return sortByAndOrder( + this.report.report.scenarioExecutionReports, + (i) => i[property] == null ? '' : i[property], + this.reverseOrder + ); + } + + exportReport() { + this.campaignService.findExecution(this.report.report.executionId) + .subscribe({ + next: (report: CampaignExecutionFullReport) => { + this.campaignReportService.toPDF(report).save('campaignExecutionReport.pdf'); + }, + error: error => { + this.errors.push(error.message); + } + }); + } +} diff --git a/chutney/ui/src/app/modules/database-admin/components/resultReportList/database-admin-report-list.component.scss b/chutney/ui/src/app/modules/database-admin/components/resultReportList/database-admin-report-list.component.scss index 2672b3d42..30b733164 100644 --- a/chutney/ui/src/app/modules/database-admin/components/resultReportList/database-admin-report-list.component.scss +++ b/chutney/ui/src/app/modules/database-admin/components/resultReportList/database-admin-report-list.component.scss @@ -1,58 +1,58 @@ -/*! - * SPDX-FileCopyrightText: 2017-2024 Enedis - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -table { - .headers-labels th { - padding-bottom: 0; - } -} - -:host ::ng-deep { - - .popover { - max-width: 30vw; /* optional max width */ - width: intrinsic; /* Safari/WebKit uses a non-standard name */ - width: -moz-max-content; /* Firefox/Gecko */ - width: -webkit-max-content; /* Chrome */ - border: 0; - border-radius: 0.5rem; - - .popover-arrow { - &::after { - border-left-color: var(--bs-primary); - } - } - } - - .popover-body { - background-color: var(--bs-primary); - color: var(--bs-white); - border-radius: 0.5rem; - } - - .cuppa-dropdown { - border: none; - - .selected-list { - .c-angle-up { - display: none!important; - } - - .c-angle-down { - display: none!important; - } - - .clear-all { - display: none!important; - } - } - - .dropdown-list { - width: max-content!important; - } - } -} +/*! + * SPDX-FileCopyrightText: 2017-2024 Enedis + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +table { + .headers-labels th { + padding-bottom: 0; + } +} + +:host ::ng-deep { + + .popover { + max-width: 30vw; /* optional max width */ + width: intrinsic; /* Safari/WebKit uses a non-standard name */ + width: -moz-max-content; /* Firefox/Gecko */ + width: -webkit-max-content; /* Chrome */ + border: 0; + border-radius: 0.5rem; + + .popover-arrow { + &::after { + border-left-color: var(--bs-primary); + } + } + } + + .popover-body { + background-color: var(--bs-primary); + color: var(--bs-white); + border-radius: 0.5rem; + } + + .cuppa-dropdown { + border: none; + + .selected-list { + .c-angle-up { + display: none!important; + } + + .c-angle-down { + display: none!important; + } + + .clear-all { + display: none!important; + } + } + + .dropdown-list { + width: max-content!important; + } + } +}