From 2020cfecd19bfe2bb76001068742b9416b1ed166 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Wed, 26 Aug 2020 14:35:49 +0200 Subject: [PATCH 01/64] Work on #431 - make QA variable in PAB --- jalhyd_branch | 2 +- .../pab-table/pab-table.component.html | 9 +++ .../pab-table/pab-table.component.scss | 10 +++ .../pab-table/pab-table.component.ts | 66 +++++++++++++------ .../param-field-line.component.ts | 12 +++- src/styles.scss | 49 ++++++++++++++ 6 files changed, 124 insertions(+), 24 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index de50629b8..47cea4573 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -278-prebarrage-calculable-avec-champs-vides-cassiopee-nghyd-470 +261-pab-pouvoir-lier-et-varier-le-debit-d-attrait diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html index 96efe09a1..777573a7f 100644 --- a/src/app/components/pab-table/pab-table.component.html +++ b/src/app/components/pab-table/pab-table.component.html @@ -96,6 +96,15 @@ </mat-option> </mat-select> + <div *ngIf="isQA(cell)" class="qaFieldLineContainer"> + <div class="qaLabel"> + {{ cell.title }} + </div> + <param-field-line class="qaFieldLine" [param]="cell.model" (radio)="inputValueChanged($event, cell)" + (input)="inputValueChanged($event, cell)"> + </param-field-line> + </div> + <span *ngIf="! hasModel(cell)">{{ cellValue(cell) }}</span> </td> </tr> diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss index abd5be33c..5b64df679 100644 --- a/src/app/components/pab-table/pab-table.component.scss +++ b/src/app/components/pab-table/pab-table.component.scss @@ -47,3 +47,13 @@ mat-card-content { } } } + +.qaFieldLineContainer { + padding: 0 10px; +} + +.qaLabel { + margin-top: 13px; + margin-right: 10px; + font-weight: bold; +} diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index b3c8934ec..bacee1c96 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1,6 +1,6 @@ import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit } from "@angular/core"; -import { LoiDebit } from "jalhyd"; +import { LoiDebit, ParamCalculability } from "jalhyd"; import { MatDialog } from "@angular/material/dialog"; @@ -27,6 +27,7 @@ import { NotificationsService } from "../../services/notifications.service"; import { PabTable } from "../../formulaire/elements/pab-table"; import { DialogEditPabComponent } from "../dialog-edit-pab/dialog-edit-pab.component"; import { AppComponent } from "../../app.component"; +import { NgParameter, ParamRadioConfig } from "../../formulaire/elements/ngparam"; /** * The big editable data grid for calculator type "Pab" (component) @@ -101,7 +102,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { /** returns true if the cell is an editable number */ public isNumberInput(cell: any): boolean { - return this.hasModel(cell) && ! this.isSelect(cell); + return this.hasModel(cell) && ! this.isSelect(cell) && ! this.isQA(cell); } /** returns true if the cell is a select box */ @@ -109,6 +110,11 @@ export class PabTableComponent implements AfterViewInit, OnInit { return this.hasModel(cell) && (cell.options !== undefined); } + /** returns true if the cell is a QA (Attraction flow) editor */ + public isQA(cell: any): boolean { + return this.hasModel(cell) && cell.qa; + } + /** value to display in a cell, if it is not editable */ public cellValue(cell: any) { if (cell === undefined) { @@ -166,8 +172,12 @@ export class PabTableComponent implements AfterViewInit, OnInit { */ public isInvalid(cell: any): boolean { let valid = true; - if (this.hasModel(cell) && cell.model instanceof ParamDefinition) { - valid = valid && cell.model.isValid; + if (this.hasModel(cell)) { + if (cell.model instanceof ParamDefinition) { + valid = valid && cell.model.isValid; + } else if (cell.model instanceof NgParameter) { // for QA (currently has domain ANY but that might change) + valid = valid && cell.model.paramDefinition.isValid; + } } if (cell.uiValidity !== undefined) { valid = valid && cell.uiValidity; @@ -443,7 +453,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { const nDigits = this.appSetupService.displayPrecision; for (const c of this.model.children) { for (const p of c.parameterIterator) { - if (p.visible) { + if (p.visible && p.symbol !== "QA") { // QA might vary ! p.singleValue = round(p.singleValue, nDigits); } } @@ -461,7 +471,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { bs = bs.concat(this.model.downWall); this.headers.push({ title: this.i18nService.localizeText("INFO_PAB_BASSIN"), - colspan: 6, + colspan: 5, selectable: bs }); // 1 header for each device of the wall having the most devices (including downwall) @@ -476,7 +486,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { // A. build columns set this.cols = []; - // 6 cols for basin + // 5 cols for basin this.cols.push({ title: this.i18nService.localizeText("INFO_PAB_NUM_BASSIN"), selectable: bs @@ -489,10 +499,10 @@ export class PabTableComponent implements AfterViewInit, OnInit { title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB"), selectable: bs }); - this.cols.push({ + /* this.cols.push({ title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA"), selectable: bs - }); + }); */ this.cols.push({ title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB"), selectable: bs @@ -543,14 +553,14 @@ export class PabTableComponent implements AfterViewInit, OnInit { // basin number deviceParamRow.cells.push({ value: childIndex + 1, - rowspan: maxNbParams + 1, + rowspan: maxNbParams + 2, class: "basin_number", selectable: cloison }); - // 4 empty cells + // 3 empty cells deviceParamRow.cells.push({ - colspan: 4, - rowspan: maxNbParams , + colspan: 3, + rowspan: maxNbParams, selectable: cloison }); // ZRAM @@ -562,7 +572,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { // 1 empty cell if (i === 1) { deviceParamRow.cells.push({ - rowspan: maxNbParams, + rowspan: maxNbParams + 1, selectable: cloison }); } @@ -639,10 +649,6 @@ export class PabTableComponent implements AfterViewInit, OnInit { model: cloison.prms.BB, title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB") }, - { - model: cloison.prms.QA, - title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA") - }, { model: cloison.prms.ZRMB, title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB") @@ -652,11 +658,29 @@ export class PabTableComponent implements AfterViewInit, OnInit { // fill horizontal space for (let i = 0; i < maxNbDevices; i++) { basinRow.cells.push({ - colspan: 3 + colspan: 3, + rowspan: 2 }); } // done ! this.rows.push(basinRow); + // 1 row for QA editor + const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form); + qaParam.radioConfig = ParamRadioConfig.VAR; + const qaRow: { selectable: any, cells: any[] } = { + selectable: undefined, + cells: [ + { + model: qaParam, + colspan: 3, + qa: true, + title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA") + } + ] + }; + this.rows.push(qaRow); + // done ! + childIndex ++; } @@ -681,9 +705,9 @@ export class PabTableComponent implements AfterViewInit, OnInit { class: "basin_number", selectable: this.model.downWall }); - // 4 empty cells + // 3 empty cells deviceParamRowDW.cells.push({ - colspan: 4, + colspan: 3, rowspan: maxNbParamsDW , selectable: this.model.downWall }); diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index 22b7a92ad..614521e14 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -4,7 +4,7 @@ import { I18nService } from "../../services/internationalisation.service"; import { NgParameter, ParamRadioConfig } from "../../formulaire/elements/ngparam"; import { NgParamInputComponent } from "../ngparam-input/ngparam-input.component"; import { ServiceFactory } from "../../services/service-factory"; -import { ParamValueMode, ParallelStructure, ParamCalculability } from "jalhyd"; +import { ParamValueMode, ParallelStructure, ParamCalculability, Pab } from "jalhyd"; import { FormulaireService } from "../../services/formulaire.service"; import { ParamLinkComponent } from "../param-link/param-link.component"; import { ParamValuesComponent } from "../param-values/param-values.component"; @@ -173,7 +173,7 @@ export class ParamFieldLineComponent implements OnChanges { return this._formService.getLinkableValues(this.param).length > 0; } - // ou un seul module de calcul "ouvrages parallèles" + // ou un seul module de calcul "ouvrages parallèles" avec au moins 2 ouvrages if (this._formService.formulaires[0].currentNub instanceof ParallelStructure) { const ps: ParallelStructure = this._formService.formulaires[0].currentNub; if (ps.structures.length > 1) { @@ -181,6 +181,14 @@ export class ParamFieldLineComponent implements OnChanges { } } + // ou un seul module de calcul "PAB" avec au mois 2 ouvrages + if (this._formService.formulaires[0].currentNub instanceof Pab) { + const pab: Pab = this._formService.formulaires[0].currentNub; + if (pab.children.length > 1) { + return this._formService.getLinkableValues(this.param).length > 0; + } + } + } return false; } diff --git a/src/styles.scss b/src/styles.scss index 4f086079e..727ac59f1 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -136,6 +136,55 @@ field-set { } } +.qaFieldLineContainer { + + .qaFieldLine { + .mat-button-toggle-label-content { + line-height: 24px !important; + } + } + + ngparam-input { + height: 38px; + margin-top: 0; + } + + param-values { + margin-top: 0; + } + + param-link { + margin-top: 0; + + .status-icons-container { + display: none; + } + } + + mat-form-field { + + .mat-form-field-wrapper { + padding-bottom: 5px; + } + + input.form-control.mat-input-element { + width: 100%; + } + + button.param-values-more { + display: none; + } + + .mat-form-field-underline { + display: none; + } + + mat-error.mat-error { + display: none; + } + } +} + .pab-data-table { .editable-cell-bg { -- GitLab From c5d0eecb96c67ea1a73595819016c9ccb8688458 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 27 Aug 2020 10:52:40 +0200 Subject: [PATCH 02/64] Work on #431 - update label in Pab QA links --- src/app/components/param-link/param-link.component.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts index 058ed5a28..89255ef13 100644 --- a/src/app/components/param-link/param-link.component.ts +++ b/src/app/components/param-link/param-link.component.ts @@ -1,7 +1,7 @@ import { Component, Input, Output, EventEmitter, OnChanges, OnDestroy } from "@angular/core"; import { NgParameter } from "../../formulaire/elements/ngparam"; -import { LinkedValue, ParamValueMode, Observer, Structure, acSection, ParamDefinition, ChildNub } from "jalhyd"; +import { LinkedValue, ParamValueMode, Observer, acSection, ParamDefinition, ChildNub, Cloisons, Pab } from "jalhyd"; import { FormulaireService } from "../../services/formulaire.service"; import { I18nService } from "../../services/internationalisation.service"; import { FormulaireDefinition } from "../../formulaire/definition/form-definition"; @@ -169,7 +169,14 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy { } // 1. Paramètre / résultat d'un Nub enfant au sein d'un Nub parent - if (i.nub instanceof ChildNub) { + if ( + (i.nub instanceof ChildNub) + || ( + (i.nub instanceof Cloisons) + && i.nub.parent !== undefined + && (i.nub.parent instanceof Pab) + ) + ) { let pos: number; pos = i.nub.findPositionInParent(); return `${preview} - ` + sprintf( -- GitLab From de4c556edf0a43284624d11ba4ee4ffcfeb8a9f8 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 27 Aug 2020 12:03:56 +0200 Subject: [PATCH 03/64] Work on #431 - do not capture Tab events --- .../ngparam-input/ngparam-input.component.ts | 21 +++++++++++++++++-- .../pab-table/pab-table.component.html | 2 +- .../pab-table/pab-table.component.ts | 2 +- .../param-field-line.component.html | 2 +- .../param-field-line.component.ts | 4 ++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/app/components/ngparam-input/ngparam-input.component.ts b/src/app/components/ngparam-input/ngparam-input.component.ts index 81db20827..cbaf4e2fd 100644 --- a/src/app/components/ngparam-input/ngparam-input.component.ts +++ b/src/app/components/ngparam-input/ngparam-input.component.ts @@ -1,6 +1,6 @@ // cf. https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html -import { Component, ChangeDetectorRef, OnDestroy } from "@angular/core"; +import { Component, ChangeDetectorRef, OnDestroy, Input, ElementRef } from "@angular/core"; import { Message, Observer } from "jalhyd"; @@ -17,6 +17,10 @@ import { ApplicationSetupService } from "../../services/app-setup.service"; ] }) export class NgParamInputComponent extends GenericInputComponentDirective implements Observer, OnDestroy { + + @Input() + public captureTabEvents: boolean; + /** * paramètre géré */ @@ -33,9 +37,11 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem constructor( intlService: I18nService, appSetupService: ApplicationSetupService, - cdRef: ChangeDetectorRef + cdRef: ChangeDetectorRef, + private element: ElementRef ) { super(cdRef, intlService, appSetupService); + this.captureTabEvents = true; } /** @@ -114,6 +120,17 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem } } + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event, shift: boolean) { + this.tabPressed.emit({ originalEvent: event, shift: shift }); + // stop event propagation ? + if (this.captureTabEvents) { + return false; + } // else let it bubble ! + } + public ngOnDestroy() { this._paramDef.removeObserver(this); } diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html index 777573a7f..488fe6565 100644 --- a/src/app/components/pab-table/pab-table.component.html +++ b/src/app/components/pab-table/pab-table.component.html @@ -101,7 +101,7 @@ {{ cell.title }} </div> <param-field-line class="qaFieldLine" [param]="cell.model" (radio)="inputValueChanged($event, cell)" - (input)="inputValueChanged($event, cell)"> + (input)="inputValueChanged($event, cell)" [captureTabEvents]="false"> </param-field-line> </div> diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index bacee1c96..5f8455f9a 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1,6 +1,6 @@ import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit } from "@angular/core"; -import { LoiDebit, ParamCalculability } from "jalhyd"; +import { LoiDebit } from "jalhyd"; import { MatDialog } from "@angular/material/dialog"; diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html index 1143ac972..e1faeebf2 100644 --- a/src/app/components/param-field-line/param-field-line.component.html +++ b/src/app/components/param-field-line/param-field-line.component.html @@ -4,7 +4,7 @@ <div fxFlex="1 0 120px"> <!-- composant pour gérer le cas général (valeur numérique à saisir) --> <ngparam-input [title]="param.title" [hidden]="! isRadioFixChecked" (change)="onInputChange($event)" - (tabPressed)="onTabPressed($event)"> + (tabPressed)="onTabPressed($event)" [captureTabEvents]="captureTabEvents"> </ngparam-input> <!-- composant pour gérer le cas "paramètre calculé" --> diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index 614521e14..f76d819c2 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -26,6 +26,7 @@ export class ParamFieldLineComponent implements OnChanges { this._formService = ServiceFactory.formulaireService; this.valid = new EventEmitter(); this.inputChange = new EventEmitter(); + this.captureTabEvents = true; } public get uitextParamFixe() { @@ -86,6 +87,9 @@ export class ParamFieldLineComponent implements OnChanges { @Input() public param: NgParameter; + @Input() + public captureTabEvents: boolean; + @ViewChild(NgParamInputComponent, { static: true }) private _ngParamInputComponent: NgParamInputComponent; -- GitLab From 7b8271250a863d4bdb233317d727144574e6e791 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 27 Aug 2020 15:17:04 +0200 Subject: [PATCH 04/64] Work on #431 - proper display of variating QA in boundaries selector and chart --- .../pab-profile-chart.component.ts | 8 ++- .../pab-table/pab-table.component.ts | 22 ++++++- .../variable-results-selector.component.ts | 43 +------------- src/app/formulaire/definition/form-pab.ts | 17 +++++- src/app/results/calculator-results.ts | 59 ++++++++++++++++++- src/locale/messages.en.json | 1 + src/locale/messages.fr.json | 1 + 7 files changed, 102 insertions(+), 49 deletions(-) diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts index 5d9220b27..449c050ff 100644 --- a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts +++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts @@ -12,6 +12,7 @@ import { AppComponent } from "../../app.component"; import { CloisonAval, Cloisons, LoiDebit } from "jalhyd"; import { sprintf } from "sprintf-js"; +import { CalculatorResults } from 'app/results/calculator-results'; @Component({ selector: "pab-profile-chart", @@ -453,13 +454,14 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen * @param n index of the variating parameter(s) iteration */ private getLegendForSeries(n: number): string { - let i = 0; + /* let i = 0; return this.varValues.map((vv) => { const vp = this._results.variatedParameters[i]; i++; let value = "0"; value = vv[n]; - return `${vp.param.symbol} = ${value}`; - }).join(", "); + return `${vp.symbol} = ${value}`; + }).join(", "); */ + return CalculatorResults.variatingModalityLabel(this.varValues, this._results, n); } } diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 5f8455f9a..225d7da87 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1,6 +1,6 @@ import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit } from "@angular/core"; -import { LoiDebit } from "jalhyd"; +import { LoiDebit, ParamValueMode } from "jalhyd"; import { MatDialog } from "@angular/material/dialog"; @@ -1057,7 +1057,10 @@ export class PabTableComponent implements AfterViewInit, OnInit { ); // copy parameter values for (const p of si.prms) { - newChild.getParameter(p.symbol).singleValue = p.singleValue; + // @TODO QA may vary + if (p.visible && p.symbol !== "QA") { // QA might vary ! + newChild.getParameter(p.symbol).singleValue = p.singleValue; + } } // copy children if (si instanceof ParallelStructure) { @@ -1242,7 +1245,8 @@ export class PabTableComponent implements AfterViewInit, OnInit { for (const av of availableVariables) { for (const c of this.selectedItems) { for (const p of c.parameterIterator) { - if (p.visible && p.symbol === av.value) { + // @TODO what todo when p varies (QA only) ? + if (p.visible && p.symbol === av.value && ! p.hasMultipleValues) { av.occurrences ++; if (av.first === undefined) { av.first = p.singleValue; @@ -1319,6 +1323,10 @@ export class PabTableComponent implements AfterViewInit, OnInit { case "set-value": for (const s of this.selectedItems) { for (const p of s.parameterIterator) { // deep + // force single mode (QA only) + if (p.hasMultipleValues) { + p.valueMode = ParamValueMode.SINGLE; + } if (p.symbol === result.variable) { p.singleValue = result.value; } @@ -1329,6 +1337,10 @@ export class PabTableComponent implements AfterViewInit, OnInit { case "delta": for (const s of this.selectedItems) { for (const p of s.parameterIterator) { // deep + // force single mode (QA only) + if (p.hasMultipleValues) { + p.valueMode = ParamValueMode.SINGLE; + } if (p.symbol === result.variable) { p.singleValue += result.delta; } @@ -1405,6 +1417,10 @@ export class PabTableComponent implements AfterViewInit, OnInit { // for ZRMB, interpolatedValues length is shorter by 1 element if (interpolatedValues[idx] !== undefined) { for (const p of s.parameterIterator) { // deep + // force single mode (QA only) + if (p.hasMultipleValues) { + p.valueMode = ParamValueMode.SINGLE; + } if (p.symbol === result.variable) { p.singleValue = interpolatedValues[idx]; idx ++; diff --git a/src/app/components/variable-results-selector/variable-results-selector.component.ts b/src/app/components/variable-results-selector/variable-results-selector.component.ts index 9f91c26b0..663f1f0e5 100644 --- a/src/app/components/variable-results-selector/variable-results-selector.component.ts +++ b/src/app/components/variable-results-selector/variable-results-selector.component.ts @@ -4,8 +4,8 @@ import { I18nService } from "../../services/internationalisation.service"; import { fv, longestVarParam } from "../../util"; import { MultiDimensionResults } from "../../results/multidimension-results"; import { PrebarrageResults } from "../../results/prebarrage-results"; - import { CalculatorType, PbBassin, PbCloison, Structure, VariatedDetails } from "jalhyd"; +import { CalculatorResults } from "../../results/calculator-results"; @Component({ selector: "variable-results-selector", @@ -81,46 +81,7 @@ export class VariableResultsSelectorComponent implements OnChanges { } protected entryLabel(index: number): string { - const kv = []; - for (let i = 0; i < this.varValues.length; i++) { - const vv = this.varValues[i]; - const vp = this.results.variatedParameters[i]; - let symbol = vp.param.symbol; - // is vp a parameter of a child Nub ? - if ( - vp.param.parentNub - && vp.param.parentNub !== vp.param.originNub - ) { - let childPrefix: string; - // prefix the label depending on (grand)children type - switch (vp.param.originNub.calcType) { - case CalculatorType.PreBarrage: - const pbRes = this.results as PrebarrageResults; - if (vp.param.parentNub instanceof Structure) { - const struct = vp.param.parentNub as Structure; - const wall = struct.parent as PbCloison; - const posS = struct.findPositionInParent() + 1; - childPrefix = this.intlService.localizeMessage(wall.description); - // there might be multiple walls between the same pair of basins - if (wall.uid in pbRes.wallsSuffixes) { - childPrefix += " (" + pbRes.wallsSuffixes[wall.uid] + ")"; - } - childPrefix += "_" + this.intlService.localizeText("INFO_LIB_STRUCTURE_N_COURT") + posS; - } else if (vp.param.parentNub instanceof PbBassin) { - const bassin = vp.param.parentNub as PbBassin; - childPrefix = this.intlService.localizeMessage(bassin.description); - } - break; - case CalculatorType.MacroRugoCompound: - const posMR = vp.param.parentNub.findPositionInParent() + 1; - childPrefix = this.intlService.localizeText("INFO_LIB_RADIER_N_COURT") + posMR; - break; - } - symbol = childPrefix + "_" + symbol; - } - kv.push(`${symbol} = ${vv[index]}`); - } - return kv.join(", "); + return CalculatorResults.variatingModalityLabel(this.varValues, this.results, index); } public get selectedValue(): number { diff --git a/src/app/formulaire/definition/form-pab.ts b/src/app/formulaire/definition/form-pab.ts index d88ae7826..0bafb5760 100644 --- a/src/app/formulaire/definition/form-pab.ts +++ b/src/app/formulaire/definition/form-pab.ts @@ -2,7 +2,7 @@ import { Pab, Result, VariatedDetails } from "jalhyd"; import { FormulaireDefinition } from "./form-definition"; import { PabResults } from "../../results/pab-results"; -import { NgParameter } from "../elements/ngparam"; +import { NgParameter, ParamRadioConfig } from "../elements/ngparam"; import { longestVarParam } from "../../util"; import { CalculatorResults } from "../../results/calculator-results"; @@ -78,6 +78,21 @@ export class FormulairePab extends FormulaireDefinition { } } + public getVariatedParameters(): NgParameter[] { + const res: NgParameter[] = super.getVariatedParameters(); + // add artificial NgParameters for any variated QA @WARNING clodo trick + if (this.pabNub) { + for (const c of this.pabNub.children) { + if (c.prms.QA.hasMultipleValues) { + const qaParam = new NgParameter(c.prms.QA, this); + qaParam.radioConfig = ParamRadioConfig.VAR; + res.push(qaParam); + } + } + } + return res; + } + public get pabResults() { return this._pabResults; } diff --git a/src/app/results/calculator-results.ts b/src/app/results/calculator-results.ts index f573b6c99..95954608a 100644 --- a/src/app/results/calculator-results.ts +++ b/src/app/results/calculator-results.ts @@ -1,9 +1,11 @@ -import { Nub, capitalize } from "jalhyd"; +import { CalculatorType, Nub, capitalize, MacrorugoCompound, Pab, Structure, PbCloison, PbBassin } from "jalhyd"; import { NgParameter } from "../formulaire/elements/ngparam"; import { ServiceFactory } from "../services/service-factory"; import { sprintf } from "sprintf-js"; +import { MultiDimensionResults } from "./multidimension-results"; +import { PrebarrageResults } from "./prebarrage-results"; export abstract class CalculatorResults { @@ -45,6 +47,61 @@ export abstract class CalculatorResults { return res; } + /** + * Returns a label showing the boundary conditions values of all variating parameters, + * for the given iteration + * @param varvalues array of values: one element per variating parameter, itself an array of + * values, one per iteration + * @param variatedParameters array of variating parameters, in the same order as varvalues + * @param n index of the variating parameter(s) iteration + */ + public static variatingModalityLabel(varValues: any[], results: MultiDimensionResults, index: number): string { + const kv = []; + for (let i = 0; i < varValues.length; i++) { + const vv = varValues[i]; + const vp = results.variatedParameters[i]; + let symbol = vp.param.symbol; + // is vp a parameter of a child Nub ? + if ( + vp.param.parentNub + && vp.param.parentNub !== vp.param.originNub + ) { + let childPrefix: string; + // prefix the label depending on (grand)children type + switch (vp.param.originNub.calcType) { + case CalculatorType.PreBarrage: + const pbRes = results as PrebarrageResults; + if (vp.param.parentNub instanceof Structure) { + const struct = vp.param.parentNub as Structure; + const wall = struct.parent as PbCloison; + const posS = struct.findPositionInParent() + 1; + childPrefix = ServiceFactory.i18nService.localizeMessage(wall.description); + // there might be multiple walls between the same pair of basins + if (wall.uid in pbRes.wallsSuffixes) { + childPrefix += " (" + pbRes.wallsSuffixes[wall.uid] + ")"; + } + childPrefix += "_" + ServiceFactory.i18nService.localizeText("INFO_LIB_STRUCTURE_N_COURT") + posS; + } else if (vp.param.parentNub instanceof PbBassin) { + const bassin = vp.param.parentNub as PbBassin; + childPrefix = ServiceFactory.i18nService.localizeMessage(bassin.description); + } + break; + case CalculatorType.MacroRugoCompound: + const posMR = vp.param.parentNub.findPositionInParent() + 1; + childPrefix = ServiceFactory.i18nService.localizeText("INFO_LIB_RADIER_N_COURT") + posMR; + break; + case CalculatorType.PAB: + const posPAB = vp.param.parentNub.findPositionInParent() + 1; + childPrefix = ServiceFactory.i18nService.localizeText("INFO_LIB_CLOISON_N_COURT") + posPAB; + break; + } + symbol = childPrefix + "_" + symbol; + } + kv.push(`${symbol} = ${vv[index]}`); + } + return kv.join(", "); + } + /** * remet tous les résultats à zero */ diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index d8e491c12..009ebec32 100755 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -285,6 +285,7 @@ "INFO_LIB_CDT": "Discharge coefficient triangular weir", "INFO_LIB_CDO": "Discharge coefficient orifice", "INFO_LIB_CLOISON": "Cross wall #", + "INFO_LIB_CLOISON_N_COURT": "W", "INFO_LIB_COTE": "Elevation (m)", "INFO_LIB_COTE_VANNE_LEVANTE": "Lift gate elevation", "INFO_LIB_CV": "Cv: Velocity coefficient", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index ca8fc400d..b018c642d 100755 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -286,6 +286,7 @@ "INFO_LIB_CDT": "Coefficient de débit seuil triangulaire", "INFO_LIB_CDO": "Coefficient de débit orifice", "INFO_LIB_CLOISON": "Cloison n°", + "INFO_LIB_CLOISON_N_COURT": "C", "INFO_LIB_COTE": "Cote (m)", "INFO_LIB_COTE_VANNE_LEVANTE": "Cote vanne levante", "INFO_LIB_CV": "Cv : Coefficient de vitesse d'approche", -- GitLab From 7cbea8820e41d89688ab0262925a70e5e342d648 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 3 Sep 2020 10:13:49 +0200 Subject: [PATCH 05/64] Work on #431 - compact rows and add missing cells --- .../pab-table/pab-table.component.ts | 78 ++++++++----------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 225d7da87..0095fb838 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -499,10 +499,6 @@ export class PabTableComponent implements AfterViewInit, OnInit { title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB"), selectable: bs }); - /* this.cols.push({ - title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "QA"), - selectable: bs - }); */ this.cols.push({ title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB"), selectable: bs @@ -533,16 +529,16 @@ export class PabTableComponent implements AfterViewInit, OnInit { // B. Build rows set this.rows = []; + // admissible LoiDebit (same for all cloisons) + const loisCloisons = this.model.children[0].getLoisAdmissiblesArray().map(l => { + return { + label: this.localizeLoiDebit(l), + value: l + }; + }); // B.1 many rows for each wall let childIndex = 0; for (const cloison of this.model.children) { - // admissible LoiDebit - const loisCloisons = cloison.getLoisAdmissiblesArray().map(l => { // @TODO move up ? (same for all cloisons) - return { - label: this.localizeLoiDebit(l), - value: l - }; - }); // as much rows as the greatest number of parameters among its devices const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison); for (let i = 0; i < maxNbParams; i++) { @@ -553,14 +549,14 @@ export class PabTableComponent implements AfterViewInit, OnInit { // basin number deviceParamRow.cells.push({ value: childIndex + 1, - rowspan: maxNbParams + 2, + rowspan: maxNbParams + 1, class: "basin_number", selectable: cloison }); // 3 empty cells deviceParamRow.cells.push({ colspan: 3, - rowspan: maxNbParams, + rowspan: maxNbParams - 1, selectable: cloison }); // ZRAM @@ -569,10 +565,25 @@ export class PabTableComponent implements AfterViewInit, OnInit { title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRAM") }); } - // 1 empty cell + // basin cells on the last but 1 row + if (i === maxNbParams - 1) { + deviceParamRow.cells.push({ + model: cloison.prms.LB, + title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB") + }); + deviceParamRow.cells.push({ + model: cloison.prms.BB, + title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB") + }); + deviceParamRow.cells.push({ + model: cloison.prms.ZRMB, + title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB") + }); + } + // 1 empty cell below ZRAM if (i === 1) { deviceParamRow.cells.push({ - rowspan: maxNbParams + 1, + rowspan: maxNbParams, selectable: cloison }); } @@ -589,7 +600,7 @@ export class PabTableComponent implements AfterViewInit, OnInit { selectable: ouvrage }); } - // fill space + // fill space below device type selector if (i === 1) { deviceParamRow.cells.push({ rowspan: (maxNbParams - 1), @@ -636,34 +647,6 @@ export class PabTableComponent implements AfterViewInit, OnInit { // done ! this.rows.push(deviceParamRow); } - // 1 row for the basin after the wall - const basinRow: { selectable: any, cells: any[] } = { - selectable: cloison, - cells: [ - // no cell for basin number (defined by rowspan-n cell above) - { - model: cloison.prms.LB, - title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "LB") - }, - { - model: cloison.prms.BB, - title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "BB") - }, - { - model: cloison.prms.ZRMB, - title: this.formService.expandVariableNameAndUnit(CalculatorType.Pab, "ZRMB") - } - ] - }; - // fill horizontal space - for (let i = 0; i < maxNbDevices; i++) { - basinRow.cells.push({ - colspan: 3, - rowspan: 2 - }); - } - // done ! - this.rows.push(basinRow); // 1 row for QA editor const qaParam = new NgParameter(cloison.prms.QA, this.pabTable.form); qaParam.radioConfig = ParamRadioConfig.VAR; @@ -678,8 +661,13 @@ export class PabTableComponent implements AfterViewInit, OnInit { } ] }; - this.rows.push(qaRow); + // as many pairs of columns as the maximum number of devices + qaRow.cells.push({ + colspan: maxNbDevices * 3, + // selectable: cloison @TODO oui ou non ? + }); // done ! + this.rows.push(qaRow); childIndex ++; } -- GitLab From 165576c9cf32486d1369c00750532d269c8ea66a Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Tue, 29 Sep 2020 14:57:08 +0200 Subject: [PATCH 06/64] fix: rebase compilation issue Refs #431 --- src/app/formulaire/definition/form-pab.ts | 15 --------------- src/app/results/calculator-results.ts | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/app/formulaire/definition/form-pab.ts b/src/app/formulaire/definition/form-pab.ts index 0bafb5760..af9b7f56d 100644 --- a/src/app/formulaire/definition/form-pab.ts +++ b/src/app/formulaire/definition/form-pab.ts @@ -78,21 +78,6 @@ export class FormulairePab extends FormulaireDefinition { } } - public getVariatedParameters(): NgParameter[] { - const res: NgParameter[] = super.getVariatedParameters(); - // add artificial NgParameters for any variated QA @WARNING clodo trick - if (this.pabNub) { - for (const c of this.pabNub.children) { - if (c.prms.QA.hasMultipleValues) { - const qaParam = new NgParameter(c.prms.QA, this); - qaParam.radioConfig = ParamRadioConfig.VAR; - res.push(qaParam); - } - } - } - return res; - } - public get pabResults() { return this._pabResults; } diff --git a/src/app/results/calculator-results.ts b/src/app/results/calculator-results.ts index 95954608a..a205ceddd 100644 --- a/src/app/results/calculator-results.ts +++ b/src/app/results/calculator-results.ts @@ -90,7 +90,7 @@ export abstract class CalculatorResults { const posMR = vp.param.parentNub.findPositionInParent() + 1; childPrefix = ServiceFactory.i18nService.localizeText("INFO_LIB_RADIER_N_COURT") + posMR; break; - case CalculatorType.PAB: + case CalculatorType.Pab: const posPAB = vp.param.parentNub.findPositionInParent() + 1; childPrefix = ServiceFactory.i18nService.localizeText("INFO_LIB_CLOISON_N_COURT") + posPAB; break; -- GitLab From 7cc67ab8cfb6d466ad673f1f99ffd7e0b8e0c191 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Tue, 23 Nov 2021 11:46:09 +0100 Subject: [PATCH 07/64] fix(pab): update vary value from pab fish ladder and unable compute Button ref #431 --- src/app/components/pab-table/pab-table.component.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 0095fb838..5f6042646 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit } from "@angular/core"; +import { Component, Input, Output, EventEmitter, OnInit, AfterViewInit, AfterViewChecked } from "@angular/core"; import { LoiDebit, ParamValueMode } from "jalhyd"; @@ -39,7 +39,7 @@ import { NgParameter, ParamRadioConfig } from "../../formulaire/elements/ngparam "./pab-table.component.scss" ] }) -export class PabTableComponent implements AfterViewInit, OnInit { +export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnInit { @Input() private pabTable: PabTable; @@ -86,6 +86,12 @@ export class PabTableComponent implements AfterViewInit, OnInit { this.selectedItems = []; } + /** update vary value from pab fish ladder and unable compute Button */ + ngAfterViewChecked(): void { + this.updateValidity(); + } + + public get title(): string { return this.i18nService.localizeText("INFO_PAB_TABLE"); } -- GitLab From a2bba80e3e20dea71bd171a54b8c51182b9aff29 Mon Sep 17 00:00:00 2001 From: manmohan <man-mohan.gargani@inrae.fr> Date: Thu, 25 Nov 2021 10:22:26 +0100 Subject: [PATCH 08/64] fix #431 display QA-label on the line as control --- .../components/pab-table/pab-table.component.html | 2 +- .../components/pab-table/pab-table.component.scss | 5 +++-- .../param-field-line/param-field-line.component.html | 2 +- .../param-field-line/param-field-line.component.scss | 3 ++- src/styles.scss | 12 ++++++------ 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html index 488fe6565..293bd1b07 100644 --- a/src/app/components/pab-table/pab-table.component.html +++ b/src/app/components/pab-table/pab-table.component.html @@ -111,4 +111,4 @@ </ng-template> </p-table> -</mat-card-content> \ No newline at end of file +</mat-card-content> diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss index 5b64df679..9f6b1055a 100644 --- a/src/app/components/pab-table/pab-table.component.scss +++ b/src/app/components/pab-table/pab-table.component.scss @@ -50,10 +50,11 @@ mat-card-content { .qaFieldLineContainer { padding: 0 10px; + display: flex; } .qaLabel { - margin-top: 13px; - margin-right: 10px; + margin-top: 2px; + margin-right: 20px; font-weight: bold; } diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html index e1faeebf2..daad0ba4b 100644 --- a/src/app/components/param-field-line/param-field-line.component.html +++ b/src/app/components/param-field-line/param-field-line.component.html @@ -52,4 +52,4 @@ </mat-button-toggle-group> </div> -</div> \ No newline at end of file +</div> diff --git a/src/app/components/param-field-line/param-field-line.component.scss b/src/app/components/param-field-line/param-field-line.component.scss index 16c2b9153..d05bd95c8 100644 --- a/src/app/components/param-field-line/param-field-line.component.scss +++ b/src/app/components/param-field-line/param-field-line.component.scss @@ -1,8 +1,9 @@ .toggle-group-container { text-align: right; + margin-bottom: 10px; } mat-button-toggle-group { - margin-top: 4px; + margin-top: 8px; box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); } diff --git a/src/styles.scss b/src/styles.scss index 727ac59f1..87774a115 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -129,7 +129,7 @@ field-set { .mat-select-value, .mat-select-arrow { color: #fff; } - + .mat-form-field-infix { border-bottom: 2px solid #fff; } @@ -186,7 +186,7 @@ field-set { } .pab-data-table { - + .editable-cell-bg { @extend .bg-accent-extralight; } @@ -271,7 +271,7 @@ field-set { > input[type="number"] { -moz-appearance: textfield; } - input[type=number]::-webkit-outer-spin-button, + input[type=number]::-webkit-outer-spin-button, input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; @@ -297,7 +297,7 @@ mat-checkbox.wrapped-checkbox { param-computed, param-values { mat-form-field { - + input.mat-input-element { width: calc(100% - 40px); text-overflow: ellipsis; @@ -353,7 +353,7 @@ mat-list { > .mat-list-item { height: auto; margin-bottom: .5em; - + > .mat-list-item-content { align-items: start; @@ -366,7 +366,7 @@ mat-list { } table.mat-table { - + .material-icons { font-size: 1.4em; vertical-align: bottom; -- GitLab From 187dab72e638d4530c5508f1ed2ec3d83271913a Mon Sep 17 00:00:00 2001 From: manmohan <man-mohan.gargani@inrae.fr> Date: Thu, 25 Nov 2021 17:34:34 +0100 Subject: [PATCH 09/64] fix(pab): #431 Modification of dispaly QA-label on the same line --- src/app/components/pab-table/pab-table.component.scss | 9 +++++++-- .../param-field-line/param-field-line.component.scss | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss index 9f6b1055a..775e64397 100644 --- a/src/app/components/pab-table/pab-table.component.scss +++ b/src/app/components/pab-table/pab-table.component.scss @@ -36,10 +36,12 @@ mat-card-content { } .hyd-window-btns { text-align: right; + align-items: flex-end; #add-many-children { width: 3em; vertical-align: middle; + align-items: flex-start; } button.mat-icon-button { @@ -51,10 +53,13 @@ mat-card-content { .qaFieldLineContainer { padding: 0 10px; display: flex; + flex-wrap: wrap; + flex-direction: row; + justify-content:space-between; } .qaLabel { - margin-top: 2px; - margin-right: 20px; + margin-top: 13px; font-weight: bold; } + diff --git a/src/app/components/param-field-line/param-field-line.component.scss b/src/app/components/param-field-line/param-field-line.component.scss index d05bd95c8..4723ca170 100644 --- a/src/app/components/param-field-line/param-field-line.component.scss +++ b/src/app/components/param-field-line/param-field-line.component.scss @@ -1,9 +1,9 @@ .toggle-group-container { text-align: right; - margin-bottom: 10px; } mat-button-toggle-group { - margin-top: 8px; + margin-top: 4px; box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); } + -- GitLab From 1b25d95112e95f450de23ad346a9dc38ed789c94 Mon Sep 17 00:00:00 2001 From: manmohan <man-mohan.gargani@inrae.fr> Date: Wed, 1 Dec 2021 15:47:52 +0100 Subject: [PATCH 10/64] Bug-fix #431 clone of QA and VARIE parameters --- src/app/components/pab-table/pab-table.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 5f6042646..9b9c48095 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1052,10 +1052,12 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni // copy parameter values for (const p of si.prms) { // @TODO QA may vary - if (p.visible && p.symbol !== "QA") { // QA might vary ! - newChild.getParameter(p.symbol).singleValue = p.singleValue; - } + if (p.visible) { // QA might vary ! + newChild.getParameter(p.symbol).loadObjectRepresentation(p.objectRepresentation()); + console.log(newChild.getParameter(p.symbol).loadObjectRepresentation(p.objectRepresentation())); + } + } // copy children if (si instanceof ParallelStructure) { for (const c of si.getChildren()) { -- GitLab From a3f0cda9e5daac12e4fd431cd0e72506bab39705 Mon Sep 17 00:00:00 2001 From: manmohan gargani <man-mohan-gargani@inrae.fr> Date: Thu, 2 Dec 2021 13:24:03 +0100 Subject: [PATCH 11/64] fix(pab): #431 -copying QA value by cloning loadObjectRepresentation(p.objectRepresentation --- src/app/components/pab-table/pab-table.component.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 9b9c48095..0c7d9c089 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1051,11 +1051,8 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni ); // copy parameter values for (const p of si.prms) { - // @TODO QA may vary - if (p.visible) { // QA might vary ! + if (p.visible) { newChild.getParameter(p.symbol).loadObjectRepresentation(p.objectRepresentation()); - console.log(newChild.getParameter(p.symbol).loadObjectRepresentation(p.objectRepresentation())); - } } // copy children -- GitLab From dd9b2fd5c5801e821dcde052f5791c20362e235f Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Wed, 8 Dec 2021 12:01:45 +0100 Subject: [PATCH 12/64] fix(Pab): display varied and linked values for Excel export of the Pab table Refs #431 --- src/app/components/pab-table/pab-table.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 0c7d9c089..6c6088f8a 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1466,7 +1466,11 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni const inputs = td.getElementsByTagName("input"); if (inputs.length > 0) { const input = inputs[0]; - td.innerHTML = input.value; + if (input.id.split("_")[1] == "QA") { + td.innerHTML = NgParameter.preview(this.model.children[input.id.split("_")[0]].prms.QA) + } else { + td.innerHTML = input.value; + } } } } -- GitLab From 31193c8ddaa633a2c86dc6ae746514b726598d8e Mon Sep 17 00:00:00 2001 From: manmohan <man-mohan.gargani@inrae.fr> Date: Wed, 8 Dec 2021 12:21:59 +0100 Subject: [PATCH 13/64] lint(pab): #431 --- src/app/components/pab-table/pab-table.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 6c6088f8a..486789521 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1466,8 +1466,8 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni const inputs = td.getElementsByTagName("input"); if (inputs.length > 0) { const input = inputs[0]; - if (input.id.split("_")[1] == "QA") { - td.innerHTML = NgParameter.preview(this.model.children[input.id.split("_")[0]].prms.QA) + if (input.id.split("_")[1] === "QA") { + td.innerHTML = NgParameter.preview(this.model.children[input.id.split("_")[0]].prms.QA); } else { td.innerHTML = input.value; } -- GitLab From 17ca971a9eda2962cec744c987e1d7e8ad0471ca Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Tue, 14 Dec 2021 16:16:25 +0100 Subject: [PATCH 14/64] feat(PreBarrage): highlight in red items in error - known issue: The color changes only on item selection Refs #484 --- jalhyd_branch | 2 +- .../calculator.component.ts | 2 +- .../pb-schema/pb-schema.component.ts | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index 1f7391f92..3aff35fb1 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -master +298-prebarrages-mettre-les-enfants-invalides-en-rouge-dans-le-schema-cassiopee-nghyd-484 diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 718ff08f5..668a28eeb 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -520,7 +520,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } if (this._formulaire.currentNub.calcType === CalculatorType.PreBarrage) { const form: FormulairePrebarrage = this._formulaire as FormulairePrebarrage; - this._isUIValid = this._isUIValid && form.currentNub.check(); + this._isUIValid = this._isUIValid && form.currentNub.check().length === 0; } } } diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index cdbe3fad0..853cdd6cd 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -138,6 +138,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni } catch (e) { console.error(e); } + this.highlightErrorItems(null); } /** @@ -229,6 +230,8 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni def.push("classDef basin fill:#e0f3fb,stroke:#003A80;"); // irstea-ocean 50 / 500 def.push("classDef basin::first-line color:green,font-size:0.5em;"); def.push("classDef node-highlighted fill:#4DBBE9;"); // irstea-ocean (material "accent"), 300 + def.push("classDef node-error fill:#ec7430;"); // irstea-rouille (material "accent"), 400 + def.push("classDef node-highlighted-error fill:#d92f03;"); // irstea-rouille (material "accent"), 900 const sortedWalls: PbCloison[] = []; for (const c of this.model.children) { @@ -240,6 +243,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni sortedWalls.push(c); } } + // sort then draw walls sortedWalls.sort(this.triCloisonsGaucheDroite); for (const c of sortedWalls) { @@ -308,6 +312,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni } else { this._selectedItem = this.model.findChild(item.id); } + this.highlightErrorItems(item.id); // show proper form and hide results this.nodeSelected.emit({ node: this._selectedItem @@ -649,6 +654,29 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni }); } + private highlightErrorItems(selectedUid: string) { + this.nativeElement.querySelectorAll("g.node").forEach(item => { + item.classList.remove("node-error"); + item.classList.remove("node-highlighted-error"); + }); + const invalidUids: string[] = this.model.check(); + this.nativeElement.querySelectorAll("g.node").forEach(item => { + let itemId: string; + if ([this.upstreamId, this.downstreamId].includes(item.id)) { + itemId = this.model.uid; + } else { + itemId = item.id + } + if (invalidUids.includes(itemId)) { + if (item.id === selectedUid) { + item.classList.add("node-highlighted-error"); + } else { + item.classList.add("node-error"); + } + } + }); + } + private unselect() { // console.debug(`PbSchemaComponent.unselect()`); this._selectedItem = undefined; -- GitLab From 17e600533a3fd50b287deeeb010184118072f027 Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Wed, 15 Dec 2021 17:13:52 +0100 Subject: [PATCH 15/64] fix(PreBarrage): regression after 17ca971a9eda2962cec744c987e1d7e8ad0471ca - migrate empty parameter check to FormPrebarrage Refs #484 --- .../calculator.component.ts | 2 +- .../pb-schema/pb-schema.component.ts | 2 +- .../formulaire/definition/form-prebarrage.ts | 32 ++++++++++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 668a28eeb..2608ce76e 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -520,7 +520,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } if (this._formulaire.currentNub.calcType === CalculatorType.PreBarrage) { const form: FormulairePrebarrage = this._formulaire as FormulairePrebarrage; - this._isUIValid = this._isUIValid && form.currentNub.check().length === 0; + this._isUIValid = this._isUIValid && form.checkParameters().length === 0; } } } diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index 853cdd6cd..40217b619 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -659,7 +659,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni item.classList.remove("node-error"); item.classList.remove("node-highlighted-error"); }); - const invalidUids: string[] = this.model.check(); + const invalidUids: string[] = this.pbSchema.form.checkParameters(); this.nativeElement.querySelectorAll("g.node").forEach(item => { let itemId: string; if ([this.upstreamId, this.downstreamId].includes(item.id)) { diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts index 4400467c8..143a6991d 100644 --- a/src/app/formulaire/definition/form-prebarrage.ts +++ b/src/app/formulaire/definition/form-prebarrage.ts @@ -1,4 +1,4 @@ -import { CalculatorType, PbBassin, PbCloison, IObservable, PreBarrage, VariatedDetails, ParamDefinition } from "jalhyd"; +import { CalculatorType, PbBassin, PbCloison, IObservable, PreBarrage, VariatedDetails, ParamDefinition, IParamDefinitionIterator, ParamDefinitionIterator } from "jalhyd"; import { FormulaireFixedVar } from "./form-fixedvar"; import { PbSchema } from "../elements/pb-schema"; @@ -335,4 +335,34 @@ export class FormulairePrebarrage extends FormulaireFixedVar { } this.currentNub.calculatedParam = paramCalculated; } + + /** + * Check validity of all model parameters + * @param withChildren check parameters of child nub as well + * @return array of uid nubs in error + */ + public checkParameters(withChildren: boolean = true): string[] { + let prmIt: IParamDefinitionIterator; + if(withChildren) { + prmIt = this.currentNub.parameterIterator; + } else { + prmIt = new ParamDefinitionIterator(this.currentNub.prms); + } + const uids: string[] = []; + for (const p of prmIt) { + if (!p.isCalculated && p.visible) { + try { + // will throw an error if no value is defined at all + p.paramValues.check(); + } catch (e) { + if (p.parentNub.calcType === CalculatorType.Structure) { + uids.push(p.parentNub.getParent().uid); + } else { + uids.push(p.parentNub.uid); + } + } + } + } + return uids; + } } -- GitLab From 104178195fcbf51ce32fa0cdce1238bf444d0695 Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Tue, 15 Feb 2022 15:29:59 +0100 Subject: [PATCH 16/64] update jalhyd_branch before merge to devel Refs #484 --- jalhyd_branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jalhyd_branch b/jalhyd_branch index 3aff35fb1..626e97d71 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -298-prebarrages-mettre-les-enfants-invalides-en-rouge-dans-le-schema-cassiopee-nghyd-484 +devel \ No newline at end of file -- GitLab From efb673df00b560894e37c1551667e6a9870128d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 15 Mar 2022 15:47:55 +0100 Subject: [PATCH 17/64] ci: fix Nightly build: clean folder before installation Closes #495 --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 496309b0b..76965e220 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,7 +103,7 @@ deploy: - build script: # Copie de la branche / du tag - - rsync -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_URL/$CI_COMMIT_REF_NAME" + - rsync --delete -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_URL/$CI_COMMIT_REF_NAME" deploy-stable: stage: deploy-stable @@ -114,7 +114,7 @@ deploy-stable: - build script: # Copie de la branche production - - rsync -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_STABLE_URL/" + - rsync --delete -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_STABLE_URL/" # Modification du dossier base href - ssh $DEPLOY_HOST_LOGIN "sed -i 's:/cassiopee/stable/:/:g' $DEPLOY_STABLE_URL/index.html" -- GitLab From 3321f57bba1105ebe698b35212a91a9b78a37495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 16 Mar 2022 12:25:09 +0100 Subject: [PATCH 18/64] docs: fix typos Closes #498 --- docs/en/calculators/hsl/section_parametree.md | 18 +++++++++--------- docs/fr/calculators/hsl/section_parametree.md | 4 ++-- .../hyd_en_charge/lechapt-calmon.md | 4 ++-- src/app/calculators/courberemous/config.json | 4 ++-- src/app/calculators/pabdimensions/en.json | 2 +- src/app/calculators/regimeuniforme/en.json | 2 +- .../calculators/sectionparametree/config.json | 2 +- src/app/calculators/sectionparametree/en.json | 2 +- src/app/results/remous-results.ts | 2 +- src/locale/messages.en.json | 2 +- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/en/calculators/hsl/section_parametree.md b/docs/en/calculators/hsl/section_parametree.md index e3e8ad8f0..7d74e2bd9 100644 --- a/docs/en/calculators/hsl/section_parametree.md +++ b/docs/en/calculators/hsl/section_parametree.md @@ -3,7 +3,7 @@ This module calculates the hydraulic quantities associated to: - a section with a defined geometrical shape ([See section types managed by Cassiopée](types_sections.md)) -- a draft \(y\) in m +- a water depth \(y\) in m - a flow \(Q\) in m<sup>3</sup>/s - a bottom slope \(I_f\) in m/m - a roughness expressed with the Strickler's coefficient \(K\) in m<sup>1/3</sup>/s @@ -23,7 +23,7 @@ The calculated hydraulic quantities are: - Critical depth (m) - Critical head (m) - Corresponding depth (m) -- Impulsion (kgâ‹…mâ‹…s<sup>-1</sup>) +- Impulsion (N) - Conjugate depth - Tractive force (Pa) @@ -122,15 +122,15 @@ We use Newton's method by posing \(y_{k+1} = y_k - \frac{f(y_k)}{f'(y_k)}\) with <div style="position: relative"><div style="position: relative"><a id="la-charge-critique-m" style="position: absolute; top: -100px;" style="position: absolute; top: -60px;"></a></div></div> ## Critical head (m) -This is the head calculated for a draft equal to the critical depth. \(H_c = H(y_c)\). +This is the head calculated for a water depth equal to the critical depth. \(H_c = H(y_c)\). <div style="position: relative"><a id="le-tirant-deau-correspondant-m" style="position: absolute; top: -60px;"></a></div> -## Corresponing depth (m) +## Corresponding depth (m) -For a fluvial (respectively torrential draft) \(y\), corresponding depth is the torrential (respectively fluvial) draft for the which \(H(y) = H(y_{cor})\). +For a fluvial (respectively torrential water depth) \(y\), corresponding depth is the torrential (respectively fluvial) water depth for which \(H(y) = H(y_{cor})\). -<div style="position: relative"><a id="limpulsion-hydraulique-kgms-1" style="position: absolute; top: -60px;"></a></div> -## Hydraulic impulsion (kgâ‹…mâ‹…s<sup>-1</sup>) +<div style="position: relative"><a id="limpulsion-hydraulique-N" style="position: absolute; top: -60px;"></a></div> +## Hydraulic impulsion (N) The impulsion \(I\) is the sum of the amount of movement and the resultant of the pressure force in a section: @@ -145,7 +145,7 @@ The distance from the centre of gravity of the section to the free surface \(y_g $$S.y_g = \int_{0}^{y} (y-z)B(z)dz$$ -With \(y\) the depth and \(B(z)\) the width at mirror for a draft \(z\) +With \(y\) the depth and \(B(z)\) the width at mirror for a water depth \(z\) Formulas of \(S.y_g\) for the different section shapes are : @@ -157,7 +157,7 @@ Formulas of \(S.y_g\) for the different section shapes are : <div style="position: relative"><a id="le-tirant-deau-conjugue-m" style="position: absolute; top: -60px;"></a></div> ## Conjugate depth (m) -For a fluvial (respectively torrential draft) \(y\), conjugate depth is the torrential (respectively fluvial) draft for the which \(I(y) = I(y_{con})\). +For a fluvial (respectively torrential water depth) \(y\), conjugate depth is the torrential (respectively fluvial) water depth for which \(I(y) = I(y_{con})\). <div style="position: relative"><a id="la-force-tractrice-pa" style="position: absolute; top: -60px;"></a></div> ## Tractive force (Pa) diff --git a/docs/fr/calculators/hsl/section_parametree.md b/docs/fr/calculators/hsl/section_parametree.md index eef566ac7..18c4bfa59 100644 --- a/docs/fr/calculators/hsl/section_parametree.md +++ b/docs/fr/calculators/hsl/section_parametree.md @@ -23,7 +23,7 @@ Les grandeurs hydrauliques calculées sont : - Le tirant d'eau critique (m) - La charge critique (m) - Le tirant d'eau correspondant (m) -- L'impulsion (kgâ‹…mâ‹…s<sup>-1</sup>) +- L'impulsion (N) - Le tirant d'eau conjugué - La force tractrice (Pa) @@ -117,7 +117,7 @@ C'est la charge calculée pour un tirant d'eau égal au tirant d'eau critique \( Pour un tirant d'eau fluvial (respectivement torrentiel) \(y\), le tirant correspondant est le tirant d'eau torrentiel (respectivement fluvial) pour lequel \(H(y) = H(y_{cor})\). -## L'impulsion hydraulique (kgâ‹…mâ‹…s<sup>-1</sup>) +## L'impulsion hydraulique (N) L'impulsion \(I\) est la somme de la quantité de mouvement et de la résultante de la force de pression dans une section : diff --git a/docs/fr/calculators/hyd_en_charge/lechapt-calmon.md b/docs/fr/calculators/hyd_en_charge/lechapt-calmon.md index c423136c1..6001e5572 100644 --- a/docs/fr/calculators/hyd_en_charge/lechapt-calmon.md +++ b/docs/fr/calculators/hyd_en_charge/lechapt-calmon.md @@ -49,7 +49,7 @@ Table: Matériaux et coefficients utilisés dans la formule de Lechapt et Calmon $$ J_S = K_S \frac{V^2}{2g}$$ -Avec : +Avec : - \(K_S\) : le coefficient de perte de charge singulière - \(V\) : la vitesse de l'eau dans la conduite (\(V = 4 Q / \pi / D^2\)) @@ -60,4 +60,4 @@ $$ K_L = \frac{2g J_L}{V^2} $$ ## Coefficient de perte de charge de Darcy -$$ f_D = \frac{2g J D}{l_T V^2} +$$ f_D = \frac{2g J D}{l_T V^2} $$ diff --git a/src/app/calculators/courberemous/config.json b/src/app/calculators/courberemous/config.json index 455e9d73b..272de8687 100644 --- a/src/app/calculators/courberemous/config.json +++ b/src/app/calculators/courberemous/config.json @@ -89,7 +89,7 @@ "Hsc": "hsl/section_parametree.html#la-charge-critique-m", "J": "hsl/section_parametree.html#la-perte-de-charge-mm", "I-J": "hsl/section_parametree.html#la-variation-lineaire-de-lenergie-specifique-mm", - "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-kgms-1", + "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-N", "Tau0": "hsl/section_parametree.html#la-force-tractrice-pa" } } @@ -115,7 +115,7 @@ "Hsc": "hsl/section_parametree.html#la-charge-critique-m", "J": "hsl/section_parametree.html#la-perte-de-charge-mm", "I-J": "hsl/section_parametree.html#la-variation-lineaire-de-lenergie-specifique-mm", - "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-kgms-1", + "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-N", "Tau0": "hsl/section_parametree.html#la-force-tractrice-pa" } } diff --git a/src/app/calculators/pabdimensions/en.json b/src/app/calculators/pabdimensions/en.json index df5b11b45..88df27b9d 100644 --- a/src/app/calculators/pabdimensions/en.json +++ b/src/app/calculators/pabdimensions/en.json @@ -2,6 +2,6 @@ "fs_dimensions": "Basin dimensions", "L": "Length", "W": "Width", - "Y": "Draft", + "Y": "Water depth", "V": "Volume" } \ No newline at end of file diff --git a/src/app/calculators/regimeuniforme/en.json b/src/app/calculators/regimeuniforme/en.json index 4a5a3327a..f1ea50fcc 100644 --- a/src/app/calculators/regimeuniforme/en.json +++ b/src/app/calculators/regimeuniforme/en.json @@ -17,5 +17,5 @@ "If": "Bottom slope", "YB": "Embankment elevation", "fs_hydraulique": "Hydraulic features", - "Y": "Draft" + "Y": "Water depth" } \ No newline at end of file diff --git a/src/app/calculators/sectionparametree/config.json b/src/app/calculators/sectionparametree/config.json index 63235d9a5..f24b88ca8 100644 --- a/src/app/calculators/sectionparametree/config.json +++ b/src/app/calculators/sectionparametree/config.json @@ -67,7 +67,7 @@ "Hsc": "hsl/section_parametree.html#la-charge-critique-m", "J": "hsl/section_parametree.html#la-perte-de-charge-mm", "I-J": "hsl/section_parametree.html#la-variation-lineaire-de-lenergie-specifique-mm", - "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-kgms-1", + "Imp": "hsl/section_parametree.html#limpulsion-hydraulique-N", "Tau0": "hsl/section_parametree.html#la-force-tractrice-pa" } } diff --git a/src/app/calculators/sectionparametree/en.json b/src/app/calculators/sectionparametree/en.json index 92a0479a8..b13efd538 100644 --- a/src/app/calculators/sectionparametree/en.json +++ b/src/app/calculators/sectionparametree/en.json @@ -17,7 +17,7 @@ "If": "Bottom slope", "YB": "Embankment elevation", "fs_hydraulique": "Hydraulic features", - "Y": "Draft", + "Y": "Water depth", "fs_param_calc": "Calculation parameters", "Hs": "Specific head", "Hsc": "Critical head", diff --git a/src/app/results/remous-results.ts b/src/app/results/remous-results.ts index dedfd9a6f..abb20aa69 100644 --- a/src/app/results/remous-results.ts +++ b/src/app/results/remous-results.ts @@ -90,7 +90,7 @@ export class RemousResults extends CalculatorResults { // série de valeurs de X this._xValues = new ParamDefinition( p, - ServiceFactory.i18nService.localizeText("INFO_REMOUSRESULTS_ABSCISSE"), + "ABSCISSE", ParamDomainValue.POS_NULL ); } diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 94d4434ca..022f3ee46 100755 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -567,7 +567,7 @@ "INFO_REMOUSRESULTS_ABSCISSE": "Abscissa", "INFO_REMOUSRESULTS_BERGE": "Embankment", "INFO_REMOUSRESULTS_FOND": "Bottom", - "INFO_REMOUSRESULTS_TIRANT": "Draft (m)", + "INFO_REMOUSRESULTS_TIRANT": "Water depth (m)", "INFO_REMOUSRESULTS_TIRANTCRITIQUE": "Critical water level", "INFO_REMOUSRESULTS_TIRANTNORMAL": "Normal water level", "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", -- GitLab From 4cdfe3ffb2bdca6c4f7c983210d4f0f68efdc6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 21 Mar 2022 15:46:52 +0100 Subject: [PATCH 19/64] feat: add cancel button to variable parameter dialog - fix enabled "switch to graph" button when form is invalid - fix modification of the original parameter (now only modified when form is closed with "validate" button) Fix #507 --- jalhyd_branch | 2 +- .../dialog-edit-param-values.component.html | 12 ++-- .../dialog-edit-param-values.component.ts | 70 +++++++++++-------- src/app/formulaire/elements/ngparam.ts | 8 +++ 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index 626e97d71..084f9effb 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -devel \ No newline at end of file +300-supprimer-le-champ-_valuemode-dans-paramdefinition \ No newline at end of file diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html index 8a454d5c1..e8dbbb2c9 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html @@ -1,4 +1,5 @@ -<button mat-icon-button id="show-values-chart" (click)="toggleViewChart()" [title]="uitextShowValuesChart"> +<button mat-icon-button id="show-values-chart" (click)="toggleViewChart()" [title]="uitextShowValuesChart" + [disabled]="!viewChart && !isFormValid"> <mat-icon *ngIf="! viewChart">show_chart</mat-icon> <mat-icon *ngIf="viewChart">mode_edit</mat-icon> </button> @@ -119,16 +120,11 @@ </div> <div mat-dialog-actions [attr.align]="'end'"> - <div *ngIf="isMinMax || viewChart"> - <button mat-raised-button [mat-dialog-close]="true" [disabled]="minMaxFormInvalid" cdkFocusInitial> - {{ uitextClose }} - </button> - </div> - <div *ngIf="isListe && ! viewChart"> + <div> <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> {{ uitextCancel }} </button> - <button mat-raised-button color="warn" (click)="onValidate()"> + <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid"> {{ uitextValidate }} </button> </div> diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts index 3c419f000..d84c85459 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts @@ -53,7 +53,7 @@ export class DialogEditParamValuesComponent implements OnInit { private fb: FormBuilder, @Inject(MAT_DIALOG_DATA) public data: any ) { - this.param = data.param; + this.param = data.param.clone(); // an explicit ReactiveForm is required for file input component const initialValue = (this.param.valueMode === ParamValueMode.LISTE ? this.valuesList : ""); this.valuesListForm = this.fb.group({ @@ -245,42 +245,56 @@ export class DialogEditParamValuesComponent implements OnInit { this.param.setValueList(this, vals); } - /** returns true if min/max/step form is invalid */ - public get minMaxFormInvalid(): boolean { - return this.minMaxForm === undefined || ! this.minMaxForm.valid; - } - public toggleViewChart() { - // validate list values before switching views ? - if (! this.viewChart && this.param.valueMode === ParamValueMode.LISTE) { - if (this.onValidate(false)) { + // validate values before switching views ? + if (!this.viewChart && this.isFormValid) { // toggle - this.viewChart = ! this.viewChart; + this.viewChart = true; } - } else { - // toggle - this.viewChart = ! this.viewChart; - } + else + this.viewChart = false; + // refresh chart when displaying it only if (this.viewChart) { this.drawChart(); } } - public onValidate(close = true) { - const status = this.validateValuesListString(this.valuesListForm.controls.valuesList.value); + /** returns true if form is valid */ + public get isFormValid(): boolean { + var ret: boolean = false; + switch (this.param.valueMode) { + case ParamValueMode.LISTE: + const status = this.validateValuesListString(this.valuesListForm.controls.valuesList.value); + ret = status.ok; + if (ret) { + this.valuesListForm.controls.valuesList.setErrors(null); + this.valuesList = this.valuesListForm.controls.valuesList.value; + } + else + this.valuesListForm.controls.valuesList.setErrors({ "model": status.message }); + break; - if (status.ok) { - this.valuesListForm.controls.valuesList.setErrors(null); - this.valuesList = this.valuesListForm.controls.valuesList.value; - if (close) { - this.dialogRef.close(); - } - return true; - } else { - this.valuesListForm.controls.valuesList.setErrors({ "model": status.message }); - return false; + case ParamValueMode.MINMAX: + ret = this.minMaxForm !== undefined && this.minMaxForm.valid; + break; } + return ret; + } + + public onValidate() { + switch (this.param.valueMode) { + case ParamValueMode.LISTE: + this.data.param.setValueList(this, this.param.valueList); + break; + + case ParamValueMode.MINMAX: + this.data.param.setMinValue(this, this.param.minValue); + this.data.param.setMaxValue(this, this.param.maxValue); + this.data.param.setStepValue(this, this.param.stepValue); + break; + } + this.dialogRef.close(); } /** @@ -442,10 +456,6 @@ export class DialogEditParamValuesComponent implements OnInit { return this.intlService.localizeText("INFO_PARAMFIELD_PASVARIATION"); } - public get uitextClose(): string { - return this.intlService.localizeText("INFO_OPTION_CLOSE"); - } - public get uitextCancel(): string { return this.intlService.localizeText("INFO_OPTION_CANCEL"); } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index 7943071ed..697667f6c 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -42,6 +42,14 @@ export class NgParameter extends InputField implements Observer { this.disabled = false; } + public clone(): NgParameter { + const ret: NgParameter = new NgParameter(this._paramDef.clone(), this.parent); + ret._allowEmpty = this._allowEmpty; + ret.unit = this.unit; + ret.disabled = this.disabled; + return ret; + } + /** * Returns a text preview of the current value(s), depending on the value mode * @param compact if true, will represent multiple values in a more compact way -- GitLab From 9e6aa160ce71b02765278e100c6e441c476164e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 24 Mar 2022 14:51:52 +0100 Subject: [PATCH 20/64] fix: ParamValuesComponent notified of changes on parameter fixed value refs #480 --- .../param-values/param-values.component.ts | 5 +- src/app/formulaire/elements/ngparam.ts | 56 ++++++++++++++++--- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts index 62a212791..05738ddc4 100644 --- a/src/app/components/param-values/param-values.component.ts +++ b/src/app/components/param-values/param-values.component.ts @@ -102,7 +102,10 @@ export class ParamValuesComponent implements AfterViewInit, Observer { public update(sender: any, data: any): void { if (sender instanceof DialogEditParamValuesComponent) { switch (data.action) { - case "ngparamAfterValue": + case "ngparamAfterMinValue": + case "ngparamAfterMaxValue": + case "ngparamAfterStepValue": + case "ngparamAfterListValue": // tell the form to clear the results this.emitModelChanged(); break; diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index 007814148..ca5ff2240 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -341,6 +341,46 @@ export class NgParameter extends InputField implements Observer { ); } + private notifyMinValueModified(sender: any) { + this.notifyObservers( + { + "action": "ngparamAfterMinValue", + "param": this, + "value": this._paramDef.min + }, sender + ); + } + + private notifyMaxValueModified(sender: any) { + this.notifyObservers( + { + "action": "ngparamAfterMaxValue", + "param": this, + "value": this._paramDef.max + }, sender + ); + } + + private notifyStepValueModified(sender: any) { + this.notifyObservers( + { + "action": "ngparamAfterStepValue", + "param": this, + "value": this._paramDef.step + }, sender + ); + } + + private notifyListValueModified(sender: any) { + this.notifyObservers( + { + "action": "ngparamAfterStepValue", + "param": this, + "value": this._paramDef.valueList + }, sender + ); + } + /** * fixe la valeur du paramètre. * une notification préalable est envoyée pour laisser l'occasion aux objets liés de préciser le contexte @@ -355,33 +395,33 @@ export class NgParameter extends InputField implements Observer { public setMinValue(sender: any, v: number) { const changed = (this._paramDef.min !== v); - this._paramDef.min = v; if (changed) { - this.notifyValueModified(sender); + this._paramDef.min = v; + this.notifyMinValueModified(sender); } } public setMaxValue(sender: any, v: number) { const changed = (this._paramDef.max !== v); - this._paramDef.max = v; if (changed) { - this.notifyValueModified(sender); + this._paramDef.max = v; + this.notifyMaxValueModified(sender); } } public setStepValue(sender: any, v: number) { const changed = (this._paramDef.step !== v); - this._paramDef.step = v; if (changed) { - this.notifyValueModified(sender); + this._paramDef.step = v; + this.notifyStepValueModified(sender); } } public setValueList(sender: any, l: number[]) { const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); - this._paramDef.valueList = l; if (changed) { - this.notifyValueModified(sender); + this._paramDef.valueList = l; + this.notifyListValueModified(sender); } } -- GitLab From ce23cd73456e6ed506f3424eea89d7a714107cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 25 Mar 2022 11:56:58 +0100 Subject: [PATCH 21/64] fix: .d.ts file displayed by debugger instead of .ts source. refs #509 --- angular.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/angular.json b/angular.json index 0f22c724b..b106949db 100644 --- a/angular.json +++ b/angular.json @@ -104,7 +104,12 @@ "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "ngHyd:build", - "aot": true + "aot": true, + "sourceMap": { + "scripts": true, + "styles": true, + "vendor": true + } }, "configurations": { "production": { @@ -193,4 +198,4 @@ "cli": { "analytics": false } -} \ No newline at end of file +} -- GitLab From 1617b30d6976843940959c8fc8efc14e1acec2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 25 Mar 2022 12:11:22 +0100 Subject: [PATCH 22/64] refactor: move list of parameters not to be emptied by "create new calculators with empty fields" to constant in FormulaireNode refs #480 --- src/app/formulaire/definition/form-prebarrage.ts | 3 ++- src/app/formulaire/elements/formulaire-node.ts | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts index 143a6991d..ebe3ea8ff 100644 --- a/src/app/formulaire/definition/form-prebarrage.ts +++ b/src/app/formulaire/definition/form-prebarrage.ts @@ -10,6 +10,7 @@ import { CalculatorResults } from "../../results/calculator-results"; import { PrebarrageResults } from "../../results/prebarrage-results"; import { NgParameter } from "../elements/ngparam"; import { longestVarParam } from "../../util"; +import { FormulaireNode } from "../elements/formulaire-node"; /** * Formulaire pour les PréBarrage @@ -324,7 +325,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar { /** * Set value of all single parameters to undefined, except for the given parameter ids */ - public emptyFields(except: string[] = [ "Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL" ]) { + public emptyFields(except: string[] = FormulaireNode.NeverEmptyFields) { // save current calculated param, as setting value on a CALC param will // change its mode and choose another calculated param by default const paramCalculated = this.currentNub.calculatedParam; diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index 7731dfd43..dca5bbe5d 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -9,6 +9,11 @@ import { NgParameter } from "./ngparam"; */ export abstract class FormulaireNode implements IObservable { + /** + * fields in fieldset that must not be empty due to enableEmptyFieldsOnFormInit option + */ + protected static NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL"]; + /** aide en ligne */ protected _helpLink: string; @@ -143,7 +148,7 @@ export abstract class FormulaireNode implements IObservable { /** * Set value of all single parameters to undefined, except for the given parameter ids */ - public emptyFields(except: string[] = [ "Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL" ]) { + public emptyFields(except: string[] = FormulaireNode.NeverEmptyFields) { // save current calculated param, as setting value on a CALC param will // change its mode and choose another calculated param by default let calcP: NgParameter; -- GitLab From 7a6483caf82b836b495879bee33c2e031836b34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 22 Mar 2022 09:27:34 +0100 Subject: [PATCH 23/64] feat: restore parameter value mode in case of cancel in variable values modification dialog refs #508 --- .../dialog-edit-param-values.component.html | 2 +- .../dialog-edit-param-values.component.ts | 10 +++++++++- .../param-field-line.component.ts | 16 +++++++++++++--- .../param-values/param-values.component.ts | 8 +++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html index 5fc7c8482..beb23b46d 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html @@ -121,7 +121,7 @@ <div mat-dialog-actions [attr.align]="'end'"> <div> - <button id="btn-cancel" mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> + <button id="btn-cancel" mat-raised-button color="primary" (click)="onCancel()" cdkFocusInitial> {{ uitextCancel }} </button> <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid"> diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts index d84c85459..a6cdcc650 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts @@ -282,6 +282,12 @@ export class DialogEditParamValuesComponent implements OnInit { return ret; } + public onCancel() { + this.dialogRef.close({ + cancelled: true + }); + } + public onValidate() { switch (this.param.valueMode) { case ParamValueMode.LISTE: @@ -294,7 +300,9 @@ export class DialogEditParamValuesComponent implements OnInit { this.data.param.setStepValue(this, this.param.stepValue); break; } - this.dialogRef.close(); + this.dialogRef.close({ + cancelled: false + }); } /** diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index f76d819c2..0e97c8b54 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -119,6 +119,12 @@ export class ParamFieldLineComponent implements OnChanges { private _formService: FormulaireService; + /** + * valeur du mode de paramètre avant clic sur un des radios, utilisé pour restaurer le mode en cas de cancel + * du dialogue de modification des valeurs en mode variable + */ + private oldValueMode: ParamValueMode; + /* * gestion des événements clic sur les radios : * envoi d'un message au composant parent @@ -236,7 +242,7 @@ export class ParamFieldLineComponent implements OnChanges { } public onRadioClick(option: string) { - const oldValue = this.param.valueMode; + this.oldValueMode = this.param.valueMode; switch (option) { case "fix": this.param.valueMode = ParamValueMode.SINGLE; @@ -245,7 +251,7 @@ export class ParamFieldLineComponent implements OnChanges { case "var": // prevent setting LISTE mode back to MINMAX if someone clicks "variable" again // after setting variable mode to LISTE - if (oldValue !== ParamValueMode.MINMAX && oldValue !== ParamValueMode.LISTE) { + if (this.oldValueMode !== ParamValueMode.MINMAX && this.oldValueMode !== ParamValueMode.LISTE) { this.param.valueMode = ParamValueMode.MINMAX; // min/max par défaut } if (this._paramValuesComponent) { @@ -273,7 +279,7 @@ export class ParamFieldLineComponent implements OnChanges { } this.radio.emit({ "param": this.param, - "oldValueMode": oldValue + "oldValueMode": this.oldValueMode }); // MAJ validité this.emitValidity(); @@ -306,6 +312,10 @@ export class ParamFieldLineComponent implements OnChanges { case "model": this.inputChange.emit(event); break; + + case "cancelvar": // cancel button clicked in DialogEditParamValuesComponent + this.param.valueMode = this.oldValueMode; + break; } } diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts index 2a0ce5d3c..7a0d4f187 100644 --- a/src/app/components/param-values/param-values.component.ts +++ b/src/app/components/param-values/param-values.component.ts @@ -55,7 +55,7 @@ export class ParamValuesComponent implements AfterViewInit, Observer { public openDialog() { // modification des valeurs variables - this.editValuesDialog.open( + const dlgRef = this.editValuesDialog.open( DialogEditParamValuesComponent, { disableClose: true, @@ -66,6 +66,12 @@ export class ParamValuesComponent implements AfterViewInit, Observer { panelClass: "dialogMinWidth320px" } ); + dlgRef.afterClosed().toPromise().then(result => { + if (result.cancelled) + this.change.emit({ + action: "cancelvar" + }); + }); } public ngAfterViewInit() { -- GitLab From 618525ce1d3845af8532c201f2e1a144ceb160c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 29 Mar 2022 14:16:32 +0200 Subject: [PATCH 24/64] feature: add modification flag to NgParameter refs #480 --- .../generic-input/generic-input.component.ts | 15 ++++++--- src/app/formulaire/elements/ngparam.ts | 31 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts index 3d9472e3b..5b31ee4e8 100644 --- a/src/app/components/generic-input/generic-input.component.ts +++ b/src/app/components/generic-input/generic-input.component.ts @@ -161,7 +161,7 @@ export abstract class GenericInputComponentDirective implements OnChanges { } } - private validateModel() { + private validateModel(): boolean { let isValid: boolean; // specific case for "allowEmpty" params if (this.model instanceof NgParameter && this.uiValue === "" && this.model.allowEmpty) { @@ -174,6 +174,8 @@ export abstract class GenericInputComponentDirective implements OnChanges { } this.detectChanges(); this.setModelValid(isValid); + + return isValid; } public validate() { @@ -211,11 +213,11 @@ export abstract class GenericInputComponentDirective implements OnChanges { }); } - protected setAndValidateModel(sender: any, v: any) { + protected setAndValidateModel(sender: any, v: any): boolean { this.setModelValue(sender, v); this.emitModelChanged(); - this.validateModel(); + return this.validateModel(); } public set model(v: any) { @@ -261,7 +263,12 @@ export abstract class GenericInputComponentDirective implements OnChanges { if (valid && this._uiValue !== "") { val = +this._uiValue; // cast UI value to Number } - this.setAndValidateModel(this, val); + if (this.setAndValidateModel(this, val)) { + // set parameter "modified" flag + if (this._model instanceof NgParameter) { + this._model.isValueModified = true; + } + } } } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index ca5ff2240..c79dc844f 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -1,5 +1,7 @@ -import { Interval, ParamDefinition, ParamDomain, ParamValueMode, INumberIterator, - Observer, asObservable, ParamCalculability, LinkedValue } from "jalhyd"; +import { + Interval, ParamDefinition, ParamDomain, ParamValueMode, INumberIterator, + Observer, asObservable, ParamCalculability, LinkedValue +} from "jalhyd"; import { sprintf } from "sprintf-js"; @@ -36,6 +38,9 @@ export class NgParameter extends InputField implements Observer { public disabled: boolean; + /** true if value has been modified by user */ + private _isValueModified = false; + constructor(private _paramDef: ParamDefinition, parent: FormulaireNode) { super(parent); this.radioConfig = this.radioState; @@ -132,7 +137,7 @@ export class NgParameter extends InputField implements Observer { } } else { // recursive call, compact mode - valuePreview = NgParameter.preview(targetParam, true); + valuePreview = NgParameter.preview(targetParam, true); } } else { // was the result already computed ? @@ -279,6 +284,14 @@ export class NgParameter extends InputField implements Observer { return this._paramDef.valuesIterator; } + public get isValueModified(): boolean { + return this._isValueModified; + } + + public set isValueModified(b: boolean) { + this._isValueModified = b; + } + /** * Reads radio config from parameter calculability */ @@ -397,6 +410,7 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.min !== v); if (changed) { this._paramDef.min = v; + this._isValueModified = true; this.notifyMinValueModified(sender); } } @@ -405,6 +419,7 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.max !== v); if (changed) { this._paramDef.max = v; + this._isValueModified = true; this.notifyMaxValueModified(sender); } } @@ -413,6 +428,7 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.step !== v); if (changed) { this._paramDef.step = v; + this._isValueModified = true; this.notifyStepValueModified(sender); } } @@ -421,6 +437,7 @@ export class NgParameter extends InputField implements Observer { const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); if (changed) { this._paramDef.valueList = l; + this._isValueModified = true; this.notifyListValueModified(sender); } } @@ -430,7 +447,8 @@ export class NgParameter extends InputField implements Observer { prmDef: this.paramDefinition.objectRepresentation(), allowEmpty: this._allowEmpty, unit: this.unit, - radioConfig: this.radioConfig + radioConfig: this.radioConfig, + modified: this._isValueModified } } @@ -440,6 +458,7 @@ export class NgParameter extends InputField implements Observer { this._allowEmpty = rep.allowEmpty; this.unit = rep.unit; this.radioConfig = rep.radioConfig; + this._isValueModified = rep._isValueModified; } } @@ -462,9 +481,9 @@ export class NgParameter extends InputField implements Observer { public linkToValue(target: LinkedValue) { const changed: boolean = // changement de mode - ! this._paramDef.isReferenceDefined() + !this._paramDef.isReferenceDefined() // ou changement de référence - || ! this._paramDef.referencedValue.equals(target); + || !this._paramDef.referencedValue.equals(target); if (changed) { let o = asObservable(this._paramDef.referencedValue); -- GitLab From 6843eb43b5861393374d376bcf2926003c1ca66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 22 Mar 2022 10:48:24 +0100 Subject: [PATCH 25/64] fix: allow validation button in DialogEditParamValuesComponent in chart view when in min/max mode refs #508 --- .../dialog-edit-param-values.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html index beb23b46d..c7b8d3803 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html @@ -124,7 +124,7 @@ <button id="btn-cancel" mat-raised-button color="primary" (click)="onCancel()" cdkFocusInitial> {{ uitextCancel }} </button> - <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid"> + <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid&&!viewChart"> {{ uitextValidate }} </button> </div> -- GitLab From 229c178e0cf548fdb1ffd35b68f358cd6897c0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 29 Mar 2022 14:18:46 +0200 Subject: [PATCH 26/64] fix: fields of min/max/list values dialog filled with default values when: - "create calculators with empty fields" is set, - a single value parameter is given a value, - parameter mode changed to variable, fields opening edition dialog are incorrectly filled. refs #480 --- .../dialog-edit-param-values.component.ts | 20 ++++--- .../formulaire/elements/formulaire-node.ts | 2 +- src/app/formulaire/elements/ngparam.ts | 55 ++++++++++++++++++- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts index 6a0a68d59..f5200cfd0 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts @@ -11,6 +11,7 @@ import { sprintf } from "sprintf-js"; import { ParamValueMode, ExtensionStrategy } from "jalhyd"; import { fv } from "../../util"; +import { ServiceFactory } from "app/services/service-factory"; @Component({ selector: "dialog-edit-param-values", @@ -395,28 +396,29 @@ export class DialogEditParamValuesComponent implements OnInit { } private initVariableValues() { + const canFill: boolean = !ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit; // init min / max / step if (this.isMinMax) { const pVal = this.param.getValue(); - if (this.param.minValue === undefined) { - this.param.setMinValue(this, pVal !== undefined ? this.param.getValue() / 2 : undefined); + if (this.param.minValue === undefined && canFill) { + this.param.resetMinValue(this, pVal !== undefined ? this.param.getValue() / 2 : undefined); } - if (this.param.maxValue === undefined) { - this.param.setMaxValue(this, pVal !== undefined ? this.param.getValue() * 2 : undefined); + if (this.param.maxValue === undefined && canFill) { + this.param.resetMaxValue(this, pVal !== undefined ? this.param.getValue() * 2 : undefined); } let step = this.param.stepValue; - if (step === undefined) { + if (step === undefined && canFill) { step = pVal !== undefined ? ((this.param.maxValue - this.param.minValue) / 20) : undefined; + this.param.resetStepValue(this, step); } - this.param.setStepValue(this, step); } // init values list if (this.isListe) { - if (this.param.valueList === undefined) { + if (this.param.valueList === undefined && canFill) { if (this.param.isDefined) { - this.param.setValueList(this, [ this.param.getValue() ]); + this.param.resetValueList(this, [this.param.getValue()]); } else { - this.param.setValueList(this, []); + this.param.resetValueList(this, []); } // set form control initial value this.valuesListForm.controls.valuesList.setValue(this.valuesList); diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index dca5bbe5d..b0e214f5e 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -161,7 +161,7 @@ export abstract class FormulaireNode implements IObservable { if (p.valueMode === ParamValueMode.CALCUL) { calcP = p; } - p.setValue(this, undefined); + p.resetValue(this, undefined); } } } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index c79dc844f..d2e4b0bd4 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -394,6 +394,18 @@ export class NgParameter extends InputField implements Observer { ); } + /** + * fixe la valeur du paramètre en tant que valeur par défaut + */ + public resetValue(sender: any, val: number) { + const changed = (this._paramDef.getValue() !== val); + this._isValueModified = false; + if (changed) { + this._paramDef.setValue(val, sender); + this.notifyValueModified(sender); + } + } + /** * fixe la valeur du paramètre. * une notification préalable est envoyée pour laisser l'occasion aux objets liés de préciser le contexte @@ -402,8 +414,20 @@ export class NgParameter extends InputField implements Observer { * @param val */ public setValue(sender: any, val: number) { - this._paramDef.setValue(val, sender); - this.notifyValueModified(sender); + const changed = (this._paramDef.getValue() !== val); + if (changed) { + this._paramDef.setValue(val, sender); + this.notifyValueModified(sender); + } + } + + public resetMinValue(sender: any, v: number) { + const changed = (this._paramDef.min !== v); + this._isValueModified = false; + if (changed) { + this._paramDef.min = v; + this.notifyMinValueModified(sender); + } } public setMinValue(sender: any, v: number) { @@ -415,6 +439,15 @@ export class NgParameter extends InputField implements Observer { } } + public resetMaxValue(sender: any, v: number) { + const changed = (this._paramDef.max !== v); + this._isValueModified = false; + if (changed) { + this._paramDef.max = v; + this.notifyMaxValueModified(sender); + } + } + public setMaxValue(sender: any, v: number) { const changed = (this._paramDef.max !== v); if (changed) { @@ -424,6 +457,15 @@ export class NgParameter extends InputField implements Observer { } } + public resetStepValue(sender: any, v: number) { + const changed = (this._paramDef.step !== v); + this._isValueModified = false; + if (changed) { + this._paramDef.step = v; + this.notifyStepValueModified(sender); + } + } + public setStepValue(sender: any, v: number) { const changed = (this._paramDef.step !== v); if (changed) { @@ -433,6 +475,15 @@ export class NgParameter extends InputField implements Observer { } } + public resetValueList(sender: any, l: number[]) { + const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); + this._isValueModified = false; + if (changed) { + this._paramDef.valueList = l; + this.notifyListValueModified(sender); + } + } + public setValueList(sender: any, l: number[]) { const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); if (changed) { -- GitLab From 9d11df0cd7e9d650802b931e89827374eef486b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 23 Mar 2022 14:52:59 +0100 Subject: [PATCH 27/64] fix: set parameter radio config back when cancel button is clicked in variable values dialog refs #508 --- .../dialog-edit-param-values.component.ts | 2 +- .../param-field-line.component.ts | 16 +++++++++------- .../param-values/param-values.component.ts | 3 ++- src/app/formulaire/elements/ngparam.ts | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts index a6cdcc650..6a0a68d59 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts @@ -53,7 +53,7 @@ export class DialogEditParamValuesComponent implements OnInit { private fb: FormBuilder, @Inject(MAT_DIALOG_DATA) public data: any ) { - this.param = data.param.clone(); + this.param = data.param; // an explicit ReactiveForm is required for file input component const initialValue = (this.param.valueMode === ParamValueMode.LISTE ? this.valuesList : ""); this.valuesListForm = this.fb.group({ diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index 0e97c8b54..2cdf93d1f 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -120,10 +120,10 @@ export class ParamFieldLineComponent implements OnChanges { private _formService: FormulaireService; /** - * valeur du mode de paramètre avant clic sur un des radios, utilisé pour restaurer le mode en cas de cancel - * du dialogue de modification des valeurs en mode variable + * sauvegarde de certaines propriétés du paramètre avant clic sur le radio "varier", utilisé pour + * restaurer le paramètre en cas de cancel du dialogue de modification des valeurs en mode variable */ - private oldValueMode: ParamValueMode; + private paramBackup: NgParameter; /* * gestion des événements clic sur les radios : @@ -242,16 +242,18 @@ export class ParamFieldLineComponent implements OnChanges { } public onRadioClick(option: string) { - this.oldValueMode = this.param.valueMode; + const oldValueMode = this.param.valueMode; switch (option) { case "fix": this.param.valueMode = ParamValueMode.SINGLE; break; case "var": + this.paramBackup = this.param.clone(); + // prevent setting LISTE mode back to MINMAX if someone clicks "variable" again // after setting variable mode to LISTE - if (this.oldValueMode !== ParamValueMode.MINMAX && this.oldValueMode !== ParamValueMode.LISTE) { + if (oldValueMode !== ParamValueMode.MINMAX && oldValueMode !== ParamValueMode.LISTE) { this.param.valueMode = ParamValueMode.MINMAX; // min/max par défaut } if (this._paramValuesComponent) { @@ -279,7 +281,7 @@ export class ParamFieldLineComponent implements OnChanges { } this.radio.emit({ "param": this.param, - "oldValueMode": this.oldValueMode + "oldValueMode": oldValueMode }); // MAJ validité this.emitValidity(); @@ -314,7 +316,7 @@ export class ParamFieldLineComponent implements OnChanges { break; case "cancelvar": // cancel button clicked in DialogEditParamValuesComponent - this.param.valueMode = this.oldValueMode; + this.param.setFrom(this.paramBackup); break; } } diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts index 7a0d4f187..62a212791 100644 --- a/src/app/components/param-values/param-values.component.ts +++ b/src/app/components/param-values/param-values.component.ts @@ -67,10 +67,11 @@ export class ParamValuesComponent implements AfterViewInit, Observer { } ); dlgRef.afterClosed().toPromise().then(result => { - if (result.cancelled) + if (result.cancelled) { this.change.emit({ action: "cancelvar" }); + } }); } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index 697667f6c..c18d7f308 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -46,6 +46,7 @@ export class NgParameter extends InputField implements Observer { const ret: NgParameter = new NgParameter(this._paramDef.clone(), this.parent); ret._allowEmpty = this._allowEmpty; ret.unit = this.unit; + ret.radioConfig = this.radioConfig; ret.disabled = this.disabled; return ret; } @@ -185,6 +186,9 @@ export class NgParameter extends InputField implements Observer { return this._paramDef; } + /** + * compute radio state from value mode + */ public get radioState() { switch (this._paramDef.valueMode) { case ParamValueMode.SINGLE: @@ -390,6 +394,16 @@ export class NgParameter extends InputField implements Observer { } } + /** + * assign given parameter to this + */ + public setFrom(p: NgParameter) { + this._allowEmpty = p._allowEmpty; + this.unit = p.unit; + this.radioConfig = p.radioConfig; + this._paramDef = p._paramDef; + } + /** * supprime un lien avec un paramètre */ -- GitLab From bdde43bfcf1899c696be3f56537f4b7d87cbde02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 29 Mar 2022 14:23:26 +0200 Subject: [PATCH 28/64] fix: parallel structures: backup and restore parameters on device creation/cloning refs #480 --- .../fieldset-container.component.ts | 30 +++------- src/app/formulaire/elements/fieldset.ts | 56 ++++++++++++++++++- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts index 45b87262e..d09ee6118 100644 --- a/src/app/components/fieldset-container/fieldset-container.component.ts +++ b/src/app/components/fieldset-container/fieldset-container.component.ts @@ -74,28 +74,16 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit { * Ajoute un nouveau sous-nub (Structure, PabCloisons, YAXN… selon le cas) * dans un nouveau fieldset */ - private addSubNub(after?: FieldSet, clone: boolean = false) { - if (after) { - const newFs = this._container.addFromTemplate(0, after.indexAsKid()); - if (this.appSetupService.enableEmptyFieldsOnFormInit && ! clone) { - newFs.emptyFields(); - } - if (clone) { - // replace in-place to change properties (overkill) - // @WTF why only those two ? - newFs.setPropValue("structureType", after.properties.getPropValue("structureType")); - newFs.setPropValue("loiDebit", after.properties.getPropValue("loiDebit")); - // copy param values - for (const p of after.nub.prms) { - newFs.nub.getParameter(p.symbol).loadObjectRepresentation(p.objectRepresentation()); - } - } - } else { - const newFs = this._container.addFromTemplate(0); - if (this.appSetupService.enableEmptyFieldsOnFormInit && ! clone) { - newFs.emptyFields(); - } + private addSubNub(after: FieldSet, clone: boolean = false) { + const prms = after.backupParameters(); + const newFs = this._container.addFromTemplate(0, after.indexAsKid()); + if (clone) { + // replace in-place to change properties (overkill) + // @WTF why only those two ? + newFs.setPropValue("structureType", after.properties.getPropValue("structureType")); + newFs.setPropValue("loiDebit", after.properties.getPropValue("loiDebit")); } + newFs.restoreParameters(prms); } private onFieldsetListChange() { diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index dce1e17d4..cf23d79c9 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -15,6 +15,8 @@ import { FieldsetContainer } from "./fieldset-container"; import { SelectFieldCustom } from "./select-field-custom"; import { FormulaireFixedVar } from "../definition/form-fixedvar"; import { SelectEntry } from "./select-entry"; +import { FormulaireNode } from "./formulaire-node"; +import { ServiceFactory } from "app/services/service-factory"; export class FieldSet extends FormulaireElement implements Observer { @@ -51,6 +53,50 @@ export class FieldSet extends FormulaireElement implements Observer { this.kids.push(f); } + /** + * backup NgParameters kids + * @returns a list of object representation with sybol, value, modification flag + */ + public backupParameters(): any[] { + const res: any[] = []; + // for (const p of this.allFormElements) { + for (const p of this._kids) { + if (p instanceof NgParameter) { + res.push(p.objectRepresentation()); + } + } + return res; + } + + /** + * restore NgParameters kids from backup list + * @param backup list of NgParameter object representation + * @see backupParameters + */ + public restoreParameters(backup: any[], except: string[] = FormulaireNode.NeverEmptyFields) { + // for (const p of this.allFormElements) { + for (const p of this._kids) { + if (p instanceof NgParameter) { + for (const bp of backup) { + if (p.symbol === bp.prmDef.symbol) { + // if source parameter has been user modified, copy value + if (bp.modified) { + p.loadObjectRepresentation(bp); + } + else { + // can parameter be emptied ? + if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit && !except.includes(bp.prmDef.symbol)) { + p.resetValue(this, undefined); + } + // else let parameter to default value + } + break; + } + } + } + } + } + public get hasInputs(): boolean { for (const f of this.kids) { if (f instanceof NgParameter) { @@ -353,9 +399,12 @@ export class FieldSet extends FormulaireElement implements Observer { }); } } else { - // for all select fields known by the form, apply received value - // to associated property if (this.parentForm instanceof FormulaireFixedVar) { + // backup parameters + const oldParams = this.backupParameters(); + + // for all select fields known by the form, apply received value + // to associated property const selectIds = this.parentForm.selectids; for (const sId of selectIds) { if (senderId === sId) { @@ -372,6 +421,9 @@ export class FieldSet extends FormulaireElement implements Observer { } } } + + // restore parameters + this.restoreParameters(oldParams, FormulaireNode.NeverEmptyFields); } } break; // switch (data.action) -- GitLab From 1de703cec3ea9630a2adda679eb29b182f70ddb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 30 Mar 2022 12:43:39 +0200 Subject: [PATCH 29/64] fix: variable mode dialog opens when copying a structure In parallel structures, when: - set a structure parameter to variated mode - cancel dialog - copy structure a dialog opens. Now use object representation instead of clone to backup parameter before opening the variable mode dialog. refs #508 --- .../param-field-line.component.ts | 6 ++-- src/app/formulaire/elements/ngparam.ts | 33 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index 2cdf93d1f..a85aa6762 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -123,7 +123,7 @@ export class ParamFieldLineComponent implements OnChanges { * sauvegarde de certaines propriétés du paramètre avant clic sur le radio "varier", utilisé pour * restaurer le paramètre en cas de cancel du dialogue de modification des valeurs en mode variable */ - private paramBackup: NgParameter; + private paramBackup: any; /* * gestion des événements clic sur les radios : @@ -249,7 +249,7 @@ export class ParamFieldLineComponent implements OnChanges { break; case "var": - this.paramBackup = this.param.clone(); + this.paramBackup = this.param.objectRepresentation(); // prevent setting LISTE mode back to MINMAX if someone clicks "variable" again // after setting variable mode to LISTE @@ -316,7 +316,7 @@ export class ParamFieldLineComponent implements OnChanges { break; case "cancelvar": // cancel button clicked in DialogEditParamValuesComponent - this.param.setFrom(this.paramBackup); + this.param.loadObjectRepresentation(this.paramBackup); break; } } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index c18d7f308..007814148 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -42,15 +42,6 @@ export class NgParameter extends InputField implements Observer { this.disabled = false; } - public clone(): NgParameter { - const ret: NgParameter = new NgParameter(this._paramDef.clone(), this.parent); - ret._allowEmpty = this._allowEmpty; - ret.unit = this.unit; - ret.radioConfig = this.radioConfig; - ret.disabled = this.disabled; - return ret; - } - /** * Returns a text preview of the current value(s), depending on the value mode * @param compact if true, will represent multiple values in a more compact way @@ -394,14 +385,22 @@ export class NgParameter extends InputField implements Observer { } } - /** - * assign given parameter to this - */ - public setFrom(p: NgParameter) { - this._allowEmpty = p._allowEmpty; - this.unit = p.unit; - this.radioConfig = p.radioConfig; - this._paramDef = p._paramDef; + public objectRepresentation(): any { + return { + prmDef: this.paramDefinition.objectRepresentation(), + allowEmpty: this._allowEmpty, + unit: this.unit, + radioConfig: this.radioConfig + } + } + + public loadObjectRepresentation(rep: any) { + if (this._paramDef.symbol === rep.prmDef.symbol) { + this._paramDef.loadObjectRepresentation(rep.prmDef); + this._allowEmpty = rep.allowEmpty; + this.unit = rep.unit; + this.radioConfig = rep.radioConfig; + } } /** -- GitLab From a1fa77c2f90898dee253626d1c655ee8db298efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 6 Apr 2022 11:56:01 +0200 Subject: [PATCH 30/64] fix: some e2e tests fail due to "empty fields on calculator creation" option --- e2e/calc-all-examples.e2e-spec.ts | 30 +++++++++++++++---- e2e/compute-reset-chained-links.e2e-spec.ts | 13 +++++++- e2e/load-linked-params.e2e-spec.ts | 4 +++ protractor.conf.js | 2 +- .../app-setup/app-setup.component.html | 2 +- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/e2e/calc-all-examples.e2e-spec.ts b/e2e/calc-all-examples.e2e-spec.ts index 957364fc6..4dae4b1dd 100644 --- a/e2e/calc-all-examples.e2e-spec.ts +++ b/e2e/calc-all-examples.e2e-spec.ts @@ -2,6 +2,8 @@ import { ListPage } from "./list.po"; import { CalculatorPage } from "./calculator.po"; import { Navbar } from "./navbar.po"; import { browser, by, element } from "protractor"; +import { PreferencesPage } from "./preferences.po"; +import { SideNav } from "./sidenav.po"; /** * Calculate all modules of all examples @@ -11,22 +13,40 @@ describe("ngHyd − example sessions −", async () => { let listPage: ListPage; let calcPage: CalculatorPage; let navbar: Navbar; + let prefPage: PreferencesPage; + let sideNav: SideNav; beforeAll(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000; - }); - - it("calcul de tous les modules de tous les exemples −", async () => { listPage = new ListPage(); calcPage = new CalculatorPage(); navbar = new Navbar(); - listPage = new ListPage(); + prefPage = new PreferencesPage(); + sideNav = new SideNav(); + }); + + it("calcul de tous les modules de tous les exemples −", async () => { + // disable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await prefPage.disableEvilEmptyFields(); + await browser.sleep(200); // for each calculator let lastExampleFound = true; let i = 0; while (lastExampleFound) { - await listPage.navigateTo(); + if (i == 0) { + // start page + await navbar.clickNewCalculatorButton(); + await browser.sleep(200); + } + else { + // empty session + await navbar.clickMenuButton(); + await browser.sleep(200); + await sideNav.clickNewSessionButton(); + await browser.sleep(200); + } const examples = await element.all(by.css("#examples-list .load-example")); if (examples.length > i) { diff --git a/e2e/compute-reset-chained-links.e2e-spec.ts b/e2e/compute-reset-chained-links.e2e-spec.ts index 2767c9d96..65e2e4e95 100644 --- a/e2e/compute-reset-chained-links.e2e-spec.ts +++ b/e2e/compute-reset-chained-links.e2e-spec.ts @@ -3,6 +3,7 @@ import { CalculatorPage } from "./calculator.po"; import { Navbar } from "./navbar.po"; import { SideNav } from "./sidenav.po"; import { browser } from "protractor"; +import { PreferencesPage } from "./preferences.po"; /** * Load a session containing 3 calculators, having linked parameters @@ -16,12 +17,14 @@ describe("ngHyd − compute then reset chained results − ", () => { let calcPage: CalculatorPage; let navbar: Navbar; let sidenav: SideNav; + let prefPage: PreferencesPage; function init() { startPage = new AppPage(); calcPage = new CalculatorPage(); navbar = new Navbar(); sidenav = new SideNav(); + prefPage = new PreferencesPage(); } beforeEach(init); @@ -128,8 +131,16 @@ describe("ngHyd − compute then reset chained results − ", () => { }); it("when loading session-results-invalidation.json, results reset should not be triggered on calculation", async () => { + // disable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await prefPage.disableEvilEmptyFields(); + await browser.sleep(200); + + // start page + await navbar.clickNewCalculatorButton(); + await browser.sleep(200); + // load session file - await startPage.navigateTo(); await navbar.clickMenuButton(); await browser.sleep(200); await sidenav.clickLoadSessionButton(); diff --git a/e2e/load-linked-params.e2e-spec.ts b/e2e/load-linked-params.e2e-spec.ts index 8e87b5f94..00b262f24 100644 --- a/e2e/load-linked-params.e2e-spec.ts +++ b/e2e/load-linked-params.e2e-spec.ts @@ -34,6 +34,10 @@ describe("ngHyd − load session with multiple linked parameters − ", () => { await prefPage.navigateTo(); await prefPage.changeLanguage(1); // fr await browser.sleep(200); + // disable evil option "empty fields on module creation" + await prefPage.disableEvilEmptyFields(); + await browser.sleep(200); + // start page await navbar.clickNewCalculatorButton(); }); diff --git a/protractor.conf.js b/protractor.conf.js index 3077d88c4..d474c230b 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -61,7 +61,7 @@ exports.config = { require('ts-node').register({ project: 'e2e/tsconfig.e2e.json' }); - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: "pretty" } })); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); browser.manage().window().setSize(1600, 1000); browser.driver.sendChromiumCommand('Page.setDownloadBehavior', { behavior: 'allow', diff --git a/src/app/components/app-setup/app-setup.component.html b/src/app/components/app-setup/app-setup.component.html index 87f52357a..bcd394688 100644 --- a/src/app/components/app-setup/app-setup.component.html +++ b/src/app/components/app-setup/app-setup.component.html @@ -102,4 +102,4 @@ </mat-card-content> </mat-card> -</div> \ No newline at end of file +</div> -- GitLab From f61e3d356a6bb66eb28e09e41df8cca3cbf3efc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 6 Apr 2022 13:57:50 +0200 Subject: [PATCH 31/64] test: e2e check that cancel button is present in variable parameter edition dialog refs #507 --- .vscode/launch.json | 24 +++++++++++++-- e2e/variable-param-cancel.e2e-spec.ts | 30 +++++++++++++++++++ .../dialog-edit-param-values.component.html | 2 +- 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 e2e/variable-param-cancel.e2e-spec.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 560298a30..1d92791fc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,10 @@ "name": "Launch Chrome (local webserver)", "url": "http://localhost:4200", "webRoot": "${workspaceFolder}", - "runtimeExecutable": "/usr/bin/chromium-browser" + "runtimeExecutable": "/usr/bin/chromium", + "runtimeArgs": [ + "--preserve-symlinks" + ] }, { "name": "Launch Firefox (local webserver)", @@ -19,6 +22,23 @@ "reAttach": true, "url": "http://localhost:4200", "webRoot": "${workspaceFolder}" + }, + { + "name": "Launch e2e current file", + "type": "node", + "request": "launch", + "stopOnEntry": false, + "program": "${workspaceRoot}/node_modules/protractor/bin/protractor", + "args": [ + "${workspaceRoot}/protractor.conf.js", + "--specs=${file}" + ], + "cwd": "${workspaceRoot}", + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/dist/out-tsc-e2e/*.js" + ], + "skipSourceMapSupport": true } ] -} \ No newline at end of file +} diff --git a/e2e/variable-param-cancel.e2e-spec.ts b/e2e/variable-param-cancel.e2e-spec.ts new file mode 100644 index 000000000..750fdd160 --- /dev/null +++ b/e2e/variable-param-cancel.e2e-spec.ts @@ -0,0 +1,30 @@ +import { ListPage } from "./list.po"; +import { by, element } from "protractor"; + +/** + * Check that a cancel button is present in min/max/list edition dialog + * for variable parameters + */ +describe("ngHyd - check cancel button for variable parameters - ", () => { + let listPage: ListPage; + + beforeAll(async () => { + listPage = new ListPage(); + }); + + fit("when min/max/list values dialog opens, a cancel button should be present", async () => { + // start page + await listPage.navigateTo(); + + // open PAB chute + await listPage.clickMenuEntryForCalcType(12); + + // click "var" radio on Z1 parameter + const z1btn = element(by.id("mat-button-toggle-2-button")); + await z1btn.click(); + + // cancel button presence + const cancelbtn = element(by.id("btn-cancel")); + expect(await cancelbtn.isPresent() && await cancelbtn.isDisplayed()).toBeTruthy(); + }); +}); diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html index e8dbbb2c9..5fc7c8482 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html @@ -121,7 +121,7 @@ <div mat-dialog-actions [attr.align]="'end'"> <div> - <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> + <button id="btn-cancel" mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> {{ uitextCancel }} </button> <button mat-raised-button color="warn" (click)="onValidate()" [disabled]=" !isFormValid"> -- GitLab From 1b3ba3abe013ba2356aa81fc7f3fccd618e0ef91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 7 Apr 2022 10:21:57 +0200 Subject: [PATCH 32/64] test: check that parameter mode is set back to its previous value when min/max/list dialog is cancelled refs #508 --- e2e/reset-param-mode.e2e-spec.ts | 42 +++++++++++++++++++++++++++ e2e/variable-param-cancel.e2e-spec.ts | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 e2e/reset-param-mode.e2e-spec.ts diff --git a/e2e/reset-param-mode.e2e-spec.ts b/e2e/reset-param-mode.e2e-spec.ts new file mode 100644 index 000000000..7cc73c007 --- /dev/null +++ b/e2e/reset-param-mode.e2e-spec.ts @@ -0,0 +1,42 @@ +import { ListPage } from "./list.po"; +import { browser, by, element, ElementFinder } from "protractor"; +import { CalculatorPage } from "./calculator.po"; + +/** + * Parameter mode should be set to its previous mode (fixed/var/...) when cancel is pressed + * in variable mode edition dialog + */ +describe("ngHyd - check parameter mode is set to its previous value - ", () => { + let listPage: ListPage; + + beforeAll(async () => { + listPage = new ListPage(); + }); + + it("when min/max/list values dialog is cancelled", async () => { + // start page + await listPage.navigateTo(); + + // open PAB chute + await listPage.clickMenuEntryForCalcType(12); + + // click "calc" radio on Z1 parameter + const z1calcbtn = element(by.id("mat-button-toggle-3")); + await z1calcbtn.click(); + + // click "var" radio on Z1 parameter + const z1varbtn = element(by.id("mat-button-toggle-2")); + await z1varbtn.click(); + + // click cancel button + const cancelbtn = element(by.id("btn-cancel")); + await cancelbtn.click(); + await browser.sleep(200); + + // check Z1 var toggle is disabled + expect(await z1varbtn.getAttribute("ng-reflect-checked")).toBe("false"); + + // check Z1 calc toggle is enabled + expect(await z1calcbtn.getAttribute("ng-reflect-checked")).toBe("true"); + }); +}); diff --git a/e2e/variable-param-cancel.e2e-spec.ts b/e2e/variable-param-cancel.e2e-spec.ts index 750fdd160..abe96d8fe 100644 --- a/e2e/variable-param-cancel.e2e-spec.ts +++ b/e2e/variable-param-cancel.e2e-spec.ts @@ -12,7 +12,7 @@ describe("ngHyd - check cancel button for variable parameters - ", () => { listPage = new ListPage(); }); - fit("when min/max/list values dialog opens, a cancel button should be present", async () => { + it("when min/max/list values dialog opens, a cancel button should be present", async () => { // start page await listPage.navigateTo(); -- GitLab From 9ec23adbc97b6f4b8360c0a6297989a73f6d2a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 31 Mar 2022 11:13:52 +0200 Subject: [PATCH 33/64] fix: empty initial value in parameter calc mode refs #480 --- .../dialog-edit-param-computed.component.html | 2 +- .../dialog-edit-param-computed.component.ts | 16 +++++++------ .../ngparam-input/ngparam-input.component.ts | 20 ++++++++++++++-- .../param-computed.component.ts | 10 ++++++-- .../param-field-line.component.ts | 9 -------- src/app/formulaire/elements/ngparam.ts | 23 ++++++++++++++++++- 6 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html index 0ec1a116e..38bcc40fb 100644 --- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html +++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html @@ -7,7 +7,7 @@ </div> <div mat-dialog-actions [attr.align]="'end'"> - <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> + <button mat-raised-button color="primary" [mat-dialog-close]="true" (click)="onCancel()" cdkFocusInitial> {{ uitextCancel }} </button> <button mat-raised-button color="warn" (click)="onValidate()"> diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts index 4984494eb..473ea11b0 100644 --- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts +++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts @@ -25,12 +25,7 @@ export class DialogEditParamComputedComponent implements OnInit { @Inject(MAT_DIALOG_DATA) public data: any ) { // copy given parameter in a "fake" Ngparameter - const nP = data.param as NgParameter; - const p = nP.paramDefinition as ParamDefinition; - const pDef = new ParamDefinition(undefined, p.symbol, p.domain, p.unit, p.getValue(), p.family, p.visible); - this.param = new NgParameter(pDef, undefined); - this.param.setLabel(nP.label); - this.param.unit = nP.unit; + this.param = data.param; } public get uitextCancel(): string { @@ -46,12 +41,19 @@ export class DialogEditParamComputedComponent implements OnInit { } public ngOnInit() { + this._ngParamInputComponent.editInitValue = true; this._ngParamInputComponent.model = this.param; } + public onCancel() { + this.dialogRef.close({ + cancel: true + }); + } + public onValidate() { this.dialogRef.close({ - value: this.param.getValue() + cancel: false }); } } diff --git a/src/app/components/ngparam-input/ngparam-input.component.ts b/src/app/components/ngparam-input/ngparam-input.component.ts index cbaf4e2fd..2449f691e 100644 --- a/src/app/components/ngparam-input/ngparam-input.component.ts +++ b/src/app/components/ngparam-input/ngparam-input.component.ts @@ -21,6 +21,11 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem @Input() public captureTabEvents: boolean; + /** + * true : edit parameter initial value (in CALC mode) instead of single value + */ + public editInitValue: boolean; + /** * paramètre géré */ @@ -42,6 +47,7 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem ) { super(cdRef, intlService, appSetupService); this.captureTabEvents = true; + this.editInitValue = false; } /** @@ -58,7 +64,12 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem */ protected afterSetModel() { if (this._paramDef) { - this._tmp = this._paramDef.getValue(); + if (this.editInitValue) { + this._tmp = this._paramDef.paramDefinition.initValue; + } + else { + this._tmp = this._paramDef.getValue(); + } this._paramDef.addObserver(this); } } @@ -70,7 +81,11 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem protected setModelValue(sender: any, v: any) { this._tmp = v; try { - this._paramDef.setValue(sender, v); + if (this.editInitValue) { + this._paramDef.setInitValue(sender, v); + } else { + this._paramDef.setValue(sender, v); + } } catch (e) { // géré par validateModelValue() } @@ -101,6 +116,7 @@ export class NgParamInputComponent extends GenericInputComponentDirective implem public update(sender: any, data: any): void { switch (data["action"]) { case "ngparamAfterValue": + case "ngparamAfterInitValue": // on ne fait rien au cas où la modif vient de l'interface (on ne remet pas à jour _uiValue ce qui permet // de garder par ex le '.' si on supprime le '2' de '1.2') if (sender !== this) { diff --git a/src/app/components/param-computed/param-computed.component.ts b/src/app/components/param-computed/param-computed.component.ts index e1f901071..5525dcf7a 100644 --- a/src/app/components/param-computed/param-computed.component.ts +++ b/src/app/components/param-computed/param-computed.component.ts @@ -20,6 +20,11 @@ export class ParamComputedComponent { @Input() public title: string; + /** + * initial value before opening dialog + */ + private initValueBackup; + /** * id de l'input, utilisé notamment pour les tests */ @@ -47,6 +52,7 @@ export class ParamComputedComponent { } public openDialog() { + this.initValueBackup = this.param.paramDefinition.initValue; // modification de la valeur initiale, sans avoir à remettre le mode de paramètre sur "fixé" const dialogRef = this.editInitialValueDialog.open( DialogEditParamComputedComponent, @@ -59,9 +65,9 @@ export class ParamComputedComponent { } ); dialogRef.afterClosed().subscribe(result => { - if (result && result.value !== undefined) { + if (result.cancel) { // use setInitValue() and not setValue() to prevent value mode from going back to SINGLE - this.param.paramDefinition.setInitValue(result.value); + this.param.paramDefinition.setInitValue(this.initValueBackup); } }); } diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index a85aa6762..1cb5750c7 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -264,15 +264,6 @@ export class ParamFieldLineComponent implements OnChanges { case "cal": this.param.setCalculated(); // sets mode to CALCUL and more - // did some nasty rascal tick the "create module with empty fields" evil option, - // then chose to set a DICHO param to CALC mode without setting a value first ? - if ( - this.param.paramDefinition.calculability === ParamCalculability.DICHO - && this.param.paramDefinition.singleValue === undefined - ) { - // restore dedicated initValue - this.param.paramDefinition.singleValue = this.param.paramDefinition.initValue; - } break; case "link": diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index d2e4b0bd4..59c4e188f 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -94,7 +94,7 @@ export class NgParameter extends InputField implements Observer { valuePreview = i18n.localizeText("INFO_PARAMFIELD_IN_CALCULATION"); if (p.calculability === ParamCalculability.DICHO) { valuePreview += " (" + i18n.localizeText("INFO_PARAMFIELD_IN_CALCULATION_INITIAL_VALUE") - + ": " + fv(p.getValue()) + ")"; + + ": " + fv(p.initValue) + ")"; } break; case ParamValueMode.LINK: @@ -394,6 +394,16 @@ export class NgParameter extends InputField implements Observer { ); } + private notifyInitValueModified(sender: any) { + this.notifyObservers( + { + "action": "ngparamAfterInitValue", + "param": this, + "value": this._paramDef.initValue + }, sender + ); + } + /** * fixe la valeur du paramètre en tant que valeur par défaut */ @@ -493,6 +503,17 @@ export class NgParameter extends InputField implements Observer { } } + /** + * set initial value for CALC mode + */ + public setInitValue(sender: any, v: number) { + const changed = (this._paramDef.initValue !== v); + if (changed) { + this._paramDef.initValue = v; + this.notifyInitValueModified(sender); + } + } + public objectRepresentation(): any { return { prmDef: this.paramDefinition.objectRepresentation(), -- GitLab From 3586da64b7ce64540977d781623d456456ecb8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 8 Apr 2022 11:34:16 +0200 Subject: [PATCH 34/64] test: check fields are empty on creation in structure calculator refs #480 --- e2e/calculator.po.ts | 4 + e2e/ouvrages-empty-fields.e2e-spec.ts | 115 ++++++++++++++++++++++++++ e2e/preferences.po.ts | 8 ++ jalhyd_branch | 2 +- 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 e2e/ouvrages-empty-fields.e2e-spec.ts diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts index 1194295c9..4be637886 100644 --- a/e2e/calculator.po.ts +++ b/e2e/calculator.po.ts @@ -67,6 +67,10 @@ export class CalculatorPage { return element(by.css("fieldset-container .hyd-window-btns button.add-structure")); } + getCopyStructureButton() { + return element(by.css("fieldset-container .hyd-window-btns button.copy-structure")); + } + getAllLinkButtons() { return element.all(by.css("mat-button-toggle.radio_link")); } diff --git a/e2e/ouvrages-empty-fields.e2e-spec.ts b/e2e/ouvrages-empty-fields.e2e-spec.ts new file mode 100644 index 000000000..9e8f1b576 --- /dev/null +++ b/e2e/ouvrages-empty-fields.e2e-spec.ts @@ -0,0 +1,115 @@ +import { ListPage } from "./list.po"; +import { browser, by, element } from "protractor"; +import { CalculatorPage } from "./calculator.po"; +import { AppPage } from "./app.po"; + +/** + * Check that created/cloned structures have empty fields when + * "empty fields on calculator creation" is enabled + */ +describe("ngHyd - check that created/cloned structures have empty fields - ", () => { + //let prefPage: PreferencesPage; + let startPage: AppPage; + let listPage: ListPage; + let calcPage: CalculatorPage; + + beforeAll(() => { + //prefPage = new PreferencesPage(); + startPage = new AppPage(); + listPage = new ListPage(); + calcPage = new CalculatorPage(); + }); + + beforeEach(async () => { + // enable evil option "empty fields on module creation" + // await prefPage.navigateTo(); + // await prefPage.enableEvilEmptyFields(); // message "stale element reference: element is not attached to the page document" + // await browser.sleep(200); + + // assume that "empty fields on module creation" is true by default + + // start page + await startPage.navigateTo(); + await browser.sleep(200); + + // open structures calculator + await listPage.clickMenuEntryForCalcType(8); + await browser.sleep(200); + }); + + /** + * check that a input set is in a given (empty/filled) state + * @param inputIds id of the inputs to check + * @param emptys empty/not empty state array + */ + async function checkFields(inputIds: string[], emptys: boolean[]) { + let n = 0; + for (const id of inputIds) { + const inp = await calcPage.getInputById(id); + const txt = await inp.getAttribute("value"); + expect(txt === "").toEqual(emptys[n]); + n++; + } + } + + it("when a structure calculator is created", async () => { + // check 1st structure empty fields + const inputIds = ["Q", "calc_Z1", "Z2", "0_ZDV", "0_L", "0_W", "0_CdGR"]; + const emptys = [true, false, true, true, true, true, false]; + await checkFields(inputIds, emptys); + + // change 1st structure type to rectangular weir + const structSelect = calcPage.getSelectById("select_structure"); + await calcPage.changeSelectValue(structSelect, 1); + await browser.sleep(200); + + // check 1st structure empty fields + const inputIds2 = ["Q", "calc_Z1", "Z2", "0_ZDV", "0_L", "0_CdWR"]; + const emptys2 = [true, false, true, true, true, false]; + await checkFields(inputIds2, emptys2); + }); + + it("when a structure is added", async () => { + // add structure + const addStruct = calcPage.getAddStructureButton(); + await addStruct.click(); + + // check 2nd structure empty fields + const inputIds = ["1_ZDV", "1_L", "1_W", "1_CdGR"]; + const emptys = [true, true, true, false]; + await checkFields(inputIds, emptys); + }); + + it("when a structure is copied", async () => { + // copy structure + const addStruct = calcPage.getCopyStructureButton(); + await addStruct.click(); + + // check 2nd structure empty fields + const inputIds = ["1_ZDV", "1_L", "1_W", "1_CdGR"]; + const emptys = [true, true, true, false]; + await checkFields(inputIds, emptys); + }); + + it("when a modified structure is copied", async () => { + // change 1st structure type to rectangular weir + const structSelect = calcPage.getSelectById("select_structure"); + await calcPage.changeSelectValue(structSelect, 1); + await browser.sleep(200); + + // copy structure + const addStruct = calcPage.getCopyStructureButton(); + await addStruct.click(); + await browser.sleep(200); + + // change 2nd structure type to rectangular gate + const structSelect2 = element(by.className("ng-tns-c3-47")); + await calcPage.changeSelectValue(structSelect2, 4); + await browser.sleep(200); + + // check empty fields + const inputIds = ["1_ZDV", "1_L", "1_W", "1_CdGR"]; + const emptys = [true, true, true, false]; + await checkFields(inputIds, emptys); + }); +}); diff --git a/e2e/preferences.po.ts b/e2e/preferences.po.ts index 016d2da96..ff9ff36ae 100644 --- a/e2e/preferences.po.ts +++ b/e2e/preferences.po.ts @@ -41,6 +41,14 @@ export class PreferencesPage { await option.click(); } + async enableEvilEmptyFields() { + const cb = this.getEmptyFieldsCheckbox(); + const underlyingCB = cb.element(by.css(`input.mat-checkbox-input`)); + if (!underlyingCB.isSelected()) { + await cb.click(); + } + } + async disableEvilEmptyFields() { const cb = this.getEmptyFieldsCheckbox(); const underlyingCB = cb.element(by.css(`input.mat-checkbox-input`)); diff --git a/jalhyd_branch b/jalhyd_branch index 084f9effb..626e97d71 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -300-supprimer-le-champ-_valuemode-dans-paramdefinition \ No newline at end of file +devel \ No newline at end of file -- GitLab From d65fcb628485158caf078317eac96f61a7b14c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 11 Apr 2022 10:49:58 +0200 Subject: [PATCH 35/64] test: add check on empty fields when creating a predams calculator refs #503 --- e2e/predam-empty-fields.e2e-spec.ts | 75 +++++++++++++++++++ .../dialog-new-pb-cloison.component.html | 3 +- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 e2e/predam-empty-fields.e2e-spec.ts diff --git a/e2e/predam-empty-fields.e2e-spec.ts b/e2e/predam-empty-fields.e2e-spec.ts new file mode 100644 index 000000000..b434bd81d --- /dev/null +++ b/e2e/predam-empty-fields.e2e-spec.ts @@ -0,0 +1,75 @@ +import { browser, by, element } from "protractor"; +import { CalculatorPage } from "./calculator.po"; +import { ListPage } from "./list.po"; +import { Navbar } from "./navbar.po"; +import { PreferencesPage } from "./preferences.po" + +/** + * check that fields are empty on creation + */ +describe("ngHyd − check that predam fields are empty on creation", () => { + let listPage: ListPage; + let prefPage: PreferencesPage; + let navBar: Navbar; + let calcPage: CalculatorPage; + + beforeEach(async () => { + prefPage = new PreferencesPage(); + listPage = new ListPage(); + navBar = new Navbar(); + calcPage = new CalculatorPage(); + + // enable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); + }); + + it("when a basin is added", async () => { + // open predam calculator + await navBar.clickNewCalculatorButton(); + await listPage.clickMenuEntryForCalcType(30); + await browser.sleep(200); + + // add basin + const addBasinBtn = element(by.id("add-basin")); + await addBasinBtn.click(); + await browser.sleep(200); + + // check "surface" input is empty + let inp = calcPage.getInputById("3_S"); + let txt = await inp.getAttribute("value"); + expect(txt).toEqual(""); + + // check "cote de fond" input is empty + inp = calcPage.getInputById("3_ZF"); + txt = await inp.getAttribute("value"); + expect(txt).toEqual(""); + }); + + it("when a wall is added", async () => { + // open predam calculator + await navBar.clickNewCalculatorButton(); + await listPage.clickMenuEntryForCalcType(30); + await browser.sleep(200); + + // add wall + const addWallBtn = element(by.id("add-wall")); + await addWallBtn.click(); + + // connect basins + const connectBasinsBtn = element(by.id("validate-connect-basins")); + await connectBasinsBtn.click(); + + // check ZDV input is empty + let inp = calcPage.getInputById("0_ZDV"); + let txt = await inp.getAttribute("value"); + expect(txt).toEqual(""); + + // check CdWSL input is NOT empty + inp = calcPage.getInputById("0_CdWSL"); + txt = await inp.getAttribute("value"); + expect(txt === "").toBe(false); + }); +}); diff --git a/src/app/components/dialog-new-pb-cloison/dialog-new-pb-cloison.component.html b/src/app/components/dialog-new-pb-cloison/dialog-new-pb-cloison.component.html index a6587c773..fdded3ee4 100644 --- a/src/app/components/dialog-new-pb-cloison/dialog-new-pb-cloison.component.html +++ b/src/app/components/dialog-new-pb-cloison/dialog-new-pb-cloison.component.html @@ -21,7 +21,8 @@ <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial> {{ uitextCancel }} </button> - <button mat-raised-button color="warn" (click)="onValidate()" [disabled]="! enableValidate"> + <button mat-raised-button id="validate-connect-basins" color="warn" (click)="onValidate()" + [disabled]="! enableValidate"> {{ uitextValidate }} </button> </div> -- GitLab From b424c10bc444f879743dbf21c9072e10a5959ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 11 Apr 2022 13:09:07 +0200 Subject: [PATCH 36/64] fix: predams: fields not empty on basin creation refs #503 --- .../pb-schema/pb-schema.component.ts | 28 ++++++++++++++++++- .../formulaire/elements/formulaire-node.ts | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index 40217b619..e1e74c9e6 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -5,7 +5,7 @@ import * as screenfull from "screenfull"; import { Screenfull } from "screenfull"; // @see https://github.com/sindresorhus/screenfull.js/issues/126#issuecomment-488796645 import { - PreBarrage, PbBassin, PbBassinParams, PbCloison, Observer, IObservable + PreBarrage, PbBassin, PbBassinParams, PbCloison, Observer, IObservable, ParamDefinition, ParamValueMode } from "jalhyd"; import * as mermaid from "mermaid"; @@ -20,6 +20,7 @@ import { FormulairePrebarrage } from "../../formulaire/definition/form-prebarrag import { AppComponent } from "../../app.component"; import { fv } from "app/util"; +import { FormulaireNode } from "app/formulaire/elements/formulaire-node"; /** * The interactive schema for calculator type "PreBarrage" (component) @@ -491,10 +492,35 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni return this.i18nService.localizeText("INFO_FIELDSET_COPY"); } + /** + * Set value of all single parameters to undefined, except for the given parameter ids + */ + private emptyFields(basin: PbBassin, except: string[] = FormulaireNode.NeverEmptyFields) { + // save current calculated param, as setting value on a CALC param will + // change its mode and choose another calculated param by default + let calcP: ParamDefinition; + for (const p of basin.parameterIterator) { + if ( + [ParamValueMode.SINGLE, ParamValueMode.CALCUL].includes(p.valueMode) + && !except.includes(p.symbol) + ) { + if (p.valueMode === ParamValueMode.CALCUL) { + calcP = p; + } + p.setValue(undefined); + } + } + // restore original calculated param + if (calcP !== undefined) { + calcP.setCalculated(); + } + } + /** Adds a new lone basin */ public onAddBasinClick() { const newBasin = new PbBassin(new PbBassinParams(20, 99)); this.model.addChild(newBasin); + this.emptyFields(newBasin); this.clearResults(); this.refreshWithSelection(newBasin.uid); this.calculatorComponent.showPBInputData = true; diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index b0e214f5e..4d48607af 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -12,7 +12,7 @@ export abstract class FormulaireNode implements IObservable { /** * fields in fieldset that must not be empty due to enableEmptyFieldsOnFormInit option */ - protected static NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL"]; + public static readonly NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL"]; /** aide en ligne */ protected _helpLink: string; -- GitLab From 8d4dcb4d2bd7c0b14efd009afbc1ff443d1901fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 11 Apr 2022 17:24:02 +0200 Subject: [PATCH 37/64] fix: remove CdWSL (Larinier weir) from fields not to be emptied with "empty fields on calculator creation" option To force user to fill CdWSL input refs #515 --- e2e/ouvrages-empty-fields.e2e-spec.ts | 17 +++++++++++++++++ e2e/predam-empty-fields.e2e-spec.ts | 10 ++++++++-- src/app/formulaire/elements/formulaire-node.ts | 6 +++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/e2e/ouvrages-empty-fields.e2e-spec.ts b/e2e/ouvrages-empty-fields.e2e-spec.ts index 9e8f1b576..096393e60 100644 --- a/e2e/ouvrages-empty-fields.e2e-spec.ts +++ b/e2e/ouvrages-empty-fields.e2e-spec.ts @@ -112,4 +112,21 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () const emptys = [true, true, true, false]; await checkFields(inputIds, emptys); }); + + it("except for discharge coefficient when a Larinier weir is used", async () => { + // change 1st structure type to rectangular weir + const structSelect = calcPage.getSelectById("select_structure"); + await calcPage.changeSelectValue(structSelect, 1); + await browser.sleep(200); + + // change discharge law to Larinier + const dischargeSelect = calcPage.getSelectById("select_loidebit"); + await calcPage.changeSelectValue(dischargeSelect, 3); + await browser.sleep(200); + + // check empty fields + const inputIds = ["0_ZDV", "0_L", "0_CdWSL"]; + const emptys = [true, true, true]; + await checkFields(inputIds, emptys); + }); }); diff --git a/e2e/predam-empty-fields.e2e-spec.ts b/e2e/predam-empty-fields.e2e-spec.ts index b434bd81d..68db87689 100644 --- a/e2e/predam-empty-fields.e2e-spec.ts +++ b/e2e/predam-empty-fields.e2e-spec.ts @@ -67,9 +67,15 @@ describe("ngHyd − check that predam fields are empty on creation", () => { let txt = await inp.getAttribute("value"); expect(txt).toEqual(""); - // check CdWSL input is NOT empty + // check L input is empty + inp = calcPage.getInputById("0_L"); + txt = await inp.getAttribute("value"); + expect(txt).toEqual(""); + + // check CdWSL input is empty (in this case, the structure happens to be a Larinier weir + // which discharge coefficient must be empty) inp = calcPage.getInputById("0_CdWSL"); txt = await inp.getAttribute("value"); - expect(txt === "").toBe(false); + expect(txt).toEqual(""); }); }); diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index 4d48607af..4ce064883 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -12,7 +12,7 @@ export abstract class FormulaireNode implements IObservable { /** * fields in fieldset that must not be empty due to enableEmptyFieldsOnFormInit option */ - public static readonly NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT", "CdWSL"]; + public static readonly NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT"]; /** aide en ligne */ protected _helpLink: string; @@ -155,8 +155,8 @@ export abstract class FormulaireNode implements IObservable { for (const p of this.allFormElements) { if (p instanceof NgParameter) { if ( - [ ParamValueMode.SINGLE, ParamValueMode.CALCUL ].includes(p.valueMode) - && ! except.includes(p.id) + [ParamValueMode.SINGLE, ParamValueMode.CALCUL].includes(p.valueMode) + && !except.includes(p.id) ) { if (p.valueMode === ParamValueMode.CALCUL) { calcP = p; -- GitLab From 51eee4434bea2d572e9ad87b39e4a4d77e433265 Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@inrae.fr> Date: Tue, 12 Apr 2022 16:33:42 +0000 Subject: [PATCH 38/64] test: add test that currently fails on critical flow calculation Refs #528 --- e2e/remous.e2e-spec.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/e2e/remous.e2e-spec.ts b/e2e/remous.e2e-spec.ts index 5c4603946..f79ad021f 100644 --- a/e2e/remous.e2e-spec.ts +++ b/e2e/remous.e2e-spec.ts @@ -47,4 +47,27 @@ describe("ngHyd − remous", () => { // 5. there should still be 6 messages in the log expect(await calcPage.nbLogEntries()).toBe(6); }); + + it("Calculation with large bed width should run successfully", async () => { + await navBar.clickNewCalculatorButton(); + + // 1. create new Remous + await listPage.clickMenuEntryForCalcType(4); + await browser.sleep(300); + + // 2. Set to trapezoidal section with bank slope of 2m/m and 20 meter width bed + await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); + await browser.sleep(300); + await calcPage.getInputById("LargeurFond").clear(); + await browser.sleep(300); + await calcPage.getInputById("LargeurFond").sendKeys("20"); + await calcPage.getInputById("Fruit").clear(); + await browser.sleep(300); + await calcPage.getInputById("Fruit").sendKeys("2"); + + // 3. Calculate, the calculation should succeed + await calcPage.getCalculateButton().click(); + const hasResults = await calcPage.hasResults(); + expect(hasResults).toBe(true); + }); }); -- GitLab From de8af88c3c57bfc53a384a7a15ed4282c718efe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 15 Apr 2022 10:34:12 +0200 Subject: [PATCH 39/64] refactor(ci): modify release-version.sh to not update releases.json/symlinks on nightly version refs #505 --- scripts/release-version.sh | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/scripts/release-version.sh b/scripts/release-version.sh index 9952d4134..83398a209 100755 --- a/scripts/release-version.sh +++ b/scripts/release-version.sh @@ -2,9 +2,10 @@ # Fabrique les exécutables electron/cordova pour une version de Cassiopée $1, les # distribue sur le serveur $2 dans le dossier $3, et met à jour le fichier releases.json +# et les liens symboliques si la version n'est pas nightly if [ "$#" -lt 3 ]; then - echo "usage: $0 X.Y.Z login@server /var/www/releases_dir" + echo "usage: $0 <X.Y.Z|nightly> <login@server> <releases dir>" exit 1 fi @@ -15,22 +16,29 @@ RELEASES_DIR="$3" RELEASES_FILE="$RELEASES_DIR/releases.json" TMP_RELEASES_FILE="tmp-releases.json" +# update flag for releases file/symlinks +update_latest=1 +if [[ $VERSION == "nightly" ]]; then + update_latest=0 +fi + echo "deploy-version.sh: building release for version $VERSION, deploying in $HOST_LOGIN:$RELEASES_DIR" # build releases npm run release-all # update existing releases file +if (( $update_latest )); then + echo "updating releases.json" -# fetch current releases file -scp "$HOST_LOGIN:$RELEASES_FILE" "./$TMP_RELEASES_FILE" + # fetch current releases file + scp "$HOST_LOGIN:$RELEASES_FILE" "./$TMP_RELEASES_FILE" -grep -P "\"latest\": \"$VERSION\"" "$TMP_RELEASES_FILE" + grep -P "\"latest\": \"$VERSION\"" "$TMP_RELEASES_FILE" -if [[ $? == 0 ]] -then + if [[ $? == 0 ]]; then echo "$VERSION est déjà la version la plus récente, pas de mise à jour du fichier releases.json" -else + else sed -i -E "s/\"latest\": .+,/\"latest\": \"$VERSION\",/" "$TMP_RELEASES_FILE" echo -e "\t\"$VERSION\": { \t\t\"darwin\": \"Cassiopée-${VERSION}-mac.zip\", @@ -41,20 +49,26 @@ else sed -i "/\"latest\": \"$VERSION\",/r releases_patch.tmp" "$TMP_RELEASES_FILE" rm releases_patch.tmp -fi + fi -# send updated file, remove local copy -scp "./$TMP_RELEASES_FILE" "$HOST_LOGIN:$RELEASES_FILE" -rm "./$TMP_RELEASES_FILE" + # send updated file, remove local copy + scp "./$TMP_RELEASES_FILE" "$HOST_LOGIN:$RELEASES_FILE" + rm "./$TMP_RELEASES_FILE" +fi # copy releases to public web directory scp "release/Cassiopée Setup $VERSION.exe" "release/fr.irstea.cassiopee_${VERSION}_amd64.deb" "release/cassiopee-$VERSION.apk" "release/Cassiopée-${VERSION}-mac.zip" "$HOST_LOGIN:$RELEASES_DIR/" # symlink "latest" version for each platform -ssh $HOST_LOGIN /bin/bash << EOF + +if (( $update_latest )); then + echo "updating 'latest' symlinks" + + ssh $HOST_LOGIN /bin/bash << EOF cd "$RELEASES_DIR" ln -sf "Cassiopée Setup $VERSION.exe" "windows-latest.exe" ln -sf "fr.irstea.cassiopee_${VERSION}_amd64.deb" "linux-latest.deb" ln -sf "Cassiopée-${VERSION}-mac.zip" "macos-latest.zip" ln -sf "cassiopee-$VERSION.apk" "android-latest.apk" EOF +fi -- GitLab From c7e4bc5b51eaa06330e25062dfbd8d9df13a101b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 15 Apr 2022 11:34:18 +0200 Subject: [PATCH 40/64] refactor(ci) : rename deployment stages deploy renamed to deploy-dev deploy-stable renamed to deploy-prod refs #505 --- .gitlab-ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 76965e220..c2c4534eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,8 +4,8 @@ stages: - test - build - clean-stale-branches - - deploy - - deploy-stable + - deploy-dev + - deploy-prod - releases-nightly - releases-version @@ -93,8 +93,8 @@ clean-stale-branches: script: - ./scripts/remove-stale-branches.sh $DEPLOY_HOST_LOGIN $DEPLOY_URL -deploy: - stage: deploy +deploy-dev: + stage: deploy-dev only: - pushes - tags @@ -105,8 +105,8 @@ deploy: # Copie de la branche / du tag - rsync --delete -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_URL/$CI_COMMIT_REF_NAME" -deploy-stable: - stage: deploy-stable +deploy-prod: + stage: deploy-prod only: variables: - $CI_COMMIT_REF_NAME == "stable" -- GitLab From b0f4433859edb27b4c728412cb3b1a78fc14d899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 15 Apr 2022 11:35:40 +0200 Subject: [PATCH 41/64] refactor(ci) : release-version.sh : split arguments login@server argument split to separate login and server refs #505 --- scripts/release-version.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/release-version.sh b/scripts/release-version.sh index 83398a209..c17a7d311 100755 --- a/scripts/release-version.sh +++ b/scripts/release-version.sh @@ -1,20 +1,22 @@ #!/bin/bash # Fabrique les exécutables electron/cordova pour une version de Cassiopée $1, les -# distribue sur le serveur $2 dans le dossier $3, et met à jour le fichier releases.json +# distribue sur le serveur $2@$3 dans le dossier $4, et met à jour le fichier releases.json # et les liens symboliques si la version n'est pas nightly -if [ "$#" -lt 3 ]; then - echo "usage: $0 <X.Y.Z|nightly> <login@server> <releases dir>" +if [ "$#" -lt 4 ]; then + echo "usage: $0 <X.Y.Z|nightly> <login> <server> <releases dir>" exit 1 fi VERSION="$1" -HOST_LOGIN="$2" -RELEASES_DIR="$3" +LOGIN="$2" +HOST="$3" +RELEASES_DIR="$4" # RELEASES_DIR="/tmp/cassiopee-releases" # debug RELEASES_FILE="$RELEASES_DIR/releases.json" TMP_RELEASES_FILE="tmp-releases.json" +HOST_LOGIN=$LOGIN@$HOST # update flag for releases file/symlinks update_latest=1 -- GitLab From 7978fd22ac489a489ef0b5bed9f54b4f3078ee6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 15 Apr 2022 11:57:32 +0200 Subject: [PATCH 42/64] refactor(ci) : .gitlab-ci.yml : use DEV_xx/PROD_xx variables from Gitlab CI/CD environment refs #505 --- .gitlab-ci.yml | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2c4534eb..196f45238 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,13 +10,20 @@ stages: - releases-version variables: +# from Gitlab CI/CD environment variables : +# - development server : +# DEV_HOST : deployment server hostname +# DEV_LOGIN : user on deployment server +# DEV_PATH : path base on deployment server +# - production server : +# PROD_HOST : deployment server hostname +# PROD_LOGIN : user on deployment server +# PROD_PASS : password for user on deployment server +# PROD_PATH : path base on deployment server LC_ALL: C.UTF-8 ANDROID_HOME: "/usr/local/android-sdk" # should already be defined in the Docker image ANDROID_SDK_ROOT: "/usr/local/android-sdk" # should already be defined in the Docker image - DEPLOY_HOST_LOGIN: "nghyd@aubes" - DEPLOY_URL: "/var/www/html/cassiopee" - DEPLOY_STABLE_URL: "/var/www/cassiopee-production" - RELEASES_URL: "$DEPLOY_STABLE_URL/cassiopee-releases" + RELEASES_PATH: "$PROD_PATH/cassiopee-releases" before_script: # load private key from GitLab CI variable, to deploy on Aubes server @@ -91,7 +98,7 @@ clean-stale-branches: - tags - web script: - - ./scripts/remove-stale-branches.sh $DEPLOY_HOST_LOGIN $DEPLOY_URL + - ./scripts/remove-stale-branches.sh $DEV_LOGIN@$DEV_HOST $DEV_PATH deploy-dev: stage: deploy-dev @@ -103,7 +110,7 @@ deploy-dev: - build script: # Copie de la branche / du tag - - rsync --delete -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_URL/$CI_COMMIT_REF_NAME" + - rsync --delete -a "dist/" "$DEV_LOGIN@$DEV_HOST:$DEV_PATH/$CI_COMMIT_REF_NAME" deploy-prod: stage: deploy-prod @@ -114,9 +121,9 @@ deploy-prod: - build script: # Copie de la branche production - - rsync --delete -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_STABLE_URL/" + - rsync --delete -a "dist/" "$PROD_LOGIN@$PROD_HOST:$PROD_PATH/" # Modification du dossier base href - - ssh $DEPLOY_HOST_LOGIN "sed -i 's:/cassiopee/stable/:/:g' $DEPLOY_STABLE_URL/index.html" + - ssh $PROD_LOGIN@PROD_HOST "sed -i 's:/cassiopee/stable/:/:g' $PROD_PATH/index.html" releases-nightly: stage: releases-nightly @@ -124,11 +131,7 @@ releases-nightly: - schedules dependencies: [] script: - - npm run release-all - - find release -name "fr.irstea.cassiopee_*.deb" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/linux-nightly.deb \; - - find release -name "Cassio*Setup*.exe" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/windows-nightly.exe \; - - find release -name "Cassio*-mac.zip" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/macos-nightly.zip \; - - find release -name "cassiopee-*.apk" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/android-nightly.apk \; + - ./scripts/release-version.sh nightly $PROD_LOGIN $PROD_HOST $RELEASES_PATH releases-version: stage: releases-version @@ -137,4 +140,4 @@ releases-version: - $CI_COMMIT_REF_NAME =~ /^[0-9]+\.[0-9]+\.[0-9]+$/ # version tag dependencies: [] script: - - ./scripts/release-version.sh $CI_COMMIT_REF_NAME $DEPLOY_HOST_LOGIN $RELEASES_URL + - ./scripts/release-version.sh $CI_COMMIT_REF_NAME $PROD_LOGIN $PROD_HOST $RELEASES_PATH -- GitLab From b8992d46b0350f7b92e754416f814f31e9cf2d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 19 Apr 2022 13:26:37 +0200 Subject: [PATCH 43/64] refactor(ci): add deploy-version.sh helper script refs #505 --- .gitlab-ci.yml | 15 +++++++++------ scripts/deploy-version.sh | 31 +++++++++++++++++++++++++++++++ scripts/release-version.sh | 18 +++++++++++++++--- 3 files changed, 55 insertions(+), 9 deletions(-) create mode 100755 scripts/deploy-version.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 196f45238..ba234b4ef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,9 +26,12 @@ variables: RELEASES_PATH: "$PROD_PATH/cassiopee-releases" before_script: - # load private key from GitLab CI variable, to deploy on Aubes server + # load private key from GitLab CI variable to deploy on Aubes server - eval $(ssh-agent -s) - ssh-add <(echo "$AUBES_B64_AUTHORIZED_SSH_PRIVATE_KEY" | base64 -d) + # load private key from GitLab CI variable to deploy on OVH server + - ssh-add <(echo "$OVH_B64_AUTHORIZED_SSH_PRIVATE_KEY" | base64 -d) + # disable console prompt for host checking - mkdir -p ~/.ssh - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config @@ -110,7 +113,7 @@ deploy-dev: - build script: # Copie de la branche / du tag - - rsync --delete -a "dist/" "$DEV_LOGIN@$DEV_HOST:$DEV_PATH/$CI_COMMIT_REF_NAME" + - ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH deploy-prod: stage: deploy-prod @@ -120,15 +123,15 @@ deploy-prod: dependencies: - build script: - # Copie de la branche production - - rsync --delete -a "dist/" "$PROD_LOGIN@$PROD_HOST:$PROD_PATH/" - # Modification du dossier base href - - ssh $PROD_LOGIN@PROD_HOST "sed -i 's:/cassiopee/stable/:/:g' $PROD_PATH/index.html" + - ./scripts/deploy-version.sh stable $PROD_LOGIN $PROD_HOST $PROD_PATH $PROD_PASS releases-nightly: stage: releases-nightly only: - schedules + except: + # exclude master to apply releases-nightly on devel only + - master dependencies: [] script: - ./scripts/release-version.sh nightly $PROD_LOGIN $PROD_HOST $RELEASES_PATH diff --git a/scripts/deploy-version.sh b/scripts/deploy-version.sh new file mode 100755 index 000000000..59ed40937 --- /dev/null +++ b/scripts/deploy-version.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -o errexit + +# deploie l'appli sur le serveur $3 (user $2/mot de passe $5) dans le dossier $4 et met à jour le fichier index.html +# si la version est "stable" + +if (( $# < 4 || $# > 5 )); then + echo "usage: $0 <version> <login> <server> <path> [<password>]" + exit 1 +fi + +VERSION="$1" +LOGIN="$2" +HOST="$3" +DIR="$4" +PASS="$5" + +echo "$(basename $0): deploying version $VERSION in $LOGIN@$HOST:$DIR" + +if [[ $VERSION == "stable" ]]; then + # Copie de la branche production + rsync -a --delete --exclude=cassiopee-releases -e "ssh -o StrictHostKeyChecking=no" dist/ ${LOGIN}@${HOST}:${DIR}/ + + # Modification du dossier base href + echo "updating index.html" + ssh $LOGIN@$HOST "sed -i 's:/cassiopee/stable/:/:g' $DIR/index.html" +else + # Copie de la branche / du tag + rsync -a --delete --exclude=cassiopee-releases -e "ssh -o StrictHostKeyChecking=no" "dist/" "$LOGIN@$HOST:$DIR/$VERSION" +fi diff --git a/scripts/release-version.sh b/scripts/release-version.sh index c17a7d311..1f810669e 100755 --- a/scripts/release-version.sh +++ b/scripts/release-version.sh @@ -1,10 +1,14 @@ #!/bin/bash +set -o errexit + # Fabrique les exécutables electron/cordova pour une version de Cassiopée $1, les # distribue sur le serveur $2@$3 dans le dossier $4, et met à jour le fichier releases.json # et les liens symboliques si la version n'est pas nightly -if [ "$#" -lt 4 ]; then +echo "args $@" + +if (( $# < 4 )); then echo "usage: $0 <X.Y.Z|nightly> <login> <server> <releases dir>" exit 1 fi @@ -24,7 +28,7 @@ if [[ $VERSION == "nightly" ]]; then update_latest=0 fi -echo "deploy-version.sh: building release for version $VERSION, deploying in $HOST_LOGIN:$RELEASES_DIR" +echo "release-version.sh: building release for version $VERSION, deploying in $HOST_LOGIN:$RELEASES_DIR" # build releases npm run release-all @@ -59,7 +63,15 @@ if (( $update_latest )); then fi # copy releases to public web directory -scp "release/Cassiopée Setup $VERSION.exe" "release/fr.irstea.cassiopee_${VERSION}_amd64.deb" "release/cassiopee-$VERSION.apk" "release/Cassiopée-${VERSION}-mac.zip" "$HOST_LOGIN:$RELEASES_DIR/" +ssh $HOST_LOGIN mkdir -p $RELEASES_DIR +if [[ $VERSION == nightly ]]; then + find release -name "fr.irstea.cassiopee_*.deb" -exec scp "{}" $HOST_LOGIN:$RELEASES_DIR/linux-nightly.deb \; + find release -name "Cassio*Setup*.exe" -exec scp "{}" $HOST_LOGIN:$RELEASES_DIR/windows-nightly.exe \; + find release -name "Cassio*-mac.zip" -exec scp "{}" $HOST_LOGIN:$RELEASES_DIR/macos-nightly.zip \; + find release -name "cassiopee-*.apk" -exec scp "{}" $HOST_LOGIN:$RELEASES_DIR/android-nightly.apk \; +else + scp "release/Cassiopée Setup $VERSION.exe" "release/fr.irstea.cassiopee_${VERSION}_amd64.deb" "release/cassiopee-$VERSION.apk" "release/Cassiopée-${VERSION}-mac.zip" "$HOST_LOGIN:$RELEASES_DIR/" +fi # symlink "latest" version for each platform -- GitLab From 60b4dee61dcbbd54da97279a8800aed70002f1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 14 Apr 2022 15:59:26 +0200 Subject: [PATCH 44/64] fix: missing help for some discharge laws refs #529 --- src/app/calculators/cloisons/config.json | 18 +++++----- .../calculators/parallelstructure/config.json | 10 +++--- src/app/calculators/prebarrage/config.json | 34 ++++++++++--------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/app/calculators/cloisons/config.json b/src/app/calculators/cloisons/config.json index 328ffe061..82ccf331e 100644 --- a/src/app/calculators/cloisons/config.json +++ b/src/app/calculators/cloisons/config.json @@ -31,14 +31,14 @@ "property": "loiDebit", "source": "device_loi_debit", "help": { - "Orifice_OrificeSubmerged": "structures/orifice_noye.html", - "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html", - "SeuilRectangulaire_WeirSubmergedLarinier": "structures/fente_noyee.html", - "SeuilRectangulaire_WeirCunge80": "structures/cunge_80.html", - "VanneRectangulaire_GateCunge80": "structures/cunge_80.html", - "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html", - "SeuilTriangulaire_TriangularWeirBroad": "structures/dever_triang.html", - "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html" + "OrificeSubmerged": "structures/orifice_noye.html", + "WeirSubmergedLarinier": "structures/fente_noyee.html", + "WeirVillemonte": "structures/kivi.html", + "WeirCem88d": "structures/cem_88_d.html", + "TriangularWeirFree": "structures/dever_triang.html", + "TriangularWeirBroad": "structures/dever_triang.html", + "TriangularTruncWeirFree": "structures/dever_triang_tronque.html", + "GateCem88d": "structures/cem_88_d.html" } }, "h1", @@ -68,4 +68,4 @@ "selectIds": [ "select_structure", "select_loidebit" ], "help": "pab/cloisons.html" } -] \ No newline at end of file +] diff --git a/src/app/calculators/parallelstructure/config.json b/src/app/calculators/parallelstructure/config.json index f46051f9d..3ac1aef2c 100644 --- a/src/app/calculators/parallelstructure/config.json +++ b/src/app/calculators/parallelstructure/config.json @@ -36,14 +36,16 @@ "GateCem88d": "structures/cem_88_d.html", "GateCem88v": "structures/cem_88_v.html", "GateCunge80": "structures/cunge_80.html", - "OrificeSubmerged": "structures/noye.html", - "OrificeFree": "structures/denoye.html", + "OrificeSubmerged": "structures/orifice_noye.html", + "OrificeFree": "structures/orifice_denoye.html", "WeirSubmergedLarinier": "structures/fente_noyee.html", "WeirSubmerged": "structures/seuil_noye.html", "WeirFree": "structures/seuil_denoye.html", "TriangularWeirFree": "structures/dever_triang.html", "TriangularWeirBroad": "structures/dever_triang.html", - "TriangularTruncWeirFree": "structures/dever_triang_tronque.html" + "TriangularTruncWeirFree": "structures/dever_triang_tronque.html", + "RectangularOrificeFree": "structures/vanne_denoyee.html", + "RectangularOrificeSubmerged": "structures/vanne_noyee.html" } }, "S", @@ -82,4 +84,4 @@ "ENUM_StructureJetType": "structures/lois_ouvrages.html#type-de-jet" } } -] \ No newline at end of file +] diff --git a/src/app/calculators/prebarrage/config.json b/src/app/calculators/prebarrage/config.json index f97c4921f..3474300cd 100644 --- a/src/app/calculators/prebarrage/config.json +++ b/src/app/calculators/prebarrage/config.json @@ -63,22 +63,24 @@ "property": "loiDebit", "source": "device_loi_debit", "help": { - "SeuilRectangulaire_KIVI": "structures/kivi.html", - "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html", - "SeuilRectangulaire_WeirCem88d": "structures/cem_88_d.html", - "SeuilRectangulaire_WeirCem88v": "structures/cem_88_v.html", - "SeuilRectangulaire_WeirCunge80": "structures/cunge_80.html", - "VanneRectangulaire_GateCem88d": "structures/cem_88_d.html", - "VanneRectangulaire_GateCem88v": "structures/cem_88_v.html", - "VanneRectangulaire_GateCunge80": "structures/cunge_80.html", - "Orifice_OrificeSubmerged": "structures/orifice_noye.html", - "Orifice_OrificeFree": "structures/orifice_denoye.html", - "SeuilRectangulaire_WeirSubmergedLarinier": "structures/fente_noyee.html", - "SeuilRectangulaire_WeirSubmerged": "structures/seuil_noye.html", - "SeuilRectangulaire_WeirFree": "structures/seuil_denoye.html", - "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html", - "SeuilTriangulaire_TriangularWeirBroad": "structures/dever_triang.html", - "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html" + "KIVI": "structures/kivi.html", + "WeirVillemonte": "structures/kivi.html", + "WeirCem88d": "structures/cem_88_d.html", + "WeirCem88v": "structures/cem_88_v.html", + "WeirCunge80": "structures/cunge_80.html", + "GateCem88d": "structures/cem_88_d.html", + "GateCem88v": "structures/cem_88_v.html", + "GateCunge80": "structures/cunge_80.html", + "OrificeSubmerged": "structures/orifice_noye.html", + "OrificeFree": "structures/orifice_denoye.html", + "WeirSubmergedLarinier": "structures/fente_noyee.html", + "WeirSubmerged": "structures/seuil_noye.html", + "WeirFree": "structures/seuil_denoye.html", + "TriangularWeirFree": "structures/dever_triang.html", + "TriangularWeirBroad": "structures/dever_triang.html", + "TriangularTruncWeirFree": "structures/dever_triang_tronque.html", + "RectangularOrificeFree": "structures/vanne_denoyee.html", + "RectangularOrificeSubmerged": "structures/vanne_noyee.html" } }, { -- GitLab From 6ea6c6182d365203b53f7540209414a1cb788dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 21 Apr 2022 14:14:01 +0200 Subject: [PATCH 45/64] test: check that fields of loaded examples are not empty when 'empty fields on calculator creation' is enabled refs #530 --- e2e/examples-empty-fields.e2e-spec.ts | 61 +++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 e2e/examples-empty-fields.e2e-spec.ts diff --git a/e2e/examples-empty-fields.e2e-spec.ts b/e2e/examples-empty-fields.e2e-spec.ts new file mode 100644 index 000000000..573012930 --- /dev/null +++ b/e2e/examples-empty-fields.e2e-spec.ts @@ -0,0 +1,61 @@ +import { browser, by, element } from "protractor"; +import { CalculatorPage } from "./calculator.po"; +import { ListPage } from "./list.po"; +import { Navbar } from "./navbar.po"; +import { PreferencesPage } from "./preferences.po" + +/** + * check that fields are empty on creation + */ +describe("ngHyd - Check that examples fields are not empty with 'empty fields on calculator creation' is enabled - ", () => { + let prefPage: PreferencesPage; + let navBar: Navbar; + let calcPage: CalculatorPage; + + beforeEach(async () => { + prefPage = new PreferencesPage(); + navBar = new Navbar(); + calcPage = new CalculatorPage(); + + // enable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); + }); + + /** + * check that a input set is in a given (empty/filled) state + * @param inputIds id of the inputs to check + * @param emptys empty/not empty state array + */ + async function checkFields(inputIds: string[], emptys: boolean[]) { + let n = 0; + for (const id of inputIds) { + const inp = await calcPage.getInputById(id); + const txt = await inp.getAttribute("value"); + expect(txt === "").toEqual(emptys[n]); + n++; + } + } + + it("when a standard fish ladder calculator is created", async () => { + // start page + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open 1st example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[0].click(); + await browser.sleep(50); + + // select wall module + await navBar.openNthCalculator(4); + await browser.sleep(50); + + // check fields are not empty + const inputIds = ["Z1", "LB", "PB", "0_L", "0_CdWSL"]; + const emptys = [false, false, false, false, false]; + await checkFields(inputIds, emptys); + }); +}); -- GitLab From d8504a8a541589f51d496c1cdd7ea1379e32a41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 21 Apr 2022 16:23:13 +0200 Subject: [PATCH 46/64] fix: empty fields on session loading when 'empty fields on calculator creation' option is enabled refs #530 --- src/app/formulaire/elements/fieldset.ts | 11 +++++------ src/app/formulaire/elements/formulaire-node.ts | 2 +- src/app/services/formulaire.service.ts | 9 +++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index cf23d79c9..e5a9ca15a 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -400,9 +400,6 @@ export class FieldSet extends FormulaireElement implements Observer { } } else { if (this.parentForm instanceof FormulaireFixedVar) { - // backup parameters - const oldParams = this.backupParameters(); - // for all select fields known by the form, apply received value // to associated property const selectIds = this.parentForm.selectids; @@ -421,11 +418,13 @@ export class FieldSet extends FormulaireElement implements Observer { } } } - - // restore parameters - this.restoreParameters(oldParams, FormulaireNode.NeverEmptyFields); } } + + if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { + const f = this.parentForm; + f.emptyFields(); + } break; // switch (data.action) } } diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index 4ce064883..0ab8a88df 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -156,7 +156,7 @@ export abstract class FormulaireNode implements IObservable { if (p instanceof NgParameter) { if ( [ParamValueMode.SINGLE, ParamValueMode.CALCUL].includes(p.valueMode) - && !except.includes(p.id) + && !except.includes(p.id) && !p.isValueModified ) { if (p.valueMode === ParamValueMode.CALCUL) { calcP = p; diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts index 5d3910bbf..1bfdbe14f 100644 --- a/src/app/services/formulaire.service.ts +++ b/src/app/services/formulaire.service.ts @@ -50,6 +50,7 @@ import { FormulairePAR } from "../formulaire/definition/form-par"; import { FormulaireVerificateur } from "../formulaire/definition/form-verificateur"; import { FormulaireEspece } from "../formulaire/definition/form-espece"; import { FormulairePrebarrage } from "../formulaire/definition/form-prebarrage"; +import { ServiceFactory } from "./service-factory"; @Injectable() export class FormulaireService extends Observable { @@ -628,6 +629,10 @@ export class FormulaireService extends Observable { */ public async loadSession(f: File, formInfos: any[] = []): Promise<{ hasErrors: boolean, loaded: string[] }> { try { + // disable "empty fields" flag temporarly + const emptyFields = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit; + ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit = false; + const s = await this.readSingleFile(f); const uids: string[] = []; formInfos.forEach((fi) => { @@ -646,6 +651,10 @@ export class FormulaireService extends Observable { } await this.createFormulaire(nn.nub.calcType, nn.nub, title); // await guarantees loading order } + + // restore "empty fields" flag + ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit = emptyFields; + // apply settings if (res.settings) { // model based settings -- GitLab From f635446d25eba4c6a4327d4cf9ace233767ba6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 13 Apr 2022 13:23:21 +0200 Subject: [PATCH 47/64] test: check field 'number of falls' of the 'generate fish ladder' dialog is empty with the 'enable empty fields on new calculators' option refs #516 --- e2e/pab-cloisons-empty-fields.e2e-spec.ts | 83 +++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 e2e/pab-cloisons-empty-fields.e2e-spec.ts diff --git a/e2e/pab-cloisons-empty-fields.e2e-spec.ts b/e2e/pab-cloisons-empty-fields.e2e-spec.ts new file mode 100644 index 000000000..1782869db --- /dev/null +++ b/e2e/pab-cloisons-empty-fields.e2e-spec.ts @@ -0,0 +1,83 @@ +import { ListPage } from "./list.po"; +import { PreferencesPage } from "./preferences.po"; +import { browser, by, element } from "protractor"; +import { CalculatorPage } from "./calculator.po"; +import { AppPage } from "./app.po"; +import { Navbar } from "./navbar.po"; + +/** + * Check that when "empty fields on calculator creation" is enabled + * fields are empty in the "generate fish ladder" dialog of the + * cross walls calculator + */ +describe("ngHyd - check the cross walls calculator has empty fields - ", () => { + let prefPage: PreferencesPage; + let listPage: ListPage; + let calcPage: CalculatorPage; + let navBar: Navbar; + + beforeAll(() => { + prefPage = new PreferencesPage(); + listPage = new ListPage(); + calcPage = new CalculatorPage(); + navBar = new Navbar(); + }); + + beforeEach(async () => { + // enable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); + }); + + /** + * check that a input set is in a given (empty/filled) state + * @param inputIds id of the inputs to check + * @param emptys empty/not empty state array + */ + async function checkFields(inputIds: string[], emptys: boolean[]) { + let n = 0; + for (const id of inputIds) { + const inp = await calcPage.getInputById(id); + const txt = await inp.getAttribute("value"); + expect(txt === "").toEqual(emptys[n]); + n++; + } + } + + async function fillInput(symbol: string) { + const inp = calcPage.getInputById(symbol); + await inp.clear(); + await inp.sendKeys("1"); + } + + it("in the 'generate fish ladder' dialog", async () => { + // open cross walls calculator + await navBar.clickNewCalculatorButton(); + await listPage.clickMenuEntryForCalcType(10); + await browser.sleep(200); + + // fill inputs + await fillInput("Q"); + await fillInput("Z1"); + await fillInput("LB"); + await fillInput("BB"); + await fillInput("PB"); + await fillInput("0_h1"); + await fillInput("0_L"); + await fillInput("0_CdWSL"); + + // calculate + const calcButton = calcPage.getCalculateButton(); + await calcButton.click(); + await browser.sleep(200); + + // click "generate PAB" button + const genButton = calcPage.getGeneratePabButton(); + await genButton.click(); + await browser.sleep(200); + + await checkFields(["generatePabNbBassins"], [true]); + }); +}); -- GitLab From 0ef436f3d20d112bc46de51a781b3f03c5c3b67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 13 Apr 2022 13:26:33 +0200 Subject: [PATCH 48/64] fix: empty field 'number of falls" of 'generate fish ladder' dialog when 'enable empty fields on new calculator' option is set refs #516 --- .../dialog-generate-pab.component.ts | 13 +++++++------ .../generic-calculator/calculator.component.ts | 12 +++++++++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts index 9634a342b..65454306a 100644 --- a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts +++ b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts @@ -29,21 +29,22 @@ export class DialogGeneratePABComponent { @Inject(MAT_DIALOG_DATA) public data: any ) { const nDigits = this.appSetupService.displayPrecision; - this.coteAmont = round(data.coteAmont, nDigits); - this.debit = round(data.debit, nDigits); + this.coteAmont = data.coteAmont ? round(data.coteAmont, nDigits) : undefined; + this.debit = data.debit ? round(data.debit, nDigits) : undefined; this.chute = round(data.chute, nDigits); + this.nbBassins = data.nbBassins; } public generatePAB() { // calculate downstream elevation - const coteAval = this.coteAmont - (this.chute * this.nbBassins); + const coteAval = +this.coteAmont - (this.chute * +this.nbBassins); // create PAB this.dialogRef.close({ generate: true, - debit: this.debit, - coteAmont: this.coteAmont, + debit: +this.debit, + coteAmont: +this.coteAmont, coteAval: coteAval, - nbBassins: this.nbBassins + nbBassins: +this.nbBassins }); } diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 2608ce76e..195796210 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -58,6 +58,7 @@ import { MatomoTracker } from "ngx-matomo"; import { sprintf } from "sprintf-js"; import * as XLSX from "xlsx"; +import { ServiceFactory } from "app/services/service-factory"; @Component({ selector: "hydrocalc", @@ -731,13 +732,18 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe public generatePAB() { // création du dialogue de génération d'une passe à bassin const cloisons = (this._formulaire.currentNub as Cloisons); + const chute = cloisons.prms.DH.V; + const debit = cloisons.prms.Q.V; + const zAmont = cloisons.prms.Z1.V; + const nbBassins = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit ? undefined : 6; const dialogRef = this.generatePABDialog.open( DialogGeneratePABComponent, { data: { - chute: cloisons.prms.DH.V, - debit: cloisons.prms.Q.V, - coteAmont: cloisons.prms.Z1.V + chute: chute, + debit: debit, + coteAmont: zAmont, + nbBassins: nbBassins }, disableClose: false } -- GitLab From 32e89a7a30f12fead5682a08ae115ce78df8b6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 13 Apr 2022 14:50:42 +0200 Subject: [PATCH 49/64] refactor: move downstream elevation calculation to GenericCalculatorComponent refs #516 --- .../dialog-generate-pab.component.ts | 6 - .../calculator.component.ts | 122 +++++++++--------- 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts index 65454306a..202aa1fd8 100644 --- a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts +++ b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts @@ -18,8 +18,6 @@ export class DialogGeneratePABComponent { public coteAmont = 102; - public chute: number; - public nbBassins = 6; constructor( @@ -31,19 +29,15 @@ export class DialogGeneratePABComponent { const nDigits = this.appSetupService.displayPrecision; this.coteAmont = data.coteAmont ? round(data.coteAmont, nDigits) : undefined; this.debit = data.debit ? round(data.debit, nDigits) : undefined; - this.chute = round(data.chute, nDigits); this.nbBassins = data.nbBassins; } public generatePAB() { - // calculate downstream elevation - const coteAval = +this.coteAmont - (this.chute * +this.nbBassins); // create PAB this.dialogRef.close({ generate: true, debit: +this.debit, coteAmont: +this.coteAmont, - coteAval: coteAval, nbBassins: +this.nbBassins }); } diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 195796210..9650543c6 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -1,5 +1,7 @@ -import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, - QueryList, AfterViewChecked, ElementRef, Inject, forwardRef, isDevMode } from "@angular/core"; +import { + Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, + QueryList, AfterViewChecked, ElementRef, Inject, forwardRef, isDevMode +} from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { @@ -308,7 +310,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public get quicknavItems() { - const elts = [ "input", "results" ]; + const elts = ["input", "results"]; if (this.isWide && this.hasResults) { elts.push("charts"); } @@ -329,7 +331,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe * the UI validity state) */ ngDoCheck() { - this.isCalculateDisabled = ! this._isUIValid; + this.isCalculateDisabled = !this._isUIValid; } ngOnDestroy() { @@ -363,7 +365,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public ngAfterViewChecked() { - if (! this.firstViewChecked) { + if (!this.firstViewChecked) { this.firstViewChecked = true; this.afterFirstViewChecked(); } @@ -394,7 +396,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public doCompute() { - if (! isDevMode()) { + if (!isDevMode()) { this.matomoTracker.trackEvent("userAction", "triggerCalculation", CalculatorType[this._formulaire.currentNub.calcType]); } this._formulaire.resetResults([]); @@ -445,7 +447,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe try { this.appComponent.scrollToQuicknav("results"); } catch (e) { - const element = document.getElementById ("fake-results-anchor"); + const element = document.getElementById("fake-results-anchor"); if (element) { element.scrollIntoView(); } @@ -472,7 +474,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe */ private updateUIValidity() { this._isUIValid = false; - if (! this._formulaire.calculateDisabled) { + if (!this._formulaire.calculateDisabled) { // all fieldsets must be valid this._isUIValid = true; if (this._fieldsetComponents !== undefined) { @@ -695,14 +697,14 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe private allParamsAreFixed(except: string[] = []) { let ret = true; for (const p of this._formulaire.currentNub.parameterIterator) { - if (! except.includes(p.symbol)) { + if (!except.includes(p.symbol)) { if (p.valueMode === ParamValueMode.LINK) { - ret = ret && (! p.hasMultipleValues); + ret = ret && (!p.hasMultipleValues); } else { // avoid calling hasMultipleValues here, because changing parameter mode in GUI // switches valueMode before setting min/max/step or valuesList, and iterator // checker fails to count values that do not exist yet - ret = ret && (! [ ParamValueMode.LISTE, ParamValueMode.MINMAX ].includes(p.valueMode)); + ret = ret && (![ParamValueMode.LISTE, ParamValueMode.MINMAX].includes(p.valueMode)); } } } @@ -717,10 +719,10 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public get uitextGeneratePabTitle() { - if (! this.hasResults) { + if (!this.hasResults) { return this.intlService.localizeText("INFO_CALCULATE_FIRST"); } - if (! this.allParamsAreFixed()) { + if (!this.allParamsAreFixed()) { return this.intlService.localizeText("INFO_PARAMETRES_FIXES"); } return ""; @@ -737,41 +739,43 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const zAmont = cloisons.prms.Z1.V; const nbBassins = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit ? undefined : 6; const dialogRef = this.generatePABDialog.open( - DialogGeneratePABComponent, - { - data: { - chute: chute, - debit: debit, - coteAmont: zAmont, - nbBassins: nbBassins - }, - disableClose: false - } + DialogGeneratePABComponent, + { + data: { + debit: debit, + coteAmont: zAmont, + nbBassins: nbBassins + }, + disableClose: false + } ); dialogRef.afterClosed().subscribe(async result => { - if (result) { - if (result.generate) { - const f: FormulaireDefinition = await this.formulaireService.createFormulaire(CalculatorType.Pab); - const pab = (f.currentNub as Pab); - const params = pab.prms; - // paramètres hydrauliques - params.Q.singleValue = result.debit; - params.Z1.singleValue = result.coteAmont; - params.Z2.singleValue = result.coteAval; - // création des bassins - pab.deleteChild(0); - pab.addCloisonsFromModel(this._formulaire.currentNub as Cloisons, result.nbBassins); - // go to new PAB - this.router.navigate(["/calculator", f.uid]); + if (result) { + if (result.generate) { + const f: FormulaireDefinition = await this.formulaireService.createFormulaire(CalculatorType.Pab); + const pab = (f.currentNub as Pab); + const params = pab.prms; + // calculate downstream elevation + const chute = cloisons.prms.DH.V; + const coteAval = result.coteAmont - (chute * result.nbBassins); + // paramètres hydrauliques + params.Q.singleValue = result.debit; + params.Z1.singleValue = result.coteAmont; + params.Z2.singleValue = coteAval; + // création des bassins + pab.deleteChild(0); + pab.addCloisonsFromModel(this._formulaire.currentNub as Cloisons, result.nbBassins); + // go to new PAB + this.router.navigate(["/calculator", f.uid]); + } } - } }); } public get generateSPAmontEnabled(): boolean { const bief = (this._formulaire.currentNub as Bief); if (bief.prms.Z1 === bief.calculatedParam) { - return this.hasResults && ! bief.result.hasErrorMessages(); + return this.hasResults && !bief.result.hasErrorMessages(); } else { // check that linked values are available, if any return ( @@ -784,7 +788,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe public get generateSPAvalEnabled(): boolean { const bief = (this._formulaire.currentNub as Bief); if (bief.prms.Z2 === bief.calculatedParam) { - return this.hasResults && ! bief.result.hasErrorMessages(); + return this.hasResults && !bief.result.hasErrorMessages(); } else { // check that linked values are available, if any return ( @@ -795,7 +799,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public get uitextGenerateSPAmontTitle(): string { - if (! this.generateSPAmontEnabled) { + if (!this.generateSPAmontEnabled) { return this.intlService.localizeText("INFO_CALCULATE_FIRST"); } else { return ""; @@ -803,7 +807,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public get uitextGenerateSPAvalTitle(): string { - if (! this.generateSPAvalEnabled) { + if (!this.generateSPAvalEnabled) { return this.intlService.localizeText("INFO_CALCULATE_FIRST"); } else { return ""; @@ -841,7 +845,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const bief = (this._formulaire.currentNub as Bief); return generateValuesCombination( bief, - [ Z, ZF ], + [Z, ZF], (nub: Nub, values: { [key: string]: number }): number => { return round(values[Z.symbol] - values[ZF.symbol], 3); } @@ -855,7 +859,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const bief = (this._formulaire.currentNub as Bief); return generateValuesCombination( bief, - [ bief.prms.ZF1, bief.prms.ZF2, bief.prms.Long ], + [bief.prms.ZF1, bief.prms.ZF2, bief.prms.Long], (nub: Nub, values: { [key: string]: number }): number => { return round((values["ZF1"] - values["ZF2"]) / values["Long"], 5); } @@ -879,7 +883,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe // "If" is hidden in Bief, for ex. bief.section.getParameter(p.symbol).visible // do not link Y and If - && ! [ "If", "Y" ].includes(p.symbol) + && !["If", "Y"].includes(p.symbol) ) { const bP = bief.section.getParameter(p.symbol); if (bP.valueMode === ParamValueMode.LINK) { @@ -901,11 +905,11 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe } public get generateRuSpEnabled(): boolean { - return this.hasResults && ! this._formulaire.currentNub.result.hasErrorMessages(); + return this.hasResults && !this._formulaire.currentNub.result.hasErrorMessages(); } public get uitextGenerateRuSpTitle(): string { - if (! this.generateRuSpEnabled) { + if (!this.generateRuSpEnabled) { return this.intlService.localizeText("INFO_CALCULATE_FIRST"); } else { return ""; @@ -941,7 +945,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const parCalage = (this._formulaire.currentNub as Par); return ( this.hasResults - && ! parCalage.result.hasErrorMessages() + && !parCalage.result.hasErrorMessages() && parCalage.prms.Z1.isDefined && parCalage.prms.Z2.isDefined ); @@ -949,12 +953,12 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe public get uitextGenerateParSimulationTitle(): string { const parCalage = (this._formulaire.currentNub as Par); - if (! this.hasResults || parCalage.result.hasErrorMessages()) { + if (!this.hasResults || parCalage.result.hasErrorMessages()) { return this.intlService.localizeText("INFO_CALCULATE_FIRST"); } if ( - ! parCalage.prms.Z1.isDefined - || ! parCalage.prms.Z2.isDefined + !parCalage.prms.Z1.isDefined + || !parCalage.prms.Z2.isDefined ) { return this.intlService.localizeText("INFO_Z1_Z2_MUST_BE_DEFINED"); } @@ -1031,7 +1035,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe public get exportAllPbResultsEnabled(): boolean { const pb = (this._formulaire as FormulairePrebarrage).currentNub as PreBarrage; - return (pb.result !== undefined && ! pb.result.hasOnlyErrors); + return (pb.result !== undefined && !pb.result.hasOnlyErrors); } /** @@ -1169,11 +1173,11 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe protected async doGenerateParSimWithValues(v: any) { const parCalage = (this._formulaire.currentNub as Par); const psim = new ParSimulationParams( - round(v.Q, 3), round(v.Z1, 3), round(v.Z2, 3), - round(v.S, 3), round(v.P, 3), round(v.Nb, 3), - round(v.ZR1, 3), round(v.ZD1, 3), round(v.ZR2, 3), - round(v.ZD2, 3), round(v.L, 3), round(v.a, 3), - round(v.N, 3), round(v.M, 3) + round(v.Q, 3), round(v.Z1, 3), round(v.Z2, 3), + round(v.S, 3), round(v.P, 3), round(v.Nb, 3), + round(v.ZR1, 3), round(v.ZD1, 3), round(v.ZR2, 3), + round(v.ZD2, 3), round(v.L, 3), round(v.a, 3), + round(v.N, 3), round(v.M, 3) ); const parSimulation = new ParSimulation(psim); parSimulation.parType = parCalage.parType; @@ -1194,7 +1198,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const dialogRef = this.loadPredefinedEspeceDialog.open( DialogLoadPredefinedEspeceComponent, { - data: { }, + data: {}, disableClose: false } ); @@ -1217,7 +1221,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe DialogConfirmCloseCalcComponent, { data: { - uid: this._formulaire.currentNub.uid + uid: this._formulaire.currentNub.uid }, disableClose: true } -- GitLab From 6e8c21d1b87bb3a0a5d3a5f34c9d0014f7435583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 22 Apr 2022 09:57:49 +0200 Subject: [PATCH 50/64] fix(e2e): failing test "calcul de tous les modules de tous les exemples" add sleep()s refs #531 --- e2e/calc-all-examples.e2e-spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/calc-all-examples.e2e-spec.ts b/e2e/calc-all-examples.e2e-spec.ts index 4dae4b1dd..5d5bcf7de 100644 --- a/e2e/calc-all-examples.e2e-spec.ts +++ b/e2e/calc-all-examples.e2e-spec.ts @@ -45,10 +45,11 @@ describe("ngHyd − example sessions −", async () => { await navbar.clickMenuButton(); await browser.sleep(200); await sideNav.clickNewSessionButton(); - await browser.sleep(200); + await browser.sleep(1000); } const examples = await element.all(by.css("#examples-list .load-example")); + await browser.sleep(200); if (examples.length > i) { // click example #i await examples[i].click(); -- GitLab From 4c6a01849c26c592f9a12152b54262d008dda73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 25 Apr 2022 12:20:13 +0200 Subject: [PATCH 51/64] fix(ci) : use jalhyd branch name to provide cache key refs #526 --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba234b4ef..2e5f7049a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,10 @@ before_script: - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config cache: + key: + files: + - jalhyd_branch + - package.json paths: - node_modules/ -- GitLab From 16502913f57d7ff1060887441a9f60eaa4f99a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Tue, 26 Apr 2022 08:19:19 +0200 Subject: [PATCH 52/64] test: check cross walls calculator has no empty field after calculation refs #516 --- e2e/pab-cloisons-empty-fields.e2e-spec.ts | 122 +++++++++++++++------- 1 file changed, 87 insertions(+), 35 deletions(-) diff --git a/e2e/pab-cloisons-empty-fields.e2e-spec.ts b/e2e/pab-cloisons-empty-fields.e2e-spec.ts index 1782869db..c7305027a 100644 --- a/e2e/pab-cloisons-empty-fields.e2e-spec.ts +++ b/e2e/pab-cloisons-empty-fields.e2e-spec.ts @@ -5,6 +5,37 @@ import { CalculatorPage } from "./calculator.po"; import { AppPage } from "./app.po"; import { Navbar } from "./navbar.po"; +/** + * enable evil option "empty fields on module creation" + */ +async function enableEmptyFieldsOption(prefPage: PreferencesPage) { + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); +} + +/** + * check that a input set is in a given (empty/filled) state + * @param inputIds id of the inputs to check + * @param emptys empty/not empty state array + */ +async function checkFields(calcPage: CalculatorPage, inputIds: string[], emptys: boolean[]) { + let n = 0; + for (const id of inputIds) { + const inp = await calcPage.getInputById(id); + const txt = await inp.getAttribute("value"); + expect(txt === "").toEqual(emptys[n]); + n++; + } +} + +async function fillInput(calcPage: CalculatorPage, symbol: string) { + const inp = calcPage.getInputById(symbol); + await inp.clear(); + await inp.sendKeys("1"); +} + /** * Check that when "empty fields on calculator creation" is enabled * fields are empty in the "generate fish ladder" dialog of the @@ -24,34 +55,9 @@ describe("ngHyd - check the cross walls calculator has empty fields - ", () => { }); beforeEach(async () => { - // enable evil option "empty fields on module creation" - await prefPage.navigateTo(); - await browser.sleep(200); - await prefPage.enableEvilEmptyFields(); - await browser.sleep(200); + await enableEmptyFieldsOption(prefPage); }); - /** - * check that a input set is in a given (empty/filled) state - * @param inputIds id of the inputs to check - * @param emptys empty/not empty state array - */ - async function checkFields(inputIds: string[], emptys: boolean[]) { - let n = 0; - for (const id of inputIds) { - const inp = await calcPage.getInputById(id); - const txt = await inp.getAttribute("value"); - expect(txt === "").toEqual(emptys[n]); - n++; - } - } - - async function fillInput(symbol: string) { - const inp = calcPage.getInputById(symbol); - await inp.clear(); - await inp.sendKeys("1"); - } - it("in the 'generate fish ladder' dialog", async () => { // open cross walls calculator await navBar.clickNewCalculatorButton(); @@ -59,14 +65,14 @@ describe("ngHyd - check the cross walls calculator has empty fields - ", () => { await browser.sleep(200); // fill inputs - await fillInput("Q"); - await fillInput("Z1"); - await fillInput("LB"); - await fillInput("BB"); - await fillInput("PB"); - await fillInput("0_h1"); - await fillInput("0_L"); - await fillInput("0_CdWSL"); + await fillInput(calcPage, "Q"); + await fillInput(calcPage, "Z1"); + await fillInput(calcPage, "LB"); + await fillInput(calcPage, "BB"); + await fillInput(calcPage, "PB"); + await fillInput(calcPage, "0_h1"); + await fillInput(calcPage, "0_L"); + await fillInput(calcPage, "0_CdWSL"); // calculate const calcButton = calcPage.getCalculateButton(); @@ -78,6 +84,52 @@ describe("ngHyd - check the cross walls calculator has empty fields - ", () => { await genButton.click(); await browser.sleep(200); - await checkFields(["generatePabNbBassins"], [true]); + await checkFields(calcPage, ["generatePabNbBassins"], [true]); + }); +}); + +/** + * Check that when "empty fields on calculator creation" is enabled + * fields are not empty after calculation + */ +describe("ngHyd - check the cross walls calculator has no empty field - ", () => { + let prefPage: PreferencesPage; + let listPage: ListPage; + let calcPage: CalculatorPage; + let navBar: Navbar; + + beforeAll(() => { + prefPage = new PreferencesPage(); + listPage = new ListPage(); + calcPage = new CalculatorPage(); + navBar = new Navbar(); + }); + + beforeEach(async () => { + await enableEmptyFieldsOption(prefPage); + }); + + it("after calculation", async () => { + // open cross walls calculator + await navBar.clickNewCalculatorButton(); + await listPage.clickMenuEntryForCalcType(10); + await browser.sleep(200); + + // fill inputs + await fillInput(calcPage, "Q"); + await fillInput(calcPage, "Z1"); + await fillInput(calcPage, "LB"); + await fillInput(calcPage, "BB"); + await fillInput(calcPage, "PB"); + await fillInput(calcPage, "0_h1"); + await fillInput(calcPage, "0_L"); + await fillInput(calcPage, "0_CdWSL"); + + // calculate + const calcButton = calcPage.getCalculateButton(); + await calcButton.click(); + await browser.sleep(200); + + await checkFields(calcPage, ["Q", "Z1", "LB", "BB", "PB", "0_h1", "0_L", "0_CdWSL"], [false, false, false, false, false, false, false, false]); }); }); -- GitLab From 4e39f6945f2c302271d32a6a054ff0b6d343c90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 28 Apr 2022 15:01:35 +0200 Subject: [PATCH 53/64] refactor: move empty fields management to jalhyd refs #516 --- jalhyd_branch | 2 +- .../base-param-input.component.ts | 2 +- .../calculator-list.component.ts | 4 --- .../pb-schema/pb-schema.component.ts | 25 --------------- .../formulaire/definition/form-prebarrage.ts | 15 --------- src/app/formulaire/definition/form-section.ts | 5 --- src/app/formulaire/elements/fieldset.ts | 18 ++--------- .../formulaire/elements/formulaire-node.ts | 31 ------------------- src/app/services/app-setup.service.ts | 12 ++++++- 9 files changed, 15 insertions(+), 99 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index 626e97d71..f6d80c358 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -devel \ No newline at end of file +306-gerer-un-flag-modified-dans-paramdefinition \ No newline at end of file diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts index 25573571b..883fa0772 100644 --- a/src/app/components/base-param-input/base-param-input.component.ts +++ b/src/app/components/base-param-input/base-param-input.component.ts @@ -15,7 +15,7 @@ export class NgBaseParam extends Observable { constructor(symb: string, d: ParamDomain | ParamDomainValue, val: number, unit?: string) { super(); - this._param = new ParamDefinition(null, symb, d, unit, val); + this._param = new ParamDefinition(null, symb, d, unit, val, undefined, undefined, false); } public get param() { diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts index fcc96d90f..cd37dad30 100644 --- a/src/app/components/calculator-list/calculator-list.component.ts +++ b/src/app/components/calculator-list/calculator-list.component.ts @@ -181,10 +181,6 @@ export class CalculatorListComponent implements OnInit { } } } - - if (this.appSetupService.enableEmptyFieldsOnFormInit) { - f.emptyFields(); - } } public get nbOpenCalculators() { diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index e1e74c9e6..1862a8dcf 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -492,35 +492,10 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni return this.i18nService.localizeText("INFO_FIELDSET_COPY"); } - /** - * Set value of all single parameters to undefined, except for the given parameter ids - */ - private emptyFields(basin: PbBassin, except: string[] = FormulaireNode.NeverEmptyFields) { - // save current calculated param, as setting value on a CALC param will - // change its mode and choose another calculated param by default - let calcP: ParamDefinition; - for (const p of basin.parameterIterator) { - if ( - [ParamValueMode.SINGLE, ParamValueMode.CALCUL].includes(p.valueMode) - && !except.includes(p.symbol) - ) { - if (p.valueMode === ParamValueMode.CALCUL) { - calcP = p; - } - p.setValue(undefined); - } - } - // restore original calculated param - if (calcP !== undefined) { - calcP.setCalculated(); - } - } - /** Adds a new lone basin */ public onAddBasinClick() { const newBasin = new PbBassin(new PbBassinParams(20, 99)); this.model.addChild(newBasin); - this.emptyFields(newBasin); this.clearResults(); this.refreshWithSelection(newBasin.uid); this.calculatorComponent.showPBInputData = true; diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts index ebe3ea8ff..811007d2c 100644 --- a/src/app/formulaire/definition/form-prebarrage.ts +++ b/src/app/formulaire/definition/form-prebarrage.ts @@ -322,21 +322,6 @@ export class FormulairePrebarrage extends FormulaireFixedVar { } } - /** - * Set value of all single parameters to undefined, except for the given parameter ids - */ - public emptyFields(except: string[] = FormulaireNode.NeverEmptyFields) { - // save current calculated param, as setting value on a CALC param will - // change its mode and choose another calculated param by default - const paramCalculated = this.currentNub.calculatedParam; - for (const p of this.currentNub.parameterIterator) { - if (! except.includes(p.symbol)) { - p.setValue(undefined); - } - } - this.currentNub.calculatedParam = paramCalculated; - } - /** * Check validity of all model parameters * @param withChildren check parameters of child nub as well diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts index fd45ceb50..c408e572a 100644 --- a/src/app/formulaire/definition/form-section.ts +++ b/src/app/formulaire/definition/form-section.ts @@ -20,11 +20,6 @@ export class FormulaireSection extends FormulaireFixedVar { } // show / hide dependent fields this.refreshFieldsets(); - // empty fields ? only those belonging to the specific section type - if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { - // "LargeurBerge" is hackily used as LargeurFond in Rectangular and Trapez sections, omit it here - this.emptyFields([ "Ks", "Q", "If", "YB", "iPrec", "Y" ]); - } this.reset(); } } diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index e5a9ca15a..4081f8241 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -73,23 +73,13 @@ export class FieldSet extends FormulaireElement implements Observer { * @param backup list of NgParameter object representation * @see backupParameters */ - public restoreParameters(backup: any[], except: string[] = FormulaireNode.NeverEmptyFields) { + public restoreParameters(backup: any[]) { // for (const p of this.allFormElements) { for (const p of this._kids) { if (p instanceof NgParameter) { for (const bp of backup) { if (p.symbol === bp.prmDef.symbol) { - // if source parameter has been user modified, copy value - if (bp.modified) { - p.loadObjectRepresentation(bp); - } - else { - // can parameter be emptied ? - if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit && !except.includes(bp.prmDef.symbol)) { - p.resetValue(this, undefined); - } - // else let parameter to default value - } + p.loadObjectRepresentation(bp); break; } } @@ -421,10 +411,6 @@ export class FieldSet extends FormulaireElement implements Observer { } } - if (ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit) { - const f = this.parentForm; - f.emptyFields(); - } break; // switch (data.action) } } diff --git a/src/app/formulaire/elements/formulaire-node.ts b/src/app/formulaire/elements/formulaire-node.ts index 0ab8a88df..b57bec770 100644 --- a/src/app/formulaire/elements/formulaire-node.ts +++ b/src/app/formulaire/elements/formulaire-node.ts @@ -9,11 +9,6 @@ import { NgParameter } from "./ngparam"; */ export abstract class FormulaireNode implements IObservable { - /** - * fields in fieldset that must not be empty due to enableEmptyFieldsOnFormInit option - */ - public static readonly NeverEmptyFields = ["Cd0", "CdWS", "CdGR", "CdGRS", "CdCunge", "CdWR", "CdO", "CdT"]; - /** aide en ligne */ protected _helpLink: string; @@ -145,32 +140,6 @@ export abstract class FormulaireNode implements IObservable { return new DeepFormulaireElementIterator(this); } - /** - * Set value of all single parameters to undefined, except for the given parameter ids - */ - public emptyFields(except: string[] = FormulaireNode.NeverEmptyFields) { - // save current calculated param, as setting value on a CALC param will - // change its mode and choose another calculated param by default - let calcP: NgParameter; - for (const p of this.allFormElements) { - if (p instanceof NgParameter) { - if ( - [ParamValueMode.SINGLE, ParamValueMode.CALCUL].includes(p.valueMode) - && !except.includes(p.id) && !p.isValueModified - ) { - if (p.valueMode === ParamValueMode.CALCUL) { - calcP = p; - } - p.resetValue(this, undefined); - } - } - } - // restore original calculated param - if (calcP !== undefined) { - calcP.setCalculated(); - } - } - /** * notifie un événement aux observateurs */ diff --git a/src/app/services/app-setup.service.ts b/src/app/services/app-setup.service.ts index d1f01b2af..193b32aaf 100644 --- a/src/app/services/app-setup.service.ts +++ b/src/app/services/app-setup.service.ts @@ -24,7 +24,6 @@ export class ApplicationSetupService extends Observable { private _maxIterations = 100; // tied to model public enableNotifications = true; public enableHotkeys = false; - public enableEmptyFieldsOnFormInit = true; public set computePrecision(p: number) { this._computePrecision = p; @@ -46,6 +45,14 @@ export class ApplicationSetupService extends Observable { return this._maxIterations; } + public get enableEmptyFieldsOnFormInit() { + return !SessionSettings.useDefaultParamValue; + } + + public set enableEmptyFieldsOnFormInit(b: boolean) { + SessionSettings.useDefaultParamValue = !b; + } + /** * just stores the current language preference, does not transmit it to I18nService, that is * not available here. @@ -71,6 +78,9 @@ export class ApplicationSetupService extends Observable { // related to @HostListener("window:beforeunload") in AppComponent this.warnBeforeTabClose = true; + // by default, create empty fields for new calculators + this.enableEmptyFieldsOnFormInit = true; + // load JSON config this.readValuesFromConfig().then((data) => { const configLanguage = this.language; -- GitLab From c04b030825e18123377a1a5c2b8c1c2cd9e4e89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 28 Apr 2022 15:03:52 +0200 Subject: [PATCH 54/64] refactor: remove unused NgParam "modified" flag refs #516 --- .../generic-input/generic-input.component.ts | 7 +--- src/app/formulaire/elements/ngparam.ts | 33 ------------------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts index 5b31ee4e8..3dc390d50 100644 --- a/src/app/components/generic-input/generic-input.component.ts +++ b/src/app/components/generic-input/generic-input.component.ts @@ -263,12 +263,7 @@ export abstract class GenericInputComponentDirective implements OnChanges { if (valid && this._uiValue !== "") { val = +this._uiValue; // cast UI value to Number } - if (this.setAndValidateModel(this, val)) { - // set parameter "modified" flag - if (this._model instanceof NgParameter) { - this._model.isValueModified = true; - } - } + this.setAndValidateModel(this, val); } } diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index 59c4e188f..43d7cb298 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -38,9 +38,6 @@ export class NgParameter extends InputField implements Observer { public disabled: boolean; - /** true if value has been modified by user */ - private _isValueModified = false; - constructor(private _paramDef: ParamDefinition, parent: FormulaireNode) { super(parent); this.radioConfig = this.radioState; @@ -284,14 +281,6 @@ export class NgParameter extends InputField implements Observer { return this._paramDef.valuesIterator; } - public get isValueModified(): boolean { - return this._isValueModified; - } - - public set isValueModified(b: boolean) { - this._isValueModified = b; - } - /** * Reads radio config from parameter calculability */ @@ -404,18 +393,6 @@ export class NgParameter extends InputField implements Observer { ); } - /** - * fixe la valeur du paramètre en tant que valeur par défaut - */ - public resetValue(sender: any, val: number) { - const changed = (this._paramDef.getValue() !== val); - this._isValueModified = false; - if (changed) { - this._paramDef.setValue(val, sender); - this.notifyValueModified(sender); - } - } - /** * fixe la valeur du paramètre. * une notification préalable est envoyée pour laisser l'occasion aux objets liés de préciser le contexte @@ -433,7 +410,6 @@ export class NgParameter extends InputField implements Observer { public resetMinValue(sender: any, v: number) { const changed = (this._paramDef.min !== v); - this._isValueModified = false; if (changed) { this._paramDef.min = v; this.notifyMinValueModified(sender); @@ -444,14 +420,12 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.min !== v); if (changed) { this._paramDef.min = v; - this._isValueModified = true; this.notifyMinValueModified(sender); } } public resetMaxValue(sender: any, v: number) { const changed = (this._paramDef.max !== v); - this._isValueModified = false; if (changed) { this._paramDef.max = v; this.notifyMaxValueModified(sender); @@ -462,14 +436,12 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.max !== v); if (changed) { this._paramDef.max = v; - this._isValueModified = true; this.notifyMaxValueModified(sender); } } public resetStepValue(sender: any, v: number) { const changed = (this._paramDef.step !== v); - this._isValueModified = false; if (changed) { this._paramDef.step = v; this.notifyStepValueModified(sender); @@ -480,14 +452,12 @@ export class NgParameter extends InputField implements Observer { const changed = (this._paramDef.step !== v); if (changed) { this._paramDef.step = v; - this._isValueModified = true; this.notifyStepValueModified(sender); } } public resetValueList(sender: any, l: number[]) { const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); - this._isValueModified = false; if (changed) { this._paramDef.valueList = l; this.notifyListValueModified(sender); @@ -498,7 +468,6 @@ export class NgParameter extends InputField implements Observer { const changed = (JSON.stringify(this._paramDef.valueList) !== JSON.stringify(l)); if (changed) { this._paramDef.valueList = l; - this._isValueModified = true; this.notifyListValueModified(sender); } } @@ -520,7 +489,6 @@ export class NgParameter extends InputField implements Observer { allowEmpty: this._allowEmpty, unit: this.unit, radioConfig: this.radioConfig, - modified: this._isValueModified } } @@ -530,7 +498,6 @@ export class NgParameter extends InputField implements Observer { this._allowEmpty = rep.allowEmpty; this.unit = rep.unit; this.radioConfig = rep.radioConfig; - this._isValueModified = rep._isValueModified; } } -- GitLab From b0910693b9eec7c0b75d3bb6743f1053d8465533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Fri, 29 Apr 2022 15:25:59 +0200 Subject: [PATCH 55/64] fix: graph crash in backwater curves calculator when embankment has a high value and calculation does not converge refs #532 --- jalhyd_branch | 2 +- .../remous-results.component.ts | 52 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index 626e97d71..189ba8cae 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -devel \ No newline at end of file +307-courbe-de-remous-crash-de-l-application-sur-donnees-erronees \ No newline at end of file diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts index b39505299..b753778b4 100644 --- a/src/app/components/remous-results/remous-results.component.ts +++ b/src/app/components/remous-results/remous-results.component.ts @@ -315,33 +315,35 @@ export class RemousResultsComponent extends ResultsComponentDirective implements // abscisses pour lesquelles on a un résultat const rrr = this._remousResults.result; - const firstResultAbscissa = rrr.resultElements[0].values.X; - const lastResultAbscissa = rrr.resultElements[rrr.resultElements.length - 1].values.X; - let resultAbscissaIndex = 0; - const itX = this.abscisseIterator; - - // parcours des abscisses une par une - while (itX.hasNext) { - const x = itX.next().value; - // skip abscissa that have no result - if (x >= firstResultAbscissa && x <= lastResultAbscissa) { - // result element for the given abscissa - const re = rrr.resultElements[resultAbscissaIndex]; - resultAbscissaIndex++; - - const yExtra = re.getValue(this._remousResults.extraParamSymbol); - if (yExtra !== undefined) { - lineExtra.setPoint(x, yExtra); - } + if (rrr.resultElements.length > 0) { + const firstResultAbscissa = rrr.resultElements[0].values.X; + const lastResultAbscissa = rrr.resultElements[rrr.resultElements.length - 1].values.X; + let resultAbscissaIndex = 0; + const itX = this.abscisseIterator; + + // parcours des abscisses une par une + while (itX.hasNext) { + const x = itX.next().value; + // skip abscissa that have no result + if (x >= firstResultAbscissa && x <= lastResultAbscissa) { + // result element for the given abscissa + const re = rrr.resultElements[resultAbscissaIndex]; + resultAbscissaIndex++; + + const yExtra = re.getValue(this._remousResults.extraParamSymbol); + if (yExtra !== undefined) { + lineExtra.setPoint(x, yExtra); + } - const yFlu = re.getValue("flu"); - if (yFlu !== undefined) { - lineFlu.setPoint(x, yFlu); - } + const yFlu = re.getValue("flu"); + if (yFlu !== undefined) { + lineFlu.setPoint(x, yFlu); + } - const yTor = re.getValue("tor"); - if (yTor !== undefined) { - lineTor.setPoint(x, yTor); + const yTor = re.getValue("tor"); + if (yTor !== undefined) { + lineTor.setPoint(x, yTor); + } } } } -- GitLab From e99d3bf6fccda221882cf5e140b57fdc0a54a5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Thu, 28 Apr 2022 15:04:21 +0200 Subject: [PATCH 56/64] test(e2e): add a test to check empty fields on a copy of modified structure refs #516 --- e2e/ouvrages-empty-fields.e2e-spec.ts | 68 +++++++++++++++++------ e2e/pab-cloisons-empty-fields.e2e-spec.ts | 6 +- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/e2e/ouvrages-empty-fields.e2e-spec.ts b/e2e/ouvrages-empty-fields.e2e-spec.ts index 096393e60..6eac089d5 100644 --- a/e2e/ouvrages-empty-fields.e2e-spec.ts +++ b/e2e/ouvrages-empty-fields.e2e-spec.ts @@ -2,40 +2,44 @@ import { ListPage } from "./list.po"; import { browser, by, element } from "protractor"; import { CalculatorPage } from "./calculator.po"; import { AppPage } from "./app.po"; +import { PreferencesPage } from "./preferences.po"; +import { Navbar } from "./navbar.po"; /** * Check that created/cloned structures have empty fields when * "empty fields on calculator creation" is enabled */ describe("ngHyd - check that created/cloned structures have empty fields - ", () => { - //let prefPage: PreferencesPage; - let startPage: AppPage; + let prefPage: PreferencesPage; let listPage: ListPage; let calcPage: CalculatorPage; + let navBar: Navbar; beforeAll(() => { - //prefPage = new PreferencesPage(); - startPage = new AppPage(); + prefPage = new PreferencesPage(); listPage = new ListPage(); calcPage = new CalculatorPage(); + navBar = new Navbar(); + browser.manage().window().setPosition(2000, 30); }); beforeEach(async () => { // enable evil option "empty fields on module creation" - // await prefPage.navigateTo(); - // await prefPage.enableEvilEmptyFields(); // message "stale element reference: element is not attached to the page document" - // await browser.sleep(200); - - // assume that "empty fields on module creation" is true by default + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); + }); + async function setup() { // start page - await startPage.navigateTo(); + await navBar.clickNewCalculatorButton(); await browser.sleep(200); // open structures calculator await listPage.clickMenuEntryForCalcType(8); await browser.sleep(200); - }); + } /** * check that a input set is in a given (empty/filled) state @@ -53,9 +57,11 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () } it("when a structure calculator is created", async () => { + await setup(); + // check 1st structure empty fields - const inputIds = ["Q", "calc_Z1", "Z2", "0_ZDV", "0_L", "0_W", "0_CdGR"]; - const emptys = [true, false, true, true, true, true, false]; + const inputIds = ["Q", "Z1", "Z2", "0_ZDV", "0_L", "0_W", "0_CdGR"]; + const emptys = [true, true, true, true, true, true, false]; await checkFields(inputIds, emptys); // change 1st structure type to rectangular weir @@ -64,12 +70,14 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () await browser.sleep(200); // check 1st structure empty fields - const inputIds2 = ["Q", "calc_Z1", "Z2", "0_ZDV", "0_L", "0_CdWR"]; - const emptys2 = [true, false, true, true, true, false]; + const inputIds2 = ["Q", "Z1", "Z2", "0_ZDV", "0_L", "0_CdWR"]; + const emptys2 = [true, true, true, true, true, false]; await checkFields(inputIds2, emptys2); }); it("when a structure is added", async () => { + await setup(); + // add structure const addStruct = calcPage.getAddStructureButton(); await addStruct.click(); @@ -81,6 +89,8 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () }); it("when a structure is copied", async () => { + await setup(); + // copy structure const addStruct = calcPage.getCopyStructureButton(); await addStruct.click(); @@ -91,7 +101,9 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () await checkFields(inputIds, emptys); }); - it("when a modified structure is copied", async () => { + it("when a modified structure is copied (type)", async () => { + await setup(); + // change 1st structure type to rectangular weir const structSelect = calcPage.getSelectById("select_structure"); await calcPage.changeSelectValue(structSelect, 1); @@ -103,7 +115,8 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () await browser.sleep(200); // change 2nd structure type to rectangular gate - const structSelect2 = element(by.className("ng-tns-c3-47")); + const selects = await element.all(by.css("mat-select#select_structure")); + const structSelect2 = selects[1]; await calcPage.changeSelectValue(structSelect2, 4); await browser.sleep(200); @@ -113,7 +126,28 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () await checkFields(inputIds, emptys); }); + it("when a modified structure is copied (input)", async () => { + await setup(); + + // fill + const inp = calcPage.getInputById("0_ZDV"); + await inp.clear(); + await inp.sendKeys("1"); + + // copy structure + const addStruct = calcPage.getCopyStructureButton(); + await addStruct.click(); + await browser.sleep(200); + + // check empty fields + const inputIds = ["1_ZDV", "1_L", "1_W", "1_CdGR"]; + const emptys = [false, true, true, false]; + await checkFields(inputIds, emptys); + }); + it("except for discharge coefficient when a Larinier weir is used", async () => { + await setup(); + // change 1st structure type to rectangular weir const structSelect = calcPage.getSelectById("select_structure"); await calcPage.changeSelectValue(structSelect, 1); diff --git a/e2e/pab-cloisons-empty-fields.e2e-spec.ts b/e2e/pab-cloisons-empty-fields.e2e-spec.ts index c7305027a..7e99a7de4 100644 --- a/e2e/pab-cloisons-empty-fields.e2e-spec.ts +++ b/e2e/pab-cloisons-empty-fields.e2e-spec.ts @@ -65,11 +65,11 @@ describe("ngHyd - check the cross walls calculator has empty fields - ", () => { await browser.sleep(200); // fill inputs - await fillInput(calcPage, "Q"); await fillInput(calcPage, "Z1"); await fillInput(calcPage, "LB"); await fillInput(calcPage, "BB"); await fillInput(calcPage, "PB"); + await fillInput(calcPage, "DH"); await fillInput(calcPage, "0_h1"); await fillInput(calcPage, "0_L"); await fillInput(calcPage, "0_CdWSL"); @@ -116,11 +116,11 @@ describe("ngHyd - check the cross walls calculator has no empty field - ", () => await browser.sleep(200); // fill inputs - await fillInput(calcPage, "Q"); await fillInput(calcPage, "Z1"); await fillInput(calcPage, "LB"); await fillInput(calcPage, "BB"); await fillInput(calcPage, "PB"); + await fillInput(calcPage, "DH"); await fillInput(calcPage, "0_h1"); await fillInput(calcPage, "0_L"); await fillInput(calcPage, "0_CdWSL"); @@ -130,6 +130,6 @@ describe("ngHyd - check the cross walls calculator has no empty field - ", () => await calcButton.click(); await browser.sleep(200); - await checkFields(calcPage, ["Q", "Z1", "LB", "BB", "PB", "0_h1", "0_L", "0_CdWSL"], [false, false, false, false, false, false, false, false]); + await checkFields(calcPage, ["Z1", "LB", "BB", "PB", "DH", "0_h1", "0_L", "0_CdWSL"], [false, false, false, false, false, false, false, false]); }); }); -- GitLab From b5e2fef235cec8b8e12ecd133eec552c30fa957a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 2 May 2022 10:26:15 +0200 Subject: [PATCH 57/64] fix(e2e): fix broken "all calculator examples" test refs #516 --- e2e/calc-all-examples.e2e-spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/e2e/calc-all-examples.e2e-spec.ts b/e2e/calc-all-examples.e2e-spec.ts index 4dae4b1dd..34d4a63f1 100644 --- a/e2e/calc-all-examples.e2e-spec.ts +++ b/e2e/calc-all-examples.e2e-spec.ts @@ -49,12 +49,14 @@ describe("ngHyd − example sessions −", async () => { } const examples = await element.all(by.css("#examples-list .load-example")); + await browser.sleep(200); if (examples.length > i) { // click example #i await examples[i].click(); - await browser.sleep(50); + await browser.sleep(200); const nbModules = await navbar.getCalculatorEntriesCount(); + await browser.sleep(200); for (let j = 0; j < nbModules; j++) { // select module await navbar.openNthCalculator(j); -- GitLab From db23cc50b8f7e8de14bd80acc1c46a96090c9f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Mon, 2 May 2022 14:44:30 +0200 Subject: [PATCH 58/64] test(e2e): check computed parameter initial value is not null with "empty fields on calculator creation" option refs #516 --- e2e/examples-empty-fields.e2e-spec.ts | 31 +++++++++++++++++++ .../dialog-edit-param-computed.component.html | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/e2e/examples-empty-fields.e2e-spec.ts b/e2e/examples-empty-fields.e2e-spec.ts index 573012930..590ac5b47 100644 --- a/e2e/examples-empty-fields.e2e-spec.ts +++ b/e2e/examples-empty-fields.e2e-spec.ts @@ -58,4 +58,35 @@ describe("ngHyd - Check that examples fields are not empty with 'empty fields on const emptys = [false, false, false, false, false]; await checkFields(inputIds, emptys); }); + + it("calculated parameter initial value when discharge law is modified", async () => { + // start page + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open 1st example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[0].click(); + await browser.sleep(50); + + // select wall module + await navBar.openNthCalculator(4); + await browser.sleep(50); + + // modify 1st structure discharge law + const dischargeSelect = calcPage.getSelectById("select_loidebit"); + await calcPage.changeSelectValue(dischargeSelect, 1); + await browser.sleep(200); + + // open initial dialog + const initDlgButton = element(by.className("param-computed-more")); + await initDlgButton.click(); + await browser.sleep(200); + + // check input value is not null + const input = calcPage.getInputById("initval-input"); + const underlyingInput = input.element(by.id("0_h1")); + const txt = await underlyingInput.getAttribute("value"); + expect(txt === "").toEqual(false); + }); }); diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html index 38bcc40fb..9037cd52b 100644 --- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html +++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html @@ -3,7 +3,7 @@ <form> <div mat-dialog-content> - <ngparam-input [title]="param.title"></ngparam-input> + <ngparam-input id="initval-input" [title]="param.title"></ngparam-input> </div> <div mat-dialog-actions [attr.align]="'end'"> -- GitLab From b97738ebea992090fbba64d75a86fcc38e0463bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 4 May 2022 07:43:15 +0200 Subject: [PATCH 59/64] test(e2e): check calculation works in generated PAB from 'standard fish ladder' example (walls calculator) refs #516 --- e2e/examples-empty-fields.e2e-spec.ts | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/e2e/examples-empty-fields.e2e-spec.ts b/e2e/examples-empty-fields.e2e-spec.ts index 590ac5b47..a9df5a682 100644 --- a/e2e/examples-empty-fields.e2e-spec.ts +++ b/e2e/examples-empty-fields.e2e-spec.ts @@ -90,3 +90,65 @@ describe("ngHyd - Check that examples fields are not empty with 'empty fields on expect(txt === "").toEqual(false); }); }); + +describe("ngHyd - Check that examples work with 'empty fields on calculator creation' enabled - ", () => { + let prefPage: PreferencesPage; + let navBar: Navbar; + let calcPage: CalculatorPage; + + beforeEach(async () => { + prefPage = new PreferencesPage(); + navBar = new Navbar(); + calcPage = new CalculatorPage(); + + // enable evil option "empty fields on module creation" + await prefPage.navigateTo(); + await browser.sleep(200); + await prefPage.enableEvilEmptyFields(); + await browser.sleep(200); + }); + + fit("when calculation is run on a generated fish ladder calculator", async () => { + debugger + // start page + await navBar.clickNewCalculatorButton(); + await browser.sleep(200); + + // open 1st example + const examples = await element.all(by.css("#examples-list .load-example")); + await examples[0].click(); + await browser.sleep(50); + + // select wall module + await navBar.openNthCalculator(4); + await browser.sleep(50); + + // run calculation + const calcButton = calcPage.getCalculateButton(); + await calcButton.click(); + await browser.sleep(200); + + // click "generate PAB" button + const genButton = calcPage.getGeneratePabButton(); + await genButton.click(); + await browser.sleep(200); + + // write "6" in basin count input + const nbBassins = calcPage.getInputById("generatePabNbBassins"); + await nbBassins.sendKeys("6"); + await browser.sleep(50); + + // click "Generate PAB" + await element(by.css("dialog-generate-pab button#do-generate")).click(); + await browser.sleep(1000); + + // calculate PAB + const calcButtonPAB = calcPage.getCalculateButton(); + await calcButtonPAB.click(); + await browser.sleep(200); + + // check that result is not empty + const hasResults = await calcPage.hasResults(); + expect(hasResults).toBe(true); + }); +}); -- GitLab From c9008f3b151d54a7ad17b6465fcade932b453460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 4 May 2022 07:44:48 +0200 Subject: [PATCH 60/64] fix: adapt to useDefaultParamValue flag removal in jalhyd refs #516 --- src/app/components/pb-schema/pb-schema.component.ts | 3 ++- src/app/formulaire/definition/form-definition.ts | 4 +++- src/app/formulaire/definition/form-parallel-structures.ts | 4 +++- src/app/services/app-setup.service.ts | 5 +++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index 1862a8dcf..7ea4ba81d 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -21,6 +21,7 @@ import { AppComponent } from "../../app.component"; import { fv } from "app/util"; import { FormulaireNode } from "app/formulaire/elements/formulaire-node"; +import { ServiceFactory } from "app/services/service-factory"; /** * The interactive schema for calculator type "PreBarrage" (component) @@ -494,7 +495,7 @@ export class PbSchemaComponent implements AfterViewInit, AfterContentInit, OnIni /** Adds a new lone basin */ public onAddBasinClick() { - const newBasin = new PbBassin(new PbBassinParams(20, 99)); + const newBasin = new PbBassin(new PbBassinParams(20, 99, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit)); this.model.addChild(newBasin); this.clearResults(); this.refreshWithSelection(newBasin.uid); diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 442a96ef6..3fd3ee3a2 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -9,7 +9,8 @@ import { acSection, ParamDefinition, Result, - VariatedDetails + VariatedDetails, + Prop_NullParameters } from "jalhyd"; import { FormulaireElement } from "../elements/formulaire-element"; @@ -110,6 +111,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs */ public initNub(props?: Props) { const p = props ? props : new Props(this.defaultProperties); + p.setPropValue(Prop_NullParameters, ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit); // transmit "empty fields" flag this.currentNub = Session.getInstance().createSessionNub(p); if (this.currentNub instanceof SectionNub) { diff --git a/src/app/formulaire/definition/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts index 5e35710f9..9e4dd86d6 100644 --- a/src/app/formulaire/definition/form-parallel-structures.ts +++ b/src/app/formulaire/definition/form-parallel-structures.ts @@ -1,4 +1,4 @@ -import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition } from "jalhyd"; +import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition, Prop_NullParameters } from "jalhyd"; import { FieldsetContainer } from "../elements/fieldset-container"; import { FieldSet } from "../elements/fieldset"; @@ -7,6 +7,7 @@ import { NgParameter } from "../elements/ngparam"; import { FieldsetTemplate } from "../elements/fieldset-template"; import { FormulaireNode } from "../elements/formulaire-node"; import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset"; +import { ServiceFactory } from "app/services/service-factory"; export class FormulaireParallelStructure extends FormulaireRepeatableFieldset { @@ -66,6 +67,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset { params["nodeType"] = templ.defaultNodeTypeFromConfig; params["structureType"] = templ.defaultStructTypeFromConfig; params["loiDebit"] = templ.defaultLoiDebitFromConfig; + params[Prop_NullParameters] = ServiceFactory.applicationSetupService.enableEmptyFieldsOnFormInit; return this.createStructure(new Props(params)); } diff --git a/src/app/services/app-setup.service.ts b/src/app/services/app-setup.service.ts index 193b32aaf..32b9f517d 100644 --- a/src/app/services/app-setup.service.ts +++ b/src/app/services/app-setup.service.ts @@ -24,6 +24,7 @@ export class ApplicationSetupService extends Observable { private _maxIterations = 100; // tied to model public enableNotifications = true; public enableHotkeys = false; + private _enableEmptyFieldsOnFormInit = true; public set computePrecision(p: number) { this._computePrecision = p; @@ -46,11 +47,11 @@ export class ApplicationSetupService extends Observable { } public get enableEmptyFieldsOnFormInit() { - return !SessionSettings.useDefaultParamValue; + return this._enableEmptyFieldsOnFormInit; } public set enableEmptyFieldsOnFormInit(b: boolean) { - SessionSettings.useDefaultParamValue = !b; + this._enableEmptyFieldsOnFormInit = b; } /** -- GitLab From 9c37bd28cc18821019e6c9a4f4aebf1a88251c4f Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@inrae.fr> Date: Wed, 4 May 2022 08:13:10 +0000 Subject: [PATCH 61/64] refactor: change jalhyd_branch to devel after merge of jalhyd Refs #516 --- jalhyd_branch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jalhyd_branch b/jalhyd_branch index f6d80c358..626e97d71 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -306-gerer-un-flag-modified-dans-paramdefinition \ No newline at end of file +devel \ No newline at end of file -- GitLab From 2d2f00d03eaa45392b72af85ce67a5784dd524cb Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@inrae.fr> Date: Wed, 4 May 2022 08:13:28 +0000 Subject: [PATCH 62/64] test: forgottent fix Refs #516 --- e2e/examples-empty-fields.e2e-spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/examples-empty-fields.e2e-spec.ts b/e2e/examples-empty-fields.e2e-spec.ts index a9df5a682..491ef77c6 100644 --- a/e2e/examples-empty-fields.e2e-spec.ts +++ b/e2e/examples-empty-fields.e2e-spec.ts @@ -108,7 +108,7 @@ describe("ngHyd - Check that examples work with 'empty fields on calculator crea await browser.sleep(200); }); - fit("when calculation is run on a generated fish ladder calculator", async () => { + it("when calculation is run on a generated fish ladder calculator", async () => { debugger // start page await navBar.clickNewCalculatorButton(); -- GitLab From 0a65bfde0c141a4b6ba877f9fb3794607bdf55cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr> Date: Wed, 4 May 2022 13:50:11 +0200 Subject: [PATCH 63/64] update CHANGELOG for v4.14.3 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6977faf6b..6ea018f31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Historique des versions +### 4.14.3 - 2022-05-02 + +#### Correction de bogues + +* Courbe de remous: crash de l'application sur données erronées ([jalhyd#307](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/307),[nghyd#532](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/532)) + Deux bugs en un, l'appli crashe quand : + - la hauteur de berge dépasse une certaine valeur avec des paramètres corrects pour effectuer un calcul (par exemple les valeurs par défaut) + - les deux cotes de l'eau se situent sous les cotes de fond amont et aval +* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530),[nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531)) + - Les champs des exemples chargés sont vides lorsque le mode "champ vides" est activé. + - Les tests e2e plantent par manque de temporisation +* Cloisons : il manque l'aide contextuelle pour les lois de débit ([nghyd#529](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/529)) +* Sections : non convergence du calcul du tirant d'eau critique ([jalhyd#301](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/301),[nghyd#528](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/528)) +* CI : les jobs build en schedule de master et devel plantent ([nghyd#527](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/527)) +* CI : affiner la gestion du cache ([nghyd#526](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/526)) +* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306),[nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516)) +* Fente Larinier : laisser le coefficient de débit vide ([nghyd#515](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/515)) +* Remettre le paramètre dans son état initial quand le dialogue "Varier" est annulé ([nghyd#508](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/508)) +* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300),[nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507)) +* Transfert du site de production sur OVH ([nghyd#505](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/505)) +* Prébarrages: les champs ne sont pas vides lors des ajouts de bassins et cloisons ([nghyd#503](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/503)) +* Documentation : corrections ([nghyd#498](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/498)) +* Nightly build: clean folder before installation ([nghyd#495](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/495)) +* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298),[nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484)) +* Mode "champs vides par défaut" : changer le type d'un ouvrage (ex: dans Cloisons) remplit les champs ([nghyd#480](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/480)) +* PréBarrages : perte du focus lorsqu'on édite un paramètre d'un enfant (cloison ou bassin) ([nghyd#469](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/469)) +* PAB : pouvoir varier le débit d'attrait ([nghyd#431](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/431)) + ### 4.14.2 - 2021-03-25 #### Nouvelles fonctionnalités -- GitLab From ec828fee1ec301f249dfc822164b87f5ff561ee9 Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@inrae.fr> Date: Wed, 4 May 2022 13:03:19 +0000 Subject: [PATCH 64/64] docs: update CHANGELOG for v4.15.0 --- CHANGELOG.md | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea018f31..8cd5b0cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Historique des versions -### 4.14.3 - 2022-05-02 +### 4.15.0 - 2022-05-04 (Salmo trutta) + +#### Nouvelles fonctionnalités + +* PAB : Variation du débit d'attrait ([nghyd#431](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/431)) +* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300),[nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507)) +* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298),[nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484)) + +#### Changements + +* Fente Larinier : laisser le coefficient de débit vide ([nghyd#515](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/515)) +* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306),[nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516)) + #### Correction de bogues @@ -8,25 +20,26 @@ Deux bugs en un, l'appli crashe quand : - la hauteur de berge dépasse une certaine valeur avec des paramètres corrects pour effectuer un calcul (par exemple les valeurs par défaut) - les deux cotes de l'eau se situent sous les cotes de fond amont et aval -* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530),[nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531)) - - Les champs des exemples chargés sont vides lorsque le mode "champ vides" est activé. - - Les tests e2e plantent par manque de temporisation -* Cloisons : il manque l'aide contextuelle pour les lois de débit ([nghyd#529](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/529)) * Sections : non convergence du calcul du tirant d'eau critique ([jalhyd#301](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/301),[nghyd#528](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/528)) -* CI : les jobs build en schedule de master et devel plantent ([nghyd#527](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/527)) -* CI : affiner la gestion du cache ([nghyd#526](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/526)) -* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306),[nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516)) -* Fente Larinier : laisser le coefficient de débit vide ([nghyd#515](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/515)) * Remettre le paramètre dans son état initial quand le dialogue "Varier" est annulé ([nghyd#508](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/508)) -* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300),[nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507)) -* Transfert du site de production sur OVH ([nghyd#505](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/505)) * Prébarrages: les champs ne sont pas vides lors des ajouts de bassins et cloisons ([nghyd#503](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/503)) -* Documentation : corrections ([nghyd#498](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/498)) -* Nightly build: clean folder before installation ([nghyd#495](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/495)) -* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298),[nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484)) * Mode "champs vides par défaut" : changer le type d'un ouvrage (ex: dans Cloisons) remplit les champs ([nghyd#480](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/480)) * PréBarrages : perte du focus lorsqu'on édite un paramètre d'un enfant (cloison ou bassin) ([nghyd#469](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/469)) -* PAB : pouvoir varier le débit d'attrait ([nghyd#431](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/431)) + +#### Documentation + +* Cloisons : il manque l'aide contextuelle pour les lois de débit ([nghyd#529](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/529)) +* Documentation : corrections ([nghyd#498](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/498)) + +#### Changements internes + +* Nightly build: clean folder before installation ([nghyd#495](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/495)) +* Transfert du site de production sur OVH ([nghyd#505](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/505)) +* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530),[nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531)) + - Les champs des exemples chargés sont vides lorsque le mode "champ vides" est activé. + - Les tests e2e plantent par manque de temporisation +* CI : les jobs build en schedule de master et devel plantent ([nghyd#527](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/527)) +* CI : affiner la gestion du cache ([nghyd#526](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/526)) ### 4.14.2 - 2021-03-25 -- GitLab