From a2223451e96d6185bd3ae98f79dbda5a531ac90e Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 21 Feb 2019 10:15:22 +0100
Subject: [PATCH 01/26] =?UTF-8?q?M=C3=A0J=20jalhyd=5Fbranch?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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

diff --git a/jalhyd_branch b/jalhyd_branch
index 1f7391f92..5da74c213 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-master
+64-implementer-la-de-serialisation-au-niveau-du-nub
-- 
GitLab


From d2cfdf5fd128de211e5e2d44dda43c66f2b234ed Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 21 Feb 2019 10:16:08 +0100
Subject: [PATCH 02/26] L'UID d'un FormulaireDefinition est maintenat l'UID de
 son Nub courant

---
 .../formulaire/definition/form-definition.ts  | 41 +++++++++----------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 390718dcd..f996ae7de 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -51,6 +51,16 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this._paramService = ServiceFactory.instance.paramService;
     }
 
+    // surcharge de FormulaireNode::get:uid()
+    // l'UID d'un formulaire est l'UID de son Nub !
+    public get uid() {
+        if (this._currentNub) {
+            return this._currentNub.uid;
+        } else {
+            throw new Error("Aucun Nub associé au formulaire !");
+        }
+    }
+
     public get calculatorType(): CalculatorType {
         const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
         return props["calcType"];
@@ -81,8 +91,8 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return this._props;
     }
 
-    public initNub(props?: {}) {
-        this._currentNub = this.createNub(props === undefined ? this.defaultProperties : props);
+    public initNub(props?: Props) {
+        this._currentNub = this.createNub(props === undefined ? new Props(this.defaultProperties) : props);
     }
 
     public get currentNub(): Nub {
@@ -99,9 +109,9 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this._currentNub = n;
     }
 
-    protected createNub(params: Props | {}): Nub {
-        const props = params instanceof Props ? params : new Props(params);
-        return this._paramService.createNub(props);
+    protected createNub(p: Props): Nub {
+        console.log("FormDefinition - createNub", p);
+        return this._paramService.createNub(p);
     }
 
     protected replaceCurrentNub(params: Props) {
@@ -164,6 +174,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     private parse_fieldset(json: {}) {
         const fs = this.createFieldset(this, json);
         fs.parseConfig(json);
+        console.log(".FormDefinition: parse_fieldset " + fs.id + " >> afterParseFieldset");
         this.afterParseFieldset(fs);
     }
 
@@ -454,19 +465,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return new TopFormulaireElementIterator(this);
     }
 
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        const res = {};
-        res["id"] = this.calculatorName;
-        res["uid"] = this.uid;
-        res["props"] = (this._currentNub.properties as Props).props;
-        res["elements"] = this.serialiseKids();
-        return { "form": res };
-    }
-
-    private deserialiseFieldset(elements: {}): FieldSet {
+   /*  private deserialiseFieldset(elements: {}): FieldSet {
         const res: FieldSet = this.getFormulaireNodeById(elements["id"]) as FieldSet;
         res.deserialiseJSON(elements);
         return res;
@@ -498,9 +497,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }
     }
 
-    /**
-     * désérialisation depuis JSON
-     */
     public deserialiseJSON(elements: {}) {
         // tslint:disable-next-line:forin
         for (const k in elements) {
@@ -523,7 +519,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
                     throw new Error(`session file : invalid key '${k}' in form object`);
             }
         }
-    }
+    } */
 
     /**
      * MAJ des liens entre paramètres lors de la désérialisation JSON
@@ -548,6 +544,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
       * @param uidMap table de correspondance uid dans le fichier de conf <-> uid en mémoire
       */
     public updateParamsLinks(json: {}, uidMap: {}[]) {
+        console.log("++ UPDATE PARAMS LINKS (form definition) ++");
         for (const ks in json) {
             switch (ks) {
                 case "elements":
-- 
GitLab


From c3211c4fefaae6920b92906b2b352118849e0b95 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 21 Feb 2019 10:16:37 +0100
Subject: [PATCH 03/26] Normalisation de type : Props vs {}

---
 .../definition/concrete/form-parallel-structures.ts           | 3 +--
 src/app/services/param/param.service.ts                       | 4 ++--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index 8e563f732..76f8b742e 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -3,7 +3,6 @@ import { Structure, Nub, ParallelStructure, StructureType, LoiDebit, StructurePr
 import { FormulaireDefinition } from "../form-definition";
 import { CalculatorResults } from "../../../results/calculator-results";
 import { FormDefParamToCalculate } from "../form-def-paramcalc";
-import { FormDefFixedVar } from "../form-def-fixedvar";
 import { FormDefParallelStructures } from "../form-def-parallel-structures";
 import { FormComputeParallelStructures } from "../form-compute-parallel-structures";
 import { FormResultFixedVar } from "../form-result-fixedvar";
@@ -52,7 +51,7 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         params["structureType"] = templ.defaultStructTypeFromConfig;
         params["loiDebit"] = templ.defaultLoiDebitFromConfig;
 
-        return this.createNub(params);
+        return this.createNub(new Props(params));
     }
 
     /**
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index d8d36ce02..7b7b5639d 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -96,8 +96,8 @@ export class ParamService {
         return p;
     }
 
-    public createNub(params: Props | {}): Nub {
-        const truc = Session.getInstance().createSessionNub(params);
+    public createNub(p: Props): Nub {
+        const truc = Session.getInstance().createSessionNub(p);
         return truc;
     }
 
-- 
GitLab


From 42890a7be5686af15f10787c9667b63a54d2e31d Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 21 Feb 2019 14:57:15 +0100
Subject: [PATCH 04/26] =?UTF-8?q?Fix=20#132,=20#135=20d=C3=A9placer=20la?=
 =?UTF-8?q?=20(d=C3=A9)s=C3=A9rialisation=20dans=20JaLHyd?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.component.ts                      |  17 +-
 .../field-set/field-set.component.ts          |   2 +-
 .../calculator.component.ts                   |  15 +-
 .../formulaire/definition/form-definition.ts  |  66 +-------
 src/app/formulaire/fieldset-container.ts      |  61 --------
 src/app/formulaire/fieldset.ts                |  70 +--------
 src/app/formulaire/formulaire-node.ts         |  20 ---
 src/app/formulaire/ngparam.ts                 |  95 ------------
 src/app/formulaire/select-entry.ts            |  10 --
 src/app/formulaire/select-field.ts            |  37 -----
 .../services/formulaire/formulaire.service.ts | 145 +++++-------------
 src/app/services/param/param.service.ts       |   4 -
 12 files changed, 69 insertions(+), 473 deletions(-)

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index acecbe6d6..d70c14882 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -3,7 +3,7 @@ import { Router, Event, NavigationEnd, ActivationEnd } from "@angular/router";
 import { MatSidenav, MatToolbar, MatDialog, MatIconRegistry } from "@angular/material";
 import { DomSanitizer } from "@angular/platform-browser";
 
-import { Observer, jalhydDateRev, CalculatorType } from "jalhyd";
+import { Observer, jalhydDateRev, CalculatorType, Session } from "jalhyd";
 
 import { environment } from "../environments/environment";
 import { I18nService } from "./services/internationalisation/internationalisation.service";
@@ -290,16 +290,23 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
     this._calculators[formIndex]["title"] = title;
   }
 
+  /**
+   * Saves a JSON serialised session file, for one or more calc modules
+   * @param calcList modules to save
+   * @param filename
+   */
   private saveSession(calcList: any[], filename) {
     const elems = [];
+    const serialiseOptions: { [key: string]: {} } = {};
     for (const c of calcList) {
       if (c.selected) {
-        const form: FormulaireDefinition = this.formulaireService.getFormulaireFromId(c.uid);
-        elems.push(form.JSONserialise());
+        serialiseOptions[c.uid] = { // GUI-dependent metadata to add to the session file
+          title: c.title
+        };
       }
     }
-    const session = { "session": { "elements": elems } };
-    this.formulaireService.saveSession(session, filename);
+    const session: string = Session.getInstance().serialise(serialiseOptions);
+    this.formulaireService.downloadTextFile(session, filename);
   }
 
   /**
diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts
index 5848aa4c1..170ba7cda 100644
--- a/src/app/components/field-set/field-set.component.ts
+++ b/src/app/components/field-set/field-set.component.ts
@@ -32,7 +32,7 @@ export class FieldSetComponent implements DoCheck {
         if (! this._fieldSet) {
             return "fs undefined";
         }
-        if (! this._fieldSet.label) { // @TODO allow "" ?
+        if (! this._fieldSet.label) {
             return "label undefined";
         }
         return this._fieldSet.label;
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index e8c970323..ebf3722c8 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -1,7 +1,7 @@
 import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, QueryList, AfterViewChecked } from "@angular/core";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
 
-import { Observer } from "jalhyd";
+import { Observer, Session } from "jalhyd";
 
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
@@ -97,6 +97,7 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
 
     constructor(
         private route: ActivatedRoute,
+        private router: Router,
         private confirmCloseCalcDialog: MatDialog
     ) {
         super();
@@ -408,8 +409,14 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         });
     }
 
+    /**
+     * Duplicates the current calculator form
+     */
     public cloneCalculator() {
-        const serializedForm = this._formulaire.JSONserialise()["form"];
-        this.formulaireService.deserialiseForm(serializedForm);
+        const serialisedNub: string = this._formulaire.currentNub.serialise({ title: this._formulaire.calculatorName });
+        const nubPointer = Session.getInstance().unserialiseSingleNub(serialisedNub);
+        this.formulaireService.createFormulaire(nubPointer.nub.calcType, nubPointer.nub, nubPointer.meta.title).then((f) => {
+            this.router.navigate(["/calculator", f.uid]);
+        });
     }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f996ae7de..f309a9a46 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -1,4 +1,4 @@
-import { CalculatorType, ComputeNodeType, Nub, Props, Observer } from "jalhyd";
+import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session } from "jalhyd";
 
 import { FormulaireElement } from "../formulaire-element";
 import { NgParameter, ParamRadioConfig } from "../ngparam";
@@ -110,16 +110,15 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     protected createNub(p: Props): Nub {
-        console.log("FormDefinition - createNub", p);
         return this._paramService.createNub(p);
     }
 
     protected replaceCurrentNub(params: Props) {
-        this.currentNub = this._paramService.replaceNub(this._currentNub, params);
+        this.currentNub = Session.getInstance().replaceNub(this._currentNub, params);
     }
 
     protected replaceNub(sn: Nub, params: Props): Nub {
-        return this._paramService.replaceNub(sn, params);
+        return Session.getInstance().replaceNub(sn, params);
     }
 
     protected deleteNub(sn: Nub) {
@@ -174,7 +173,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     private parse_fieldset(json: {}) {
         const fs = this.createFieldset(this, json);
         fs.parseConfig(json);
-        console.log(".FormDefinition: parse_fieldset " + fs.id + " >> afterParseFieldset");
         this.afterParseFieldset(fs);
     }
 
@@ -465,64 +463,8 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return new TopFormulaireElementIterator(this);
     }
 
-   /*  private deserialiseFieldset(elements: {}): FieldSet {
-        const res: FieldSet = this.getFormulaireNodeById(elements["id"]) as FieldSet;
-        res.deserialiseJSON(elements);
-        return res;
-    }
-
-    private deserialiseFieldsetContainer(elements: {}): FieldsetContainer {
-        const res: FieldsetContainer = this.getFormulaireNodeById(elements["id"]) as FieldsetContainer;
-        res.deserialiseJSON(elements);
-        return res;
-    }
-
-    private deserialiseElement(element: {}) {
-        const keys = Object.keys(element);
-        if (keys.length !== 1) {
-            throw new Error(`session file : invalid form object '${element}'`);
-        }
-
-        switch (keys[0]) {
-            case "fieldset":
-                this.deserialiseFieldset(element[keys[0]]);
-                break;
-
-            case "fieldset_container":
-                this.deserialiseFieldsetContainer(element[keys[0]]);
-                break;
-
-            default:
-                throw new Error(`session file : invalid key '${keys[0]}' in form object`);
-        }
-    }
-
-    public deserialiseJSON(elements: {}) {
-        // tslint:disable-next-line:forin
-        for (const k in elements) {
-            switch (k) {
-                case "id":
-                    this._calculatorName = elements[k];
-                    break;
-
-                case "uid":
-                case "props":
-                    break;
-
-                case "elements":
-                    for (const e of elements[k]) {
-                        this.deserialiseElement(e);
-                    }
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${k}' in form object`);
-            }
-        }
-    } */
-
     /**
-     * MAJ des liens entre paramètres lors de la désérialisation JSON
+     * MAJ des liens entre paramètres lors de la désérialisation
      */
 
     private getNthFieldset(n: number): FieldSet {
diff --git a/src/app/formulaire/fieldset-container.ts b/src/app/formulaire/fieldset-container.ts
index 6f2898e7f..38f5bdb34 100644
--- a/src/app/formulaire/fieldset-container.ts
+++ b/src/app/formulaire/fieldset-container.ts
@@ -115,65 +115,4 @@ export class FieldsetContainer extends FormulaireElement {
             super.updateLocalisation(loc);
         }
     }
-
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        const res = {};
-        res["id"] = this.id;
-        res["elements"] = this.serialiseKids();
-        return { "fieldset_container": res };
-    }
-
-    private deserialiseFieldset(elements: {}): FieldSet {
-        const ind = this.getTemplateIndex(elements["id"]);
-        const res: FieldSet = this.addFromTemplate(ind);
-        const props = elements["props"];
-        for (const k in props) {
-            if (k !== "calcType" && k !== "nodeType") {
-                res.setPropValue(k, props[k]);
-            }
-        }
-        res.deserialiseJSON(elements);
-        return res;
-    }
-
-    private deserialiseElement(element: {}) {
-        const keys = Object.keys(element);
-        if (keys.length !== 1) {
-            throw new Error(`session file : invalid fieldset object '${element}'`);
-        }
-
-        switch (keys[0]) {
-            case "fieldset":
-                this.deserialiseFieldset(element[keys[0]]);
-                break;
-
-            default:
-                throw new Error(`session file : invalid key '${keys[0]}' in fieldset object`);
-        }
-    }
-
-    /**
-     * désérialisation depuis JSON
-     */
-    public deserialiseJSON(elements: {}) {
-        for (const k in elements) {
-            switch (k) {
-                case "id":
-                    this._confId = elements[k];
-                    break;
-
-                case "elements":
-                    for (const e of elements[k]) {
-                        this.deserialiseElement(e);
-                    }
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${k}' in form object`);
-            }
-        }
-    }
 }
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 73740f7ec..8138991f9 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -375,75 +375,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        const res = {};
-        res["id"] = this.id;
-        res["props"] = this._props.props;
-        res["elements"] = this.serialiseKids();
-        return { "fieldset": res };
-    }
-
-    private deserialiseParam(elements: {}): NgParameter {
-        const res: NgParameter = this.getFormulaireNodeById(elements["id"]) as NgParameter;
-        res.deserialiseJSON(elements);
-        return res;
-    }
-
-    private deserialiseSelect(elements: {}): SelectField {
-        const res: SelectField = this.getFormulaireNodeById(elements["id"]) as SelectField;
-        res.deserialiseJSON(elements);
-        return res;
-    }
-
-    private deserialiseElement(element: {}) {
-        const keys = Object.keys(element);
-        if (keys.length !== 1) {
-            throw new Error(`session file : invalid fieldset object '${element}'`);
-        }
-
-        switch (keys[0]) {
-            case "param":
-                this.deserialiseParam(element[keys[0]]);
-                break;
-
-            case "select":
-                this.deserialiseSelect(element[keys[0]]);
-                break;
-
-            default:
-                throw new Error(`session file : invalid key '${keys[0]}' in fieldset object`);
-        }
-    }
-
-    /**
-     * désérialisation depuis JSON
-     */
-    public deserialiseJSON(elements: {}) {
-        for (const k in elements) {
-            switch (k) {
-                case "id":
-                    break;
-
-                case "props":
-                    this._props = new Props(elements[k]);
-                    break;
-
-                case "elements":
-                    for (const e of elements[k]) {
-                        this.deserialiseElement(e);
-                    }
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${k}' in form object`);
-            }
-        }
-    }
-
-    /**
-     * MAJ des liens entre paramètres lors de la désérialisation JSON
+     * MAJ des liens entre paramètres lors de la désérialisation
      * @param json conf du fieldset issue du fichier
      * @param uidMap table de correspondance uid dans le fichier de conf <-> uid en mémoire
      */
diff --git a/src/app/formulaire/formulaire-node.ts b/src/app/formulaire/formulaire-node.ts
index 128f39a67..918c6d8da 100644
--- a/src/app/formulaire/formulaire-node.ts
+++ b/src/app/formulaire/formulaire-node.ts
@@ -56,11 +56,6 @@ export abstract class FormulaireNode implements IObservable {
         return this._uid;
     }
 
-    /** utiliser uniquement pour charger des sessions (désérialisation JSON) */
-    public setUid(uid: string) {
-        this._uid = uid;
-    }
-
     /**
      * cherche un FormulaireNode par son id de conf
      */
@@ -149,19 +144,4 @@ export abstract class FormulaireNode implements IObservable {
     notifyObservers(data: any, sender?: any) {
         this._observable.notifyObservers(data, sender);
     }
-
-    protected serialiseKids() {
-        const elems = [];
-        for (const k of this.kids) {
-            elems.push(k.JSONserialise());
-        }
-        return elems;
-    }
-
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        return {};
-    }
 }
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 1c82a275a..6d61d9a78 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -319,101 +319,6 @@ export class NgParameter extends InputField implements Observer {
         }
     }
 
-    private paramValuesJSON(): any {
-        const res = {};
-        const vm = this._paramDef.valueMode;
-        res["mode"] = ParamValueMode[vm];
-        switch (vm) {
-            case ParamValueMode.SINGLE:
-                res["value"] = this.getValue();
-                break;
-
-            case ParamValueMode.MINMAX:
-                res["min"] = this.minValue;
-                res["max"] = this.maxValue;
-                res["step"] = this.stepValue;
-                break;
-
-            case ParamValueMode.LISTE:
-                res["values"] = this.valueList;
-                break;
-
-            case ParamValueMode.LINK:
-                res["form_uid"] = ServiceFactory.instance.formulaireService.getFormulaireFromNubId(this._paramDef.referencedNub["uid"]).uid;
-                res["ref"] = this.paramDefinition.referenceDefinition;
-                break;
-        }
-        return res;
-    }
-
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        const res = {};
-        res["id"] = this.id;
-        res["values"] = this.paramValuesJSON();
-        return { "param": res };
-    }
-
-    private deserialiseValues(json: {}) {
-        const m: ParamValueMode = (<any>ParamValueMode)[json["mode"]];
-        switch (m) {
-            case ParamValueMode.SINGLE:
-                this._paramValues.setValues(+json["value"]);
-                break;
-
-            case ParamValueMode.MINMAX:
-                this._paramValues.setValues(+json["min"], +json["max"], +json["step"]);
-                break;
-
-            case ParamValueMode.LISTE:
-                this._paramValues.setValues(json["values"]);
-                break;
-
-            case ParamValueMode.CALCUL:
-                this._paramValues.valueMode = ParamValueMode.CALCUL;
-                break;
-
-            case ParamValueMode.LINK:
-                const uid: string = json["form_uid"];
-                const ref: string = json["ref"];
-                this._paramValues.valueMode = ParamValueMode.LINK;
-                // formulaire dont le Nub est la cible du lien
-                const destForm = ServiceFactory.instance.formulaireService.getFormulaireFromId(uid);
-                if (destForm) {
-                    this._paramValues.defineReference(destForm.currentNub, ref);
-                } else {
-                    // @TODO et si la cible du lien n'existe pas ??
-                    // cf FormulaireService.updateParamsLinks()
-                    console.log("LA CIBLE DU LIEN N'EXISTE PAS !!");
-                }
-                break;
-
-            default:
-                throw new Error(`session file : invalid value mode '${json["mode"]}' in param object`);
-        }
-    }
-
-    /**
-     * désérialisation depuis JSON
-     */
-    public deserialiseJSON(elements: {}) {
-        for (const k in elements) {
-            switch (k) {
-                case "id":
-                    break;
-
-                case "values":
-                    this.deserialiseValues(elements[k]);
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${k}' in param object`);
-            }
-        }
-    }
-
     // interface Observer
 
     public update(sender: any, data: any) {
diff --git a/src/app/formulaire/select-entry.ts b/src/app/formulaire/select-entry.ts
index fdd7597cd..cb4082fa3 100644
--- a/src/app/formulaire/select-entry.ts
+++ b/src/app/formulaire/select-entry.ts
@@ -27,14 +27,4 @@ export class SelectEntry {
     get value(): any {
         return this._value;
     }
-
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise() {
-        const res = {};
-        res["id"] = this.id;
-        res["value"] = this._value;
-        return res;
-    }
 }
diff --git a/src/app/formulaire/select-field.ts b/src/app/formulaire/select-field.ts
index a8162bac4..df078bfbf 100644
--- a/src/app/formulaire/select-field.ts
+++ b/src/app/formulaire/select-field.ts
@@ -43,7 +43,6 @@ export class SelectField extends Field {
 
     public setValue(v: SelectEntry) {
         if (this._selectedEntry !== v) {
-            console.log("++++ select field : notify observers", v);
             this._selectedEntry = v;
             this.notifyObservers({
                 "action": "select",
@@ -121,40 +120,4 @@ export class SelectField extends Field {
             this.addEntry(e);
         }
     }
-
-    /**
-     * sérialisation en JSON
-     */
-    public JSONserialise(): {} {
-        const res = {};
-        res["id"] = this.id;
-        res["selected_id"] = this._selectedEntry.id;
-        return { "select": res };
-    }
-
-    /**
-     * désérialisation depuis JSON
-     */
-    public deserialiseJSON(elements: {}) {
-        for (const k in elements) {
-            switch (k) {
-                case "id":
-                    this._confId = elements[k];
-                    break;
-
-                case "selected_id":
-                    const sel = elements[k];
-                    for (const e of this._entries) {
-                        if (e.id === sel) {
-                            this.setValue(e);
-                            break;
-                        }
-                    }
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${k}' in select object`);
-            }
-        }
-    }
 }
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index 8be740fa2..4da19c45e 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -3,7 +3,7 @@ import { Injectable } from "@angular/core";
 import { decode } from "he";
 import { saveAs } from "file-saver";
 
-import { CalculatorType, EnumEx, Observable, ParamDefinition } from "jalhyd";
+import { CalculatorType, EnumEx, Observable, ParamDefinition, Session, Nub } from "jalhyd";
 
 import { HttpService } from "../../services/http/http.service";
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
@@ -163,32 +163,30 @@ export class FormulaireService extends Observable {
     /**
      * crée un formulaire d'un type donné
      * @param ct type de formulaire
-     * @param jsonState descripteur sérialisé du formulaire, le cal échéant
+     * @param nub nub existant à associer au formulaire (chargement de session / duplication de module)
+     * @param calculatorName nom du module, à afficher dans l'interface
      */
-    public createFormulaire(ct: CalculatorType, jsonState?: {}): Promise<FormulaireDefinition> {
+    public createFormulaire(ct: CalculatorType, nub?: Nub, calculatorName?: string): Promise<FormulaireDefinition> {
+        // Crée un formulaire du bon type
         const f: FormulaireDefinition = this.newFormulaire(ct);
-        // conserver l'UID d'origine, sauf en cas de collision
-        if (jsonState !== undefined) {
-            const originalUID = jsonState["uid"];
-            if (originalUID !== undefined && ! this.formUIDAlreadyUsed(originalUID)) {
-                f.setUid(originalUID);
-            }
-        }
         this._formulaires.push(f);
-
+        // Charge la configuration dépendamment du type
         const prom: Promise<any> = this.loadConfig(ct);
         return prom.then(s => {
             f.preparseConfig(s);
-            if (jsonState === undefined) {
+            // Associe le Nub fourni (chargement de session / duplication de module), sinon en crée un nouveau
+            if (nub) {
+                f.currentNub = nub;
+            } else {
+                f.initNub();
+            }
+            // Restaure le nom du module
+            if (calculatorName) {
+                f.calculatorName = calculatorName;
+            } else {
                 f.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct));
             }
-            f.initNub();
             f.parseConfig();
-            if (jsonState !== undefined) {
-                f.deserialiseJSON(jsonState);
-            }
-            // la méthode loadUpdateFormulaireLocalisation retourne une Promise; le fait de retourner une Promise dans un then
-            // fait que le then suivant est exécuté juste après.
             return this.loadUpdateFormulaireLocalisation(f);
         }).then(fi => {
             fi.applyDependencies();
@@ -384,24 +382,27 @@ export class FormulaireService extends Observable {
      */
     public loadSession(f: File, formInfos: any[]) {
         this.readSingleFile(f).then(s => {
-            const session = JSON.parse(s);
-            for (const k in session) {
-                switch (k) {
-                    case "session":
-                        this.deserialiseSession(session[k], formInfos);
-                        break;
-
-                    default:
-                        throw new Error(`session file : invalid key '${k}'`);
+            const uids: string[] = [];
+            formInfos.forEach((fi) => {
+                if (fi.selected) {
+                    uids.push(fi.uid);
                 }
-            }
+            });
+            const newNubs = Session.getInstance().unserialise(s, uids);
+            // for each new Nub, create the related form, set its title
+            newNubs.forEach((nn) => {
+                this.createFormulaire(nn.nub.calcType, nn.nub, nn.meta.title);
+            });
         }).catch(err => {
             throw err;
         });
     }
 
-    public saveSession(session: {}, filename?: string) {
-        const blob = new Blob([JSON.stringify(session)], { type: "text/plain;charset=utf-8" });
+    /**
+     * Sends an UTF-8 text file for download
+     */
+    public downloadTextFile(session: string, filename: string = "file_1") {
+        const blob = new Blob([session], { type: "text/plain;charset=utf-8" });
         saveAs(blob, filename);
     }
 
@@ -412,27 +413,15 @@ export class FormulaireService extends Observable {
     public calculatorInfosFromSessionFile(f: File): Promise<any[]> {
         return this.readSingleFile(f).then(s => {
             const res: any[] = [];
-            const session = JSON.parse(s);
-
+            const data = JSON.parse(s);
             // liste des noms de modules de calcul
-            for (const k in session) {
-                switch (k) {
-                    case "session":
-                        const sess = session[k];
-                        const elems = sess["elements"];
-                        for (const e of elems) {
-                            for (const l in e) {
-                                if (l === "form") {
-                                    const form = e[l];
-                                    res.push({ "uid": form["uid"], "title": form["id"] });
-                                }
-                            }
-                        }
-                        break;
-
-                    default:
-                        throw new Error(`session file : invalid key '${k}'`);
-                }
+            if (data.session && Array.isArray(data.session)) {
+                data.session.forEach((e: any) => {
+                   res.push({
+                       uid: e.uid,
+                       title: e.meta && e.meta.title ? e.meta.title : undefined
+                    });
+                });
             }
             return res;
         });
@@ -445,35 +434,6 @@ export class FormulaireService extends Observable {
         });
     }
 
-    public deserialiseForm(elements: {}): Promise<FormulaireDefinition> {
-        const props = elements["props"];
-        const ct: CalculatorType = props["calcType"];
-        return this.createFormulaire(ct, elements);
-    }
-
-    private deserialiseSessionElement(element: {}, formInfos: any[]): Promise<FormulaireDefinition> {
-        const keys = Object.keys(element);
-        if (keys.length !== 1) {
-            throw new Error(`session file : invalid session object '${element}'`);
-        }
-
-        switch (keys[0]) {
-            case "form":
-                const form = element[keys[0]];
-
-                for (const i of formInfos) {
-                    // on the loadSession dialog, was the checkbox checked for this calculator ?
-                    if (i["uid"] === form["uid"] && i["selected"]) {
-                        return this.deserialiseForm(form);
-                    }
-                }
-                break;
-
-            default:
-                throw new Error(`session file : invalid key '${keys[0]}' in session object`);
-        }
-    }
-
     /**
      * met à jour les liens d'un formulaire
      * @param json conf du formulaire
@@ -490,7 +450,7 @@ export class FormulaireService extends Observable {
     }
 
     /**
-     * MAJ des liens entre paramètres lors de la désérialisation JSON
+     * MAJ des liens entre paramètres lors de la désérialisation
      */
 
     private updateParamsLinks(json: {}, formInfos: any[], oldFormCount: number) {
@@ -538,31 +498,6 @@ export class FormulaireService extends Observable {
         }
     }
 
-    private deserialiseSession(elements: {}, formInfos: any[]) {
-        let p: Promise<FormulaireDefinition>;
-
-        const oldFormCount = this._formulaires.length;
-        for (const ks in elements) {
-            switch (ks) {
-                case "elements":
-                    for (const e of elements[ks]) {
-                        if (p === undefined) {
-                            p = this.deserialiseSessionElement(e, formInfos);
-                        } else {
-                            p = p.then(_ => {
-                                return this.deserialiseSessionElement(e, formInfos);
-                            });
-                        }
-                    }
-                    break;
-
-                default:
-                    throw new Error(`session file : invalid key '${ks}' in session object`);
-            }
-        }
-        p.then(_ => this.updateParamsLinks(elements, formInfos, oldFormCount));
-    }
-
     /**
      * @returns liste des valeurs liables à un paramètre sous la forme d'un tableau d'objets
      * {"param":<paramètre lié>, "nub":<Nub d'origine du paramètre lié>, "formTitle":<nom du module de calcul liée au nub>}
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index 7b7b5639d..aff79fb26 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -101,10 +101,6 @@ export class ParamService {
         return truc;
     }
 
-    public replaceNub(sn: Nub, params: Props): Nub {
-        return Session.getInstance().replaceNub(sn, params);
-    }
-
     public deleteNub(sn: Nub) {
         Session.getInstance().deleteNub(sn);
     }
-- 
GitLab


From 830343c8288428a2642518f938dc3bf81ad8bb23 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Fri, 22 Feb 2019 11:19:11 +0100
Subject: [PATCH 05/26] =?UTF-8?q?M=C3=A0J=20test=20e2e=20:=20clonage=20de?=
 =?UTF-8?q?=20module?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 e2e/clone-calc.e2e-spec.ts | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts
index 21b6206f7..2f200f054 100644
--- a/e2e/clone-calc.e2e-spec.ts
+++ b/e2e/clone-calc.e2e-spec.ts
@@ -44,9 +44,9 @@ describe("ngHyd − clone a calculator", () => {
       k: 0.6,
       Ks: 42
     };
-    // await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique"
-    // await calcPage.getInputById("k").clear();
-    // await calcPage.getInputById("k").sendKeys(sourceValues["k"]);
+    await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique"
+    await calcPage.getInputById("k").clear();
+    await calcPage.getInputById("k").sendKeys(sourceValues["k"]);
     await calcPage.getInputById("Ks").clear();
     await calcPage.getInputById("Ks").sendKeys(sourceValues["Ks"]);
     // link "Débit" to "Courbe de remous"
@@ -60,9 +60,34 @@ describe("ngHyd − clone a calculator", () => {
     await browser.executeScript("window.scrollTo(0, 0);");
     await calcPage.clickCloneCalcButton();
     await browser.sleep(500);
-    // 4. check the cloned module
+
+    // 4. check existence of the cloned module
     expect(await navbar.getAllCalculatorTabs().count()).toBe(4);
     await navbar.clickCalculatorTab(3); // n°3 should be the latest
+    await browser.sleep(500);
+
+    // 5. compare values
+    Object.keys(sourceValues).forEach(async (k) => {
+      const v = sourceValues[k];
+      const displayedVal = await calcPage.getInputById(k).getAttribute("value");
+      expect(displayedVal).toBe("" + v);
+    });
+  });
+
+  it("cloning a parallel-structures calculator should work", async () => {
+    await startPage.navigateTo();
+
+    // create source module to clone
+    await navbar.clickNewCalculatorButton();
+    await listPage.clickMenuEntryForCalcType(8); // Lois d'ouvrages
+    await browser.sleep(500);
+
+    // otherwise clickCloneCalcButton() fails with "Element is not clickable at point"
+    // await browser.executeScript("window.scrollTo(0, 0);");
+    await calcPage.clickCloneCalcButton();
+    await browser.sleep(500);
 
+    // check existence of the cloned module
+    expect(await navbar.getAllCalculatorTabs().count()).toBe(2);
   });
 });
-- 
GitLab


From 818a8f65dac17a4aaba92a5baeb75b757384b907 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 25 Feb 2019 10:59:07 +0100
Subject: [PATCH 06/26] =?UTF-8?q?Gestion=20du=20Nub=20parent=20lorsqu'on?=
 =?UTF-8?q?=20cr=C3=A9e=20des=20Structures?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../parallel-structures.config.json           | 10 +++++-----
 .../concrete/form-parallel-structures.ts      | 13 +++++++++----
 .../form-compute-parallel-structures.ts       |  7 +------
 .../formulaire/definition/form-definition.ts  | 19 ++++++++++++-------
 src/app/services/param/param.service.ts       | 11 ++++++++---
 5 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/src/app/calculators/parallel-structures/parallel-structures.config.json b/src/app/calculators/parallel-structures/parallel-structures.config.json
index 8ba966d27..2949378bb 100644
--- a/src/app/calculators/parallel-structures/parallel-structures.config.json
+++ b/src/app/calculators/parallel-structures/parallel-structures.config.json
@@ -29,7 +29,7 @@
         "calcType": "Structure",
         "defaultNodeType": "StructureRectangle",
         "defaultStructType": "VanneRectangulaire",
-        "defaultLoiDebit": "Cem88v",
+        "defaultLoiDebit": "GateCem88v",
         "option": "cal",
         "fields": [
             {
@@ -60,11 +60,11 @@
                 "select": [
                     {
                         "id": "select_loidebit1_cem88d",
-                        "enum": "LoiDebit.Cem88d"
+                        "enum": "LoiDebit.WeirCem88d"
                     },
                     {
                         "id": "select_loidebit1_cem88v",
-                        "enum": "LoiDebit.Cem88v"
+                        "enum": "LoiDebit.WeirCem88v"
                     },
                     {
                         "id": "select_loidebit1_seuildenoye",
@@ -92,11 +92,11 @@
                 "select": [
                     {
                         "id": "select_loidebit2_cem88v",
-                        "enum": "LoiDebit.Cem88v"
+                        "enum": "LoiDebit.GateCem88v"
                     },
                     {
                         "id": "select_loidebit2_cem88d",
-                        "enum": "LoiDebit.Cem88d"
+                        "enum": "LoiDebit.GateCem88d"
                     },
                     {
                         "id": "select_loidebit2_vannedenoye",
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index 76f8b742e..37bbdc962 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -51,7 +51,8 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         params["structureType"] = templ.defaultStructTypeFromConfig;
         params["loiDebit"] = templ.defaultLoiDebitFromConfig;
 
-        return this.createNub(new Props(params));
+        // specify the parent Nub to check admissible laws
+        return this.createNub(new Props(params), this.currentNub as ParallelStructure);
     }
 
     /**
@@ -281,7 +282,9 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
             throw new Error(`pas de select trouvé avec une dépendance au select 'type de structure' pour la valeur ${structSelect.select.id}=${structSelect.entry.id} (2)`);
         }
 
-        res.setPropValue("loiDebit", StructureProperties.findCompatibleLoiDebit(structType, loisDebit));
+        res.setPropValue("loiDebit", StructureProperties.findCompatibleLoiDebit(
+            structType, loisDebit, this.currentNub as ParallelStructure) // currentNub should always be a ParallelStructure here
+        );
 
         return res;
     }
@@ -302,7 +305,9 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         // (par ex, s'il existe un select de lois de débit dépendant du select de types
         // d'ouvrage, on prend la 1ère entrée du select de lois de débit compatible)
         if (name === "structureType") {
-            if (!StructureProperties.isCompatibleValues(val, fs.properties.getPropValue("loiDebit"))) {
+            if (!StructureProperties.isCompatibleValues(
+                val, fs.properties.getPropValue("loiDebit"), this.currentNub as ParallelStructure)
+            ) {
                 return this.adjustLoiDebit(fs, val);
             }
         }
@@ -356,7 +361,7 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
             switch (sender.id) {
                 case "fs_ouvrage":
                     const props = this.adjustProperties(sender, data["name"], data["value"]);
-                    const newNub = this.replaceNub(sender.nub, props);
+                    const newNub = this.replaceNub(sender.nub, props, this.currentNub as ParallelStructure);
                     sender.setNub(newNub);
                     this.reset();
                     break;
diff --git a/src/app/formulaire/definition/form-compute-parallel-structures.ts b/src/app/formulaire/definition/form-compute-parallel-structures.ts
index f53ef23d8..9daa4cbd6 100644
--- a/src/app/formulaire/definition/form-compute-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-compute-parallel-structures.ts
@@ -1,13 +1,8 @@
-import {
-    ComputeNode, ParamsEquation, ParallelStructure, ParallelStructureParams, CalculatorType, StructureParams,
-    Structure, CreateStructure, StructureType, ComputeNodeType, LoiDebit
-} from "jalhyd";
+import { ComputeNode, ParallelStructure } from "jalhyd";
 
 import { FormComputeFixedVar } from "./form-compute-fixedvar";
 import { FormResultFixedVar } from "./form-result-fixedvar";
 import { FormulaireDefinition } from "./form-definition";
-import { SelectField } from "../select-field";
-import { FormulaireElement } from "../formulaire-element";
 import { NgParameter } from "../ngparam";
 import { FormulaireNode } from "../formulaire-node";
 import { FieldSet } from "../fieldset";
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f309a9a46..359709ca1 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -1,4 +1,4 @@
-import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session } from "jalhyd";
+import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, ParallelStructure } from "jalhyd";
 
 import { FormulaireElement } from "../formulaire-element";
 import { NgParameter, ParamRadioConfig } from "../ngparam";
@@ -109,16 +109,21 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this._currentNub = n;
     }
 
-    protected createNub(p: Props): Nub {
-        return this._paramService.createNub(p);
+    /**
+     * Asks the ParamService to create a Nub
+     * @param p properties for the new Nub
+     * @param parentNub optional parent Nub when creating a Structure Nub, for admissible laws check
+     */
+    protected createNub(p: Props, parentNub?: ParallelStructure): Nub {
+        return this._paramService.createNub(p, parentNub);
     }
 
-    protected replaceCurrentNub(params: Props) {
-        this.currentNub = Session.getInstance().replaceNub(this._currentNub, params);
+    protected replaceCurrentNub(params: Props, parentNub?: ParallelStructure) {
+        this.currentNub = Session.getInstance().replaceNub(this._currentNub, params, parentNub);
     }
 
-    protected replaceNub(sn: Nub, params: Props): Nub {
-        return Session.getInstance().replaceNub(sn, params);
+    protected replaceNub(sn: Nub, params: Props, parentNub?: ParallelStructure): Nub {
+        return Session.getInstance().replaceNub(sn, params, parentNub);
     }
 
     protected deleteNub(sn: Nub) {
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index aff79fb26..08744b408 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -1,4 +1,4 @@
-import { ParamDomain, ParamDefinition, ParamDomainValue, ParamCalculability, Session, Props, Nub } from "jalhyd";
+import { ParamDomain, ParamDefinition, ParamDomainValue, ParamCalculability, Session, Props, Nub, ParallelStructure } from "jalhyd";
 
 import { NgParameter } from "../../formulaire/ngparam";
 import { Injectable } from "@angular/core";
@@ -96,8 +96,13 @@ export class ParamService {
         return p;
     }
 
-    public createNub(p: Props): Nub {
-        const truc = Session.getInstance().createSessionNub(p);
+    /**
+     * Asks the JaLHyd Session to create a Nub
+     * @param p properties for the new Nub
+     * @param parentNub optional parent Nub when creating a Structure Nub, for checking admissible laws
+     */
+    public createNub(p: Props, parentNub?: ParallelStructure): Nub {
+        const truc = Session.getInstance().createSessionNub(p, parentNub);
         return truc;
     }
 
-- 
GitLab


From 61b25526c77290b0e16f465b203954b617d51c07 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 25 Feb 2019 13:34:49 +0100
Subject: [PATCH 07/26] =?UTF-8?q?Param=C3=A8tres=20li=C3=A9s:=20compatibil?=
 =?UTF-8?q?it=C3=A9=20JaLHyd?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../param-link/param-link.component.ts        | 29 ++++++++++---------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index bbc231d26..0a11c36f6 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -2,7 +2,7 @@ import { Component, Input, Output, EventEmitter, OnChanges, OnDestroy } from "@a
 
 import { NgParameter } from "../../formulaire/ngparam";
 import { ServiceFactory } from "../../services/service-factory";
-import { ParamValueMode, Observer } from "jalhyd";
+import { ParamValueMode, Observer, Structure } from "jalhyd";
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 import { I18nService } from "../..//services/internationalisation/internationalisation.service";
 
@@ -116,11 +116,20 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
         const s = i.name; // nom associé au paramètre/à la valeur
         const c = i.formTitle; // nom du module de calcul
 
-        const re5 = /(\d+)\.(.+)\.$/;  // forme <nombre>.xxx. (résultat d'ouvrage)
-        const match5 = re5.exec(s);
-        if (match5 !== null) {
-            const n = +match5[1] + 1;
-            return `${match5[2]} (résultat de ${c}, ouvrage n°${n})`;
+        // pointeur direct vers une Structure dans un Nub de type parallèle
+        if (i.nub && i.nub instanceof Structure) {
+            let p: number;
+            p = i.nub.findPositionInParent();
+            // forme xxx. (résultat)
+            const re4 = /([^\.]+)\.$/;
+            const match4 = re4.exec(s);
+            if (match4 !== null) {
+                // résultat d'ouvrage
+                return `${match4[1]} (résultat de ${c}, ouvrage ${p + 1})`;
+            } else {
+                // paramètre d'ouvrage
+                return `${s} (${c}, ouvrage ${p + 1})`;
+            }
         }
 
         const re1 = /([^\.]+)\.$/;  // forme xxx. (résultat)
@@ -129,13 +138,6 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
             return `${match1[1]} (résultat de ${c})`;
         }
 
-        const re4 = /(\d+)\.(.+)/;  // forme <nombre>.xxx (ouvrage)
-        const match4 = re4.exec(s);
-        if (match4 !== null) {
-            const n = +match4[1] + 1;
-            return `${match4[2]} (${c}, ouvrage n°${n})`;
-        }
-
         const re2 = /([^\.]+)\.(.+)/;  // forme xxx.yyy (résultat complémentaire)
         const match2 = re2.exec(s);
         if (match2 !== null) {
@@ -159,7 +161,6 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
         if (this._currentIndex !== index) {
             this._currentIndex = index;
             const lp = this._linkableParams[index];
-
             this.param.linkToParameter(lp.nub, lp.name);
         }
     }
-- 
GitLab


From 73159ce4a2381e75851222c403f7c33a1b013531 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 26 Feb 2019 12:28:48 +0100
Subject: [PATCH 08/26] =?UTF-8?q?Refonte=20syst=C3=A8me=20de=20structures?=
 =?UTF-8?q?=20en=20parall=C3=A8le:=20premier=20jet=20Fix=20#144?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

possibilité d'instancier un fieldset dans un fieldset-container avec un Nub existant (Structure)
les Nub Structure ne sont plus stockés en session
simplification de l'ajout / suppression de Structure dans un fieldset-container
---
 src/app/app.component.ts                      |  2 +
 .../fieldset-container.component.ts           | 10 ++--
 .../calculator.component.ts                   | 15 ++----
 .../param-link/param-link.component.ts        |  1 -
 .../concrete/form-parallel-structures.ts      | 53 +++++++++++++++----
 .../formulaire/definition/form-definition.ts  | 23 ++++----
 src/app/formulaire/fieldset-container.ts      |  5 +-
 src/app/formulaire/fieldset-template.ts       |  9 ++--
 src/app/formulaire/fieldset.ts                | 19 +++++--
 .../services/formulaire/formulaire.service.ts | 49 ++++++++---------
 src/app/services/param/param.service.ts       | 14 -----
 11 files changed, 110 insertions(+), 90 deletions(-)

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index d70c14882..02ecfc782 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -384,6 +384,8 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
           const form = this.formulaireService.getFormulaireFromId(c.uid);
           this.formulaireService.requestCloseForm(form.uid);
         }
+        // just to be sure, get rid of any Nub possibly stuck in session without any form attached
+        Session.getInstance().clearSession();
       }
     });
   }
diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts
index 75caa880f..15ca4d3e3 100644
--- a/src/app/components/fieldset-container/fieldset-container.component.ts
+++ b/src/app/components/fieldset-container/fieldset-container.component.ts
@@ -68,7 +68,7 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit {
         }
     }
 
-    private onFielsetListChange() {
+    private onFieldsetListChange() {
         // affichage des boutons ajouter, supprimer, monter, descendre
         this._fieldsetComponents.forEach(fs => fs.showButtons = true);
 
@@ -100,8 +100,8 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit {
     }
 
     public ngAfterViewInit() {
-        this.onFielsetListChange();
-        this._fieldsetComponents.changes.subscribe(_ => this.onFielsetListChange());
+        this.onFieldsetListChange();
+        this._fieldsetComponents.changes.subscribe(_ => this.onFieldsetListChange());
     }
 
     /*
@@ -131,13 +131,13 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit {
                     // accumulator (valeur précédente du résultat)
                     acc,
                     // currentValue (élément courant dans le tableau)
-                    fielset,
+                    fieldset,
                     // currentIndex (indice courant dans le tableau)
                     currIndex,
                     // array (tableau parcouru)
                     array
                 ) => {
-                    return acc && fielset.isValid;
+                    return acc && fieldset.isValid;
                 }
                 // valeur initiale
                 , this._fieldsetComponents.length > 0);
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index ebf3722c8..4ca3d3bd4 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -1,7 +1,7 @@
 import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, QueryList, AfterViewChecked } from "@angular/core";
 import { ActivatedRoute, Router } from "@angular/router";
 
-import { Observer, Session } from "jalhyd";
+import { Observer, Session, ParallelStructure } from "jalhyd";
 
 import { FormulaireService } from "../../services/formulaire/formulaire.service";
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
@@ -209,17 +209,6 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         this.formulaireService.requestCloseForm(this._formulaire.uid);
     }
 
-    /**
-     * met à jour l'interface
-     */
-    // private updateUI() {
-    //     // this.appRef.tick();
-    //     // this.changeDetectorRef.detectChanges();  // provoque une détection des changements dans les contrôles
-    //     // if (!this.changeDetectorRef['destroyed']) // pour éviter l'erreur "Attempt to use a destroyed view: detectChanges"
-    //     //     this.changeDetectorRef.detectChanges();
-    //     this.changeDetectorRef.markForCheck();
-    // }
-
     /**
      * relit les valeurs dans l'interface et met à jour les NgParameter
      */
@@ -413,10 +402,12 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
      * Duplicates the current calculator form
      */
     public cloneCalculator() {
+        // console.log("__Nubs en session avt", Session.getInstance()["_nubs"].length);
         const serialisedNub: string = this._formulaire.currentNub.serialise({ title: this._formulaire.calculatorName });
         const nubPointer = Session.getInstance().unserialiseSingleNub(serialisedNub);
         this.formulaireService.createFormulaire(nubPointer.nub.calcType, nubPointer.nub, nubPointer.meta.title).then((f) => {
             this.router.navigate(["/calculator", f.uid]);
         });
+        // console.log("__Nubs en session apr", Session.getInstance()["_nubs"].length);
     }
 }
diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index 0a11c36f6..2ef78c3ab 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -167,7 +167,6 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
 
     public updateParamList() {
         // liste des paramètres liables
-
         if (this.param.valueMode === ParamValueMode.LINK) {
             this._linkableParams = this._formService.filterLinkableValues(this._formService.getLinkableValues(this.param));
         } else {
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index 37bbdc962..c4a773fce 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -1,4 +1,4 @@
-import { Structure, Nub, ParallelStructure, StructureType, LoiDebit, StructureProperties, Props } from "jalhyd";
+import { Structure, Nub, ParallelStructure, StructureType, LoiDebit, StructureProperties, Props, Session } from "jalhyd";
 
 import { FormulaireDefinition } from "../form-definition";
 import { CalculatorResults } from "../../../results/calculator-results";
@@ -51,8 +51,7 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         params["structureType"] = templ.defaultStructTypeFromConfig;
         params["loiDebit"] = templ.defaultLoiDebitFromConfig;
 
-        // specify the parent Nub to check admissible laws
-        return this.createNub(new Props(params), this.currentNub as ParallelStructure);
+        return this.createStructure(new Props(params));
     }
 
     /**
@@ -68,14 +67,48 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         return this.currentNub as ParallelStructure;
     }
 
-    public createFieldset(parent: FormulaireNode, json: {}, data?: {}): FieldSet {
+    /**
+     * Asks JaLHyd to create a Structure Nub as a child of the current Calculator Module
+     * 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 {
+        return Session.getInstance().createNub(p, this.currentNub as ParallelStructure) as Structure;
+    }
+
+    /**
+     * Replaces the current Nub in the current calculator module, with a new one built with properties "params"
+     * @param params properties to build the new Nub (calcType, loiDebit...)
+     */
+    protected replaceNub(sn: Structure, params: Props): Nub {
+        const parent = (this.currentNub as ParallelStructure);
+        const newStructure = this.createStructure(params);
+        parent.replaceStructureInplace(sn, newStructure);
+        return newStructure;
+    }
+
+    /**
+     * Deleted the given child Nub in the current calculator module
+     * @param params properties to build the new Nub (calcType, loiDebit...)
+     */
+    protected deleteNub(sn: Structure) {
+        const parent = (this.currentNub as ParallelStructure);
+        parent.deleteStructure(parent.getIndexForStructure(sn));
+    }
+
+    public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         if (json["calcType"] === "Structure") {
             // indice après lequel insérer le nouveau FieldSet
             const after = data["after"];
 
             const res: FieldSet = new FieldSet(parent);
-            const sn = this.createStructNub(data["template"]);
-            this.addStructureNub(sn as Structure, after);
+            let sn: Nub;
+            if (nub) { // use existing Nub (build interface based on model)
+                sn = nub;
+            } else {
+                sn = this.createStructNub(data["template"]);
+                this.addStructureNub(sn as Structure, after);
+            }
             res.setNub(sn, false);
 
             if (after !== undefined) {
@@ -139,12 +172,14 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
     }
 
     public removeFieldset(fs: FieldSet) {
+        // console.log("==> FormParallelStructures removeFieldset", fs.uid);
         if (fs.nub instanceof Structure) {
-            // suppression du nub
-            this._paramService.deleteNub(fs.nub);
+            // suppression du sous-nub dans le Nub parent
+            this.deleteNub(fs.nub);
 
             // suppression du fieldset
             this.fieldsetContainer.removeFieldset(fs);
+            // console.log("====> nb struct dans le parent après", (this.currentNub as ParallelStructure).structures.length);
 
             this.resetResults();
         } else { super.removeFieldset(fs); }
@@ -361,7 +396,7 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
             switch (sender.id) {
                 case "fs_ouvrage":
                     const props = this.adjustProperties(sender, data["name"], data["value"]);
-                    const newNub = this.replaceNub(sender.nub, props, this.currentNub as ParallelStructure);
+                    const newNub = this.replaceNub((sender.nub as Structure), props);
                     sender.setNub(newNub);
                     this.reset();
                     break;
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 359709ca1..b70997fea 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -110,24 +110,24 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     /**
-     * Asks the ParamService to create a Nub
+     * Asks JaLHyd to create a Nub and keep in in the Session (for Calculator Modules, not for Structures)
      * @param p properties for the new Nub
      * @param parentNub optional parent Nub when creating a Structure Nub, for admissible laws check
      */
-    protected createNub(p: Props, parentNub?: ParallelStructure): Nub {
-        return this._paramService.createNub(p, parentNub);
+    protected createNub(p: Props): Nub {
+        return Session.getInstance().createSessionNub(p);
     }
 
-    protected replaceCurrentNub(params: Props, parentNub?: ParallelStructure) {
-        this.currentNub = Session.getInstance().replaceNub(this._currentNub, params, parentNub);
+    protected replaceCurrentNub(params: Props) {
+        this.currentNub = Session.getInstance().replaceNub(this._currentNub, params);
     }
 
-    protected replaceNub(sn: Nub, params: Props, parentNub?: ParallelStructure): Nub {
-        return Session.getInstance().replaceNub(sn, params, parentNub);
+    protected replaceNub(sn: Nub, params: Props): Nub {
+        return Session.getInstance().replaceNub(sn, params);
     }
 
     protected deleteNub(sn: Nub) {
-        this._paramService.deleteNub(sn);
+        Session.getInstance().deleteNub(sn);
     }
 
     protected initParse() {
@@ -151,7 +151,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     public afterParseFieldset(fs: FieldSet) {
     }
 
-    public createFieldset(parent: FormulaireNode, json: {}, data?: {}): FieldSet {
+    public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         const res: FieldSet = new FieldSet(parent);
         res.setNub(this._currentNub, false);
         this.kids.push(res);
@@ -175,8 +175,8 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     public removeFieldset(fs: FieldSet) {
     }
 
-    private parse_fieldset(json: {}) {
-        const fs = this.createFieldset(this, json);
+    private parse_fieldset(json: {}, nub?: Nub) {
+        const fs = this.createFieldset(this, json, undefined, nub);
         fs.parseConfig(json);
         this.afterParseFieldset(fs);
     }
@@ -491,7 +491,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
       * @param uidMap table de correspondance uid dans le fichier de conf <-> uid en mémoire
       */
     public updateParamsLinks(json: {}, uidMap: {}[]) {
-        console.log("++ UPDATE PARAMS LINKS (form definition) ++");
         for (const ks in json) {
             switch (ks) {
                 case "elements":
diff --git a/src/app/formulaire/fieldset-container.ts b/src/app/formulaire/fieldset-container.ts
index 38f5bdb34..b94eac578 100644
--- a/src/app/formulaire/fieldset-container.ts
+++ b/src/app/formulaire/fieldset-container.ts
@@ -3,6 +3,7 @@ import { FieldSet } from "./fieldset";
 import { FieldsetTemplate } from "./fieldset-template";
 import { StringMap } from "../stringmap";
 import { FormulaireNode } from "./formulaire-node";
+import { Nub } from "jalhyd";
 
 export class FieldsetContainer extends FormulaireElement {
     private _templates: FieldsetTemplate[];
@@ -75,10 +76,10 @@ export class FieldsetContainer extends FormulaireElement {
      * @param templateIndex indice du template dans la liste
      * @param after insère le nouveau FieldSet après cette position, à la fin sinon
      */
-    public addFromTemplate(templateIndex: number, after?: number): FieldSet {
+    public addFromTemplate(templateIndex: number, after?: number, nub?: Nub): FieldSet {
         const templ: FieldsetTemplate = this._templates[templateIndex];
 
-        const inst: FieldSet = templ.instantiateTemplate(this, after);
+        const inst: FieldSet = templ.instantiateTemplate(this, after, nub);
 
         this.updateLocalisation();
 
diff --git a/src/app/formulaire/fieldset-template.ts b/src/app/formulaire/fieldset-template.ts
index 3b12fa0d1..1a47ec12d 100644
--- a/src/app/formulaire/fieldset-template.ts
+++ b/src/app/formulaire/fieldset-template.ts
@@ -1,5 +1,5 @@
 import { FieldSet } from "./fieldset";
-import { CalculatorType, ComputeNodeType, StructureType, LoiDebit } from "jalhyd";
+import { CalculatorType, ComputeNodeType, StructureType, LoiDebit, Nub } from "jalhyd";
 import { FormulaireDefinition } from "./definition/form-definition";
 import { FieldsetContainer } from "./fieldset-container";
 
@@ -40,11 +40,12 @@ export class FieldsetTemplate {
     /**
      * crée une instance de Fieldset et l'ajoute dans un conteneur
      * @param cont conteneur
-     * @param at position à laquelle on ajoute le nouveau FieldSet
+     * @param after position à laquelle on ajoute le nouveau FieldSet
+     * @param nub Nub existant à injecter dans le Fieldset
      */
-    public instantiateTemplate(cont: FieldsetContainer, after: number): FieldSet {
+    public instantiateTemplate(cont: FieldsetContainer, after: number, nub?: Nub): FieldSet {
         const parentForm = cont.parent as FormulaireDefinition;
-        const res = parentForm.createFieldset(cont, this._jsonConfig, { "template": this, "after": after });
+        const res = parentForm.createFieldset(cont, this._jsonConfig, { "template": this, "after": after }, nub);
         res.parseConfig(this._jsonConfig);
         parentForm.afterParseFieldset(res);
         return res;
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 8138991f9..489d736ea 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -133,6 +133,7 @@ export class FieldSet extends FormulaireElement implements Observer {
      * @param default_radio_config config du radio fixé/à varier/à calculer
      */
     private parse_input(json: {}, default_radio_config: string): NgParameter {
+        // console.log("parsing input", json);
         const input_id: string = json["id"];
         const paramService: ParamService = ServiceFactory.instance.paramService;
 
@@ -211,7 +212,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     /**
-     * @param createOrUpdate true pour forcer la création d'un Nub
+     * @TODO WTF ?
      */
     private updateFields() {
         this.clearFields();
@@ -254,6 +255,10 @@ export class FieldSet extends FormulaireElement implements Observer {
         this.applyDependencies();
     }
 
+    /**
+     * Set fieldset properties fron config file, unless config is already set (ex: structureType
+     * and loiDebit when deserialising existing structures)
+     */
     public parseConfig(json: {}, data?: {}) {
         this._jsonConfig = json;
 
@@ -261,19 +266,23 @@ export class FieldSet extends FormulaireElement implements Observer {
 
         const parentForm = this.parentForm as FormulaireDefinition;
         const ct: string = json["calcType"];
-        const calc_type: CalculatorType = ct ? CalculatorType[ct] : parentForm.calculatorType;
+        const currentCt = this.properties.getPropValue("calcType");
+        const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : parentForm.calculatorType);
         this.setPropValue("calcType", calc_type);
 
         const dnt: string = json["defaultNodeType"];
-        const node_type: ComputeNodeType = dnt ? ComputeNodeType[dnt] : parentForm.nodeType;
+        const currentNt = this.properties.getPropValue("nodeType");
+        const node_type: ComputeNodeType = currentNt ? currentNt : (dnt ? ComputeNodeType[dnt] : parentForm.nodeType);
         this.setPropValue("nodeType", node_type);
 
         const st: string = json["defaultStructType"];
-        if (st) {
+        const currentSt = this.properties.getPropValue("structureType");
+        if (st && ! currentSt) {
             this.setPropValue("structureType", StructureType[st]);
         }
         const ld: string = json["defaultLoiDebit"];
-        if (ld) {
+        const currentLd = this.properties.getPropValue("loiDebit");
+        if (ld && ! currentLd) {
             this.setPropValue("loiDebit", LoiDebit[ld]);
         }
 
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index 4da19c45e..842b8bdd0 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -3,7 +3,7 @@ import { Injectable } from "@angular/core";
 import { decode } from "he";
 import { saveAs } from "file-saver";
 
-import { CalculatorType, EnumEx, Observable, ParamDefinition, Session, Nub } from "jalhyd";
+import { CalculatorType, EnumEx, Observable, ParamDefinition, Session, Nub, ParallelStructure } from "jalhyd";
 
 import { HttpService } from "../../services/http/http.service";
 import { I18nService } from "../../services/internationalisation/internationalisation.service";
@@ -20,6 +20,7 @@ import { FormulaireCourbeRemous } from "../../formulaire/definition/concrete/for
 import { FormulaireRegimeUniforme } from "../../formulaire/definition/concrete/form-regime-uniforme";
 import { FormulaireParallelStructure } from "../../formulaire/definition/concrete/form-parallel-structures";
 import { NgParameter } from "../../formulaire/ngparam";
+import { FieldsetContainer } from "../..//formulaire/fieldset-container";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -81,20 +82,6 @@ export class FormulaireService extends Observable {
             });
     }
 
-    /**
-     * retourne true si l'uid passé en paramètre est déjà utilisé par un formulaire
-     * @param uid uid à tester
-     */
-    private formUIDAlreadyUsed(uid: string): boolean {
-        let alreadyUsed = false;
-        for (const f of this._formulaires) {
-            if (f.uid === uid) {
-                alreadyUsed = true;
-            }
-        }
-        return alreadyUsed;
-    }
-
     public updateLocalisation() {
         for (const c of EnumEx.getValues(CalculatorType)) {
             const prom: Promise<StringMap> = this.loadLocalisation(c);
@@ -187,6 +174,16 @@ export class FormulaireService extends Observable {
                 f.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct));
             }
             f.parseConfig();
+            // add fieldsets for existing structures if needed
+            if (f.currentNub instanceof ParallelStructure) {
+                for (s of f.currentNub.structures) {
+                    for (const e of f.allFormElements) {
+                        if (e instanceof FieldsetContainer) { // @TODO manage many containers one day
+                            e.addFromTemplate(0, undefined, s);
+                        }
+                    }
+                }
+            }
             return this.loadUpdateFormulaireLocalisation(f);
         }).then(fi => {
             fi.applyDependencies();
@@ -312,9 +309,14 @@ export class FormulaireService extends Observable {
         }
     }
 
+    /**
+     * Supprime le formulaire ciblé, et demande à JaLHyd d'effacer son Nub de la Session
+     * @param uid formulaire à supprimer
+     */
     public requestCloseForm(uid: string) {
         const form = this.getFormulaireFromId(uid);
-        if (form !== undefined) {
+        const nub = form.currentNub;
+        if (form) {
             this._formulaires = this._formulaires.filter(f => f.uid !== uid);
 
             this.notifyObservers({
@@ -322,6 +324,9 @@ export class FormulaireService extends Observable {
                 "form": form
             });
         }
+        if (nub) {
+            Session.getInstance().deleteNub(nub);
+        }
     }
 
     public get currentFormId() {
@@ -452,14 +457,12 @@ export class FormulaireService extends Observable {
     /**
      * MAJ des liens entre paramètres lors de la désérialisation
      */
-
-    private updateParamsLinks(json: {}, formInfos: any[], oldFormCount: number) {
+    /* private updateParamsLinks(json: {}, formInfos: any[], oldFormCount: number) {
         // table de correspondance des uid fichier <-> objets mémoire
         // forme : tableau d'objets de la forme :
         // { "type" : <type de l'objet. "form" pour formulaire>,
         //   "old": <uid dans le fichier>,
         //   "new": <uid de l'objet mémoire>}
-
         const uidMap = [];
         for (const ks in json) {
             switch (ks) {
@@ -477,9 +480,7 @@ export class FormulaireService extends Observable {
                     }
             }
         }
-
         // MAJ liens
-
         for (const ks in json) {
             switch (ks) {
                 case "elements":
@@ -496,7 +497,7 @@ export class FormulaireService extends Observable {
                     throw new Error(`session file : invalid key '${ks}' in session object`);
             }
         }
-    }
+    } */
 
     /**
      * @returns liste des valeurs liables à un paramètre sous la forme d'un tableau d'objets
@@ -505,16 +506,13 @@ export class FormulaireService extends Observable {
      */
     public getLinkableValues(p: NgParameter): any[] {
         const res: any[] = [];
-
         if (p !== undefined) {
             for (const f of this._formulaires) {
                 // nub associé au formulaire
                 const sn = f.currentNub;
-
                 try {
                     // on vérifie que le paramètre en entrée appartient au nub
                     const np = sn.getParameter(p.symbol);
-
                     // si oui, on demande à exclure des valeurs retournées le résultat du même nom que le paramètre
                     const exclude = np !== undefined ? p.paramDefinition.uid === np.uid : false;
                     // valeurs liables
@@ -528,7 +526,6 @@ export class FormulaireService extends Observable {
                 }
             }
         }
-
         return res;
     }
 
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index 08744b408..d34637e7c 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -95,18 +95,4 @@ export class ParamService {
 
         return p;
     }
-
-    /**
-     * Asks the JaLHyd Session to create a Nub
-     * @param p properties for the new Nub
-     * @param parentNub optional parent Nub when creating a Structure Nub, for checking admissible laws
-     */
-    public createNub(p: Props, parentNub?: ParallelStructure): Nub {
-        const truc = Session.getInstance().createSessionNub(p, parentNub);
-        return truc;
-    }
-
-    public deleteNub(sn: Nub) {
-        Session.getInstance().deleteNub(sn);
-    }
 }
-- 
GitLab


From 20a0bee4236a1b94a02480b5bcceff020b08357b Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 26 Feb 2019 14:37:25 +0100
Subject: [PATCH 09/26] Fix #145

---
 src/app/components/field-set/field-set.component.html     | 8 ++++----
 .../generic-calculator/calculator.component.html          | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/app/components/field-set/field-set.component.html b/src/app/components/field-set/field-set.component.html
index 3217d50f0..e048b3915 100644
--- a/src/app/components/field-set/field-set.component.html
+++ b/src/app/components/field-set/field-set.component.html
@@ -3,16 +3,16 @@
         {{ title }}
     </mat-card-title>
     <div *ngIf="showButtons" class="hyd-window-btns">
-        <button mat-icon-button (click)="onAddClick()">
+        <button type="button" mat-icon-button (click)="onAddClick()">
             <mat-icon>add_box</mat-icon>
         </button>
-        <button mat-icon-button [disabled]="! enableRemoveButton" (click)="onRemoveClick()">
+        <button type="button" mat-icon-button [disabled]="! enableRemoveButton" (click)="onRemoveClick()">
             <mat-icon>delete</mat-icon>
         </button>
-        <button mat-icon-button [disabled]="! enableUpButton" (click)="onMoveUpClick()">
+        <button type="button" mat-icon-button [disabled]="! enableUpButton" (click)="onMoveUpClick()">
             <mat-icon>arrow_upward</mat-icon>
         </button>
-        <button mat-icon-button [disabled]="! enableDownButton" (click)="onMoveDownClick()">
+        <button type="button" mat-icon-button [disabled]="! enableDownButton" (click)="onMoveDownClick()">
             <mat-icon>arrow_downward</mat-icon>
         </button>
     </div>
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index 4c2623ff5..455dddadb 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -40,7 +40,7 @@
 
                     <mat-card-actions>
                         <!-- bouton calculer -->
-                        <button mat-raised-button color="accent" name="Calculer" (click)="doCompute()"[disabled]="isCalculateDisabled">
+                        <button type="submit" mat-raised-button color="accent" name="Calculer" (click)="doCompute()"[disabled]="isCalculateDisabled">
                             {{ uitextCalculer }}
                         </button>
                     </mat-card-actions>
-- 
GitLab


From 6b878e0c6de172a0b73f2851e325cad0313c8b52 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 27 Feb 2019 14:29:53 +0100
Subject: [PATCH 10/26] Fix #149

---
 .../calculator.component.ts                   |  1 -
 .../services/formulaire/formulaire.service.ts | 62 +++++++++++++++++--
 src/locale/messages.en.json                   | 11 ++++
 src/locale/messages.fr.json                   | 11 ++++
 4 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 4ca3d3bd4..1dfdd380e 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -408,6 +408,5 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         this.formulaireService.createFormulaire(nubPointer.nub.calcType, nubPointer.nub, nubPointer.meta.title).then((f) => {
             this.router.navigate(["/calculator", f.uid]);
         });
-        // console.log("__Nubs en session apr", Session.getInstance()["_nubs"].length);
     }
 }
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index 842b8bdd0..85e6bb0ac 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -96,11 +96,58 @@ export class FormulaireService extends Observable {
         }
     }
 
+    /**
+     * Retourne le titre complet du type de module de calcul, dans la langue en cours
+     */
     public getLocalisedTitleFromCalculatorType(type: CalculatorType) {
         const sCalculator: string = CalculatorType[type].toUpperCase();
         return this._intlService.localizeText(`INFO_${sCalculator}_TITRE`);
     }
 
+    /**
+     * Retourne le titre cour du type de module de calcul, dans la langue en cours
+     * (pour les titres d'onglets par défaut)
+     */
+    public getLocalisedShortTitleFromCalculatorType(type: CalculatorType) {
+        const sCalculator: string = CalculatorType[type].toUpperCase();
+        return this._intlService.localizeText(`INFO_${sCalculator}_TITRE_COURT`);
+    }
+
+    /**
+     * Checks if the given calculator name (tab title) is already used by any existing
+     * form; if so, adds a number after it
+     */
+    private suffixNameIfNeeded(name: string) {
+        let found = false;
+        let maxNumber = 0;
+
+        // extract base name
+        let baseName = name;
+        const re1 = new RegExp("^.+( \\d+)$");
+        const matches1 = re1.exec(name);
+        if (matches1) {
+            baseName = baseName.replace(matches1[1], "");
+        }
+
+        // browse session calculators
+        const re2 = new RegExp("^" + baseName + "( (\\d+))?$");
+        for (const f of this.formulaires) {
+            const matches2 = re2.exec(f.calculatorName);
+            if (matches2) {
+                found = true;
+                if (matches2[2] !== undefined) {
+                    const nb = Number(matches2[2]);
+                    maxNumber = Math.max(maxNumber, nb);
+                }
+            }
+        }
+        // suffix if needed
+        if (found) {
+            name = baseName + " " + (maxNumber + 1);
+        }
+        return name;
+    }
+
     public loadConfig(ct: CalculatorType): Promise<any> {
         const f: string = this.getConfigPathPrefix(ct) + "config.json";
         return this._httpService.httpGetRequestPromise(f);
@@ -161,24 +208,31 @@ export class FormulaireService extends Observable {
         const prom: Promise<any> = this.loadConfig(ct);
         return prom.then(s => {
             f.preparseConfig(s);
+
             // Associe le Nub fourni (chargement de session / duplication de module), sinon en crée un nouveau
             if (nub) {
                 f.currentNub = nub;
             } else {
                 f.initNub();
             }
-            // Restaure le nom du module
+
+            // Restaure le nom du module, sinon affecte le nom par défaut
+            let tempName: string;
             if (calculatorName) {
-                f.calculatorName = calculatorName;
+                tempName = calculatorName;
             } else {
-                f.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct));
+                tempName = decode(this.getLocalisedShortTitleFromCalculatorType(ct));
             }
+            // Suffixe le nom du module si nécessaire
+            f.calculatorName = this.suffixNameIfNeeded(tempName);
+
             f.parseConfig();
+
             // add fieldsets for existing structures if needed
             if (f.currentNub instanceof ParallelStructure) {
                 for (s of f.currentNub.structures) {
                     for (const e of f.allFormElements) {
-                        if (e instanceof FieldsetContainer) { // @TODO manage many containers one day
+                        if (e instanceof FieldsetContainer) { // @TODO manage many containers one day ?
                             e.addFromTemplate(0, undefined, s);
                         }
                     }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 4e0057b97..d1a56cc1c 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -41,11 +41,15 @@
     "INFO_CALCULATOR_RESULTS_TITLE": "Results",
     "INFO_CALCULATOR_VALEURS": "Values",
     "INFO_CLOISONS_TITRE": "Fish ladder: Cross walls",
+    "INFO_CLOISONS_TITRE_COURT": "Cross walls",
     "INFO_CLOSE_DIALOGUE_TEXT": "Warning ! Parameters and results will be lost. Really close?",
     "INFO_CLOSE_DIALOGUE_TITRE": "Please confirm",
     "INFO_CONDUITEDISTRIBUTRICE_TITRE": "Distributor pipe",
+    "INFO_CONDUITEDISTRIBUTRICE_TITRE_COURT": "D. pipe",
     "INFO_COURBEREMOUS_TITRE": "Backwater curves",
+    "INFO_COURBEREMOUS_TITRE_COURT": "B. curves",
     "INFO_DEVER_TITRE": "Free flow weir stage-discharge laws",
+    "INFO_DEVER_TITRE_COURT": "Free flow SD",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_0": "Emergent",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-emergent",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_2": "Submerged",
@@ -104,6 +108,7 @@
     "INFO_EXTRARES_LIB_YT": "Supercritical depth (m)",
     "INFO_EXTRARES_LIB_ZF2": "Downstream bottom elevation (m)",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
+    "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-Calmon",
     "INFO_LIB_ALPHA": "Alpha coefficient",
     "INFO_LIB_BETA": "Beta coefficient",
     "INFO_LIB_CD": "Discharge coefficient",
@@ -121,6 +126,7 @@
     "INFO_LIB_ZRAM": "Upstream apron elevation (m)",
     "INFO_LIB_ZT": "Triangle top elevation (m)",
     "INFO_MACRORUGO_TITRE": "Rock-ramp fishpasses",
+    "INFO_MACRORUGO_TITRE_COURT": "RR fishpasses",
     "INFO_MENU_HELP_TITLE": "Help",
     "INFO_MENU_LOAD_SESSION_TITLE": "Load session",
     "INFO_MENU_NOUVELLE_CALC": "New calculation module",
@@ -140,8 +146,11 @@
     "INFO_OPTION_NONE_F": "None",
     "INFO_OUVRAGE": "Structure",
     "INFO_PABDIMENSIONS_TITRE": "Fish ladder: dimensions",
+    "INFO_PABDIMENSIONS_TITRE_COURT": "FL: dimensions",
     "INFO_PABPUISSANCE_TITRE": "Fish ladder: dissipated power",
+    "INFO_PABPUISSANCE_TITRE_COURT": "FL: diss. power",
     "INFO_PARALLELSTRUCTURE_TITRE": "Parallel structures",
+    "INFO_PARALLELSTRUCTURE_TITRE_COURT": "// structures",
     "INFO_PARAMFIELD_GRAPH_TYPE": "Graph type",
     "INFO_PARAMFIELD_GRAPH_TYPE_HISTOGRAM": "Histogram",
     "INFO_PARAMFIELD_IN_CALCULATION": "In calculation",
@@ -167,6 +176,7 @@
     "INFO_PARAMMODE_MINMAX": "Min/max",
     "INFO_PARAMMODE_LIST": "Values list",
     "INFO_REGIMEUNIFORME_TITRE": "Uniform flow calculation",
+    "INFO_REGIMEUNIFORME_TITRE_COURT": "Uniform flow",
     "INFO_REMOUSRESULTS_ABSCISSE": "Abscissa (m)",
     "INFO_REMOUSRESULTS_BERGE": "Embankment",
     "INFO_REMOUSRESULTS_FOND": "Bottom",
@@ -182,6 +192,7 @@
     "INFO_REMOUS_RESSAUT_DEHORS": "Hydraulic jump detected %sens% abscissa %x% m",
     "INFO_REMOUS_RESSAUT_HYDRO": "Hydraulic jump detected between abscissa %xmin% and %xmax% m",
     "INFO_SECTIONPARAMETREE_TITRE": "Parametric section",
+    "INFO_SECTIONPARAMETREE_TITRE_COURT": "Param. section",
     "INFO_SETUP_NEWTON_MAX_ITER": "Newton iteration limit",
     "INFO_SETUP_PRECISION_AFFICHAGE": "Display accuracy",
     "INFO_SETUP_PRECISION_CALCUL": "Computation accuracy",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 0b8886026..8dbc1646b 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -41,11 +41,15 @@
     "INFO_CALCULATOR_RESULTS_TITLE": "Résultats",
     "INFO_CALCULATOR_VALEURS": "Valeurs",
     "INFO_CLOISONS_TITRE": "Passe à bassin&nbsp;: Cloisons",
+    "INFO_CLOISONS_TITRE_COURT": "Cloisons",
     "INFO_CLOSE_DIALOGUE_TEXT": "Attention&nbsp;! Les paramètres et résultats du module de calcul seront perdus. Vraiment fermer&nbsp;?",
     "INFO_CLOSE_DIALOGUE_TITRE": "Confirmer la fermeture",
     "INFO_CONDUITEDISTRIBUTRICE_TITRE": "Conduite distributrice",
+    "INFO_CONDUITEDISTRIBUTRICE_TITRE_COURT": "Conduite distri.",
     "INFO_COURBEREMOUS_TITRE": "Courbes de remous",
+    "INFO_COURBEREMOUS_TITRE_COURT": "Remous",
     "INFO_DEVER_TITRE": "Lois de déversoirs dénoyés",
+    "INFO_DEVER_TITRE_COURT": "Déver. dénoyés",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_0": "Emergent",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_1": "Quasi-émergent",
     "INFO_EXTRARES_ENUM_MACRORUGOFLOWTYPE_2": "Immergé",
@@ -104,6 +108,7 @@
     "INFO_EXTRARES_LIB_YT": "Tirant d'eau torrentiel (m)",
     "INFO_EXTRARES_LIB_ZF2": "Cote de fond aval (m)",
     "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon",
+    "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-Calmon",
     "INFO_LIB_ALPHA": "Coefficient alpha",
     "INFO_LIB_BETA": "Coefficient béta",
     "INFO_LIB_CD": "Coefficient de débit",
@@ -127,6 +132,7 @@
     "INFO_MENU_EMPTY_SESSION_TITLE": "Nouvelle session",
     "INFO_MENU_NOUVELLE_CALC": "Nouveau module de calcul",
     "INFO_MACRORUGO_TITRE": "Passe à macro-rugosités",
+    "INFO_MACRORUGO_TITRE_COURT": "Macro-rugo.",
     "INFO_OPTION_NO": "Non",
     "INFO_OPTION_YES": "Oui",
     "INFO_OPTION_CANCEL": "Annuler",
@@ -140,8 +146,11 @@
     "INFO_OPTION_NONE_F": "Aucune",
     "INFO_OUVRAGE": "Ouvrage",
     "INFO_PABDIMENSIONS_TITRE": "Passe à bassin&nbsp;: dimensions",
+    "INFO_PABDIMENSIONS_TITRE_COURT": "PAB&nbsp;: dimensions",
     "INFO_PABPUISSANCE_TITRE": "Passe à bassin&nbsp;: puissance dissipée",
+    "INFO_PABPUISSANCE_TITRE_COURT": "PAB&nbsp;: puissance",
     "INFO_PARALLELSTRUCTURE_TITRE": "Lois d'ouvrages",
+    "INFO_PARALLELSTRUCTURE_TITRE_COURT": "Ouvrages",
     "INFO_PARAMFIELD_GRAPH_TYPE": "Type de graphe",
     "INFO_PARAMFIELD_GRAPH_TYPE_HISTOGRAM": "Histogramme",
     "INFO_PARAMFIELD_IN_CALCULATION": "En calcul",
@@ -167,6 +176,7 @@
     "INFO_PARAMMODE_MINMAX": "Min/max",
     "INFO_PARAMMODE_LIST": "Liste de valeurs",
     "INFO_REGIMEUNIFORME_TITRE": "Régime uniforme",
+    "INFO_REGIMEUNIFORME_TITRE_COURT": "R. uniforme",
     "INFO_REMOUSRESULTS_ABSCISSE": "Abscisse (m)",
     "INFO_REMOUSRESULTS_BERGE": "Berge",
     "INFO_REMOUSRESULTS_FOND": "Fond",
@@ -182,6 +192,7 @@
     "INFO_REMOUS_RESSAUT_DEHORS": "Ressaut hydraulique détecté à l'%sens% de l'abscisse %x% m",
     "INFO_REMOUS_RESSAUT_HYDRO": "Ressaut hydraulique détecté entre les abscisses %xmin% et %xmax% m",
     "INFO_SECTIONPARAMETREE_TITRE": "Section paramétrée",
+    "INFO_SECTIONPARAMETREE_TITRE_COURT": "Sec. param.",
     "INFO_SETUP_NEWTON_MAX_ITER": "Newton : nombre d'itérations maximum",
     "INFO_SETUP_PRECISION_AFFICHAGE": "Précision d'affichage",
     "INFO_SETUP_PRECISION_CALCUL": "Précision de calcul",
-- 
GitLab


From 5156b204e3e756fea817cd058fbcc8dad69afef6 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 27 Feb 2019 14:30:29 +0100
Subject: [PATCH 11/26] =?UTF-8?q?Cr=C3=A9ation=20fichiers=20de=20langue=20?=
 =?UTF-8?q?.en=20pour=20tous=20les=20modules=20(voir=20#151)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/calculators/cloisons/cloisons.en.json | 17 +++++++++
 src/app/calculators/dever/dever.en.json       | 36 +++++++++++++++++++
 .../calculators/macrorugo/macrorugo.en.json   | 15 ++++++++
 src/app/calculators/ouvrages/ouvrages.en.json | 29 +++++++++++++++
 .../parallel-structures.en.json               | 32 +++++++++++++++++
 5 files changed, 129 insertions(+)
 create mode 100644 src/app/calculators/cloisons/cloisons.en.json
 create mode 100644 src/app/calculators/dever/dever.en.json
 create mode 100644 src/app/calculators/macrorugo/macrorugo.en.json
 create mode 100644 src/app/calculators/ouvrages/ouvrages.en.json
 create mode 100644 src/app/calculators/parallel-structures/parallel-structures.en.json

diff --git a/src/app/calculators/cloisons/cloisons.en.json b/src/app/calculators/cloisons/cloisons.en.json
new file mode 100644
index 000000000..c8bc712cd
--- /dev/null
+++ b/src/app/calculators/cloisons/cloisons.en.json
@@ -0,0 +1,17 @@
+{
+    "fs_param_hydro": "Paramètres hydrauliques",
+    "Q": "Débit total",
+    "Z1": "Cote de l'eau amont",
+    "ZR": "Cote du lit amont",
+    "LB": "Longueur du bassin",
+    "BB": "Largeur du bassin",
+    "PB": "Profondeur moyenne du bassin",
+    "DH": "Chute",
+    "S": "Surface de l'orifice",
+    "select_ouvrage_orifice": "Orifice",
+    "select_ouvrage_seuil_rect": "Seuil rectangulaire",
+    "select_loidebit1_kivi": "Kindsvater-Carter et Villemonte",
+    "select_loidebit1_fente": "Fente noyée (Larinier 1992)",
+    "select_loidebit2_orifice": "Orifice noyé",
+    "struct_container": "Ouvrages"
+}
\ No newline at end of file
diff --git a/src/app/calculators/dever/dever.en.json b/src/app/calculators/dever/dever.en.json
new file mode 100644
index 000000000..4157c047f
--- /dev/null
+++ b/src/app/calculators/dever/dever.en.json
@@ -0,0 +1,36 @@
+{
+    "fs_param_hydro": "Paramètres hydrauliques",
+    "Q": "Débit total",
+    "Z1": "Cote de l'eau amont",
+    "ZR": "Cote du lit amont",
+    "BR": "Largeur du lit amont",
+    "fs_ouvrage": "Ouvrage",
+    "select_ouvrage": "Ouvrage",
+    "select_ouvrage_vanne_circ": "Vanne circulaire",
+    "select_ouvrage_vanne_rect": "Vanne rectangulaire",
+    "select_ouvrage_seuil_rect": "Seuil rectangulaire",
+    "select_ouvrage_seuil_trap": "Seuil trapézoïdal",
+    "select_ouvrage_vanne_trap": "Vanne trapézoïdale",
+    "select_ouvrage_seuil_triang": "Seuil triangulaire",
+    "select_ouvrage_seuil_triangtrunc": "Seuil triangulaire tronqué",
+    "W": "Ouverture de vanne",
+    "select_loidebit1_seuildenoye": "Seuil dénoyé",
+    "select_loidebit1_cunge80": "Cunge 80",
+    "select_loidebit1_cem88d": "Déversoir/Orifice Cemagref 88",
+    "select_loidebit1_cem88v": "Déversoir/Vanne de fond Cemagref 88",
+    "select_loidebit1_kivi": "Kindsvater-Carter et Villemonte",
+    "select_loidebit2_vannedenoye": "Vanne dénoyé",
+    "select_loidebit2_vannenoye": "Vanne noyé",
+    "select_loidebit2_cunge80": "Cunge 80",
+    "select_loidebit2_cem88d": "Déversoir/Orifice Cemagref 88",
+    "select_loidebit2_cem88v": "Déversoir/Vanne de fond Cemagref 88",
+    "select_loidebit3_seuiltriang": "Déversoir triangulaire dénoyé",
+    "select_loidebit4_seuiltriangtrunc": "Déversoir triangulaire tronqué dénoyé",
+    "ZDV": "Cote de la crête du déversoir ou du radier de la vanne",
+    "L": "Largeur du déversoir",
+    "Cd": "Coefficient de débit",
+    "alpha": "Coefficient alpha",
+    "beta": "Coefficient béta",
+    "ZRAM": "Cote du radier amont",
+    "struct_container": "Ouvrages"
+}
\ No newline at end of file
diff --git a/src/app/calculators/macrorugo/macrorugo.en.json b/src/app/calculators/macrorugo/macrorugo.en.json
new file mode 100644
index 000000000..0fb76a0b9
--- /dev/null
+++ b/src/app/calculators/macrorugo/macrorugo.en.json
@@ -0,0 +1,15 @@
+{
+    "fs_hydraulique_fix": "Données hydrauliques fixées",
+    "fs_hydraulique_cal": "Données hydrauliques calculables",
+    "fs_bloc": "Paramètres des blocs",
+    "ZF1": "Cote de fond amont",
+    "L": "Longueur",
+    "B": "Largeur",
+    "If": "Pente",
+    "Y": "Profondeur",
+    "Ks": "Rugosité de fond",
+    "C": "Concentration de blocs",
+    "PBD": "Paramètre de bloc : Diamètre",
+    "PBH": "Paramètre de bloc : Hauteur",
+    "Cd0": "Paramètre de bloc : Forme (1 pour rond, 2 pour carré)"
+}
\ No newline at end of file
diff --git a/src/app/calculators/ouvrages/ouvrages.en.json b/src/app/calculators/ouvrages/ouvrages.en.json
new file mode 100644
index 000000000..16ac2c4c7
--- /dev/null
+++ b/src/app/calculators/ouvrages/ouvrages.en.json
@@ -0,0 +1,29 @@
+{
+    "fs_ouvrage": "Type d'ouvrage",
+    "select_ouvrage": "Ouvrage",
+    "select_ouvrage_vanne_rect": "Vanne rectangulaire",
+    "select_loidebit1": "Loi de débit",
+    "select_loidebit1_cemagref88": "Déversoir/Orifice Cemagref 88",
+    "select_loidebit1_vannedenoye": "Vanne dénoyé",
+    "select_loidebit1_vannenoye": "Vanne noyé",
+    "select_loidebit2": "Loi de débit",
+    "select_loidebit2_cemagref88": "Déversoir/Orifice Cemagref 88",
+    "select_ouvrage_circ": "Vanne circulaire",
+    "select_ouvrage_seuil_rect": "Seuil rectangulaire",
+    "select_ouvrage_seuil_trap": "Seuil trapézoïdal",
+    "select_ouvrage_vanne_trap": "Vanne trapézoïdale",
+    "fs_caract_1": "Caractéristiques de l'ouvrage",
+    "larg": "Largeur",
+    "ouv": "Ouverture",
+    "kq": "Coefficient de débit",
+    "fs_caract_2": "Caractéristiques de l'ouvrage",
+    "fs_caract_3": "Caractéristiques de l'ouvrage",
+    "largf": "Largeur au fond",
+    "kqr": "Coefficient de débit partie rectangulaire",
+    "kqt": "Coefficient de débit partie triangulaire",
+    "fruit": "Fruit",
+    "fs_surverse": "Surverse",
+    "fs_hydraulique": "Caractéristiques globales",
+    "Y_A": "Cote de l'eau à l'amont",
+    "Y_a": "Cote de l'eau à l'aval"
+}
\ No newline at end of file
diff --git a/src/app/calculators/parallel-structures/parallel-structures.en.json b/src/app/calculators/parallel-structures/parallel-structures.en.json
new file mode 100644
index 000000000..41e093726
--- /dev/null
+++ b/src/app/calculators/parallel-structures/parallel-structures.en.json
@@ -0,0 +1,32 @@
+{
+    "fs_param_hydro": "Paramètres hydrauliques",
+    "Q": "Débit total",
+    "Z1": "Cote amont",
+    "Z2": "Cote aval",
+    "fs_ouvrage": "Ouvrage",
+    "select_ouvrage": "Ouvrage",
+    "select_ouvrage_vanne_circ": "Vanne circulaire",
+    "select_ouvrage_vanne_rect": "Vanne rectangulaire",
+    "select_ouvrage_seuil_rect": "Seuil rectangulaire",
+    "select_ouvrage_seuil_triang": "Seuil triangulaire",
+    "select_ouvrage_seuil_triangtrunc": "Seuil triangulaire tronqué",
+    "select_ouvrage_seuil_trap": "Seuil trapézoïdal",
+    "select_ouvrage_vanne_trap": "Vanne trapézoïdale",
+    "W": "Ouverture de vanne",
+    "select_loidebit1_seuildenoye": "Seuil dénoyé",
+    "select_loidebit1_cunge80": "Cunge 80",
+    "select_loidebit1_cem88d": "Déversoir/Orifice Cemagref 88",
+    "select_loidebit1_cem88v": "Déversoir/Vanne de fond Cemagref 88",
+    "select_loidebit1_kivi": "Kindsvater-Carter et Villemonte",
+    "select_loidebit2_vannedenoye": "Vanne dénoyé",
+    "select_loidebit2_vannenoye": "Vanne noyé",
+    "select_loidebit2_cunge80": "Cunge 80",
+    "select_loidebit2_cem88d": "Déversoir/Orifice Cemagref 88",
+    "select_loidebit2_cem88v": "Déversoir/Vanne de fond Cemagref 88",
+    "select_loidebit3_seuiltriang": "Déversoir triangulaire dénoyé",
+    "select_loidebit4_seuiltriangtrunc": "Déversoir triangulaire tronqué dénoyé",
+    "alpha2": "Demi-angle au sommet (°)",
+    "BT": "Demi-ouverture du triangle (m)",
+    "ZT": "Cote haute du triangle (m)",
+    "struct_container": "Ouvrages"
+}
\ No newline at end of file
-- 
GitLab


From e3b028f83c60745448e5d3014b74649c7afa426a Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 27 Feb 2019 14:32:36 +0100
Subject: [PATCH 12/26] =?UTF-8?q?Am=C3=A9lioration=20des=20Fieldset?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

gestion des propriétés varCalc et
 methodeResolution
suppression du proxy de Props (accès direct aux Props du Nub)
courbe de remous: transmission de varCalc et methodeResolution comme propriétés du Nub
---
 .../calculator.component.ts                   |   1 -
 .../definition/concrete/form-courbe-remous.ts |   5 +-
 .../definition/form-compute-courbe-remous.ts  |  11 +-
 .../formulaire/definition/form-definition.ts  |   4 +-
 src/app/formulaire/fieldset.ts                | 121 +++++++++++-------
 5 files changed, 82 insertions(+), 60 deletions(-)

diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index 1dfdd380e..14e30fc0a 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -402,7 +402,6 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
      * Duplicates the current calculator form
      */
     public cloneCalculator() {
-        // console.log("__Nubs en session avt", Session.getInstance()["_nubs"].length);
         const serialisedNub: string = this._formulaire.currentNub.serialise({ title: this._formulaire.calculatorName });
         const nubPointer = Session.getInstance().unserialiseSingleNub(serialisedNub);
         this.formulaireService.createFormulaire(nubPointer.nub.calcType, nubPointer.nub, nubPointer.meta.title).then((f) => {
diff --git a/src/app/formulaire/definition/concrete/form-courbe-remous.ts b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
index 2789da339..5c3f0f0be 100644
--- a/src/app/formulaire/definition/concrete/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
@@ -1,4 +1,4 @@
-import { IObservable } from "jalhyd";
+import { IObservable, MethodeResolution } from "jalhyd";
 
 import { FormResultRemous } from "../form-result-remous";
 import { FormDefSection } from "../form-def-section";
@@ -24,6 +24,9 @@ export class FormulaireCourbeRemous extends FormulaireDefinition {
         this._formSection = new FormDefSection(this);
         this._formResult = new FormResultRemous(this);
         this._formCompute = new FormComputeCourbeRemous(this, this._formSection, this._formResult);
+        // default properties
+        this._props["methodeResolution"] = MethodeResolution.Trapezes;
+        this._props["varCalc"] = undefined; // important
     }
 
     protected parseOptions(json: {}) {
diff --git a/src/app/formulaire/definition/form-compute-courbe-remous.ts b/src/app/formulaire/definition/form-compute-courbe-remous.ts
index e65553d0e..d8bf8dc2d 100644
--- a/src/app/formulaire/definition/form-compute-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-compute-courbe-remous.ts
@@ -1,6 +1,5 @@
 import { acSection, Result, MethodeResolution, CourbeRemousParams, CourbeRemous } from "jalhyd";
 
-import { SelectField } from "../select-field";
 import { RemousResults } from "../../results/remous-results";
 import { FormulaireDefinition } from "./form-definition";
 import { FormDefSection } from "./form-def-section";
@@ -27,21 +26,13 @@ export class FormComputeCourbeRemous extends FormCompute {
 
         this.remousResults.parameters = prmCR;
 
-        // méthode de résolution
-
-        const msf: SelectField = <SelectField>this._formBase.getFormulaireNodeById("select_resolution");
-        const methRes: MethodeResolution = msf.getValue().value;
-
         // variable supplémentaire à calculer
-
-        this.remousResults.extraParamSymbol = this._formBase.getSelectedValue("select_target");
+        this.remousResults.extraParamSymbol = this._formBase.currentNub.properties.getPropValue("varCalc");
 
         // calcul
-
         this.remousResults.result = cr.calculRemous(this.remousResults.extraParamSymbol);
 
         // données du graphe
-
         this.remousResults.hauteurNormale = Yn.resultElement;
         this.remousResults.hauteurCritique = Yc.resultElement;
         if (this.remousResults.extraParamSymbol) {
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index b70997fea..469f34060 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -32,7 +32,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     /**
      * propriétés par défaut (lues si _currentNub === undefined )
      */
-    private _props = {};
+    protected _props = {};
 
     /**
      * fichier de configuration
@@ -92,7 +92,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     }
 
     public initNub(props?: Props) {
-        this._currentNub = this.createNub(props === undefined ? new Props(this.defaultProperties) : props);
+        this._currentNub = this.createNub(props ? props : new Props(this.defaultProperties));
     }
 
     public get currentNub(): Nub {
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 489d736ea..0bfc3a85f 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -1,4 +1,4 @@
-import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType, Props, Observer, Nub } from "jalhyd";
+import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType, Props, Observer, Nub, MethodeResolution } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
@@ -30,11 +30,11 @@ export class FieldSet extends FormulaireElement implements Observer {
     /**
      * propriétés déterminant l'état actuel du FieldSet (type de section, loi de débit, ...)
      */
-    private _props: Props;
+    // private _props: Props;
 
     constructor(parent: FormulaireNode) {
         super(parent);
-        this._props = new Props();
+        // this._props = new Props();
     }
 
     public get nub(): Nub {
@@ -44,7 +44,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     public setNub(sn: Nub, update: boolean = true) {
         this._nub = sn;
         this.setParentNubForAllFields();
-        this._props.setProps(sn.properties || new Props({}), this);
+        // this._props.setProps(sn.properties || new Props({}), this);
         if (update) {
             this.updateFields();
         }
@@ -104,15 +104,16 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     public get properties(): Props {
-        return this._props;
+        return this.nub.properties;
+        // return this._props;
     }
 
     private getPropValue(key: string): any {
-        return this._props.getPropValue(key);
+        return this.properties.getPropValue(key);
     }
 
     public setPropValue(key: string, val: any): boolean {
-        return this._props.setPropValue(key, val, this);
+        return this.properties.setPropValue(key, val, this);
     }
 
     private getNubParamFromSymbol(symbol: string): ParamDefinition {
@@ -212,7 +213,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     /**
-     * @TODO WTF ?
+     * Reflects all properties values in the interface, through the values of the <select> fields
      */
     private updateFields() {
         this.clearFields();
@@ -222,42 +223,76 @@ export class FieldSet extends FormulaireElement implements Observer {
 
         // MAJ des selects avec les valeurs actuelles des propriétés
         // spécifique à chaque modul de calcul, à revoir
+        switch (this._confId) {
 
-        if (this._confId === "fs_ouvrage") {
-            const sf1: SelectField = this.getFormulaireNodeById("select_ouvrage") as SelectField;
-            const st: StructureType = this.getPropValue("structureType");
-            const se1 = sf1.getSelectedEntryFromValue(st);
-            sf1.setValue(se1);
-
-            switch (st) {
-                case StructureType.SeuilRectangulaire:
-                    const sf2: SelectField = this.getFormulaireNodeById("select_loidebit1") as SelectField;
-                    const se2 = sf2.getSelectedEntryFromValue(this.getPropValue("loiDebit"));
-                    sf2.setValue(se2);
-                    break;
+            case "fs_ouvrage":
+                this.setSelectValueFromProperty("select_ouvrage", "structureType");
 
-                case StructureType.VanneRectangulaire:
-                    const sf3: SelectField = this.getFormulaireNodeById("select_loidebit2") as SelectField;
-                    const se3 = sf3.getSelectedEntryFromValue(this.getPropValue("loiDebit"));
-                    sf3.setValue(se3);
-                    break;
-            }
-        } else if (this._confId === "fs_section") {
-            const sf: SelectField = this.getFormulaireNodeById("select_section") as SelectField;
-            const nt: ComputeNodeType = this.getPropValue("nodeType");
-            const se = sf.getSelectedEntryFromValue(nt);
-            sf.setValue(se);
-        }
+                const st: StructureType = this.getPropValue("structureType");
+                switch (st) {
+                    case StructureType.SeuilRectangulaire:
+                        this.setSelectValueFromProperty("select_loidebit1", "loiDebit");
+                        break;
 
+                    case StructureType.VanneRectangulaire:
+                        this.setSelectValueFromProperty("select_loidebit2", "loiDebit");
+                        break;
+                }
+                break;
 
-        // fin MAJ selects
+            case "fs_section":
+                this.setSelectValueFromProperty("select_section", "nodeType");
+                break;
 
+            case "fs_param_calc":
+                this.setSelectValueFromProperty("select_resolution", "methodeResolution");
+                break;
+
+            case "fs_target_data":
+                this.setSelectValueFromProperty("select_target", "varCalc");
+                break;
+
+        }
+
+        // fin MAJ selects
         this.applyDependencies();
     }
 
     /**
-     * Set fieldset properties fron config file, unless config is already set (ex: structureType
-     * and loiDebit when deserialising existing structures)
+     * Reflects a property value in the interface, through the value of a <select> field, if this select exists
+     */
+    private setSelectValueFromProperty(selectId: string, propertyKey: string) {
+        const selectField: SelectField = this.getFormulaireNodeById(selectId) as SelectField;
+        if (selectField) {
+            const propVal: any = this.getPropValue(propertyKey);
+            const selectElement = selectField.getSelectedEntryFromValue(propVal); // @TODO juste setValue() ?
+            try {
+                selectField.setValue(selectElement);
+            } catch (e) {
+                console.error(`setSelectValueFromProperty: cannot set value ${propVal} on <select> ${selectId}`);
+            }
+        }
+    }
+
+    /**
+     * Sets Nub default property from config file, unless this property is already set
+     */
+    private setPropertyValueFromConfig(json: {}, configKey: string, propertyKey: string, enumClass?) {
+        const configValue: string = json[configKey];
+        const currentValue = this.properties.getPropValue(propertyKey);
+        if (configValue && ! currentValue) {
+            let formalValue =  configValue;
+            if (enumClass) {
+                formalValue = enumClass[configValue];
+            }
+            this.setPropValue(propertyKey, formalValue);
+        }
+    }
+
+    /**
+     * Sets Nub default properties from config file, unless properties values are already set
+     * (when deserialising an existing Nub)
+     * @TODO default values should be held by model, not interface !
      */
     public parseConfig(json: {}, data?: {}) {
         this._jsonConfig = json;
@@ -275,16 +310,10 @@ export class FieldSet extends FormulaireElement implements Observer {
         const node_type: ComputeNodeType = currentNt ? currentNt : (dnt ? ComputeNodeType[dnt] : parentForm.nodeType);
         this.setPropValue("nodeType", node_type);
 
-        const st: string = json["defaultStructType"];
-        const currentSt = this.properties.getPropValue("structureType");
-        if (st && ! currentSt) {
-            this.setPropValue("structureType", StructureType[st]);
-        }
-        const ld: string = json["defaultLoiDebit"];
-        const currentLd = this.properties.getPropValue("loiDebit");
-        if (ld && ! currentLd) {
-            this.setPropValue("loiDebit", LoiDebit[ld]);
-        }
+        this.setPropertyValueFromConfig(json, "defaultStructType", "structureType", StructureType);
+        this.setPropertyValueFromConfig(json, "defaultLoiDebit", "loiDebit", LoiDebit);
+        this.setPropertyValueFromConfig(json, "methodeResolution", "methodeResolution", MethodeResolution);
+        this.setPropertyValueFromConfig(json, "varCalc", "varCalc");
 
         this.updateFields();
     }
@@ -400,7 +429,7 @@ export class FieldSet extends FormulaireElement implements Observer {
                                 const oldFormUid = +prm["values"]["form_uid"];
 
                                 // correspondance avec l'objet mémoire
-                                let newFormUid;
+                                let newFormUid: string;
                                 for (const m of uidMap) {
                                     if (m["type"] === "form" && m["old"] === oldFormUid) {
                                         newFormUid = m["new"];
-- 
GitLab


From 17d04c1b3be7bd61fda0ab590372b875df98db51 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 27 Feb 2019 16:55:50 +0100
Subject: [PATCH 13/26] =?UTF-8?q?Fix=20#136=20suppression=20de=20ParamServ?=
 =?UTF-8?q?ice=20la=20localisation=20sp=C3=A9cifique=20=C3=A0=20un=20modul?=
 =?UTF-8?q?e=20est=20conserv=C3=A9e=20dans=20un=20attribut=20localisation?=
 =?UTF-8?q?=20sp=C3=A9cifique=20pour=20SectionParam:=20ajout=20des=20varia?=
 =?UTF-8?q?bles=20calcul=C3=A9es=20suppression=20de=20code=20inutile?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.component.ts                      |  3 -
 src/app/app.module.ts                         |  2 -
 .../section-param/section-param.fr.json       | 22 ++++-
 .../concrete/form-section-parametree.ts       |  2 +
 .../form-compute-section-parametree.ts        | 79 ++++++++++++---
 .../formulaire/definition/form-definition.ts  | 31 +++---
 src/app/formulaire/fieldset.ts                | 27 +++--
 src/app/formulaire/formulaire-element.ts      |  2 +-
 src/app/results/param-calc-results.ts         | 36 ++-----
 src/app/results/var-results.ts                |  6 +-
 src/app/services/param/param.service.ts       | 98 -------------------
 src/app/services/service-factory.ts           |  3 -
 src/locale/messages.en.json                   |  6 +-
 src/locale/messages.fr.json                   |  6 +-
 14 files changed, 135 insertions(+), 188 deletions(-)
 delete mode 100644 src/app/services/param/param.service.ts

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 02ecfc782..968194eae 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -11,7 +11,6 @@ import { ErrorService } from "./services/error/error.service";
 import { FormulaireService } from "./services/formulaire/formulaire.service";
 import { FormulaireDefinition } from "./formulaire/definition/form-definition";
 import { ServiceFactory } from "./services/service-factory";
-import { ParamService } from "./services/param/param.service";
 import { HttpService } from "./services/http/http.service";
 import { ApplicationSetupService } from "./services/app-setup/app-setup.service";
 import { nghydDateRev } from "../date_revision";
@@ -61,7 +60,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
 
   constructor(
     private intlService: I18nService,
-    private paramService: ParamService,
     private appSetupService: ApplicationSetupService,
     private appRef: ApplicationRef,
     private errorService: ErrorService,
@@ -76,7 +74,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
   ) {
     ServiceFactory.instance.httpService = httpService;
     ServiceFactory.instance.applicationSetupService = appSetupService;
-    ServiceFactory.instance.paramService = paramService;
     ServiceFactory.instance.i18nService = intlService;
     ServiceFactory.instance.formulaireService = formulaireService;
 
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index e20d52534..13c9b193d 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -37,7 +37,6 @@ import { RouterModule, Routes } from "@angular/router";
 import { NgxMdModule } from "ngx-md";
 
 import { FormulaireService } from "./services/formulaire/formulaire.service";
-import { ParamService } from "./services/param/param.service";
 import { I18nService } from "./services/internationalisation/internationalisation.service";
 import { HttpService } from "./services/http/http.service";
 import { ApplicationSetupService } from "./services/app-setup/app-setup.service";
@@ -184,7 +183,6 @@ const appRoutes: Routes = [
     FormulaireService,
     HttpService,
     I18nService,
-    ParamService,
     {
       provide: ErrorStateMatcher,
       useClass: ImmediateErrorStateMatcher
diff --git a/src/app/calculators/section-param/section-param.fr.json b/src/app/calculators/section-param/section-param.fr.json
index 3620678eb..891e7b95e 100644
--- a/src/app/calculators/section-param/section-param.fr.json
+++ b/src/app/calculators/section-param/section-param.fr.json
@@ -40,5 +40,23 @@
     "select_target_J": "La perte de charge (m)",
     "select_target_I-J": "Variation linéaire de l'énergie spécifique (m/m)",
     "select_target_Imp": "Impulsion (N)",
-    "select_target_Tau0": "La force tractrice (Pa)"
-}
\ No newline at end of file
+    "select_target_Tau0": "La force tractrice (Pa)",
+
+    "Hs": "Charge spécifique",
+    "Hsc": "Charge critique",
+    "B": "Largeur au miroir",
+    "P": "Périmètre mouillé",
+    "S": "Surface mouillée",
+    "R": "Rayon hydraulique",
+    "V": "Vitesse moyenne",
+    "Fr": "Froude",
+    "Yc": "Tirant d'eau critique",
+    "Yn": "Tirant d'eau normal",
+    "Yf": "Tirant d'eau fluvial",
+    "Yt": "Tirant d'eau torrentiel",
+    "Yco": "Tirant d'eau conjugué",
+    "J": "Perte de charge",
+    "I-J": "Variation linéaire de l'énergie spécifique",
+    "Imp": "Impulsion",
+    "Tau0": "Force tractrice"
+}
diff --git a/src/app/formulaire/definition/concrete/form-section-parametree.ts b/src/app/formulaire/definition/concrete/form-section-parametree.ts
index 651ec0453..9d7da09ab 100644
--- a/src/app/formulaire/definition/concrete/form-section-parametree.ts
+++ b/src/app/formulaire/definition/concrete/form-section-parametree.ts
@@ -23,6 +23,8 @@ export class FormulaireSectionParametree extends FormulaireDefinition {
         this._formSection = new FormDefSection(this);
         this._formSectionResult = new FormResultSection(this, this._formSection);
         this._formCompute = new FormComputeSectionParametree(this, this._formSection, this._formSectionResult);
+        // default properties
+        this._props["varCalc"] = "Hs";
     }
 
     protected parseOptions(json: {}) {
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
index ab2c327b5..9640c2e47 100644
--- a/src/app/formulaire/definition/form-compute-section-parametree.ts
+++ b/src/app/formulaire/definition/form-compute-section-parametree.ts
@@ -1,33 +1,25 @@
-import { SectionParametree, acSection, Result } from "jalhyd";
+import { SectionParametree, acSection, Result, ParamDomain, ParamDefinition, ParamDomainValue } from "jalhyd";
 
 import { FormCompute } from "./form-compute";
 import { NgParameter } from "../ngparam";
 import { FormResult } from "./form-result";
 import { FormDefSection } from "./form-def-section";
 import { FormResultSection } from "./form-result-section";
-import { FixedResults } from "../../results/fixed-results";
 import { VarResults } from "../../results/var-results";
 import { SectionResults } from "../../results/section-results";
 import { FormulaireDefinition } from "./form-definition";
-import { ServiceFactory } from "../../services/service-factory";
-import { ParamService } from "../../services/param/param.service";
+import { FormulaireNode } from "../formulaire-node";
 
 export class FormComputeSectionParametree extends FormCompute {
-    private _paramService: ParamService;
 
     constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResult) {
         super(formBase, formResult);
-        this._paramService = ServiceFactory.instance.paramService;
     }
 
     private get _formSectionResult(): FormResultSection {
         return this._formResult as FormResultSection;
     }
 
-    private get _fixResults(): FixedResults {
-        return this._formSectionResult.fixedResults;
-    }
-
     private get _varResults(): VarResults {
         return this._formSectionResult.varResults;
     }
@@ -42,7 +34,6 @@ export class FormComputeSectionParametree extends FormCompute {
      */
     private doComputeSectionVar(varParam: NgParameter) {
         const computePrec: number = this._formBase.getParameterValue("Pr"); // précision de calcul
-        const nDigits = -Math.log10(computePrec);
 
         this._formSectionResult.addSectionFixedParameters(false);
 
@@ -51,17 +42,14 @@ export class FormComputeSectionParametree extends FormCompute {
 
         const sectNub: SectionParametree = this._formBase.currentNub as SectionParametree;
         const sect: acSection = sectNub.section;
-        const prms = sectNub.parameters;
 
         this._sectionResults.section = sect;
 
         this._varResults.variatedParameter = varParam;
 
-        const computedParam: NgParameter = this._paramService.createParameter(computedParamInfo.symbol, this._formBase);
+        const computedParam: NgParameter = this.createParameter(computedParamInfo.symbol, this._formBase);
         this._varResults.calculatedParameter = computedParam;
 
-        const compSymbol: string = computedParamInfo["symbol"];
-
         this._varResults.result = this.runNubCalc(sectNub, computedParam, computePrec);
         this._varResults.graphTitle = computedParamInfo.symbol + " = f( " + varParam.symbol + " )";
         this._varResults.update(false);
@@ -92,4 +80,65 @@ export class FormComputeSectionParametree extends FormCompute {
         this._formSectionResult.addSectionFixedParameters(false);
         this._formSectionResult.fixedResults.result = tmpResult;
     }
+
+    /**
+     *
+     * @param calcType crée un NgParameter n'appartenant pas à un ComputeNode
+     * @param symbol symbole du paramètre à créer
+     */
+    private createParameter(symbol: string, parent: FormulaireNode): NgParameter {
+        let p: NgParameter;
+        const dom = new ParamDomain(ParamDomainValue.POS_NULL);
+        p = new NgParameter(new ParamDefinition(null, symbol, dom), parent);
+        p.confId = symbol;
+
+        switch (symbol) {
+            case "Hs":
+            case "Hsc":
+            case "B":
+            case "P":
+            case "R":
+            case "Yc":
+            case "Yn":
+            case "Yf":
+            case "Yt":
+            case "Yco":
+            case "J":
+                p.unit = "m";
+                break;
+
+            case "S":
+                p.unit = "m2";
+                break;
+
+            case "V":
+                p.unit = "m/s";
+                break;
+
+            case "I-J":
+                p.unit = "m/m";
+                break;
+
+            case "Fr":
+                p.unit = "";
+                break;
+
+            case "Imp":
+                p.unit = "N";
+                break;
+
+            case "Tau0":
+                p.unit = "Pa";
+                break;
+
+            case "Pr":
+                break;
+
+            default:
+                throw new Error(`ParamService.createParameter() : symbole ${symbol} non pris en charge`);
+        }
+        p.updateLocalisation(this._formBase.specificLocalisation);
+
+        return p;
+    }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 469f34060..c683185d7 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -5,8 +5,6 @@ import { NgParameter, ParamRadioConfig } from "../ngparam";
 import { Field } from "../field";
 import { StringMap } from "../../stringmap";
 import { FormulaireNode } from "../formulaire-node";
-import { ServiceFactory } from "../../services/service-factory";
-import { ParamService } from "../../services/param/param.service";
 import { FieldSet } from "../fieldset";
 import { FieldsetContainer } from "../fieldset-container";
 import { SelectField } from "../select-field";
@@ -19,36 +17,26 @@ import { CalculatorResults } from "../../results/calculator-results";
  * classe de base pour tous les formulaires
  */
 export abstract class FormulaireDefinition extends FormulaireNode implements Observer {
-    /**
-     * nom du module de calcul
-     */
+    /** nom du module de calcul */
     private _calculatorName: string;
 
-    /**
-     * Nub courant
-     */
+    /** Nub courant */
     protected _currentNub: Nub;
 
-    /**
-     * propriétés par défaut (lues si _currentNub === undefined )
-     */
+    /** propriétés par défaut (lues si _currentNub === undefined ) */
     protected _props = {};
 
-    /**
-     * fichier de configuration
-     */
+    /** fichier de configuration */
     private _jsonConfig: {};
 
-    /**
-     * aide en ligne
-     */
+    /** aide en ligne */
     private _helpLink: string;
 
-    protected _paramService: ParamService;
+    /** clé-valeurs du fichier de localisation spécifique à ce module */
+    private _specificLocalisation: StringMap;
 
     constructor() {
         super(undefined);
-        this._paramService = ServiceFactory.instance.paramService;
     }
 
     // surcharge de FormulaireNode::get:uid()
@@ -61,6 +49,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         }
     }
 
+    public get specificLocalisation() {
+        return this._specificLocalisation;
+    }
+
     public get calculatorType(): CalculatorType {
         const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
         return props["calcType"];
@@ -409,6 +401,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     public abstract get results(): CalculatorResults[];
 
     public updateLocalisation(localisation: StringMap) {
+        this._specificLocalisation = localisation;
         for (const fe of this.topFormElements) {
             fe.updateLocalisation(localisation);
         }
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 0bfc3a85f..66973a184 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -1,4 +1,5 @@
-import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType, Props, Observer, Nub, MethodeResolution } from "jalhyd";
+import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType,
+    Props, Observer, Nub, MethodeResolution, ParamCalculability, ParamDomain, ParamDomainValue } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
@@ -6,10 +7,10 @@ import { CheckField } from "./check-field";
 import { SelectField } from "./select-field";
 import { NgParameter, ParamRadioConfig } from "./ngparam";
 import { ServiceFactory } from "../services/service-factory";
-import { ParamService } from "../services/param/param.service";
 import { FormulaireDefinition } from "./definition/form-definition";
 import { StringMap } from "../stringmap";
 import { FormulaireNode } from "./formulaire-node";
+import { ApplicationSetupService } from "../services/app-setup/app-setup.service";
 
 export class FieldSet extends FormulaireElement implements Observer {
     /**
@@ -27,14 +28,11 @@ export class FieldSet extends FormulaireElement implements Observer {
      */
     private _jsonConfig: {};
 
-    /**
-     * propriétés déterminant l'état actuel du FieldSet (type de section, loi de débit, ...)
-     */
-    // private _props: Props;
+    private _appSetupService: ApplicationSetupService;
 
     constructor(parent: FormulaireNode) {
         super(parent);
-        // this._props = new Props();
+        this._appSetupService = ServiceFactory.instance.applicationSetupService;
     }
 
     public get nub(): Nub {
@@ -136,13 +134,12 @@ export class FieldSet extends FormulaireElement implements Observer {
     private parse_input(json: {}, default_radio_config: string): NgParameter {
         // console.log("parsing input", json);
         const input_id: string = json["id"];
-        const paramService: ParamService = ServiceFactory.instance.paramService;
 
         let res: NgParameter;
 
         switch (input_id) {
             case "Pr":
-                res = paramService.createParameter(input_id, this);
+                res = this.createAccuracyParameter(this);
                 break;
 
             default:
@@ -212,6 +209,15 @@ export class FieldSet extends FormulaireElement implements Observer {
         }
     }
 
+    private createAccuracyParameter(parent: FormulaireNode): NgParameter {
+        const d = new ParamDomain(ParamDomainValue.INTERVAL, 1e-10, 100);
+        const p = new ParamDefinition(null, "Pr", d, this._appSetupService.computePrecision);
+        p.calculability = ParamCalculability.FREE;
+        const np = new NgParameter(p, parent);
+        np.confId = "Pr";
+        return np;
+    }
+
     /**
      * Reflects all properties values in the interface, through the values of the <select> fields
      */
@@ -248,7 +254,8 @@ export class FieldSet extends FormulaireElement implements Observer {
                 this.setSelectValueFromProperty("select_resolution", "methodeResolution");
                 break;
 
-            case "fs_target_data":
+            case "fs_target_data": // courbe de remous
+            case "fs_computed_var": // section paramétrée
                 this.setSelectValueFromProperty("select_target", "varCalc");
                 break;
 
diff --git a/src/app/formulaire/formulaire-element.ts b/src/app/formulaire/formulaire-element.ts
index c2347b6ee..fd3f87b74 100644
--- a/src/app/formulaire/formulaire-element.ts
+++ b/src/app/formulaire/formulaire-element.ts
@@ -188,7 +188,7 @@ export abstract class FormulaireElement extends FormulaireNode {
         if (loc[key] !== undefined) {
             this._label = this.intlService.localizeText(key, loc);
         } else {
-            // Recherche du code dans locale/error_message.xx.json
+            // Recherche du code dans locale/message.xx.json
             this._label = this.intlService.localizeText("INFO_LIB_" + key.replace(/\d+$/, "").toLocaleUpperCase());
         }
         for (const f of this.getKids()) {
diff --git a/src/app/results/param-calc-results.ts b/src/app/results/param-calc-results.ts
index 5a3d6adec..bdcabde2d 100644
--- a/src/app/results/param-calc-results.ts
+++ b/src/app/results/param-calc-results.ts
@@ -15,17 +15,17 @@ export abstract class CalculatedParamResults extends CalculatorResults {
     /**
      * titre de la colonne
      */
-    private _calculatedParamHeader: string;
+    public calculatedParameterHeader: string;
 
     /**
      * résultat du calcul sur le paramètre calculé
      */
-    protected _result: Result;
+    public result: Result;
 
     protected reset() {
         this._calculatedParam = undefined;
-        this._calculatedParamHeader = undefined;
-        this._result = undefined;
+        this.calculatedParameterHeader = undefined;
+        this.result = undefined;
     }
 
     public get calculatedParameter(): NgParameter {
@@ -34,40 +34,24 @@ export abstract class CalculatedParamResults extends CalculatorResults {
 
     public set calculatedParameter(p: NgParameter) {
         this._calculatedParam = p;
-        this._calculatedParamHeader = CalculatorResults.paramLabel(this._calculatedParam, true);
-    }
-
-    public get calculatedParameterHeader() {
-        return this._calculatedParamHeader;
-    }
-
-    public set calculatedParameterHeader(s: string) {
-        this._calculatedParamHeader = s;
-    }
-
-    public get result(): Result {
-        return this._result;
-    }
-
-    public set result(r: Result) {
-        this._result = r;
+        this.calculatedParameterHeader = CalculatorResults.paramLabel(this._calculatedParam, true);
     }
 
     public get hasResults(): boolean {
-        if (this._result === undefined) {
+        if (this.result === undefined) {
             return false;
         }
-        return this._result.ok;
+        return this.result.ok;
     }
 
     public get hasLog(): boolean {
-        if (this._result === undefined) {
+        if (this.result === undefined) {
             return false;
         }
-        return this._result.hasLog;
+        return this.result.hasLog;
     }
 
     public get log(): cLog {
-        return this._result && this._result.log;  // return x === undefined ? undefined : x.y
+        return this.result && this.result.log;  // return x === undefined ? undefined : x.y
     }
 }
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index 657dd44f6..177f36a60 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -93,7 +93,7 @@ export class VarResults extends CalculatedParamResults {
     }
 
     public get resultElements(): ResultElement[] {
-        return this._result.resultElements;
+        return this.result.resultElements;
     }
 
     public get graphTitle() {
@@ -122,14 +122,14 @@ export class VarResults extends CalculatedParamResults {
         }
 
         // valeurs du paramètre à calculer
-        for (const r of this._result.resultElements) {
+        for (const r of this.result.resultElements) {
             this._yValues.push(r.vCalc);
         }
 
         // clés des résultats supplémentaires
 
         if (this._extraResultKeys.length === 0) {
-            for (const re of this._result.resultElements) { // re:ResultElement
+            for (const re of this.result.resultElements) { // re:ResultElement
                 for (const erk in re.extraResults) {
                     if (!this._extraResultKeys.includes(erk)) {
                         this._extraResultKeys.push(erk);
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
deleted file mode 100644
index d34637e7c..000000000
--- a/src/app/services/param/param.service.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { ParamDomain, ParamDefinition, ParamDomainValue, ParamCalculability, Session, Props, Nub, ParallelStructure } from "jalhyd";
-
-import { NgParameter } from "../../formulaire/ngparam";
-import { Injectable } from "@angular/core";
-import { I18nService } from "../internationalisation/internationalisation.service";
-import { ApplicationSetupService } from "../app-setup/app-setup.service";
-import { FormulaireNode } from "../../formulaire/formulaire-node";
-
-@Injectable()
-export class ParamService {
-
-    constructor(
-        private i18nService: I18nService,
-        private applicationSetupService: ApplicationSetupService
-        ) { }
-
-    private get _intlService(): I18nService {
-        return this.i18nService;
-    }
-
-    private get _appSetupService(): ApplicationSetupService {
-        return this.applicationSetupService;
-    }
-
-    private createAccuracyParameter(): ParamDefinition {
-        const d = new ParamDomain(ParamDomainValue.INTERVAL, 1e-10, 100);
-        const p = new ParamDefinition(null, "Pr", d, this._appSetupService.computePrecision);
-        p.calculability = ParamCalculability.FREE;
-        return p;
-    }
-
-    /**
-     *
-     * @param calcType crée un NgParameter n'appartenant pas à un ComputeNode
-     * @param symbol symbole du paramètre à créer
-     */
-    public createParameter(symbol: string, parent: FormulaireNode): NgParameter {
-        let p: NgParameter;
-        if (symbol === "Pr") {
-            const prmDef: ParamDefinition = this.createAccuracyParameter();
-            p = new NgParameter(prmDef.clone(), parent);
-            p.confId = "Pr";
-        } else {
-            const dom = new ParamDomain(ParamDomainValue.POS_NULL);
-            p = new NgParameter(new ParamDefinition(null, symbol, dom), parent);
-            p.confId = symbol;
-
-            switch (symbol) {
-                case "Hs":
-                case "Hsc":
-                case "B":
-                case "P":
-                case "R":
-                case "Yc":
-                case "Yn":
-                case "Yf":
-                case "Yt":
-                case "Yco":
-                case "J":
-                    p.unit = "m";
-                    break;
-
-                case "S":
-                    p.unit = "m2";
-                    break;
-
-                case "V":
-                    p.unit = "m/s";
-                    break;
-
-                case "I-J":
-                    p.unit = "m/m";
-                    break;
-
-                case "Fr":
-                    p.unit = "";
-                    break;
-
-                case "Imp":
-                    p.unit = "N";
-                    break;
-
-                case "Tau0":
-                    p.unit = "Pa";
-                    break;
-
-                case "Pr":
-                    break;
-
-                default:
-                    throw new Error(`ParamService.createParameter() : symbole ${symbol} non pris en charge`);
-            }
-            p.updateLocalisation(this._intlService.currentMap);
-        }
-
-        return p;
-    }
-}
diff --git a/src/app/services/service-factory.ts b/src/app/services/service-factory.ts
index 0e84febab..0627bdf99 100644
--- a/src/app/services/service-factory.ts
+++ b/src/app/services/service-factory.ts
@@ -1,5 +1,4 @@
 import { ApplicationSetupService } from "./app-setup/app-setup.service";
-import { ParamService } from "./param/param.service";
 import { FormulaireService } from "./formulaire/formulaire.service";
 import { I18nService } from "./internationalisation/internationalisation.service";
 import { HttpService } from "./http/http.service";
@@ -11,8 +10,6 @@ export class ServiceFactory {
 
     public applicationSetupService: ApplicationSetupService;
 
-    public paramService: ParamService;
-
     public formulaireService: FormulaireService;
 
     public i18nService: I18nService;
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index d1a56cc1c..4c96c5aa5 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -112,7 +112,7 @@
     "INFO_LIB_ALPHA": "Alpha coefficient",
     "INFO_LIB_BETA": "Beta coefficient",
     "INFO_LIB_CD": "Discharge coefficient",
-    "INFO_LIB_BT": "Half opening of the triangle (m)",
+    "INFO_LIB_BT": "Half opening of the triangle",
     "INFO_LIB_FS_PARAM_CALC": "Calculation parameters",
     "INFO_LIB_FS_OUVRAGE": "Device",
     "INFO_LIB_L": "Weir width",
@@ -123,8 +123,8 @@
     "INFO_LIB_SELECT_OUVRAGE": "Device",
     "INFO_LIB_SELECT_OUVRAGE_SEUIL_RECT": "Rectangular weir",
     "INFO_LIB_ZDV": "Crest weir elevation or gate base",
-    "INFO_LIB_ZRAM": "Upstream apron elevation (m)",
-    "INFO_LIB_ZT": "Triangle top elevation (m)",
+    "INFO_LIB_ZRAM": "Upstream apron elevation",
+    "INFO_LIB_ZT": "Triangle top elevation",
     "INFO_MACRORUGO_TITRE": "Rock-ramp fishpasses",
     "INFO_MACRORUGO_TITRE_COURT": "RR fishpasses",
     "INFO_MENU_HELP_TITLE": "Help",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 8dbc1646b..69ceb18ec 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -112,7 +112,7 @@
     "INFO_LIB_ALPHA": "Coefficient alpha",
     "INFO_LIB_BETA": "Coefficient béta",
     "INFO_LIB_CD": "Coefficient de débit",
-    "INFO_LIB_BT": "Demi-ouverture du triangle (m)",
+    "INFO_LIB_BT": "Demi-ouverture du triangle",
     "INFO_LIB_FS_PARAM_CALC": "Paramètres de calcul",
     "INFO_LIB_FS_OUVRAGE": "Ouvrage",
     "INFO_LIB_L": "Largeur du déversoir",
@@ -123,8 +123,8 @@
     "INFO_LIB_SELECT_OUVRAGE": "Ouvrage",
     "INFO_LIB_SELECT_OUVRAGE_SEUIL_RECT": "Seuil rectangulaire",
     "INFO_LIB_ZDV": "Cote de la crête du déversoir ou du radier de la vanne",
-    "INFO_LIB_ZRAM": "Cote du radier amont (m)",
-    "INFO_LIB_ZT": "Cote haute du triangle (m)",
+    "INFO_LIB_ZRAM": "Cote du radier amont",
+    "INFO_LIB_ZT": "Cote haute du triangle",
     "INFO_MENU_HELP_TITLE": "Aide",
     "INFO_MENU_LOAD_SESSION_TITLE": "Charger une session",
     "INFO_MENU_SAVE_SESSION_TITLE": "Enregistrer la session",
-- 
GitLab


From 0f5864fa65f79d814dcd939facfc756406ddf308 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 09:12:19 +0100
Subject: [PATCH 14/26] =?UTF-8?q?Section=20param:=20m=C3=A0j=20du=20fichie?=
 =?UTF-8?q?r=20de=20localisation=20"en"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../section-param/section-param.en.json       | 22 +++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/src/app/calculators/section-param/section-param.en.json b/src/app/calculators/section-param/section-param.en.json
index 22e764298..e84aae88d 100644
--- a/src/app/calculators/section-param/section-param.en.json
+++ b/src/app/calculators/section-param/section-param.en.json
@@ -41,5 +41,23 @@
     "select_target_J": "Head loss (m)",
     "select_target_I-J": "Linear variation of specific head (m/m)",
     "select_target_Imp": "Impulse (N)",
-    "select_target_Tau0": "Tractive force (Pa)"
-}
\ No newline at end of file
+    "select_target_Tau0": "Tractive force (Pa)",
+
+    "Hs": "Charge spécifique",
+    "Hsc": "Charge critique",
+    "B": "Largeur au miroir",
+    "P": "Périmètre mouillé",
+    "S": "Surface mouillée",
+    "R": "Rayon hydraulique",
+    "V": "Vitesse moyenne",
+    "Fr": "Froude",
+    "Yc": "Tirant d'eau critique",
+    "Yn": "Tirant d'eau normal",
+    "Yf": "Tirant d'eau fluvial",
+    "Yt": "Tirant d'eau torrentiel",
+    "Yco": "Tirant d'eau conjugué",
+    "J": "Perte de charge",
+    "I-J": "Variation linéaire de l'énergie spécifique",
+    "Imp": "Impulsion",
+    "Tau0": "Force tractrice"
+}
-- 
GitLab


From a12f8de5ada60ff30036ee15106e0ec745bb469b Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 09:12:55 +0100
Subject: [PATCH 15/26] =?UTF-8?q?Fix=20#152=20traiter=20la=20pr=C3=A9cisio?=
 =?UTF-8?q?n=20comme=20un=20param=C3=A8tre?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/formulaire/fieldset.ts | 40 ++++++++++------------------------
 src/app/formulaire/ngparam.ts  |  8 +------
 2 files changed, 13 insertions(+), 35 deletions(-)

diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 66973a184..f8129a9e8 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -132,30 +132,23 @@ export class FieldSet extends FormulaireElement implements Observer {
      * @param default_radio_config config du radio fixé/à varier/à calculer
      */
     private parse_input(json: {}, default_radio_config: string): NgParameter {
-        // console.log("parsing input", json);
         const input_id: string = json["id"];
 
         let res: NgParameter;
 
-        switch (input_id) {
-            case "Pr":
-                res = this.createAccuracyParameter(this);
-                break;
-
-            default:
-                const nt: string = json["nodeType"];
-                const nodeType: ComputeNodeType = nt ? ComputeNodeType[nt] : this.getPropValue("nodeType");
+        const nt: string = json["nodeType"];
+        const nodeType: ComputeNodeType = nt ? ComputeNodeType[nt] : this.getPropValue("nodeType");
 
-                if (nodeType === this.getPropValue("nodeType")) { // si le nodeType du paramètre est le même que celui du fieldset
-                    let nubParam: ParamDefinition;
-                    try {
-                        nubParam = this.getNubParamFromSymbol(input_id);
-                    } catch (e) {
-                    }
-                    if (nubParam) {
-                        res = new NgParameter(nubParam, this);
-                    }
-                }
+        if (nodeType === this.getPropValue("nodeType")) { // si le nodeType du paramètre est le même que celui du fieldset
+            let nubParam: ParamDefinition;
+            try {
+                nubParam = this.getNubParamFromSymbol(input_id);
+            } catch (e) {
+                console.error(`FieldSet::parse_input : cannot find param from symbol ${input_id}`);
+            }
+            if (nubParam) {
+                res = new NgParameter(nubParam, this);
+            }
         }
 
         if (res) {
@@ -209,15 +202,6 @@ export class FieldSet extends FormulaireElement implements Observer {
         }
     }
 
-    private createAccuracyParameter(parent: FormulaireNode): NgParameter {
-        const d = new ParamDomain(ParamDomainValue.INTERVAL, 1e-10, 100);
-        const p = new ParamDefinition(null, "Pr", d, this._appSetupService.computePrecision);
-        p.calculability = ParamCalculability.FREE;
-        const np = new NgParameter(p, parent);
-        np.confId = "Pr";
-        return np;
-    }
-
     /**
      * Reflects all properties values in the interface, through the values of the <select> fields
      */
diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts
index 6d61d9a78..56006d64d 100644
--- a/src/app/formulaire/ngparam.ts
+++ b/src/app/formulaire/ngparam.ts
@@ -281,17 +281,11 @@ export class NgParameter extends InputField implements Observer {
     }
 
     public parseConfig(json: {}, data?: {}) {
-        const appSetupService: ApplicationSetupService = ServiceFactory.instance.applicationSetupService;
         const radioConfig: string = data["radioConfig"];
 
         this._confId = json["id"];
         this.unit = json["unit"];
-        let val: number;
-        if (this.symbol === "Pr") {
-            val = appSetupService.computePrecision;
-        } else {
-            val = json["value"];
-        }
+        const val: number = json["value"];
         if (val) {
             this.setValue(this, +val);
         }
-- 
GitLab


From d19efa476801913a449dab1574dc256c27732d4f Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 09:13:12 +0100
Subject: [PATCH 16/26] =?UTF-8?q?M=C3=A0J=20package-lock?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 package-lock.json | 363 ----------------------------------------------
 1 file changed, 363 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index bead599e1..e4a04b40c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6899,369 +6899,6 @@
       "version": "file:../jalhyd",
       "requires": {
         "buffer": "^5.2.1"
-      },
-      "dependencies": {
-        "@types/jasmine": {
-          "version": "2.8.8",
-          "bundled": true
-        },
-        "@types/node": {
-          "version": "10.5.2",
-          "bundled": true
-        },
-        "ansi-regex": {
-          "version": "2.1.1",
-          "bundled": true
-        },
-        "ansi-styles": {
-          "version": "2.2.1",
-          "bundled": true
-        },
-        "argparse": {
-          "version": "1.0.10",
-          "bundled": true,
-          "requires": {
-            "sprintf-js": "~1.0.2"
-          }
-        },
-        "babel-code-frame": {
-          "version": "6.26.0",
-          "bundled": true,
-          "requires": {
-            "chalk": "^1.1.3",
-            "esutils": "^2.0.2",
-            "js-tokens": "^3.0.2"
-          },
-          "dependencies": {
-            "chalk": {
-              "version": "1.1.3",
-              "bundled": true,
-              "requires": {
-                "ansi-styles": "^2.2.1",
-                "escape-string-regexp": "^1.0.2",
-                "has-ansi": "^2.0.0",
-                "strip-ansi": "^3.0.0",
-                "supports-color": "^2.0.0"
-              }
-            }
-          }
-        },
-        "balanced-match": {
-          "version": "1.0.0",
-          "bundled": true
-        },
-        "base64-js": {
-          "version": "1.3.0",
-          "bundled": true
-        },
-        "brace-expansion": {
-          "version": "1.1.8",
-          "bundled": true,
-          "requires": {
-            "balanced-match": "^1.0.0",
-            "concat-map": "0.0.1"
-          }
-        },
-        "buffer": {
-          "version": "5.2.1",
-          "bundled": true,
-          "requires": {
-            "base64-js": "^1.0.2",
-            "ieee754": "^1.1.4"
-          }
-        },
-        "builtin-modules": {
-          "version": "1.1.1",
-          "bundled": true
-        },
-        "chalk": {
-          "version": "2.3.0",
-          "bundled": true,
-          "requires": {
-            "ansi-styles": "^3.1.0",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^4.0.0"
-          },
-          "dependencies": {
-            "ansi-styles": {
-              "version": "3.2.0",
-              "bundled": true,
-              "requires": {
-                "color-convert": "^1.9.0"
-              }
-            },
-            "supports-color": {
-              "version": "4.5.0",
-              "bundled": true,
-              "requires": {
-                "has-flag": "^2.0.0"
-              }
-            }
-          }
-        },
-        "coffeescript": {
-          "version": "2.3.1",
-          "bundled": true
-        },
-        "color-convert": {
-          "version": "1.9.1",
-          "bundled": true,
-          "requires": {
-            "color-name": "^1.1.1"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "bundled": true
-        },
-        "commander": {
-          "version": "2.12.2",
-          "bundled": true
-        },
-        "concat-map": {
-          "version": "0.0.1",
-          "bundled": true
-        },
-        "diff": {
-          "version": "3.4.0",
-          "bundled": true
-        },
-        "escape-string-regexp": {
-          "version": "1.0.5",
-          "bundled": true
-        },
-        "esprima": {
-          "version": "4.0.1",
-          "bundled": true
-        },
-        "esutils": {
-          "version": "2.0.2",
-          "bundled": true
-        },
-        "fs.realpath": {
-          "version": "1.0.0",
-          "bundled": true
-        },
-        "glob": {
-          "version": "7.1.2",
-          "bundled": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "globule": {
-          "version": "1.2.1",
-          "bundled": true,
-          "requires": {
-            "glob": "~7.1.1",
-            "lodash": "~4.17.10",
-            "minimatch": "~3.0.2"
-          }
-        },
-        "has-ansi": {
-          "version": "2.0.0",
-          "bundled": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "2.0.0",
-          "bundled": true
-        },
-        "ieee754": {
-          "version": "1.1.12",
-          "bundled": true
-        },
-        "inflight": {
-          "version": "1.0.6",
-          "bundled": true,
-          "requires": {
-            "once": "^1.3.0",
-            "wrappy": "1"
-          }
-        },
-        "inherits": {
-          "version": "2.0.3",
-          "bundled": true
-        },
-        "jasmine": {
-          "version": "3.1.0",
-          "bundled": true,
-          "requires": {
-            "glob": "^7.0.6",
-            "jasmine-core": "~3.1.0"
-          }
-        },
-        "jasmine-core": {
-          "version": "3.1.0",
-          "bundled": true
-        },
-        "jasmine-node": {
-          "version": "1.15.0",
-          "bundled": true,
-          "requires": {
-            "coffeescript": ">=1.0.1",
-            "gaze": "~1.1.2",
-            "jasmine-growl-reporter": "~1.0.1",
-            "jasmine-reporters": "~1.0.0",
-            "mkdirp": "~0.3.5",
-            "requirejs": ">=0.27.1",
-            "underscore": ">= 1.3.1",
-            "walkdir": ">= 0.0.1"
-          },
-          "dependencies": {
-            "gaze": {
-              "version": "1.1.3",
-              "bundled": true,
-              "requires": {
-                "globule": "^1.0.0"
-              }
-            },
-            "growl": {
-              "version": "1.10.5",
-              "bundled": true
-            },
-            "jasmine-growl-reporter": {
-              "version": "1.0.1",
-              "bundled": true,
-              "requires": {
-                "growl": "^1.10.2"
-              }
-            }
-          }
-        },
-        "jasmine-reporters": {
-          "version": "1.0.2",
-          "bundled": true,
-          "requires": {
-            "mkdirp": "~0.3.5"
-          }
-        },
-        "js-tokens": {
-          "version": "3.0.2",
-          "bundled": true
-        },
-        "js-yaml": {
-          "version": "3.12.0",
-          "bundled": true,
-          "requires": {
-            "argparse": "^1.0.7",
-            "esprima": "^4.0.0"
-          }
-        },
-        "lodash": {
-          "version": "4.17.10",
-          "bundled": true
-        },
-        "minimatch": {
-          "version": "3.0.4",
-          "bundled": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
-        "mkdirp": {
-          "version": "0.3.5",
-          "bundled": true
-        },
-        "once": {
-          "version": "1.4.0",
-          "bundled": true,
-          "requires": {
-            "wrappy": "1"
-          }
-        },
-        "path-is-absolute": {
-          "version": "1.0.1",
-          "bundled": true
-        },
-        "path-parse": {
-          "version": "1.0.5",
-          "bundled": true
-        },
-        "requirejs": {
-          "version": "2.3.5",
-          "bundled": true
-        },
-        "resolve": {
-          "version": "1.5.0",
-          "bundled": true,
-          "requires": {
-            "path-parse": "^1.0.5"
-          }
-        },
-        "semver": {
-          "version": "5.4.1",
-          "bundled": true
-        },
-        "sprintf-js": {
-          "version": "1.0.3",
-          "bundled": true
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "bundled": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "2.0.0",
-          "bundled": true
-        },
-        "tslib": {
-          "version": "1.8.1",
-          "bundled": true
-        },
-        "tslint": {
-          "version": "5.11.0",
-          "bundled": true,
-          "requires": {
-            "babel-code-frame": "^6.22.0",
-            "builtin-modules": "^1.1.1",
-            "chalk": "^2.3.0",
-            "commander": "^2.12.1",
-            "diff": "^3.2.0",
-            "glob": "^7.1.1",
-            "js-yaml": "^3.7.0",
-            "minimatch": "^3.0.4",
-            "resolve": "^1.3.2",
-            "semver": "^5.3.0",
-            "tslib": "^1.8.0",
-            "tsutils": "^2.27.2"
-          },
-          "dependencies": {
-            "tsutils": {
-              "version": "2.28.0",
-              "bundled": true,
-              "requires": {
-                "tslib": "^1.8.1"
-              }
-            }
-          }
-        },
-        "typescript": {
-          "version": "2.9.2",
-          "bundled": true
-        },
-        "underscore": {
-          "version": "1.8.3",
-          "bundled": true
-        },
-        "walkdir": {
-          "version": "0.0.12",
-          "bundled": true
-        },
-        "wrappy": {
-          "version": "1.0.2",
-          "bundled": true
-        }
       }
     },
     "jasmine": {
-- 
GitLab


From 47d298d37141c6d062a302ba90a210655289f2c8 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 10:57:16 +0100
Subject: [PATCH 17/26] Update #152

---
 .../formulaire/definition/form-compute-fixedvar.ts  | 13 ++-----------
 .../definition/form-compute-section-parametree.ts   |  6 ++----
 src/app/formulaire/definition/form-compute.ts       |  4 ++--
 3 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
index 7b64ec15d..300703a6d 100644
--- a/src/app/formulaire/definition/form-compute-fixedvar.ts
+++ b/src/app/formulaire/definition/form-compute-fixedvar.ts
@@ -44,27 +44,18 @@ export class FormComputeFixedVar extends FormCompute {
 
     protected compute() {
         const nub: Nub = this._formBase.currentNub;
-        let computePrec: number;
-        if (this._formBase.hasParameter("Pr")) {
-            computePrec = this._formBase.getParameterValue("Pr"); // précision de calcul
-        }
-
         const computedParam: NgParameter = this.getComputedParameter();
-
         this.formResult.addFixedParameters();
-
         const varParam: NgParameter = this.getVariatedParameter();
 
         if (varParam === undefined) {
             // pas de paramètre à varier
-
-            const res: Result = this.runNubCalc(nub, computedParam, computePrec);
+            const res: Result = this.runNubCalc(nub, computedParam);
             this.formResult.fixedResults.result = res;
             this.formResult.fixedResults.calculatedParameter = computedParam;
         } else {
             // il y a un paramètre à varier
-
-            const res: Result = this.runNubCalc(nub, computedParam, computePrec);
+            const res: Result = this.runNubCalc(nub, computedParam);
 
             this.formResult.varResults.variatedParameter = varParam;
             this.formResult.varResults.calculatedParameter = computedParam;
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
index 9640c2e47..1da49fa7e 100644
--- a/src/app/formulaire/definition/form-compute-section-parametree.ts
+++ b/src/app/formulaire/definition/form-compute-section-parametree.ts
@@ -33,7 +33,6 @@ export class FormComputeSectionParametree extends FormCompute {
      * @param varParam paramètre à varier
      */
     private doComputeSectionVar(varParam: NgParameter) {
-        const computePrec: number = this._formBase.getParameterValue("Pr"); // précision de calcul
 
         this._formSectionResult.addSectionFixedParameters(false);
 
@@ -50,7 +49,7 @@ export class FormComputeSectionParametree extends FormCompute {
         const computedParam: NgParameter = this.createParameter(computedParamInfo.symbol, this._formBase);
         this._varResults.calculatedParameter = computedParam;
 
-        this._varResults.result = this.runNubCalc(sectNub, computedParam, computePrec);
+        this._varResults.result = this.runNubCalc(sectNub, computedParam);
         this._varResults.graphTitle = computedParamInfo.symbol + " = f( " + varParam.symbol + " )";
         this._varResults.update(false);
     }
@@ -67,8 +66,7 @@ export class FormComputeSectionParametree extends FormCompute {
         const sect: acSection = sectNub.section;
         this._sectionResults.section = sect;
 
-        const computePrec: number = this._formBase.getParameterValue("Pr"); // précision de calcul
-        const tmpResult: Result = sectNub.CalcSerie(computePrec,
+        const tmpResult: Result = sectNub.CalcSerie(
             undefined, // valeur initiale, non utilisée dans ce cas
             undefined // variable à calculer, non utilisée
         );
diff --git a/src/app/formulaire/definition/form-compute.ts b/src/app/formulaire/definition/form-compute.ts
index 6d9b33ea2..4e8494753 100644
--- a/src/app/formulaire/definition/form-compute.ts
+++ b/src/app/formulaire/definition/form-compute.ts
@@ -25,7 +25,7 @@ export abstract class FormCompute {
     /**
      * lance le calcul d'un paramètre en déterminant une valeur initiale
      */
-    protected runNubCalc(nub: Nub, computedParam: NgParameter, prec: number): Result {
+    protected runNubCalc(nub: Nub, computedParam: NgParameter): Result {
         let init: number;
         switch (computedParam.domain.domain) {
             case ParamDomainValue.ANY:
@@ -69,7 +69,7 @@ export abstract class FormCompute {
                 break;
         }
 
-        return nub.CalcSerie(prec, init, this.getParameterRefid(computedParam));
+        return nub.CalcSerie(init, this.getParameterRefid(computedParam));
     }
 
     public doCompute() {
-- 
GitLab


From 7a343a3935b5201b0fe150162f45758222358b48 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 15:53:28 +0100
Subject: [PATCH 18/26] Rename ComputeNode .parameters() accessor to .prms()

---
 src/app/formulaire/definition/form-compute-courbe-remous.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/formulaire/definition/form-compute-courbe-remous.ts b/src/app/formulaire/definition/form-compute-courbe-remous.ts
index d8bf8dc2d..dc3a6a2e2 100644
--- a/src/app/formulaire/definition/form-compute-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-compute-courbe-remous.ts
@@ -18,7 +18,7 @@ export class FormComputeCourbeRemous extends FormCompute {
 
     protected compute() {
         const cr: CourbeRemous = this._formBase.currentNub as CourbeRemous;
-        const prmCR: CourbeRemousParams = cr.parameters as CourbeRemousParams;
+        const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams;
         const sect: acSection = prmCR.Sn;
 
         const Yn: Result = sect.Calc("Yn"); // hauteur normale
-- 
GitLab


From 9d376536dcb9fdc59b5ea8fb089367f7e02391ce Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 28 Feb 2019 17:22:53 +0100
Subject: [PATCH 19/26] =?UTF-8?q?M=C3=A0J=20tests=20e2e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 e2e/load-save-session.e2e-spec.ts     |   4 +-
 e2e/session-6-calc.test.json          | 812 +-------------------------
 e2e/session-optional-params.test.json | 161 +----
 3 files changed, 4 insertions(+), 973 deletions(-)

diff --git a/e2e/load-save-session.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts
index b288a375f..506e1f937 100644
--- a/e2e/load-save-session.e2e-spec.ts
+++ b/e2e/load-save-session.e2e-spec.ts
@@ -78,9 +78,9 @@ describe("ngHyd − save and load sessions", () => {
     const fileContent = fs.readFileSync(filename, { encoding: "utf8" });
 
     // tslint:disable-next-line:quotemark
-    expect(fileContent).toContain('{"id":"select_section","selected_id":"select_section_circ"}');
+    expect(fileContent).toContain('"nodeType":3');
     // tslint:disable-next-line:quotemark
-    expect(fileContent).toContain('{"param":{"id":"Ks","values":{"mode":"SINGLE","value":42}}}');
+    expect(fileContent).toContain('{"symbol":"Ks","mode":"SINGLE","value":42}');
   });
 
 });
diff --git a/e2e/session-6-calc.test.json b/e2e/session-6-calc.test.json
index 4dab5ec3d..54df75d63 100644
--- a/e2e/session-6-calc.test.json
+++ b/e2e/session-6-calc.test.json
@@ -1,811 +1 @@
-{
-    "session": {
-        "elements": [
-            {
-                "form": {
-                    "id": "Conduite distributrice (MTJmNH)",
-                    "uid": "MTJmNH",
-                    "props": {
-                        "calcType": 0,
-                        "nodeType": 0
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_hydraulique",
-                                "props": {
-                                    "calcType": 0,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 3
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "D",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "J",
-                                            "values": {
-                                                "mode": "CALCUL"
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Lg",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 100
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Nu",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.000001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 0,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            },
-            {
-                "form": {
-                    "id": "Lechapt-Calmon (NHdtdT)",
-                    "uid": "NHdtdT",
-                    "props": {
-                        "calcType": 1,
-                        "nodeType": 0
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_materiau",
-                                "props": {
-                                    "calcType": 1,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_material",
-                                            "selected_id": "select_material_1"
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "L",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.863
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "M",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "N",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 5.33
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_hydraulique",
-                                "props": {
-                                    "calcType": 1,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 3
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "D",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "J",
-                                            "values": {
-                                                "mode": "CALCUL"
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Lg",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 100
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 1,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            },
-            {
-                "form": {
-                    "id": "Section paramétrée (YjZxc2)",
-                    "uid": "YjZxc2",
-                    "props": {
-                        "calcType": 2,
-                        "nodeType": 2
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_section",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_section",
-                                            "selected_id": "select_section_rect"
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "LargeurBerge",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 2.5
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_bief",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Ks",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 40
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "If",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.001
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "YB",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_hydraulique",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Y",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.8
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_computed_var",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_target",
-                                            "selected_id": "select_target_Hs"
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            },
-            {
-                "form": {
-                    "id": "Régime uniforme (ZmEwcX)",
-                    "uid": "ZmEwcX",
-                    "props": {
-                        "calcType": 3,
-                        "nodeType": 2
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_section",
-                                "props": {
-                                    "calcType": 3,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_section",
-                                            "selected_id": "select_section_rect"
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "LargeurBerge",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 2.5
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_bief",
-                                "props": {
-                                    "calcType": 3,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Ks",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 40
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "If",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.001
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "YB",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_hydraulique",
-                                "props": {
-                                    "calcType": 3,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "CALCUL"
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Y",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.8
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 3,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            },
-            {
-                "form": {
-                    "id": "Courbes de remous (NHdmeG)",
-                    "uid": "NHdmeG",
-                    "props": {
-                        "calcType": 4,
-                        "nodeType": 2
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_section",
-                                "props": {
-                                    "calcType": 4,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_section",
-                                            "selected_id": "select_section_rect"
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "LargeurBerge",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 2.5
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_bief",
-                                "props": {
-                                    "calcType": 4,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Ks",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 40
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Long",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 100
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "If",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.001
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "YB",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_condlim",
-                                "props": {
-                                    "calcType": 4,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Yaval",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.4
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Yamont",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.15
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 4,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Dx",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 5
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "select": {
-                                            "id": "select_resolution",
-                                            "selected_id": "select_resolution_trap"
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_target_data",
-                                "props": {
-                                    "calcType": 4,
-                                    "nodeType": 2
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_target",
-                                            "selected_id": "select_target_none"
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            },
-            {
-                "form": {
-                    "id": "Lois d'ouvrages (Yzgxan)",
-                    "uid": "Yzgxan",
-                    "props": {
-                        "calcType": 8,
-                        "nodeType": 0
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_param_hydro",
-                                "props": {
-                                    "calcType": 8,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "CALCUL"
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Z1",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 102
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Z2",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 101.5
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset_container": {
-                                "id": "struct_container",
-                                "elements": [
-                                    {
-                                        "fieldset": {
-                                            "id": "fs_ouvrage",
-                                            "props": {
-                                                "calcType": 7,
-                                                "nodeType": 5,
-                                                "structureType": 1,
-                                                "loiDebit": 1
-                                            },
-                                            "elements": [
-                                                {
-                                                    "select": {
-                                                        "id": "select_ouvrage",
-                                                        "selected_id": "select_ouvrage_vanne_rect"
-                                                    }
-                                                },
-                                                {
-                                                    "select": {
-                                                        "id": "select_loidebit1",
-                                                        "selected_id": "select_loidebit1_cem88d"
-                                                    }
-                                                },
-                                                {
-                                                    "select": {
-                                                        "id": "select_loidebit2",
-                                                        "selected_id": "select_loidebit2_cem88v"
-                                                    }
-                                                },
-                                                {
-                                                    "select": {
-                                                        "id": "select_loidebit3",
-                                                        "selected_id": "select_loidebit3_seuiltriang"
-                                                    }
-                                                },
-                                                {
-                                                    "select": {
-                                                        "id": "select_loidebit4",
-                                                        "selected_id": "select_loidebit4_seuiltriangtrunc"
-                                                    }
-                                                },
-                                                {
-                                                    "param": {
-                                                        "id": "ZDV",
-                                                        "values": {
-                                                            "mode": "SINGLE",
-                                                            "value": 100
-                                                        }
-                                                    }
-                                                },
-                                                {
-                                                    "param": {
-                                                        "id": "L",
-                                                        "values": {
-                                                            "mode": "SINGLE",
-                                                            "value": 2
-                                                        }
-                                                    }
-                                                },
-                                                {
-                                                    "param": {
-                                                        "id": "W",
-                                                        "values": {
-                                                            "mode": "SINGLE",
-                                                            "value": null
-                                                        }
-                                                    }
-                                                },
-                                                {
-                                                    "param": {
-                                                        "id": "Cd",
-                                                        "values": {
-                                                            "mode": "SINGLE",
-                                                            "value": 0.4
-                                                        }
-                                                    }
-                                                }
-                                            ]
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 8,
-                                    "nodeType": 0
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            }
-        ]
-    }
-}
\ No newline at end of file
+{"session":[{"uid":"NHY0cX","props":{"calcType":5,"nodeType":0},"meta":{"title":"PAB : dimensions"},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"W","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.5},{"symbol":"V","mode":"CALCUL"}]},{"uid":"YzAwMW","props":{"calcType":11,"nodeType":0},"meta":{"title":"Macro-rugo."},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"ZF1","mode":"SINGLE","value":12.5},{"symbol":"L","mode":"SINGLE","value":6},{"symbol":"B","mode":"SINGLE","value":1},{"symbol":"If","mode":"SINGLE","value":0.05},{"symbol":"Q","mode":"CALCUL"},{"symbol":"Y","mode":"SINGLE","value":0.6},{"symbol":"Ks","mode":"SINGLE","value":0.01},{"symbol":"C","mode":"SINGLE","value":0.05},{"symbol":"PBD","mode":"SINGLE","value":0.5},{"symbol":"PBH","mode":"SINGLE","value":0.8},{"symbol":"Cd0","mode":"SINGLE","value":1.5}]},{"uid":"dGc5MD","props":{"calcType":8,"nodeType":0},"meta":{"title":"Ouvrages"},"structures":[{"uid":"NjZob3","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"Cd","mode":"SINGLE","value":0.6}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"CALCUL"},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"SINGLE","value":101.5}]},{"uid":"OGZ4cm","props":{"varCalc":"Hs","calcType":2,"nodeType":2},"meta":{"title":"Sec. param."},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"SINGLE","value":1.2},{"symbol":"If","mode":"SINGLE","value":0.001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"SINGLE","value":2.5}]},{"uid":"ZTNvMD","props":{"methodeResolution":0,"calcType":4,"nodeType":2},"meta":{"title":"Remous"},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Yamont","mode":"SINGLE","value":0.15},{"symbol":"Yaval","mode":"SINGLE","value":0.4},{"symbol":"Long","mode":"SINGLE","value":100},{"symbol":"Dx","mode":"SINGLE","value":5},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"SINGLE","value":1.2},{"symbol":"If","mode":"SINGLE","value":0.001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.2863766123093061},{"symbol":"LargeurBerge","mode":"SINGLE","value":2.5}]},{"uid":"eWllan","props":{"calcType":1,"nodeType":0},"meta":{"title":"Lechapt-Calmon"},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"SINGLE","value":3},{"symbol":"D","mode":"SINGLE","value":1.2},{"symbol":"J","mode":"CALCUL"},{"symbol":"Lg","mode":"SINGLE","value":100},{"symbol":"L","mode":"SINGLE","value":"1.863"},{"symbol":"M","mode":"SINGLE","value":"2"},{"symbol":"N","mode":"SINGLE","value":"5.33"}]}]}
\ No newline at end of file
diff --git a/e2e/session-optional-params.test.json b/e2e/session-optional-params.test.json
index 0d5cea59e..804c559cb 100644
--- a/e2e/session-optional-params.test.json
+++ b/e2e/session-optional-params.test.json
@@ -1,160 +1 @@
-{
-    "session": {
-        "elements": [
-            {
-                "form": {
-                    "id": "Section paramétrée",
-                    "uid": "ZDZ1Yn",
-                    "props": {
-                        "calcType": 2,
-                        "nodeType": 4
-                    },
-                    "elements": [
-                        {
-                            "fieldset": {
-                                "id": "fs_section",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 4
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_section",
-                                            "selected_id": "select_section_puiss"
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "k",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.5
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "LargeurBerge",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 4
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_bief",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 4
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Ks",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 40
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "If",
-                                            "values": {
-                                                "mode": "MINMAX",
-                                                "min": 0.0005,
-                                                "max": 0.002,
-                                                "step": 0.00007500000000000001
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "YB",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_hydraulique",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 4
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Q",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 1.2
-                                            }
-                                        }
-                                    },
-                                    {
-                                        "param": {
-                                            "id": "Y",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.8
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_param_calc",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 4
-                                },
-                                "elements": [
-                                    {
-                                        "param": {
-                                            "id": "Pr",
-                                            "values": {
-                                                "mode": "SINGLE",
-                                                "value": 0.0001
-                                            }
-                                        }
-                                    }
-                                ]
-                            }
-                        },
-                        {
-                            "fieldset": {
-                                "id": "fs_computed_var",
-                                "props": {
-                                    "calcType": 2,
-                                    "nodeType": 4,
-                                    "varCalc": "B"
-                                },
-                                "elements": [
-                                    {
-                                        "select": {
-                                            "id": "select_target",
-                                            "selected_id": "select_target_B"
-                                        }
-                                    }
-                                ]
-                            }
-                        }
-                    ]
-                }
-            }
-        ]
-    }
-}
\ No newline at end of file
+{"session":[{"uid":"N2U4OH","props":{"varCalc":"Hs","calcType":2,"nodeType":4},"meta":{"title":"Sec. param."},"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"SINGLE","value":1.2},{"symbol":"If","mode":"SINGLE","value":0.001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"SINGLE","value":4},{"symbol":"k","mode":"SINGLE","value":0.5}]}]}
\ No newline at end of file
-- 
GitLab


From edaa63bc121ae7e7f70a804e6548741b56ca1231 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Fri, 1 Mar 2019 09:39:12 +0100
Subject: [PATCH 20/26] =?UTF-8?q?D=C3=A9s=C3=A9rialisation=20:=20emp=C3=AA?=
 =?UTF-8?q?che=20le=20param=C3=A8tre=20calcul=C3=A9=20par=20d=C3=A9faut=20?=
 =?UTF-8?q?de=20se=20remettre=20en=20mode=20calcul?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../definition/concrete/form-base.ts          |  6 -----
 .../concrete/form-parallel-structures.ts      |  4 ----
 .../concrete/form-regime-uniforme.ts          |  4 ----
 .../definition/form-def-paramcalc.ts          | 24 ++++++++++++-------
 .../formulaire/definition/form-definition.ts  |  5 ----
 5 files changed, 16 insertions(+), 27 deletions(-)

diff --git a/src/app/formulaire/definition/concrete/form-base.ts b/src/app/formulaire/definition/concrete/form-base.ts
index ca294f0b2..6b28a0a2f 100644
--- a/src/app/formulaire/definition/concrete/form-base.ts
+++ b/src/app/formulaire/definition/concrete/form-base.ts
@@ -7,8 +7,6 @@ import { FormComputeFixedVar } from "../form-compute-fixedvar";
 
 export class FormulaireBase extends FormulaireDefinition {
 
-    private _formFixedVar: FormDefFixedVar;
-
     private _formParamCalc: FormDefParamToCalculate;
 
     private _formCompute: FormComputeFixedVar;
@@ -23,10 +21,6 @@ export class FormulaireBase extends FormulaireDefinition {
         this._formCompute = new FormComputeFixedVar(this, this._formResult);
     }
 
-    protected initParse() {
-        this._formParamCalc.initParse();
-    }
-
     protected completeParse(json: {}) {
         this._formParamCalc.parseOptions(json);
     }
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index c4a773fce..1e5703f50 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -125,10 +125,6 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
         }
     }
 
-    protected initParse() {
-        this._formParamCalc.initParse();
-    }
-
     protected parseOptions(json: {}) {
         super.parseOptions(json);
 
diff --git a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
index 63ed5d5a8..dd4de57d4 100644
--- a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
+++ b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
@@ -28,10 +28,6 @@ export class FormulaireRegimeUniforme extends FormulaireDefinition implements Ob
         this._formCompute = new FormComputeFixedVar(this, this._formResult);
     }
 
-    protected initParse() {
-        this._formParamCalc.initParse();
-    }
-
     protected parseOptions(json: {}) {
         super.parseOptions(json);
         this._formSection.parseOptions(json);
diff --git a/src/app/formulaire/definition/form-def-paramcalc.ts b/src/app/formulaire/definition/form-def-paramcalc.ts
index b31c93a14..c78cbc8e7 100644
--- a/src/app/formulaire/definition/form-def-paramcalc.ts
+++ b/src/app/formulaire/definition/form-def-paramcalc.ts
@@ -1,9 +1,8 @@
 import { ParamValueMode } from "jalhyd";
 
-import { ParamRadioConfig, NgParameter } from "../ngparam";
+import { NgParameter } from "../ngparam";
 import { FormulaireDefinition } from "./form-definition";
 import { FormDefFixedVar } from "./form-def-fixedvar";
-import { NgParamInputComponent } from "../../components/ngparam-input/ngparam-input.component";
 
 /**
  * gestion des formulaires avec "paramètre à calculer" (conduite distributrice, Lechapt-Calmon, régime uniforme, passes à bassin)
@@ -18,18 +17,16 @@ export class FormDefParamToCalculate extends FormDefFixedVar {
         super(base);
     }
 
-    public initParse() {
-        this._defaultCalculatedParam = undefined;
-    }
-
     public parseOptions(json: {}) {
+        this._defaultCalculatedParam = undefined;
+        // browse config file to find "options" chapter
         for (const k in json) {
             const o = json[k];
             if (o.type === "options") {
                 // id du paramètre à calculer par défaut
-
                 this._defaultCalculatedParam = o["idCal"];
-                if (this._defaultCalculatedParam !== undefined) {
+                // this._formBase
+                if (this._defaultCalculatedParam && ! this.findCalculatedParam()) {
                     const p = this.setDefault();
                     p.isDefault = true;
                 }
@@ -37,6 +34,17 @@ export class FormDefParamToCalculate extends FormDefFixedVar {
         }
     }
 
+    /**
+     * Find the parameter that is set to CALC mode
+     */
+    private findCalculatedParam() {
+        for (const p of this._formBase.currentNub.parameterIterator) {
+            if (p.valueMode === ParamValueMode.CALCUL) {
+                return p;
+            }
+        }
+    }
+
     /**
      * met le paramètre par défaut à CAL sauf si c'est "except"
      * @param except paramètre à ne pas remettre à CAL
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index c683185d7..c78215b08 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -122,9 +122,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         Session.getInstance().deleteNub(sn);
     }
 
-    protected initParse() {
-    }
-
     protected parseOptions(json: {}) {
         const dnt = json["defaultNodeType"];
         this._props["nodeType"] = dnt === undefined ? ComputeNodeType.None : ComputeNodeType[dnt];
@@ -214,8 +211,6 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     public preparseConfig(json: {}) {
         this._jsonConfig = json;
 
-        this.initParse();
-
         // analyse des options globales
         // il est utile de le faire avant le reste pour les modules de calcul utilisant
         // des sections (id des selects type de section/variable à calculer)
-- 
GitLab


From 43528b2b2f2cb1c502594982d7524d2e2a429890 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Fri, 1 Mar 2019 14:31:04 +0100
Subject: [PATCH 21/26] =?UTF-8?q?M=C3=A0J=20tests=20e2e;=20ajout=20d'un=20?=
 =?UTF-8?q?test=20calculant=20tous=20les=20param=C3=A8tres=20calculables?=
 =?UTF-8?q?=20de=20chaque=20module?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 e2e/app.e2e-spec.ts                           | 10 ++--
 e2e/calculate-all-params.e2e-spec.ts          | 60 +++++++++++++++++++
 e2e/calculator.e2e-spec.ts                    |  3 +
 e2e/calculator.po.ts                          | 43 ++++++++++++-
 e2e/clone-calc.e2e-spec.ts                    |  3 +
 e2e/list.e2e-spec.ts                          |  3 +
 e2e/list.po.ts                                | 20 +++++++
 e2e/load-save-session.e2e-spec.ts             |  3 +
 e2e/navigate-through-calculators.e2e-spec.ts  |  3 +
 e2e/preferences.e2e-spec.ts                   |  3 +
 .../calculator.component.html                 |  2 +-
 .../param-field-line.component.html           |  8 +--
 12 files changed, 149 insertions(+), 12 deletions(-)
 create mode 100644 e2e/calculate-all-params.e2e-spec.ts

diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts
index 721ce55a1..673034353 100644
--- a/e2e/app.e2e-spec.ts
+++ b/e2e/app.e2e-spec.ts
@@ -1,6 +1,9 @@
 import { AppPage } from "./app.po";
 import { browser } from "protractor";
 
+/**
+ * Start app
+ */
 describe("ngHyd − start page", () => {
   let page: AppPage;
 
@@ -10,12 +13,7 @@ describe("ngHyd − start page", () => {
 
   it("when app starts, user should be redirected to /list page", async () => {
     await page.navigateTo();
-    const url = await browser.driver.getCurrentUrl(); // @TODO move brower related stuff to .po ?
+    const url = await browser.driver.getCurrentUrl();
     expect(url).toContain("/list");
   });
-
-  /*it("when app starts, user should see the list of available compute nodes", () => {
-    page.navigateTo();
-    expect(page.getListLength()).toBeGreaterThan(8);
-  });*/
 });
diff --git a/e2e/calculate-all-params.e2e-spec.ts b/e2e/calculate-all-params.e2e-spec.ts
new file mode 100644
index 000000000..e71105a54
--- /dev/null
+++ b/e2e/calculate-all-params.e2e-spec.ts
@@ -0,0 +1,60 @@
+import { AppPage } from "./app.po";
+import { ListPage } from "./list.po";
+import { CalculatorPage } from "./calculator.po";
+import { Navbar } from "./navbar.po";
+import { SideNav } from "./sidenav.po";
+import { browser } from "protractor";
+
+/**
+ * For all calculators, try to calculate every parameter: check that only one parameter
+ * is set to CAL mode, trigger the calculation, check that result is not empty
+ */
+describe("ngHyd − calculate all parameters of all calculators", () => {
+  let listPage: ListPage;
+  let calcPage: CalculatorPage;
+
+  beforeEach(() => {
+    listPage = new ListPage();
+    calcPage = new CalculatorPage();
+  });
+
+  // get calculators list (IDs) @TODO read it from config !
+  const calcTypes = [ 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11 ];
+
+  // for each calculator
+  for (const ct of calcTypes) {
+    describe(" − calculate all parameters of calculator type [" + ct + "]", async () => {
+      it("", async () => {
+        // go to list page
+        await listPage.navigateTo();
+        // click calculator button (instanciate)
+        await listPage.clickMenuEntryForCalcType(ct);
+        // get all parameters IDs
+        const inputs = await calcPage.getParamInputsHavingCalcMode();
+
+        // console.log("> Inputs having calc", inputs.length);
+        if (inputs.length > 0) {
+          // for each param
+          for (const input of inputs) {
+            // console.log(">> Trying", await input.getAttribute("id"));
+            // click "calc" mode button for this parameter
+            await calcPage.setParamMode(input, "cal");
+            // check that only 1 button is in "calc" state
+            const nbParamsCalc = await calcPage.getCheckedCalcModeButtons().count();
+            expect(nbParamsCalc).toBe(1);
+            // check that "compute" button is active
+            const calcButton = calcPage.getCalculateButton();
+            const disabledState = await calcButton.getAttribute("disabled");
+            expect(disabledState).not.toBe("disabled");
+            // click "compute" button
+            await calcButton.click();
+            // check that result is not empty
+            const hasResults = await calcPage.hasResults();
+            expect(hasResults).toBe(true);
+          }
+        }
+      });
+    });
+  }
+
+});
diff --git a/e2e/calculator.e2e-spec.ts b/e2e/calculator.e2e-spec.ts
index f7e986344..835e71536 100644
--- a/e2e/calculator.e2e-spec.ts
+++ b/e2e/calculator.e2e-spec.ts
@@ -1,6 +1,9 @@
 import { CalculatorPage } from "./calculator.po";
 import { ListPage } from "./list.po";
 
+/**
+ * Create a random calculator
+ */
 describe("ngHyd − calculator page", () => {
   let page: CalculatorPage;
   let listPage: ListPage;
diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 9d05454ed..6b6707611 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -6,6 +6,21 @@ export class CalculatorPage {
     return element.all(by.css("ngparam-input input:not([disabled]) label"));
   }
 
+  getParamInputs() {
+    return element.all(by.css("ngparam-input input.form-control"));
+  }
+
+  async getParamInputsHavingCalcMode() {
+    const ret = [];
+    const inputs = this.getParamInputs();
+    await inputs.each(async (i) => {
+      if (await this.inputHasCalcModeButton(i)) {
+        ret.push(i);
+      }
+    });
+    return ret;
+  }
+
   getHeader1() {
     return element(by.css("h1"));
   }
@@ -22,12 +37,37 @@ export class CalculatorPage {
     return element(by.css("dialog-save-session button[type=submit]"));
   }
 
+  getCalculateButton() {
+    return element(by.css("button#trigger-calculate"));
+  }
+
+  getCheckedCalcModeButtons() {
+    // tslint:disable-next-line:quotemark
+    return element.all(by.css('mat-button-toggle.radio_cal[ng-reflect-checked="true"]'));
+  }
+
   scrollTo(elt: ElementFinder) {
     browser.controlFlow().execute(function() {
       browser.executeScript("arguments[0].scrollIntoView(true)", elt.getWebElement());
     });
   }
 
+  async inputHasCalcModeButton(input: ElementFinder) {
+    // get parent (div.container)
+    const container = await this.findParentContainer(input);
+    // find radio buttons
+    const button: ElementFinder = container.element(by.css("mat-button-toggle.radio_cal > button"));
+    return await button.isPresent();
+  }
+
+  async hasResults() {
+    return (
+      await element(by.css("fixedvar-results fixed-results > .fixed-results-container")).isPresent()
+      ||
+      await element(by.css("fixedvar-results results-graph > graph-results-container")).isPresent()
+    );
+  }
+
   async clickSaveCalcButton() {
     return await element(by.css("#save-calc")).click();
   }
@@ -63,7 +103,8 @@ export class CalculatorPage {
     // get parent (div.container)
     const container = await this.findParentContainer(elt);
     // find radio buttons
-    const button = container.element(by.css("button#radio_" + mode + "-button"));
+    const button = container.element(by.css("mat-button-toggle.radio_" + mode + " > button"));
+    await browser.executeScript("window.scrollTo(0, 0);"); // sometimes button slides behind navbar and click() fails
     await button.click();
     // for "var" mode, close the modal
     if (mode === "var") {
diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts
index 2f200f054..459b3d767 100644
--- a/e2e/clone-calc.e2e-spec.ts
+++ b/e2e/clone-calc.e2e-spec.ts
@@ -5,6 +5,9 @@ import { Navbar } from "./navbar.po";
 import { SideNav } from "./sidenav.po";
 import { browser } from "protractor";
 
+/**
+ * Clone calculators
+ */
 describe("ngHyd − clone a calculator", () => {
   let startPage: AppPage;
   let listPage: ListPage;
diff --git a/e2e/list.e2e-spec.ts b/e2e/list.e2e-spec.ts
index 775a2735f..3100e7274 100644
--- a/e2e/list.e2e-spec.ts
+++ b/e2e/list.e2e-spec.ts
@@ -1,5 +1,8 @@
 import { ListPage } from "./list.po";
 
+/**
+ * Show calculators list (home page)
+ */
 describe("ngHyd − list page", () => {
   let page: ListPage;
 
diff --git a/e2e/list.po.ts b/e2e/list.po.ts
index 4e32624df..ce64e022e 100644
--- a/e2e/list.po.ts
+++ b/e2e/list.po.ts
@@ -21,6 +21,21 @@ export class ListPage {
     return await this.getCalculatorsMenuEntries().count();
   }
 
+  async getAvailableCalcTypes() {
+    const ids = [];
+    const menuEntries = this.getCalculatorsMenuEntries();
+    await menuEntries.each(async (elt, i) => {
+      const eltid = await elt.getAttribute("id");
+      const ct = eltid.replace("create-calc-", "");
+      const nct = Number(ct);
+      // remove duplicates
+      if (! ids.includes(nct)) {
+        ids.push(nct);
+      }
+    });
+    return ids;
+  }
+
   async clickRandomCalculatorMenuEntry() {
     const menuEntries = this.getCalculatorsMenuEntries();
     const l = await menuEntries.count();
@@ -32,4 +47,9 @@ export class ListPage {
     const but = element(by.css("#create-calc-" + type));
     return but.click();
   }
+
+  async getCalcMenuTextForCalcType(type: number): Promise<string> {
+    const but = element(by.css("#create-calc-" + type));
+    return but.getText();
+  }
 }
diff --git a/e2e/load-save-session.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts
index 506e1f937..8ea125de9 100644
--- a/e2e/load-save-session.e2e-spec.ts
+++ b/e2e/load-save-session.e2e-spec.ts
@@ -5,6 +5,9 @@ import { Navbar } from "./navbar.po";
 import { SideNav } from "./sidenav.po";
 import { browser } from "protractor";
 
+/**
+ * Save and load (serialise and unserialise) calculators to/from JSON files
+ */
 describe("ngHyd − save and load sessions", () => {
   let startPage: AppPage;
   let listPage: ListPage;
diff --git a/e2e/navigate-through-calculators.e2e-spec.ts b/e2e/navigate-through-calculators.e2e-spec.ts
index f2f91340e..f886d7ca1 100644
--- a/e2e/navigate-through-calculators.e2e-spec.ts
+++ b/e2e/navigate-through-calculators.e2e-spec.ts
@@ -3,6 +3,9 @@ import { Navbar } from "./navbar.po";
 import { CalculatorPage } from "./calculator.po";
 import { browser } from "protractor";
 
+/**
+ * Use navbar buttons to navigate from one open calculator to another
+ */
 describe("ngHyd − create calculators and navigate among them", () => {
   let listPage: ListPage;
   let calculatorPage: CalculatorPage;
diff --git a/e2e/preferences.e2e-spec.ts b/e2e/preferences.e2e-spec.ts
index 42d4dc611..0321b2856 100644
--- a/e2e/preferences.e2e-spec.ts
+++ b/e2e/preferences.e2e-spec.ts
@@ -1,6 +1,9 @@
 import { PreferencesPage } from "./preferences.po";
 import { browser } from "protractor";
 
+/**
+ * Open app preferences, check the default values, the validators, the language change
+ */
 describe("ngHyd − preferences page", () => {
   let page: PreferencesPage;
 
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index 455dddadb..064f4f5ec 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -40,7 +40,7 @@
 
                     <mat-card-actions>
                         <!-- bouton calculer -->
-                        <button type="submit" mat-raised-button color="accent" name="Calculer" (click)="doCompute()"[disabled]="isCalculateDisabled">
+                        <button type="submit" id="trigger-calculate" mat-raised-button color="accent" name="Calculer" (click)="doCompute()"[disabled]="isCalculateDisabled">
                             {{ uitextCalculer }}
                         </button>
                     </mat-card-actions>
diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html
index f1ea01b5c..a9847d2b2 100644
--- a/src/app/components/param-field-line/param-field-line.component.html
+++ b/src/app/components/param-field-line/param-field-line.component.html
@@ -19,25 +19,25 @@
     <div class="toggle-group-container" fxFlex="0 0 auto">
         <mat-button-toggle-group *ngIf="hasRadioFix() || hasRadioVar() || hasRadioCal() || hasRadioLink()">
 
-            <mat-button-toggle id="radio_fix" value="radio_fix" 
+            <mat-button-toggle class="radio_fix" value="radio_fix" 
                 (click)="onRadioClick('fix')" [checked]="isRadioFixChecked">
                 <span fxHide.xxs>{{ uitextParamFixe }}</span>
                 <span fxHide.gt-xxs>F</span>
             </mat-button-toggle>
         
-            <mat-button-toggle id="radio_var" value="radio_var" *ngIf="hasRadioVar()"
+            <mat-button-toggle class="radio_var" value="radio_var" *ngIf="hasRadioVar()"
                 (click)="onRadioClick('var')" [checked]="isRadioVarChecked">
                 <span fxHide.xxs>{{ uitextParamVarier }}</span>
                 <span fxHide.gt-xxs>V</span>
             </mat-button-toggle>
         
-            <mat-button-toggle id="radio_cal" value="radio_cal" *ngIf="hasRadioCal()"
+            <mat-button-toggle class="radio_cal" value="radio_cal" *ngIf="hasRadioCal()"
                 (click)="onRadioClick('cal')" [checked]="isRadioCalChecked">
                 <span fxHide.xxs>{{ uitextParamCalculer }}</span>
                 <span fxHide.gt-xxs>C</span>
             </mat-button-toggle>
         
-            <mat-button-toggle id="radio_link" value="radio_link" *ngIf="hasRadioLink()"
+            <mat-button-toggle class="radio_link" value="radio_link" *ngIf="hasRadioLink()"
                 (click)="onRadioClick('link')" [checked]="isRadioLinkChecked">
                 <span fxHide.xxs>{{ uitextParamLie }}</span>
                 <span fxHide.gt-xxs>L</span>
-- 
GitLab


From fcc233e5782b6a0d878211de2c81dae839d3827e Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Fri, 1 Mar 2019 15:27:32 +0100
Subject: [PATCH 22/26] Update fix #145

---
 src/app/components/param-computed/param-computed.component.html | 2 +-
 src/app/components/param-values/param-values.component.html     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/app/components/param-computed/param-computed.component.html b/src/app/components/param-computed/param-computed.component.html
index eb582f98d..ee50ccaaf 100644
--- a/src/app/components/param-computed/param-computed.component.html
+++ b/src/app/components/param-computed/param-computed.component.html
@@ -1,7 +1,7 @@
 <!-- a fake input bound to nothing, for the sake of UI consistency -->
 <mat-form-field>
     <input matInput disabled [id]="inputId" class="form-control" type="text" [ngModel]="infoText" [placeholder]="param.title">
-    <button *ngIf="isDicho" mat-icon-button class="param-computed-more" (click)="openDialog()">
+    <button type="button" *ngIf="isDicho" mat-icon-button class="param-computed-more" (click)="openDialog()">
         <mat-icon>more_horiz</mat-icon>
     </button>
 </mat-form-field>
diff --git a/src/app/components/param-values/param-values.component.html b/src/app/components/param-values/param-values.component.html
index 37cda318b..171010493 100644
--- a/src/app/components/param-values/param-values.component.html
+++ b/src/app/components/param-values/param-values.component.html
@@ -1,7 +1,7 @@
 <!-- a fake input bound to nothing, for the sake of UI consistency -->
 <mat-form-field>
     <input matInput disabled class="form-control" type="text" [ngModel]="infoText" [placeholder]="param.title">
-    <button mat-icon-button class="param-values-more" (click)="openDialog()">
+    <button type="button" mat-icon-button class="param-values-more" (click)="openDialog()">
         <mat-icon>more_horiz</mat-icon>
     </button>
 </mat-form-field>
-- 
GitLab


From 8b0d3347674867d9fb533ef2565e52cc94692a14 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 4 Mar 2019 10:49:33 +0100
Subject: [PATCH 23/26] Fix #154

---
 src/app/formulaire/definition/concrete/form-courbe-remous.ts   | 2 ++
 .../formulaire/definition/concrete/form-parallel-structures.ts | 2 ++
 src/app/formulaire/definition/concrete/form-regime-uniforme.ts | 2 ++
 .../formulaire/definition/concrete/form-section-parametree.ts  | 2 ++
 src/app/formulaire/fieldset.ts                                 | 3 +--
 5 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/app/formulaire/definition/concrete/form-courbe-remous.ts b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
index 5c3f0f0be..a10cd4b88 100644
--- a/src/app/formulaire/definition/concrete/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/concrete/form-courbe-remous.ts
@@ -75,6 +75,8 @@ export class FormulaireCourbeRemous extends FormulaireDefinition {
                     this.replaceCurrentNub(sender.properties);
                     for (const fs of this.allFieldsets) {
                         fs.setNub(this._currentNub);
+                        // treat the fieldset as new to re-seubscribe to Nub properties change events
+                        this.afterParseFieldset(fs);
                     }
                     this.reset();
                     break;
diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
index 1e5703f50..615bf5c26 100644
--- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts
@@ -394,6 +394,8 @@ export class FormulaireParallelStructure extends FormulaireDefinition {
                     const props = this.adjustProperties(sender, data["name"], data["value"]);
                     const newNub = this.replaceNub((sender.nub as Structure), props);
                     sender.setNub(newNub);
+                    // treat the fieldset as new to re-seubscribe to Nub properties change events
+                    this.afterParseFieldset(sender);
                     this.reset();
                     break;
             }
diff --git a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
index dd4de57d4..611098f1f 100644
--- a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
+++ b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts
@@ -78,6 +78,8 @@ export class FormulaireRegimeUniforme extends FormulaireDefinition implements Ob
             this.replaceCurrentNub(sender.properties);
             for (const fs of this.allFieldsets) {
                 fs.setNub(this._currentNub);
+                // treat the fieldset as new to re-seubscribe to Nub properties change events
+                this.afterParseFieldset(fs);
             }
             this.reset();
         }
diff --git a/src/app/formulaire/definition/concrete/form-section-parametree.ts b/src/app/formulaire/definition/concrete/form-section-parametree.ts
index 9d7da09ab..5e4409b91 100644
--- a/src/app/formulaire/definition/concrete/form-section-parametree.ts
+++ b/src/app/formulaire/definition/concrete/form-section-parametree.ts
@@ -70,6 +70,8 @@ export class FormulaireSectionParametree extends FormulaireDefinition {
                     this.replaceCurrentNub(sender.properties);
                     for (const fs of this.allFieldsets) {
                         fs.setNub(this._currentNub);
+                        // treat the fieldset as new to re-seubscribe to Nub properties change events
+                        this.afterParseFieldset(fs);
                     }
                     this.reset();
                     break;
diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index f8129a9e8..2e5dfec81 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -1,5 +1,4 @@
-import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType,
-    Props, Observer, Nub, MethodeResolution, ParamCalculability, ParamDomain, ParamDomainValue } from "jalhyd";
+import { CalculatorType, ComputeNodeType, ParamDefinition, LoiDebit, StructureType, Props, Observer, Nub, MethodeResolution } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
-- 
GitLab


From 9a0d456399b0473fec2aaa10da060c1586e8b279 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 4 Mar 2019 12:18:49 +0100
Subject: [PATCH 24/26] =?UTF-8?q?Ajout=20test=20e2e=20:=20clonage=20de=20t?=
 =?UTF-8?q?ous=20les=20modules=20en=20chageant=20les=20valeurs=20des=20par?=
 =?UTF-8?q?am=C3=A8tres=20num=C3=A9riques?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 e2e/calculator.po.ts           | 27 ++++++++++++++++
 e2e/clone-all-calc.e2e-spec.ts | 56 ++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 e2e/clone-all-calc.e2e-spec.ts

diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts
index 6b6707611..75d501000 100644
--- a/e2e/calculator.po.ts
+++ b/e2e/calculator.po.ts
@@ -112,4 +112,31 @@ export class CalculatorPage {
       await element(by.css("dialog-edit-param-values .mat-dialog-actions button")).click();
     }
   }
+
+  /**
+   * Returns an object containing all the calculator's inputs values, indexed
+   * by parameter ID
+   */
+  async storeAllInputValues() {
+    const inputs = this.getParamInputs();
+    const values = {};
+    await inputs.each(async (i) => {
+      const inputId = await i.getAttribute("id");
+      const inputValue = await i.getAttribute("value");
+      values[inputId] = inputValue;
+    });
+    return values;
+  }
+
+  /**
+   * Modifies all the calculator's editable inputs values by adding a random digit other than 0 at the end
+   */
+  async modifyAllInputValues() {
+    const inputs = this.getParamInputs();
+    await inputs.each(async (i) => {
+      if (await i.isDisplayed()) {
+        await i.sendKeys("" + Math.floor(Math.random() * 9) + 1);
+      }
+    });
+  }
 }
diff --git a/e2e/clone-all-calc.e2e-spec.ts b/e2e/clone-all-calc.e2e-spec.ts
new file mode 100644
index 000000000..69ab36417
--- /dev/null
+++ b/e2e/clone-all-calc.e2e-spec.ts
@@ -0,0 +1,56 @@
+import { ListPage } from "./list.po";
+import { CalculatorPage } from "./calculator.po";
+import { Navbar } from "./navbar.po";
+import { browser } from "protractor";
+
+/**
+ * Clone calculators
+ */
+describe("ngHyd − clone all calculators with all possible <select> values", () => {
+  let listPage: ListPage;
+  let calcPage: CalculatorPage;
+  let navbar: Navbar;
+
+  beforeEach(() => {
+    listPage = new ListPage();
+    calcPage = new CalculatorPage();
+    navbar = new Navbar();
+  });
+
+  // get calculators list (IDs) @TODO read it from config !
+  const calcTypes = [ 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11 ];
+
+  // for each calculator
+  for (const ct of calcTypes) {
+    describe(" − clone all variations of calculator type [" + ct + "]", async () => {
+      it("", async () => {
+        await listPage.navigateTo();
+        // click calculator button (instanciate)
+        await listPage.clickMenuEntryForCalcType(ct);
+
+        // get all select IDs outside Structures
+        // get select IDs inside Structures
+        // @TODO set configuration to every combination of <select> options
+
+        // modify all <input> values and store them
+        await calcPage.modifyAllInputValues();
+        const sourceValues = await calcPage.storeAllInputValues();
+
+        // clone calculator
+        await browser.executeScript("window.scrollTo(0, 0);");
+        await calcPage.clickCloneCalcButton();
+        await browser.sleep(300);
+
+        // check existence of the cloned module
+        expect(await navbar.getAllCalculatorTabs().count()).toBe(2);
+
+        // @TODO check <select> values
+
+        // read all <input> values and compare them to stored ones
+        const cloneValues = await calcPage.storeAllInputValues();
+        expect(cloneValues).toEqual(sourceValues);
+      });
+    });
+  }
+
+});
-- 
GitLab


From 49d5648087e7b061ab4fe1b9e594a913697afbde Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 4 Mar 2019 12:19:27 +0100
Subject: [PATCH 25/26] =?UTF-8?q?Lechapt-Calmon=20:=20am=C3=A9lioration=20?=
 =?UTF-8?q?du=20s=C3=A9lecteur=20de=20mat=C3=A9riau?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../lechapt-calmon/lechapt-calmon.config.json       |  3 +++
 .../lechapt-calmon/lechapt-calmon.en.json           |  1 +
 .../lechapt-calmon/lechapt-calmon.fr.json           |  1 +
 .../definition/concrete/form-lechapt-calmon.ts      | 13 +++++++++++++
 4 files changed, 18 insertions(+)

diff --git a/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json b/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json
index b2bf6dac9..fd24f30d6 100644
--- a/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json
+++ b/src/app/calculators/lechapt-calmon/lechapt-calmon.config.json
@@ -8,6 +8,9 @@
                 "id": "select_material",
                 "type": "select",
                 "select": [
+                    {
+                        "id": "select_material_0"
+                    },
                     {
                         "id": "select_material_1"
                     },
diff --git a/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json b/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
index 47b3a9b00..8a22b96b9 100644
--- a/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
+++ b/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
@@ -1,6 +1,7 @@
 {
     "fs_materiau": "Type of material",
     "select_material": "Choice of material",
+    "select_material_0": "",
     "select_material_1": "Unlined cast iron - Coarse concrete (corrosive water)",
     "select_material_2": "Cast steel or uncoated - Coarse concrete (somewhat corrosive water)",
     "select_material_3": "Cast steel or cement coating",
diff --git a/src/app/calculators/lechapt-calmon/lechapt-calmon.fr.json b/src/app/calculators/lechapt-calmon/lechapt-calmon.fr.json
index 2db51b945..4455f5680 100644
--- a/src/app/calculators/lechapt-calmon/lechapt-calmon.fr.json
+++ b/src/app/calculators/lechapt-calmon/lechapt-calmon.fr.json
@@ -1,6 +1,7 @@
 {
     "fs_materiau": "Type du matériau",
     "select_material": "Choix du matériau",
+    "select_material_0": "",
     "select_material_1": "Fonte ou acier non revêtus - Béton grossier (eau corrosive)",
     "select_material_2": "Fonte ou acier non revêtus - Béton grossier (eau peu corrosive)",
     "select_material_3": "Fonte ou acier revêtement ciment",
diff --git a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
index 586bd9330..69124f646 100644
--- a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
+++ b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts
@@ -1,6 +1,7 @@
 import { Observer } from "jalhyd";
 import { SelectField } from "../../select-field";
 import { FormulaireBase } from "./form-base";
+import { NgParamInputComponent } from "../../../components/ngparam-input/ngparam-input.component";
 
 export class FormulaireLechaptCalmon extends FormulaireBase implements Observer {
 
@@ -8,6 +9,10 @@ export class FormulaireLechaptCalmon extends FormulaireBase implements Observer
         super.completeParse(json);
         // abonnement au changement de valeur du select de matériau
         this.getFormulaireNodeById("select_material").addObserver(this);
+        // abonnement au changement de valeur de l'un dex trois champs affectés par le changement de matériau
+        this.getParamFromSymbol("L").addObserver(this);
+        this.getParamFromSymbol("M").addObserver(this);
+        this.getParamFromSymbol("N").addObserver(this);
     }
 
     // interface Observer
@@ -19,5 +24,13 @@ export class FormulaireLechaptCalmon extends FormulaireBase implements Observer
                 this.reset();
             }
         }
+        if (sender instanceof NgParamInputComponent) {
+            if (data.action === "ngparamAfterValue") {
+                // value of L, M or N changed
+                const materialSelect = this.getFormulaireNodeById("select_material") as SelectField;
+                // reset material select field to "" (empty)
+                materialSelect.setValue(materialSelect.entries[0]);
+            }
+        }
     }
 }
-- 
GitLab


From 3fc750402e17e272168840f6cce454a6b087c076 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 4 Mar 2019 15:59:15 +0100
Subject: [PATCH 26/26] =?UTF-8?q?D=C3=A9s=C3=A9rialisation=20correcte=20de?=
 =?UTF-8?q?s=20ouvrages=20en=20parall=C3=A8le?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/formulaire/fieldset.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts
index 2e5dfec81..5dd19f2e5 100644
--- a/src/app/formulaire/fieldset.ts
+++ b/src/app/formulaire/fieldset.ts
@@ -270,7 +270,7 @@ export class FieldSet extends FormulaireElement implements Observer {
     private setPropertyValueFromConfig(json: {}, configKey: string, propertyKey: string, enumClass?) {
         const configValue: string = json[configKey];
         const currentValue = this.properties.getPropValue(propertyKey);
-        if (configValue && ! currentValue) {
+        if (configValue && (currentValue === undefined)) {
             let formalValue =  configValue;
             if (enumClass) {
                 formalValue = enumClass[configValue];
-- 
GitLab