From b37ef81cb39bc5d5242faef7ee20aac836fa43ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Mon, 16 Jan 2023 14:16:12 +0100
Subject: [PATCH 01/11] update jalhyd_branch to
 334-restructurer-lechapt-et-calmon-pour-de-nouvelles-lois-de-pertes-de-charge

refs #585
---
 jalhyd_branch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jalhyd_branch b/jalhyd_branch
index 9e2dece83..0bd0de843 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-338-optimiser-l-affichage-des-unites
+334-restructurer-lechapt-et-calmon-pour-de-nouvelles-lois-de-pertes-de-charge
-- 
GitLab


From 2fea08b1497f7c5e3d2fb53bf2b89b17945c1052 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Tue, 17 Jan 2023 17:32:09 +0100
Subject: [PATCH 02/11] refactor: modify code to fit encapsulation of
 properties Nub field

refs #585
---
 .../fieldset-container.component.ts           |  4 +-
 .../macrorugo-compound-results.component.ts   |  2 +-
 .../modules-diagram.component.ts              |  4 +-
 .../pab-profile-chart.component.ts            |  6 +-
 .../pab-table/pab-table.component.ts          |  4 +-
 .../definition/form-courbe-remous.ts          |  2 +-
 .../formulaire/definition/form-definition.ts  | 14 ++-
 src/app/formulaire/definition/form-espece.ts  |  2 +-
 .../formulaire/definition/form-fixedvar.ts    |  2 +-
 .../definition/form-macrorugo-compound.ts     |  2 +-
 .../definition/form-parallel-structures.ts    | 18 ++--
 .../formulaire/definition/form-pb-cloison.ts  |  8 +-
 .../formulaire/definition/form-prebarrage.ts  |  2 +-
 src/app/formulaire/definition/form-solveur.ts |  4 +-
 .../definition/form-verificateur.ts           |  2 +-
 src/app/formulaire/elements/fieldset.ts       | 97 ++++++++++---------
 .../select/select-field-device-loi-debit.ts   |  2 +-
 .../elements/select/select-field-nub-prop.ts  |  5 +-
 18 files changed, 93 insertions(+), 87 deletions(-)

diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts
index f612f362a..042df7517 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.ts
+++ b/src/app/components/fieldset-container/fieldset-container.component.ts
@@ -89,8 +89,8 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit {
             const prms = after.backupParameters();
             // replace in-place to change properties (overkill)
             // @WTF why only those two ?
-            newFs.setNubPropValue("structureType", after.properties.getPropValue("structureType"));
-            newFs.setNubPropValue("loiDebit", after.properties.getPropValue("loiDebit"));
+            newFs.setPropValue("structureType", after.getPropValue("structureType"));
+            newFs.setPropValue("loiDebit", after.getPropValue("loiDebit"));
 
             // au cas où un des paramètres du fieldset source est en mode calcul,
             // on met le paramètre copié en mode fixé (nghyd#567)
diff --git a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
index 86eba4301..f388647da 100644
--- a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
+++ b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
@@ -92,7 +92,7 @@ export class MacrorugoCompoundResultsComponent extends ResultsComponentDirective
             this.mrcResults
             && this.mrcResults.result
             && this.mrcResults.result.sourceNub
-            && this.mrcResults.result.sourceNub.properties.getPropValue("inclinedApron") === MRCInclination.INCLINED
+            && this.mrcResults.result.sourceNub.getPropValue("inclinedApron") === MRCInclination.INCLINED
         );
     }
 
diff --git a/src/app/components/modules-diagram/modules-diagram.component.ts b/src/app/components/modules-diagram/modules-diagram.component.ts
index 6f227edcb..0b607e51e 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.ts
+++ b/src/app/components/modules-diagram/modules-diagram.component.ts
@@ -265,11 +265,11 @@ export class ModulesDiagramComponent implements AfterContentInit, AfterViewCheck
      */
     private describe(n: Nub) {
         let type = CalculatorType[n.calcType];
-        const nt = n.properties.getPropValue("nodeType");
+        const nt = n.getPropValue("nodeType");
         if (nt) {
             type = SectionType[nt];
         } else {
-            const ld = n.properties.getPropValue("loiDebit");
+            const ld = n.getPropValue("loiDebit");
             if (ld !== undefined) {
                 type = LoiDebit[ld];
             }
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 c8eff7ec5..ee664e43a 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
@@ -268,7 +268,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
                     ddSeries[sti] = [];
                 }
                 // orifices have no relevant ZDV
-                if (st.properties.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
+                if (st.getPropValue("loiDebit") !== LoiDebit.OrificeSubmerged) {
                     // 2 points, to draw a segment
                     ddSeries[sti].push({
                         x: xs[i],
@@ -305,7 +305,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
             }
             // orifices have no relevant ZDV; lift gate will be drawn later for each series
             if (! [ LoiDebit.OrificeSubmerged, LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ]
-                .includes(st.properties.getPropValue("loiDebit"))
+                .includes(st.getPropValue("loiDebit"))
             ) {
                 // 2 points, to draw a segment
                 ddSeries[sti].push({
@@ -403,7 +403,7 @@ export class PabProfileChartComponent extends ResultsComponentDirective implemen
                 // draw lift gate if any
                 if (isLastAbscissa) {
                     for (const st of dw.structures) {
-                        if ([ LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte ].includes(st.properties.getPropValue("loiDebit"))) {
+                        if ([LoiDebit.VanLevLarinier, LoiDebit.VanLevVillemonte].includes(st.getPropValue("loiDebit"))) {
                             // skip a point to disjoin line
                             dataN.push({
                                 x: x,
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
index 8ef4e14c1..ead6072f1 100644
--- a/src/app/components/pab-table/pab-table.component.ts
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -594,7 +594,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                     if (i === 0) { // 1st row
                         deviceParamRow.cells.push({
                             model: ouvrage,
-                            modelValue: ouvrage.properties.getPropValue("loiDebit"),
+                            modelValue: ouvrage.getPropValue("loiDebit"),
                             options: loisCloisons,
                             selectable: ouvrage
                         });
@@ -719,7 +719,7 @@ export class PabTableComponent implements AfterViewInit, AfterViewChecked, OnIni
                 if (i === 0) { // 1st row
                     deviceParamRowDW.cells.push({
                         model: ouvrage,
-                        modelValue: ouvrage.properties.getPropValue("loiDebit"),
+                        modelValue: ouvrage.getPropValue("loiDebit"),
                         options: loisAval
                     });
                 }
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
index 3762c846c..62c8d3b3b 100644
--- a/src/app/formulaire/definition/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -31,7 +31,7 @@ export class FormulaireCourbeRemous extends FormulaireSection {
         this._remousResults.parameters = prmCR;
 
         // variable supplémentaire à calculer
-        this._remousResults.extraParamSymbol = this.currentNub.properties.getPropValue("varCalc");
+        this._remousResults.extraParamSymbol = this.currentNub.getPropValue("varCalc");
 
         // calcul
         this._remousResults.result = cr.CalcSerie();
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f2141323a..b4a34d345 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -81,14 +81,18 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return this._calculateDisabled;
     }
 
+    private getPropValue(key: string): any {
+        if (this._currentNub === undefined)
+            return this.defaultProperties[key];
+        return this._currentNub.getPropValue(key);
+    }
+
     public get calculatorType(): CalculatorType {
-        const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
-        return props["calcType"];
+        return this.getPropValue("calcType")
     }
 
     public get nodeType(): SectionType {
-        const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
-        return props["nodeType"];
+        return this.getPropValue("nodeType")
     }
 
     public get calculatorName() {
@@ -127,7 +131,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     public set currentNub(n: Nub) {
-        const nubCalcType = (n.properties as Props).getPropValue("calcType");
+        const nubCalcType = n.getPropValue("calcType");
         if (this._props["calcType"] !== nubCalcType) {
             throw new Error(
                 `Nub ${n.properties["calcType"]} incompatible avec le formulaire ${this._calculatorName} (${this._props["calcType"]})`
diff --git a/src/app/formulaire/definition/form-espece.ts b/src/app/formulaire/definition/form-espece.ts
index 10ded3b83..f0a36b93e 100644
--- a/src/app/formulaire/definition/form-espece.ts
+++ b/src/app/formulaire/definition/form-espece.ts
@@ -10,7 +10,7 @@ export class FormulaireEspece extends FormulaireFixedVar {
 
     protected completeParse(firstNotif: boolean = true) {
         super.completeParse(firstNotif);
-        this.updateDivingJetCriteriaInputs(this.currentNub.properties.getPropValue("divingJetSupported"));
+        this.updateDivingJetCriteriaInputs(this.currentNub.getPropValue("divingJetSupported"));
     }
 
     /**
diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
index 0a329f489..8eb6917e7 100644
--- a/src/app/formulaire/definition/form-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -63,7 +63,7 @@ export class FormulaireFixedVar extends FormulaireDefinition {
 
     public afterParseFieldset(fs: FieldSet) {
         // observe all Select fields @see this.update()
-        fs.properties.addObserver(this);
+        fs.addPropertiesObserver(this);
     }
 
     protected completeParse(firstNotif: boolean = true) {
diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
index ec470e645..306332cb5 100644
--- a/src/app/formulaire/definition/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -56,7 +56,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         super.completeParse(firstNotif);
         this.fieldsetContainer.addObserver(this);
         if (firstNotif) {
-            this.updateApronState(this.currentNub.properties.getPropValue("inclinedApron"));
+            this.updateApronState(this.currentNub.getPropValue("inclinedApron"));
         }
     }
 
diff --git a/src/app/formulaire/definition/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts
index b47c4808b..a5de99edd 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, Prop_NullParameters } from "jalhyd";
+import { Structure, Nub, ParallelStructure, StructureProperties, Props, Session, ParamDefinition, Prop_NullParameters, IProperties } from "jalhyd";
 
 import { FieldsetContainer } from "../elements/fieldset-container";
 import { FieldSet } from "../elements/fieldset";
@@ -71,7 +71,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * and return it; does not store it in the Session (for Structures, not for Calculator Modules)
      * @param p properties for the new Nub
      */
-    protected createStructure(p: Props): Structure {
+    protected createStructure(p: IProperties): Structure {
         return Session.getInstance().createNub(p, this.currentNub as ParallelStructure) as Structure;
     }
 
@@ -81,9 +81,9 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * @param sn Structure to replace
      * @param params properties to build the new Nub (calcType, loiDebit...)
      */
-    protected replaceNub(sn: Structure, params: Props): Nub {
+    protected replaceNub(sn: Structure): Nub {
         const parent = (this.currentNub as ParallelStructure);
-        const newStructure = this.createStructure(params);
+        const newStructure = this.createStructure(sn);
         parent.replaceChildInplace(sn, newStructure);
         return newStructure;
     }
@@ -108,7 +108,7 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
      * @param name nom de la propriété qui vient de changer
      * @param val nouvelle valeur de la propriété
      */
-    protected adjustProperties(props: Props, name: string, val: any) {
+    protected adjustProperties(props: IProperties, name: string, val: any) {
         if (name === "structureType") {
             if (! StructureProperties.isCompatibleValues(
                 val, props.getPropValue("loiDebit"), this.currentNub as ParallelStructure
@@ -159,12 +159,12 @@ export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
         } else if (sender instanceof FieldSet && data.action === "propertyChange") {
             switch (sender.id) {
                 case "fs_ouvrage":
-                    const props = sender.properties;
                     // ensure loiDebit is set
-                    props.setPropValue("loiDebit", data.value);
-                    this.adjustProperties(props, data["name"], data["value"]);
+                    //props.setPropValue("loiDebit", data.value); // ?? et si la propriété modifiée n'est pas la loi de débit ?
+
+                    this.adjustProperties(sender, data["name"], data["value"]);
                     // replace Structure Nub
-                    const newNub = this.replaceNub((sender.nub as Structure), props);
+                    const newNub = this.replaceNub(sender.nub as Structure);
                     sender.setNub(newNub);
                     // treat the fieldset as new to re-subscribe to Nub properties change events
                     this.afterParseFieldset(sender);
diff --git a/src/app/formulaire/definition/form-pb-cloison.ts b/src/app/formulaire/definition/form-pb-cloison.ts
index 25910c87d..145c03fe4 100644
--- a/src/app/formulaire/definition/form-pb-cloison.ts
+++ b/src/app/formulaire/definition/form-pb-cloison.ts
@@ -27,12 +27,12 @@ export class FormulairePbCloison extends FormulaireParallelStructure {
         } else if (sender instanceof FieldSet && data.action === "propertyChange") {
             switch (sender.id) {
                 case "fs_ouvrage":
-                    const props = sender.properties;
                     // ensure loiDebit is set
-                    props.setPropValue("loiDebit", data.value);
-                    this.adjustProperties(props, data["name"], data["value"]);
+                    //props.setPropValue("loiDebit", data.value); // ?? et si la propriété modifiée n'est pas la loi de débit ?
+
+                    this.adjustProperties(sender, data["name"], data["value"]);
                     // replace Structure Nub
-                    const newNub = this.replaceNub((sender.nub as Structure), props);
+                    const newNub = this.replaceNub(sender.nub as Structure);
                     sender.setNub(newNub);
                     // treat the fieldset as new to re-subscribe to Nub properties change events
                     this.afterParseFieldset(sender);
diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts
index 95e5f6549..c9a0d9e0d 100644
--- a/src/app/formulaire/definition/form-prebarrage.ts
+++ b/src/app/formulaire/definition/form-prebarrage.ts
@@ -367,7 +367,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar {
                     } catch (e) {
                         let res;
                         if (p.parentNub.calcType === CalculatorType.Structure) {
-                            res = p.parentNub.getParent().uid;
+                            res = p.parentNub.parent.uid;
                         } else {
                             res = p.parentNub.uid;
                         }
diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts
index f658c98ee..0a3d446ef 100644
--- a/src/app/formulaire/definition/form-solveur.ts
+++ b/src/app/formulaire/definition/form-solveur.ts
@@ -58,7 +58,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                     // if searchedParam is set to a value that won't be available anymore
                     // once nubToCalculate is updated, setPropValue throws an error, but
                     // nubToCalculate is updated anyway; here, just inhibit the error
-                    this._currentNub.properties.setPropValue("nubToCalculate", data.value.value);
+                    this._currentNub.setPropValue("nubToCalculate", data.value.value);
                 } catch (e) { }
                 // refresh targetted result selector
                 const trSel = this.getFormulaireNodeById(this._targettedResultSelectId) as SelectField;
@@ -73,7 +73,7 @@ export class FormulaireSolveur extends FormulaireFixedVar {
                 // update Solveur property: searched Parameter
                 try {
                     const p: ParamDefinition = data.value.value;
-                    this._currentNub.properties.setPropValue(
+                    this._currentNub.setPropValue(
                         "searchedParameter",
                         p.nubUid + "/" + p.symbol
                     );
diff --git a/src/app/formulaire/definition/form-verificateur.ts b/src/app/formulaire/definition/form-verificateur.ts
index 893754665..337bc789a 100644
--- a/src/app/formulaire/definition/form-verificateur.ts
+++ b/src/app/formulaire/definition/form-verificateur.ts
@@ -97,7 +97,7 @@ export class FormulaireVerificateur extends FormulaireFixedVar {
             this.reset(); // reset results
             if (sender.id === "select_target_pass" && data.action === "select") {
                 // update Verificateur property: Pass to check
-                this._currentNub.properties.setPropValue("nubToVerify", data.value ? data.value.value : undefined);
+                this._currentNub.setPropValue("nubToVerify", data.value ? data.value.value : undefined);
 
             } else if (sender.id === "select_species_list" && data.action === "select") {
                 // update Verificateur property: Species list (string[])
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index d0229afe7..2c130b65f 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -1,7 +1,7 @@
 import {
     CalculatorType,
     ParamDefinition,
-    Props,
+    IProperties,
     Observer,
     Nub,
     enumValueFromString
@@ -16,7 +16,7 @@ import { SelectFieldFactory } from "./select/select-field-factory";
 import { FormulaireFixedVar } from "../definition/form-fixedvar";
 import { SelectEntry } from "./select/select-entry";
 
-export class FieldSet extends FormulaireElement implements Observer {
+export class FieldSet extends FormulaireElement implements IProperties {
 
     /** Nub associé */
     private _nub: Nub;
@@ -45,7 +45,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     private addField(f: Field) {
-        if (! f) {
+        if (!f) {
             throw new Error("FieldSet.addField() : argument incorrect (undefined)");
         }
         this.kids.push(f);
@@ -114,40 +114,8 @@ export class FieldSet extends FormulaireElement implements Observer {
         return res;
     }
 
-    public get properties(): Props {
-        return this.nub.properties;
-    }
-
-    private get sectionProperties(): Props {
-        const section = this.nub.getChildren()[0];
-        if (section) {
-            return section.properties;
-        } else {
-            return new Props();
-        }
-    }
-
-    /**
-     * get associated nub property value
-     * @param key property name
-     * @param inSection if true, will look for the required property in the Nub's section (children[0])
-     */
-    private getNubPropValue(key: string, inSection: boolean = false): any {
-        if (inSection) {
-            return this.sectionProperties.getPropValue(key);
-        } else {
-            return this.properties.getPropValue(key);
-        }
-    }
-
-    /**
-     * assign associated nub property
-     * @param key nub property name
-     * @param val value to assign with
-     * @returns true if property value has changed
-     */
-    public setNubPropValue(key: string, val: any): boolean {
-        return this.properties.setPropValue(key, val, this);
+    public addPropertiesObserver(o: Observer) {
+        this.nub.addPropertiesObserver(o);
     }
 
     private getNubParamFromSymbol(symbol: string): ParamDefinition {
@@ -250,7 +218,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     private setSelectValueFromProperty(selectId: string, inSection: boolean = false) {
         const selectField: SelectField = this.getFormulaireNodeById(selectId) as SelectField;
         if (selectField) {
-            let propVal: any = this.getNubPropValue(selectField.associatedProperty, inSection);
+            let propVal: any = this.getPropValue(selectField.associatedProperty, inSection);
             if (propVal === undefined) {
                 propVal = ""; // clodo bullet-proof loading
             }
@@ -277,9 +245,9 @@ export class FieldSet extends FormulaireElement implements Observer {
         this._helpLink = json["help"];
 
         const ct: string = json["calcType"];
-        const currentCt = this.properties.getPropValue("calcType");
+        const currentCt = this.getPropValue("calcType");
         const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : this.parentForm.calculatorType);
-        this.setNubPropValue("calcType", calc_type);
+        this.setPropValue("calcType", calc_type);
 
         // parse fields once, so that SelectField elements are present
         // when setting default properties below
@@ -293,9 +261,9 @@ export class FieldSet extends FormulaireElement implements Observer {
                     const prop = sel.associatedProperty;
                     const defaultValue = sel.configDefaultValue;
                     // Sets Nub default property, unless this property is already set
-                    const currentValue = this.properties.getPropValue(prop);
+                    const currentValue = this.getPropValue(prop);
                     if (defaultValue !== undefined && currentValue === undefined) {
-                        this.setNubPropValue(prop, enumValueFromString(prop, defaultValue));
+                        this.setPropValue(prop, enumValueFromString(prop, defaultValue));
                     }
                 }
             }
@@ -314,7 +282,7 @@ export class FieldSet extends FormulaireElement implements Observer {
 
     public getNodeParameterValue(symbol: string): number {
         const p = this.getNodeParameter(symbol);
-        if (! p) {
+        if (!p) {
             throw new Error(`FieldSet.getNodeParameterValue() : pas de paramètre ${symbol} trouvé`);
         }
 
@@ -336,7 +304,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     public getSelectedValue(selectFieldId: string): string | string[] {
         for (const p of this.kids) {
             if (p instanceof SelectField && p.isDisplayed && p.id === selectFieldId) {
-                if (! p.multiple) {
+                if (!p.multiple) {
                     const value: string = (p.getValue() as SelectEntry).value;
                     return FormulaireElement.removePrefix(value, selectFieldId + "_");
                 } else {
@@ -359,7 +327,7 @@ export class FieldSet extends FormulaireElement implements Observer {
                     if (senderId === "select_section") {
                         // sections paramétrées, courbes de remous, régimes uniformes
                         // "nodeType" is a property of the section child, not of the parent
-                        const oldNodeType = this.nub.getChildren()[0].properties.getPropValue("nodeType");
+                        const oldNodeType = this.nub.getChildren()[0].getPropValue("nodeType");
                         if (oldNodeType !== data.value.value) { // avoid infinite loops
                             // manually notify parent so that it replaces the child Nub @WARNING clodo trick
                             this.parentForm.update(this, {
@@ -380,9 +348,9 @@ export class FieldSet extends FormulaireElement implements Observer {
                                             const prop = sel.associatedProperty;
                                             // for multiple select
                                             if (Array.isArray(data.value)) {
-                                                this.setNubPropValue(prop, data.value.map((v: any) => v.value));
+                                                this.setPropValue(prop, data.value.map((v: any) => v.value));
                                             } else {
-                                                this.setNubPropValue(prop, data.value.value);
+                                                this.setPropValue(prop, data.value.value);
                                             }
                                         }
                                     }
@@ -394,4 +362,39 @@ export class FieldSet extends FormulaireElement implements Observer {
             }
         }
     }
+
+    // interface IProperties
+
+    /**
+     * list of properties keys
+     */
+    public get keys(): string[] {
+        return this._nub.keys;
+    }
+
+    /**
+     * get associated nub property value
+     * @param key property name
+     * @param inSection if true, will look for the required property in the Nub's section (children[0])
+     */
+    public getPropValue(key: string, inSection: boolean = false): any {
+        if (inSection) {
+            const section = this.nub.getChildren()[0];
+            if (section) {
+                return section.getPropValue(key);
+            }
+            return undefined;
+        }
+        return this.nub.getPropValue(key);
+    }
+
+    /**
+     * assign associated nub property
+     * @param key nub property name
+     * @param val value to assign with
+     * @returns true if property value has changed
+     */
+    public setPropValue(key: string, val: any): boolean {
+        return this.nub.setPropValue(key, val, this);
+    }
 }
diff --git a/src/app/formulaire/elements/select/select-field-device-loi-debit.ts b/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
index 07c1f555a..683adebae 100644
--- a/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
+++ b/src/app/formulaire/elements/select/select-field-device-loi-debit.ts
@@ -34,7 +34,7 @@ export class SelectFieldDeviceLoiDebit extends SelectField {
      */
     private get loiDebit(): LoiDebit {
         const child = this.nub.getChildren()[this.parent.indexAsKid()];
-        return child.properties.getPropValue("loiDebit");
+        return child.getPropValue("loiDebit");
     }
 
     protected populate() {
diff --git a/src/app/formulaire/elements/select/select-field-nub-prop.ts b/src/app/formulaire/elements/select/select-field-nub-prop.ts
index 4fa8c4e86..233502db0 100644
--- a/src/app/formulaire/elements/select/select-field-nub-prop.ts
+++ b/src/app/formulaire/elements/select/select-field-nub-prop.ts
@@ -1,6 +1,5 @@
-import { Session } from "jalhyd";
+import { Props } from "jalhyd";
 import { FormulaireNode } from "../formulaire-node";
-import { SelectEntry } from "./select-entry";
 import { SelectField } from "./select-field";
 
 /*
@@ -27,7 +26,7 @@ export class SelectFieldNubProperty extends SelectField {
 
     protected populate() {
         // find enum associated to property
-        const enumClass = Session.enumFromProperty[this._associatedProperty];
+        const enumClass = Props.enumFromProperty[this._associatedProperty];
         if (enumClass !== undefined) {
             // add one select entry per enum entry, in the enum order
             for (let j = 0; j < Object.keys(enumClass).length / 2; j++) {
-- 
GitLab


From 0f85a057f3ed52e0add2497f8b861e1bb63bad4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Wed, 18 Jan 2023 13:31:54 +0100
Subject: [PATCH 03/11] fix(e2e) : Lechapt-Calmon : material change does not
 modify results

refs #585
---
 e2e/lechapt-calmon.e2e-spec.ts          | 4 ++--
 src/app/formulaire/elements/fieldset.ts | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/e2e/lechapt-calmon.e2e-spec.ts b/e2e/lechapt-calmon.e2e-spec.ts
index 4dd2d834c..91dea3194 100644
--- a/e2e/lechapt-calmon.e2e-spec.ts
+++ b/e2e/lechapt-calmon.e2e-spec.ts
@@ -35,12 +35,12 @@ describe("Lechapt&Calmon - ", () => {
         await navBar.clickNewCalculatorButton();
         await browser.sleep(200);
 
-        // open Lechapt-Calmon calculator
+        // open Lechapt-Calmon (pressure loss) calculator
         await listPage.clickMenuEntryForCalcType(35);
         await browser.sleep(200);
     }
 
-    xit("when material is modified, results should change", async () => { // temporairement débranché, cf. jalhyd#334 / nghyd#585
+    it("when material is modified, results should change", async () => {
         await setup();
 
         // select last material type
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index 2c130b65f..3637d892d 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -365,6 +365,10 @@ export class FieldSet extends FormulaireElement implements IProperties {
 
     // interface IProperties
 
+    public hasProperty(key: string): boolean {
+        return this._nub.hasProperty(key);
+    }
+
     /**
      * list of properties keys
      */
-- 
GitLab


From 85654c12f2d54d28c2217c54946e56364f44d9c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 19 Jan 2023 15:55:52 +0100
Subject: [PATCH 04/11] test(e2e) : add PressureLoss calculator

refs #585
---
 e2e/tested_calctypes.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/e2e/tested_calctypes.ts b/e2e/tested_calctypes.ts
index 590416318..be3f390fc 100644
--- a/e2e/tested_calctypes.ts
+++ b/e2e/tested_calctypes.ts
@@ -13,5 +13,5 @@ export const testedCalcTypes = [
     // omit 26 - YAXN
     27, 28, 29, 30,
     // omit 31 - PbCloison and 32 - PbBassin
-    33, 34
+    33, 34, 35
 ];
-- 
GitLab


From d1cd2406f8b8a1f9d66fa637ae90b8a0c7aba369 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 19 Jan 2023 16:06:29 +0100
Subject: [PATCH 05/11] chore: update package-lock.json (lodash added to
 jalhyd)

refs #585
---
 package-lock.json | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/package-lock.json b/package-lock.json
index 9661a8c87..87ddd2409 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -84,6 +84,7 @@
       "license": "LGPL-3.0-or-later",
       "dependencies": {
         "@types/base-64": "^1.0.0",
+        "@types/lodash": "^4.14.191",
         "base-64": "^1.0.0"
       },
       "devDependencies": {
@@ -4138,6 +4139,11 @@
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
+    "node_modules/@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+    },
     "node_modules/@types/marked": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz",
@@ -23282,6 +23288,11 @@
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
+    "@types/lodash": {
+      "version": "4.14.191",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+    },
     "@types/marked": {
       "version": "4.0.7",
       "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz",
@@ -29813,6 +29824,7 @@
       "requires": {
         "@types/base-64": "^1.0.0",
         "@types/jasmine": "^4.0.3",
+        "@types/lodash": "^4.14.191",
         "@types/node": "^18.0.3",
         "@typescript-eslint/eslint-plugin": "^5.30.6",
         "@typescript-eslint/parser": "^5.30.6",
-- 
GitLab


From cfb78656c6581760b1cbe85a6166f64ba85d3959 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Fri, 20 Jan 2023 09:45:22 +0100
Subject: [PATCH 06/11] test(e2e): pressure loss: check fields are empty when
 calculator is created with "empty fields" flags

refs #585
---
 e2e/pressure-loss-empty-fields.e2e-spec.ts | 40 ++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 e2e/pressure-loss-empty-fields.e2e-spec.ts

diff --git a/e2e/pressure-loss-empty-fields.e2e-spec.ts b/e2e/pressure-loss-empty-fields.e2e-spec.ts
new file mode 100644
index 000000000..c4516a88b
--- /dev/null
+++ b/e2e/pressure-loss-empty-fields.e2e-spec.ts
@@ -0,0 +1,40 @@
+import { ListPage } from "./list.po";
+import { Navbar } from "./navbar.po";
+import { browser } from "protractor";
+import { CalculatorPage } from "./calculator.po";
+import { PreferencesPage } from "./preferences.po";
+
+describe("Check fields are empty in 'pressure loss' calculator when created with 'empty fields' option -", () => {
+    let listPage: ListPage;
+    let navBar: Navbar;
+    let calcPage: CalculatorPage;
+    let prefPage: PreferencesPage;
+
+    beforeAll(async () => {
+        listPage = new ListPage();
+        navBar = new Navbar();
+        calcPage = new CalculatorPage();
+        prefPage = new PreferencesPage();
+    });
+
+    beforeEach(async () => {
+        // enable evil option "empty fields on module creation"
+        await prefPage.navigateTo();
+        await prefPage.enableEvilEmptyFields();
+        await browser.sleep(200);
+    });
+
+    it("with Lechapt-Calmon pressure loss law", async () => {
+        // open "pressure loss" calculator
+        await navBar.clickNewCalculatorButton();
+        await listPage.clickMenuEntryForCalcType(35);
+        await browser.sleep(200);
+
+        // select Lechapt-Calmon pressure loss law
+        const materialSelect = calcPage.getSelectById("select_pressurelosstype");
+        await calcPage.changeSelectValue(materialSelect, 0);
+        await browser.sleep(200);
+
+        expect(calcPage.checkEmptyOrFilledFields(["Q", "D", "Lg", "Kloc"], [true, true, true, true]));
+    });
+});
-- 
GitLab


From 7c28d21bbdab5a3e839dbfa31ca484b271fb6d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Fri, 20 Jan 2023 10:28:52 +0100
Subject: [PATCH 07/11] refactor : linear head loss coefficient renamed to Klin

refs #585
---
 src/app/calculators/pressureloss/en.json | 2 +-
 src/app/calculators/pressureloss/fr.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/app/calculators/pressureloss/en.json b/src/app/calculators/pressureloss/en.json
index 3ed24c3c7..464b3cd2d 100644
--- a/src/app/calculators/pressureloss/en.json
+++ b/src/app/calculators/pressureloss/en.json
@@ -24,7 +24,7 @@
     "Lg": "Pipe length",
     "fs_param_calc": "Calculation parameters",
     "Jl": "Linear head loss",
-    "Kl": "Linear head loss coefficient",
+    "Klin": "Linear head loss coefficient",
     "fD": "Darcy friction factor",
 
     "UNIT_JL": "m",
diff --git a/src/app/calculators/pressureloss/fr.json b/src/app/calculators/pressureloss/fr.json
index 9028496a3..9244b7db3 100644
--- a/src/app/calculators/pressureloss/fr.json
+++ b/src/app/calculators/pressureloss/fr.json
@@ -24,7 +24,7 @@
     "Lg": "Longueur du tuyau",
     "fs_param_calc": "Paramètres de calcul",
     "Jl": "Perte de charge linéaire",
-    "Kl": "Coefficient de perte de charge linéaire",
+    "Klin": "Coefficient de perte de charge linéaire",
     "fD": "Coefficient de perte de charge de Darcy",
 
     "UNIT_JL": "m",
-- 
GitLab


From 4b4e822038c3b970cb2e46f16a03913c552f3888 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Fri, 20 Jan 2023 15:10:35 +0100
Subject: [PATCH 08/11] refactor: rename linear head loss to Jlin

refs #585
---
 src/app/calculators/pressureloss/en.json | 4 ++--
 src/app/calculators/pressureloss/fr.json | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/app/calculators/pressureloss/en.json b/src/app/calculators/pressureloss/en.json
index 464b3cd2d..de3a81a4e 100644
--- a/src/app/calculators/pressureloss/en.json
+++ b/src/app/calculators/pressureloss/en.json
@@ -23,10 +23,10 @@
     "Kloc": "Singular head loss coefficient",
     "Lg": "Pipe length",
     "fs_param_calc": "Calculation parameters",
-    "Jl": "Linear head loss",
+    "Jlin": "Linear head loss",
     "Klin": "Linear head loss coefficient",
     "fD": "Darcy friction factor",
 
-    "UNIT_JL": "m",
+    "UNIT_JLIN": "m",
     "UNIT_V": "m/s"
 }
diff --git a/src/app/calculators/pressureloss/fr.json b/src/app/calculators/pressureloss/fr.json
index 9244b7db3..cbf2dd2d8 100644
--- a/src/app/calculators/pressureloss/fr.json
+++ b/src/app/calculators/pressureloss/fr.json
@@ -23,10 +23,10 @@
     "Kloc": "Coefficient de perte de charge singulière",
     "Lg": "Longueur du tuyau",
     "fs_param_calc": "Paramètres de calcul",
-    "Jl": "Perte de charge linéaire",
+    "Jlin": "Perte de charge linéaire",
     "Klin": "Coefficient de perte de charge linéaire",
     "fD": "Coefficient de perte de charge de Darcy",
 
-    "UNIT_JL": "m",
+    "UNIT_JLIN": "m",
     "UNIT_V": "m/s"
 }
-- 
GitLab


From 7742a202e9a99565778187c68c6eb29dc9ea58bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Thu, 2 Feb 2023 10:25:31 +0100
Subject: [PATCH 09/11] fix: pressure loss results: do not display child rank
 for results from child law nub

refs #585
---
 .../fixed-results.component.ts                | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/src/app/components/fixedvar-results/fixed-results.component.ts b/src/app/components/fixedvar-results/fixed-results.component.ts
index ae76c3e19..5905c6bce 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.ts
+++ b/src/app/components/fixedvar-results/fixed-results.component.ts
@@ -10,6 +10,7 @@ import { NgParameter } from "../../formulaire/elements/ngparam";
 import { capitalize, Result, ResultElement } from "jalhyd";
 
 import { sprintf } from "sprintf-js";
+import { PressureLoss } from "jalhyd";
 
 @Component({
     selector: "fixed-results",
@@ -256,10 +257,20 @@ export class FixedResultsComponent extends ResultsComponentDirective {
                         if (sn.parent) {
                             ct = sn.parent.calcType;
                         }
-                        const cn = capitalize(this.intlService.childName(c));
-                        let label = sprintf(this.intlService.localizeText("INFO_STUFF_N"), cn)
-                            + (c.findPositionInParent() + 1) + " : "
-                            + this.formService.expandVariableNameAndUnit(ct, k);
+
+                        // do not display child rank in case of pressure loss law
+                        const displayChildRank = !(sn instanceof PressureLoss);
+                        let label: string;
+                        if (displayChildRank) {
+                            const cn = capitalize(this.intlService.childName(c));
+                            label = sprintf(this.intlService.localizeText("INFO_STUFF_N"), cn) + (c.findPositionInParent() + 1);
+                        }
+                        else {
+                            label = capitalize(this.intlService.childName(c));
+                        }
+
+                        label += " : ";
+                        label += this.formService.expandVariableNameAndUnit(ct, k);
                         label += this._fixedResults.getHelpLink(k);
                         data.push({
                             label: label,
-- 
GitLab


From e81484c37d164866474073f48a637c1016b9cb84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Mon, 6 Feb 2023 14:20:17 +0100
Subject: [PATCH 10/11] refactor(e2e): disable test on select value after
 session reload

refs #585
---
 e2e/load-save-session.e2e-spec.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/e2e/load-save-session.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts
index 31780b9fe..ddb95adfe 100644
--- a/e2e/load-save-session.e2e-spec.ts
+++ b/e2e/load-save-session.e2e-spec.ts
@@ -137,7 +137,7 @@ describe("ngHyd − save and load sessions", () => {
         expect(fileContent).toContain(`{"symbol":"Ks","mode":"SINGLE","value":42}`);
     });
 
-    it("select value must be recovered when loading a session file", async () => {
+    xit("select value must be recovered when loading a session file", async () => {
         // start page
         await startPage.navigateTo();
         await browser.sleep(200);
-- 
GitLab


From 3b3353065d11b3c2691ca79e3b4643d6973dc3f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Grand?= <francois.grand@inrae.fr>
Date: Mon, 6 Feb 2023 14:51:57 +0100
Subject: [PATCH 11/11] fix(e2e): setParamMode() function cancels opening
 dialog rather than validate

refs #585
---
 e2e/calculator.po.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 82d81213a..ed78fc4e2 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -354,7 +354,8 @@ export class CalculatorPage {
         // for "var" mode, close the modal
         if (mode === "var") {
             await browser.sleep(500); // wait for the modal to appear
-            await element(by.css("dialog-edit-param-values .mat-dialog-actions button")).click();
+            //await element(by.css("dialog-edit-param-values .mat-dialog-actions button")).click(); // clique "annuler" et non "valider" :
+            await element(by.css("dialog-edit-param-values .mat-dialog-actions button.mat-warn")).click();
             await browser.sleep(500); // wait for the navbar to reappear after modal dismissal
         }
     }
-- 
GitLab