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 01/13] 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 02/13] 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 03/13] 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 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 04/13] 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 05/13] 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 06/13] 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 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 07/13] 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 08/13] 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 09/13] 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 10/13] 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 11/13] 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 12/13] 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 13/13] 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