diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6506b6c3a5257818341fca6d2484cd62713af465..69328bd5fe0b0e395432d09c6de258b8009581d0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -83,6 +83,7 @@ import { DialogEditParamComputedComponent } from "./components/dialog-edit-param import { DialogEditParamValuesComponent } from "./components/dialog-edit-param-values/dialog-edit-param-values.component"; import { DialogGeneratePABComponent } from "./components/dialog-generate-pab/dialog-generate-pab.component"; import { DialogLoadSessionComponent } from "./components/dialog-load-session/dialog-load-session.component"; +import { DialogLogEntriesDetailsComponent } from "./components/dialog-log-entries-details/dialog-log-entries-details.component"; import { DialogSaveSessionComponent } from "./components/dialog-save-session/dialog-save-session.component"; import { JalhydAsyncModelValidationDirective } from "./directives/jalhyd-async-model-validation.directive"; @@ -154,6 +155,7 @@ const appRoutes: Routes = [ DialogEditParamValuesComponent, DialogGeneratePABComponent, DialogLoadSessionComponent, + DialogLogEntriesDetailsComponent, DialogSaveSessionComponent, FieldSetComponent, FieldsetContainerComponent, @@ -193,7 +195,8 @@ const appRoutes: Routes = [ DialogEditParamValuesComponent, DialogGeneratePABComponent, DialogSaveSessionComponent, - DialogLoadSessionComponent + DialogLoadSessionComponent, + DialogLogEntriesDetailsComponent ], providers: [ // services ApplicationSetupService, diff --git a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html new file mode 100644 index 0000000000000000000000000000000000000000..ef999517ca0d7675b13b92ec6901b3dac51f2805 --- /dev/null +++ b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html @@ -0,0 +1,10 @@ +<h1 mat-dialog-title [innerHTML]="uitextLogEntriesDetailsTitle"></h1> +<div mat-dialog-content> + <!-- entrées du journal --> + <log-entry *ngFor="let m of data.messages" [_message]="m"></log-entry> +</div> +<div mat-dialog-actions> + <button mat-raised-button [mat-dialog-close]="true"> + {{ uitextClose }} + </button> +</div> diff --git a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1bf57c65b854c9ce867ab62528a135d4a6bc9a0 --- /dev/null +++ b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts @@ -0,0 +1,24 @@ +import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; +import { Inject, Component } from "@angular/core"; +import { I18nService } from "../../services/internationalisation/internationalisation.service"; + +@Component({ + selector: "dialog-log-entries-details", + templateUrl: "dialog-log-entries-details.component.html", +}) +export class DialogLogEntriesDetailsComponent { + + constructor( + public dialogRef: MatDialogRef<DialogLogEntriesDetailsComponent>, + private intlService: I18nService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { } + + public get uitextLogEntriesDetailsTitle() { + return this.intlService.localizeText("INFO_TITREJOURNAL"); + } + + public get uitextClose() { + return this.intlService.localizeText("INFO_OPTION_CLOSE"); + } +} diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts index ca402293f108bfda22d83e7a75ea6aee5381828d..8beb3a78d380a6ed772cc4496b06b81c70ae3c38 100644 --- a/src/app/components/fixedvar-results/fixedvar-results.component.ts +++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts @@ -111,10 +111,6 @@ export class FixedVarResultsComponent implements DoCheck { if (this._fixedResults) { this.mergeLog(this._fixedResults.result, res); } - - if (this._varResults) { - this.mergeLog(this._varResults.result, res); - } return res; } diff --git a/src/app/components/fixedvar-results/var-results.component.html b/src/app/components/fixedvar-results/var-results.component.html index e7bbd993fc9ca551f693db5de401dc47d5430af8..252c579fca9fb572ef196ba433af7e4c00b31daa 100644 --- a/src/app/components/fixedvar-results/var-results.component.html +++ b/src/app/components/fixedvar-results/var-results.component.html @@ -17,9 +17,24 @@ <div class="var-results-inner-container" #tableContainer> <table mat-table [dataSource]="dataSet"> - <ng-container *ngFor="let h of headers; let i = index" [matColumnDef]="h"> + <!-- log messages column --> + <ng-container *ngIf="hasMessages" matColumnDef="logMessagesColumn"> + <mat-header-cell *matHeaderCellDef> + <mat-icon>info</mat-icon> + </mat-header-cell> + <mat-cell *matCellDef="let element"> + <span *ngIf="element[0].messages.length > 0" class="log-messages-column" + (click)="openLogDetails(element[0].messages)"> + <mat-icon *ngIf="element[0].isInfo" style="color:green">check_circle</mat-icon> + <mat-icon *ngIf="element[0].isWarning" style="color:orange">error_outline</mat-icon> + <mat-icon *ngIf="element[0].isError" style="color:red">warning</mat-icon> + </span> + </mat-cell> + </ng-container> + <!-- generic column --> + <ng-container *ngFor="let h of headersWithoutLogColumn; let i = index" [matColumnDef]="h"> <th mat-header-cell *matHeaderCellDef>{{ h }}</th> - <td mat-cell *matCellDef="let element">{{ element[i] }}</td> + <td mat-cell *matCellDef="let element">{{ element[i+1] }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="headers"></tr> diff --git a/src/app/components/fixedvar-results/var-results.component.scss b/src/app/components/fixedvar-results/var-results.component.scss index 12d1148fcf6f0adc02c335a3d2dc0b5b016d03b8..d897f54841d63ad93bc8847f6263ffb15c22fd9c 100644 --- a/src/app/components/fixedvar-results/var-results.component.scss +++ b/src/app/components/fixedvar-results/var-results.component.scss @@ -46,6 +46,10 @@ table.mat-table { &:nth-child(odd) { background-color: #f4f4f4; } + + .log-messages-column { + cursor: pointer; + } } ::ng-deep .mat-cell { @@ -56,5 +60,10 @@ table.mat-table { font-size: 1em; color: black; padding: 5px; + border: none; + } + + ::ng-deep .mat-cell { + border: none; } } diff --git a/src/app/components/fixedvar-results/var-results.component.ts b/src/app/components/fixedvar-results/var-results.component.ts index f737e1d4c03120fa6833e76c3dd0eb8ed21093d8..a58eb8ea78d1ec086e3f4d46c860ece511256c4b 100644 --- a/src/app/components/fixedvar-results/var-results.component.ts +++ b/src/app/components/fixedvar-results/var-results.component.ts @@ -1,10 +1,14 @@ import { Component, ViewChild, ElementRef } from "@angular/core"; + +import { MatDialog } from "@angular/material"; + import { VarResults } from "../../results/var-results"; import { ApplicationSetupService } from "../../services/app-setup/app-setup.service"; -import { ResultElement } from "jalhyd"; +import { ResultElement, Message, MessageSeverity } from "jalhyd"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; import * as XLSX from "xlsx"; import { ResultsComponent } from "./results.component"; +import { DialogLogEntriesDetailsComponent } from '../dialog-log-entries-details/dialog-log-entries-details.component'; @Component({ selector: "var-results", @@ -27,11 +31,15 @@ export class VarResultsComponent extends ResultsComponent { /** entêtes des colonnes (param à varier, à calculer + extraResults) */ protected _headers: string[]; + /** messages de log issus des résultats variés */ + protected _messages: Message[]; + @ViewChild("tableContainer") table: ElementRef; constructor( protected appSetupService: ApplicationSetupService, - protected intlService: I18nService + protected intlService: I18nService, + protected logEntriesDetailsDialog: MatDialog ) { super(); } @@ -41,11 +49,20 @@ export class VarResultsComponent extends ResultsComponent { this._varResults = r; this._results = []; this._headers = []; + this._messages = []; const nDigits = this.appSetupService.displayDigits; if (this._varResults) { - // A. build headers + // A. gather messages + for (const re of this._varResults.resultElements) { + this._messages = this._messages.concat(re.log.messages); // es6 concat; + } + + // B. build headers + if (this._messages.length > 0) { // has log messages + this._headers.push("logMessagesColumn"); + } for (let i = 0; i < this._varResults.variatedParameters.length; i++) { this._headers.push(this._varResults.variableParamHeaders[i]); } @@ -54,7 +71,7 @@ export class VarResultsComponent extends ResultsComponent { } this._headers = this._headers.concat(this._varResults.extraResultHeaders); - // B. pre-extract variable parameters valueslet longest = 0; + // C. pre-extract variable parameters valueslet longest = 0; const varValues = []; // find longest list this.size = 0; @@ -75,13 +92,32 @@ export class VarResultsComponent extends ResultsComponent { varValues.push(vv); } - // C. build dataset + // D. build dataset for (let i = 0; i < this._varResults.resultElements.length; i++) { const re: ResultElement = this._varResults.resultElements[i]; if (re) { // build ordered list of : variable params values; result; extra results const list = []; + // log messages for this computation step + if (this._messages.length > 0) { + if (re.log.messages.length > 0) { + // find highest log level to display + let highest = 100; + for (const lm of re.log.messages) { + highest = Math.min(highest, lm.getSeverity()); + } + list.push({ + messages: re.log.messages, + isInfo: (highest === MessageSeverity.INFO), + isWarning: (highest === MessageSeverity.WARNING), + isError: (highest === MessageSeverity.ERROR) + }); + } + } else { + list.push({ messages: [] }); // empty log element to preserve row length + } + // 1. variable params values for this computation step for (const vv of varValues) { list.push(vv[i]); @@ -108,6 +144,10 @@ export class VarResultsComponent extends ResultsComponent { } } + public get hasMessages() { + return this._messages.length > 0; + } + public get hasResults(): boolean { return this._varResults && this._varResults.hasResults; } @@ -116,6 +156,14 @@ export class VarResultsComponent extends ResultsComponent { return this._headers; } + public get headersWithoutLogColumn() { + if (this.hasMessages) { + return this._headers.slice(1); + } else { + return this._headers; + } + } + /** * Returns a combination of results and extraResults for mat-table */ @@ -131,4 +179,20 @@ export class VarResultsComponent extends ResultsComponent { // save and download XLSX.writeFile(wb, "VariableResults.xlsx"); } + + /** Shows a modal displaying the log messages details for a calcutation step */ + public openLogDetails(messages: Message[]) { + if (this.isFullscreen) { + this.exitFullscreen(); + } + this.logEntriesDetailsDialog.open( + DialogLogEntriesDetailsComponent, + { + data: { + messages: messages + }, + autoFocus: false + } + ); + } } diff --git a/src/app/components/log/log.component.ts b/src/app/components/log/log.component.ts index bd710cb56a43ed8a4c927fe06ef90c9ae1f94c9a..6ab7883505321926fb9209f9a00bfe8c9d5938f0 100644 --- a/src/app/components/log/log.component.ts +++ b/src/app/components/log/log.component.ts @@ -22,7 +22,7 @@ export class LogComponent { ) { } private get uitextTitreJournal() { - return this.intlService.localizeText("INFO_REMOUSRESULTS_TITREJOURNAL"); + return this.intlService.localizeText("INFO_TITREJOURNAL"); } public get hasEntries(): boolean { diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 1392829d879fde9b0fde40256e036ef314b97b9e..b0c817f26119426a96ebf183e6239d049118198a 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -247,7 +247,6 @@ "INFO_REMOUSRESULTS_TIRANT": "Draft (m)", "INFO_REMOUSRESULTS_TIRANTCRITIQUE": "Critical water level", "INFO_REMOUSRESULTS_TIRANTNORMAL": "Normal water level", - "INFO_REMOUSRESULTS_TITREJOURNAL": "Calculation log", "INFO_REPORT_BUG_BODY": "This is an issue report.\n\nPlease describe quickly the issue you encoutered, and the steps you followed:\n\n\n\n\n--- Current session state - do not modify text below ---\n------------------------------------------------------------------------\n\n", "INFO_REPORT_BUG_SUBJECT": "Issue report", "INFO_REQUIRES": "requires", @@ -275,6 +274,7 @@ "INFO_THEME_PASSE_A_BASSIN_TITRE": "Fish ladder", "INFO_THEME_PASSE_NATURELLE_DESCRIPTION": "Tools for sizing a natural fish pass also called macroroughness pass or rock-ramp fish pass", "INFO_THEME_PASSE_NATURELLE_TITRE": "Natural pass", + "INFO_TITREJOURNAL": "Calculation log", "INFO_WELCOME_CONTENT": "<p>The Cassiopée software was developed by <a href=\"https://www.afbiodiversite.fr\" target=\"_blank\">AFB</a> (French Agency for Biodiversity) and <a href=\"http://g-eau.fr/index.php/en/\" target=\"_blank\">UMR G-EAU</a> (Joint Research Unit \"Water Management, Actors, Territories\").</p><p>It includes tools for designing fish passes, and hydraulic calculation tools useful for environmental and agricultural engineering.</p><p>For more information, consult <a href=\"assets/docs-fr/mentions_legales.html\" target=\"_blank\">legal notice</a> and <a href=\"assets/docs-fr/index.html\" target=\"_blank\">documentation</a>.</p>", "INFO_WELCOME_SUBTITLE": "Hydraulic calculators", "WARNING_REMOUS_ARRET_CRITIQUE": "Calculation stopped: critical elevation reached at abscissa %x%", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 16cdbe471511ef08abc998ec52456f7105fcecdd..47a63e9364b43faec33d58337cfbeeecedfce9fd 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -247,7 +247,6 @@ "INFO_REMOUSRESULTS_TIRANT": "Tirant d'eau (m)", "INFO_REMOUSRESULTS_TIRANTCRITIQUE": "Tirant d'eau critique", "INFO_REMOUSRESULTS_TIRANTNORMAL": "Tirant d'eau normal", - "INFO_REMOUSRESULTS_TITREJOURNAL": "Journal de calcul", "INFO_REPORT_BUG_BODY": "Ceci est un rapport d'erreur.\n\nMerci de décrire rapidement ci-dessous le problème rencontré, et les étapes qui vous y ont mené :\n\n\n\n\n--- État de la session en cours - ne pas modifier le texte ci-dessous ---\n--------------------------------------------------------------------------------------------\n\n", "INFO_REPORT_BUG_SUBJECT": "Rapport d'erreur", "INFO_REQUIRES": "dépend de", @@ -275,6 +274,7 @@ "INFO_THEME_PASSE_A_BASSIN_TITRE": "Passe à bassins", "INFO_THEME_PASSE_NATURELLE_DESCRIPTION": "Outils de dimensionnement d'une passe à poissons de type passe naturelle ou encore appelée passe à macro-rugosités", "INFO_THEME_PASSE_NATURELLE_TITRE": "Passe naturelle", + "INFO_TITREJOURNAL": "Journal de calcul", "INFO_WELCOME_CONTENT": "<p>Le logiciel Cassiopée a été développé par l'<a href=\"https://www.afbiodiversite.fr\" target=\"_blank\">AFB</a> (Agence Française pour la Biodiversité) et <a href=\"http://g-eau.fr\" target=\"_blank\">L'UMR G-EAU</a> (UMR Gestion de l'Eau, Acteurs, Usages).</p><p>Il regroupe des outils d'aide à la conception de passes à poissons et des outils de calcul hydraulique utiles pour l'ingénierie en environnement et agriculture.</p><p>Pour plus d'informations, consulter les <a href=\"assets/docs-fr/mentions_legales.html\" target=\"_blank\">mentions légales</a> et la <a href=\"assets/docs-fr/index.html\" target=\"_blank\">documentation</a>.</p>", "INFO_WELCOME_SUBTITLE": "Modules de calcul d'hydraulique", "WARNING_REMOUS_ARRET_CRITIQUE": "Arrêt du calcul : hauteur critique atteinte à l'abscisse %x%",