From a93ee1266be7f0fcb03046c370c61c24162957a9 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Thu, 23 Jan 2020 16:04:02 +0100
Subject: [PATCH 1/2] Fix #359 - genericize select fields

SPP
Lechapt-Calmon
CourbeRemous
Trigo
Grille
Bief
ParallelStructures
MacroRugoCompound
Sections

updated e2e

updated Documentation
---
 DEVELOPERS.md                                 | 276 ++++++++++++------
 e2e/session/session-cascade-params.json       |  12 +-
 e2e/session/session-liens-spaghetti.json      |  25 +-
 e2e/session/session-optional-params.test.json |   4 +-
 src/app/calculators/bief/config.json          |  19 +-
 src/app/calculators/bief/en.json              |   8 +-
 src/app/calculators/bief/fr.json              |   8 +-
 src/app/calculators/cloisons/config.json      |   8 +-
 src/app/calculators/courberemous/config.json  |  26 +-
 src/app/calculators/courberemous/en.json      |  14 +-
 src/app/calculators/courberemous/fr.json      |  14 +-
 src/app/calculators/dever/config.json         |   8 +-
 src/app/calculators/grille/config.json        |  11 +-
 src/app/calculators/lechaptcalmon/config.json |   5 +-
 .../calculators/macrorugocompound/config.json |   4 +-
 .../calculators/parallelstructure/config.json |   8 +-
 .../calculators/regimeuniforme/config.json    |  14 +-
 src/app/calculators/regimeuniforme/en.json    |   8 +-
 src/app/calculators/regimeuniforme/fr.json    |   8 +-
 .../calculators/sectionparametree/config.json |  15 +-
 src/app/calculators/sectionparametree/en.json |   8 +-
 src/app/calculators/sectionparametree/fr.json |   8 +-
 src/app/calculators/spp/config.json           |   8 +-
 src/app/calculators/trigo/config.json         |  11 +-
 .../macrorugo-compound-results.component.ts   |   4 +-
 .../modules-diagram.component.ts              |   4 +-
 src/app/formulaire/definition/form-bief.ts    |  62 ----
 .../definition/form-courbe-remous.ts          |  57 +---
 .../formulaire/definition/form-definition.ts  |  19 +-
 .../formulaire/definition/form-fixedvar.ts    |  42 ++-
 src/app/formulaire/definition/form-grille.ts  |  49 ----
 .../definition/form-lechapt-calmon.ts         |  38 ---
 .../definition/form-macrorugo-compound.ts     |  29 +-
 .../definition/form-parallel-structures.ts    |  23 --
 .../definition/form-regime-uniforme.ts        |  23 --
 .../definition/form-section-parametree.ts     |  32 +-
 src/app/formulaire/definition/form-section.ts |  51 +---
 src/app/formulaire/definition/form-spp.ts     |  28 +-
 src/app/formulaire/definition/form-trigo.ts   |  46 ---
 .../formulaire/elements/fieldset-template.ts  |   6 +-
 src/app/formulaire/elements/fieldset.ts       | 233 +++++----------
 src/app/formulaire/elements/select-field.ts   |  97 ++----
 src/app/services/formulaire.service.ts        |  20 +-
 43 files changed, 509 insertions(+), 884 deletions(-)
 delete mode 100644 src/app/formulaire/definition/form-bief.ts
 delete mode 100644 src/app/formulaire/definition/form-lechapt-calmon.ts
 delete mode 100644 src/app/formulaire/definition/form-regime-uniforme.ts
 delete mode 100644 src/app/formulaire/definition/form-trigo.ts

diff --git a/DEVELOPERS.md b/DEVELOPERS.md
index 342b4e970..306e7fcf3 100644
--- a/DEVELOPERS.md
+++ b/DEVELOPERS.md
@@ -13,7 +13,7 @@ Elle est déclinée à l'aide d'Electron et Cordova sous forme d'application hor
 
 Les tests unitaires sont réalisés avec Protractor.
 
-La documentation est générée avec Mkdocs.
+La documentation est générée avec Mkdocs, pandoc et LaTeX.
 
 ## Pile logicielle
 
@@ -24,6 +24,8 @@ La documentation est générée avec Mkdocs.
  * electron
  * cordova
  * mkdocs
+ * pandoc
+ * LaTeX
 
 ## Prérequis
 
@@ -34,6 +36,8 @@ La documentation est générée avec Mkdocs.
  * wine (pour Electron / windows)
  * java (pour cordova / Android)
  * SDK Android (pour cordova / Android)
+ * pandoc (pour la documentation PDF)
+ * une distribution LaTeX, par exemple texlive (pour la documentation PDF)
 
 ### pour l'exécution
 
@@ -60,9 +64,7 @@ Pour chaque module chargé en session, un arbre d'objets partant d'une instance
 
 #### formulaires
 
-Les formulaires dérivent de `FormulaireBase`. Lors de leur instanciation, ils se chargent de lire leur configuration (voir "configuration/modules" ci-dessous) et instancier les éléments enfants qui y sont déclarés : groupes de champs ("fieldset"), groupes de champs répétables ("fieldset_container"), paramètres d'entrée ("ngparam"), listes déroulantes ("select_field"). Ensuite le formulaire est lié au Nub de JaLHyd correspondant au module créé.
-
-Chaque formulaire est associé à une instance d'une classe `FormCompute*` et une instance d'une classe `FormResult*`. La première est chargée d'exécuter le Nub de JaLHYd associé au formulaire, et de transmettre les résultats de calcul à la seconde. La seconde est chargée d'organiser les résultats (par défaut les grouper en résultats fixes / résultats variés) afin de faciliter leur représentation par les composants graphiques.
+Les formulaires dérivent de `FormulaireDefinition`. Lors de leur instanciation, ils se chargent de lire leur configuration (voir "configuration/modules" ci-dessous) et instancier les éléments enfants qui y sont déclarés : groupes de champs ("fieldset"), groupes de champs répétables ("fieldset_container"), paramètres d'entrée ("ngparam"), listes déroulantes ("select_field"). Ensuite le formulaire est lié au Nub de JaLHyd correspondant au module créé.
 
 ### configuration
 
@@ -76,7 +78,7 @@ Dans `themes` on trouve l'organisation des modules en thèmes sur la page d'accu
 
 #### modules
 
-Chaque module de calcul JaLHyd doit être configuré dans `src/app/calculators`, dans un dossier portant le nom du module.
+Chaque module de calcul de JaLHyd doit être configuré dans `src/app/calculators`, dans un dossier portant le nom du module.
 
 Le fichier de configuration principal est `src/app/calculators/lemodule/config.json` (exemple pour le module "bief" : `src/app/calculators/bief/config.json`). Il contient la liste des composants graphiques à afficher à l'écran, de haut en bas (généralement des "fieldset"), la répartition des paramètres du module dans ces éléments, et un bloc de configuration à la fin.
 
@@ -92,7 +94,7 @@ Les chaînes de l'application sont traduites à l'aide du service `I18nService`,
 
 Les traductions doivent être placées dans les fichiers de langues du dossier `src/locale`.
 
-Lorsqu'un module de calcul a besoin d'une traduction contextualisée, par exemple dans le cas d'une variable ayant le même symbole que dans d'autres modules de calcul, les traductions doivent être placées dans `src/app/calculators/lemodule/lemodule.lalangue.json` (exemple pour le module "bief" en anglais : `src/app/calculators/bief/bief.en.json`).
+Lorsqu'un module de calcul a besoin d'une traduction contextualisée, par exemple dans le cas d'une variable ayant le même symbole que dans d'autres modules de calcul, les traductions doivent être placées dans `src/app/calculators/lemodule/lalangue.json` (exemple pour le module "bief" en anglais : `src/app/calculators/bief/en.json`).
 
 ### electron
 
@@ -112,19 +114,25 @@ Le déploiement de ngHyd sous forme d'application mobile se fait à l'aide de Co
 
 ### documentation
 
-La documentation est générée à l'aide de MkDocs.
+La documentation est générée à l'aide de MkDocs (`npm run mkdocs`).
 
 Les fichiers source pour une langue donnée se trouvent dans le dossier `docs/lang` (ex: `docs/fr`). Pour traduire la documentation dans une autre langue, il faut recopier l'intégralité des fichiers source puis les traduire. Afin de faciliter les liens de l'application vers la documentation, les noms des fichiers ne sont pas traduits et restent en français pour toutes les langues.
 
 L'organisation hiérarchique de la documentation est définie dans les fichiers `mkdocs-lang.yml` (ex: `mkdocs-fr.yml`).
 
+#### version PDF
+
+La documentation de chaque langue est compilée au format PDF via pandoc, qui convertit les sources markdown vers du LaTeX. Cette conversion est réalisée par le script python 3 `mkdocs2pdf.py`.
+
+Les préambules LaTeX pour chaque langue se trouvent dans `docs/latex`, par exemple `docs/latex/cassiopee_doc_fr.tex`. Les PDF générés sont placés dans `src/assets/docs/pdf`.
+
 ### tests unitaires
 
 Les tests unitaires dits "end-to-end" ou "e2e" sont réalisés avec Protractor, basé sur Selenium et fourni avec Angular. Les tests se trouvent dans le dossier `e2e` et sont configurés dans `protractor.conf.js`.
 
 Bien qu'elle soit supposée fonctionner avec d'autres navigateurs, l'exécution des tests n'est garantie qu'avec Chrome / Chromium. Le pilote Selenium pour Chrome ("chromedriver") posant parfois problème, `protractor.conf.js` contient une astuce qui recherche le pilote dans le système avant de le rechercher dans node_modules.
 
-Pour plus d'informations sur les problèmes liés à la version du pilote Selenium pour Chrome, consulter le chapitre "chromedriver version in e2e tests" dans la documentation développeurs (en anglais).
+Pour plus d'informations sur les problèmes liés à la version du pilote Selenium pour Chrome, consulter le chapitre "chromedriver version in e2e tests" dans la documentation utilisateurs (en anglais).
 
 ### scripts
 
@@ -170,9 +178,10 @@ Dans cet exemple, on définit un seul groupe de champs nommé arbitrairement "fs
 Le deuxième et dernier bloc contient les options pour ce module: le paramètre à calculer par défaut (`idCal`) qui peut être différent de celui choisi dans JaLHyd, et le lien vers la page de documentation pour ce module (`help`).
 
 Les options peuvent également contenir :
- * `defaultNodeType` : le type de noeud par défaut du module de calcul. Ce champ sert par exemple pour les sections paramétrées à déterminer le type de section à afficher lors de la création du module. Si ce champ est absent, sa valeur est `ComputeNodeType.None`.
+ * `defaultNodeType` : le type de section par défaut du module de calcul, pour les modules contenant une section
  * les valeurs par défaut des **propriétés** du module
  * les identifiants des listes déroulantes
+ * l'aide associée aux résultats (voir ci-dessous)
 
 #### aide contextuelle
 
@@ -230,36 +239,160 @@ Dans les fichiers `locale/messages.*.json` :
 
 ### classes de formulaire personnalisées
 
-En général la classe `FormulaireBase` est suffisante pour gérer un nouveau module, et est instanciée automatiquement par `FormulaireService` lors de la création d'un nouveau module. Elle agrège des instances de `FormComputeFixedVar` et `FormResultFixedVar`.
+En général la classe `FormulaireDefinition` est suffisante pour gérer un nouveau module, et est instanciée automatiquement par `FormulaireService` lors de la création d'un nouveau module.
 
 Mais dans des cas plus complexes, par exemple si le module contient des listes déroulantes ou des sous-modules, répétables ou non, il est nécessaire de créer de nouvelles classes de formulaires dérivées de celles-ci.
 
 Dans un tel cas, créer la classe du formulaire dans un nouveau fichier, dans le dossier `src/app/formulaire/definition` Par exemple `form-macrorugo-compound.ts`.
 
-Si les mécanismes de calcul ou de récupération des résultats doivent être modifiés, créer les classes nécessaires dans le dossier `src/app/formulaire/definition`, par exemple `form-compute-macrorugo-compound.ts` et `form-result-macrorugo-compound.ts`. Sinon, agréger des classes `FormCompute*` et `FormResult*` existantes.
-
 Si une nouvelle classe de formulaire a été créée, ajouter un `case` dans la méthode `newFormulaire()` de `FormulaireService`, dans `src/app/services/formulaire.service.ts`. Exemple :
 
 ```typescript
-case CalculatorType.Trigo:
-  f = new FormulaireTrigo();
+case CalculatorType.MacroRugoCompound:
+  f = new FormulaireMacrorugoCompound();
   break;
 ```
 
+### si le formulaire comprend des listes déroulantes
+
+Les listes déroulantes sont toujours associées à des **propriétés** du Nub.
+
+En général les valeurs autorisées sont tirées de l'**enum** correspondant, d'après le tableau `Session.enumFromProperty` de JaLHyd. Pour les autres cas, voir "si la liste n'est pas associée à un enum" ci-dessous.
+
+#### configuration
+
+Dans le fichier de configuration du module, ajouter la définition des listes déroulantes dans "fields", notamment la propriété associée et la valeur par défaut. Puis dans le bloc de configuration, déclarer les identifiants des listes dans "selectIds". Exemple dans `trigo/config.json`
+
+```json
+{
+    …
+    "fields": [
+        {
+            "id": "select_operation",
+            "type": "select",
+            "property": "trigoOperation",
+            "default": "COS"
+        },
+        {
+            "id": "select_unit",
+            "type": "select",
+            "property": "trigoUnit",
+            "default": "DEG"
+        },
+        …
+    ]
+},
+…
+{
+    "type": "options",
+    "selectIds": [ "select_operation", "select_unit" ],
+    …
+}
+```
+
+#### si la liste n'est pas associée à un enum
+ 
+Une liste déroulante peut être associée à une **source**, qui détermine quels sont les choix possibles.
+
+Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`.
+
+Exemple pour la source "remous_target" associée à la propriété "varCalc", dans le module CourbeRemous :
+
+```typescript
+switch (source) {
+    // driven by string[], not enum (easier for variable names)
+    case "remous_target":
+        this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
+        for (const at of CourbeRemous.availableTargets) {
+            const e: SelectEntry = new SelectEntry(this._entriesBaseId + at, at);
+            this.addEntry(e);
+        }
+        break;
+```
+
+Ici on ajoute des options de type `SelectEntry` à l'aide de la méthode `addEntry()` : une option vide au début, puis une pour chaque élément d'un tableau.
+
+Puis dans le fichier de configuration du module, déclarer la source :
+
+```json
+{
+    "id": "select_target",
+    "type": "select",
+    "property": "varCalc",
+    "source": "remous_target",
+    …
+```
+
+#### si l'affichage de certains champs dépend du choix dans la liste
+
+Les listes dont l'identifiant est déclaré dans le fichier de configuration du module déclencheront, lorsque leur valeur change, un effacement des résultats du module et une mise à jour de tous les "fieldset" du formulaire.
+
+Cette dernière opération permet de vérifier la visibilité de chaque champ du formulaire, et afficher / masquer ceux dont la visibilité a changé.
+
+Ainsi, pour rendre la visibilité d'un champ dépendante du choix dans la liste, il faut, **dans le code du Nub dans JaLHyd** :
+
+ * écouter le changement de propriété (méthode `update()`, action `propertyChange`)
+ * selon la nouvelle valeur, ajuster la propriété `.visible` des paramètres concernés
+ 
+ Il n'y a rien à faire de particulier dans ngHyd.
+
+### si le module agrège une section
+
+Il faut utiliser ou étendre `FormulaireSection`.
+
+Dans la configuration du module, ajouter un sélecteur de section, associé à la propriété "nodeType" :
+
+```json
+{
+    "id": "select_section",
+    "type": "select",
+    "property": "nodeType",
+    "help": {
+        "1": "hsl/types_sections.html#section-rectangulaire",
+        "0": "hsl/types_sections.html#section-circulaire",
+        "2": "hsl/types_sections.html#section-trapezoidale",
+        "3": "hsl/types_sections.html#section-parabolique"
+    }
+}
+```
+
+Puis dans les options, déclarer  ce sélecteur et ajouter "defaultNodeType" :
+
+```json
+{
+    "type": "options",
+    "defaultNodeType": "SectionRectangle",
+    "selectIds": [ "select_section" ],
+    …
+}
+```
+
 ### si le module agrège des modules enfants
 
 La traduction des variables des modules enfants doit aussi être ajoutée dans les fichiers de langues, dans le dossier de configuration du module.
 
 #### si ces modules enfants sont répétables ("fs_container")
 
-Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de `FormulaireMacrorugoCompound` par exemple. Notamment, implémenter ou surcharger les méthodes :
+Il faut utiliser ou étendre `FormulaireRepeatableFieldset`.
 
- * `createFieldset()`
- * `moveFieldsetUp()`
- * `moveFieldsetDown()`
- * `removeFieldset()`
- * `completeParse()`
- * `update()` (action "newFieldset")
+Dans la configuration du module, créer un "fieldset_template" en donnant le type des Nubs enfants dans la propriété "calcType", et créer un "template_container" associé à ce "fieldset_template" (exemple pour SPP) :
+
+```json
+{
+    "id": "fs_yaxn",
+        "type": "fieldset_template",
+        "calcType": "YAXN",
+        "fields": [
+        	…
+},
+{
+    "id": "yaxn_container",
+    "type": "template_container",
+    "templates": [
+        "fs_yaxn"
+    ]
+}
+```
 
 Dans la méthode `create()` de `CalculatorListComponent`, dans le fichier `src/app/components/calculator-list/calculator-list.component.ts`, ajouter la création d'un enfant par défaut. Exemple pour `MacrorugoCompound` :
 
@@ -297,93 +430,44 @@ Dans chaque fichier de langue du dossier `src/locale`, ajouter les traductions p
 "INFO_CHILD_TYPE_MACRORUGO_PLUR": "radiers",
 ```
 
-### si le formulaire comprend des listes déroulantes
-
-Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de FormulaireTrigo par exemple. Notamment, implémenter ou surcharger les méthodes :
+#### si ces enfants sont des structures avec des lois de débit
 
- * `afterParseFieldset()`
- * `parseOptions()`
- * `update()` (appeler `reset()` lors de l'action "propertyChange")
+Il faut utiliser ou étendre `FormulaireParallelStructure` (ex: Cloisons, Dever…).
 
-#### configuration
-
-Dans le fichier de configuration du module, ajouter la définition des listes déroulantes dans "fields" notamment leur **source** (voir "sources" plus bas), ainsi que leur valeur par défaut dans le "fieldset" parent. Exemple dans `trigo/config.json`
+Dans la configuration du module, dans le "fieldset_template", ajouter un sélecteur de structure associé à la propriété "structureType" et un sélecteur de loi de débit associé à la propriété  "loiDebit", noter les propriétés "calcType" (toujours "Structure" dans ce cas), "defaultStructType" et "defaultLoiDebit" :
 
 ```json
 {
-  "id": "fs_trigo",
-  "type": "fieldset",
-  "defaultOperation": "COS",
-  "defaultUnit": "DEG",
-  "fields": [
-    {
-      "id": "select_operation",
-      "type": "select",
-      "source": "trigo_operation"
-    },
-    {
-      "id": "select_unit",
-      "type": "select",
-      "source": "trigo_unit"
-    }
-  ]
-},
+    "id": "fs_ouvrage",
+    "type": "fieldset_template",
+    "calcType": "Structure",
+    "defaultStructType": "VanneRectangulaire",
+    "defaultLoiDebit": "GateCem88v",
+    "fields": [
+        {
+            "id": "select_structure",
+            "type": "select",
+            "property": "structureType",
+            "source": "device_structure_type"
+        },
+        {
+            "id": "select_loidebit",
+            "type": "select",
+            "property": "loiDebit",
+            "source": "device_loi_debit"
+        }
 ```
 
-Dans ce même fichier de configuration, dans le dernier élément "options", ajouter une entrée par liste déroulante :
+Dans les options, déclarer  les sélecteurs :
 
 ```json
-…
 {
-  "type": "options",
-  "operationSelectId": "select_operation",
-  "unitSelectId": "select_unit",
-  …
-```
- 
-#### sources
- 
-Chaque liste déroulante est associée à une **source** (voir "configuration" plus haut), qui détermine quels sont les choix possibles. Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/elements/select-field.ts`. Exemple pour "trigoOperation" :
-
-```typescript
-case "trigo_operation": // (cos, sin…)
-  for (let j = 0; j < Object.keys(TrigoOperation).length / 2; j++) {
-    this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
-  }
-  break;
-```
-
-#### lien avec les propriétés
-
-Les listes déroulantes doivent être liées à des **propriétés** du Nub. Pour ce faire, modifier la classe `FieldSet` dans le fichier `src/app/formulaire/elements/fieldset.ts` comme suit (exemple pour le module `Trigo`).
-
-Ajouter un `case` dans la fonction `updateFields()`
-
-```typescript
-case "fs_trigo": // Trigo
-  this.setSelectValueFromProperty("select_operation", "trigoOperation");
-  this.setSelectValueFromProperty("select_unit", "trigoUnit");
-  break;
-```
-
-Ajouter un `case` dans la fonction `update()`
-
-```typescript
-case "select_operation": // Trigo
-  this.setPropValue("trigoOperation", data.value.value);
-  break;
-case "select_unit": // Trigo
-  this.setPropValue("trigoUnit", data.value.value);
-  break;
+    "type": "options",
+    "selectIds": [ "select_structure", "select_loidebit" ],
+    …
+}
 ```
 
-Dans la fonction `parseConfig()`, ajouter un appel par à `setPropertyValueFromConfig()` pour chaque liste déroulante.
-
-```typescript
-  this.setPropertyValueFromConfig(json, "defaultOperation", "trigoOperation", TrigoOperation);
-  this.setPropertyValueFromConfig(json, "defaultUnit", "trigoUnit", TrigoUnit);
-```
- 
 ### documentation
 
 Pour chaque langue, ajouter un fichier .md dans les dossiers `docs/*/calculators`, puis placer ce nouveau fichier dans la hiérarchie de la documentation, en ajoutant son chemin dans les fichiers `mkdocs-*.yml`.
diff --git a/e2e/session/session-cascade-params.json b/e2e/session/session-cascade-params.json
index a17049558..7c8477307 100644
--- a/e2e/session/session-cascade-params.json
+++ b/e2e/session/session-cascade-params.json
@@ -4,7 +4,7 @@
             "uid": "ZTFxeW",
             "props": {
                 "calcType": 2,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "Sec. param."
@@ -14,7 +14,7 @@
                     "uid": "b21rNG",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -58,7 +58,7 @@
             "uid": "Z3EwY2",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme"
@@ -68,7 +68,7 @@
                     "uid": "ZnU0bn",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -112,7 +112,7 @@
             "uid": "Y2l2Y3",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme 1"
@@ -122,7 +122,7 @@
                     "uid": "MmV0dG",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
diff --git a/e2e/session/session-liens-spaghetti.json b/e2e/session/session-liens-spaghetti.json
index d33e60fd5..97852c215 100644
--- a/e2e/session/session-liens-spaghetti.json
+++ b/e2e/session/session-liens-spaghetti.json
@@ -9,7 +9,7 @@
             "uid": "ZHh1YW",
             "props": {
                 "calcType": 2,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "Sec. param."
@@ -19,7 +19,7 @@
                     "uid": "bXB1Y3",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -63,8 +63,7 @@
         {
             "uid": "eTgwMG",
             "props": {
-                "calcType": 11,
-                "nodeType": 0
+                "calcType": 11
             },
             "meta": {
                 "title": "Macro-rugo."
@@ -129,8 +128,7 @@
         {
             "uid": "dGx0em",
             "props": {
-                "calcType": 8,
-                "nodeType": 0
+                "calcType": 8
             },
             "meta": {
                 "title": "Ouvrages"
@@ -140,7 +138,7 @@
                     "uid": "ZmZ3bX",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -166,7 +164,7 @@
                     "uid": "aWo0M2",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -194,7 +192,7 @@
                     "uid": "YTBjcm",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 1,
                         "loiDebit": 1
                     },
@@ -242,7 +240,7 @@
             "uid": "dzA1OX",
             "props": {
                 "calcType": 3,
-                "nodeType": 2
+                "nodeType": 1
             },
             "meta": {
                 "title": "R. uniforme"
@@ -252,7 +250,7 @@
                     "uid": "Ynlna2",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 2
+                        "nodeType": 1
                     },
                     "children": [],
                     "parameters": [
@@ -297,8 +295,7 @@
         {
             "uid": "cXFraW",
             "props": {
-                "calcType": 9,
-                "nodeType": 0
+                "calcType": 9
             },
             "meta": {
                 "title": "Déver. dénoyés"
@@ -308,7 +305,7 @@
                     "uid": "Zzd1cH",
                     "props": {
                         "calcType": 7,
-                        "nodeType": 5,
+                        "nodeType": 4,
                         "structureType": 0,
                         "loiDebit": 7
                     },
diff --git a/e2e/session/session-optional-params.test.json b/e2e/session/session-optional-params.test.json
index 7f4df3fcf..94d46a3d0 100644
--- a/e2e/session/session-optional-params.test.json
+++ b/e2e/session/session-optional-params.test.json
@@ -4,7 +4,7 @@
             "uid": "eHpub2",
             "props": {
                 "calcType": 2,
-                "nodeType": 4
+                "nodeType": 3
             },
             "meta": {
                 "title": "Sec. param."
@@ -14,7 +14,7 @@
                     "uid": "YXNoY2",
                     "props": {
                         "calcType": 14,
-                        "nodeType": 4
+                        "nodeType": 3
                     },
                     "children": [],
                     "parameters": [
diff --git a/src/app/calculators/bief/config.json b/src/app/calculators/bief/config.json
index 12251aaaa..5dec17342 100644
--- a/src/app/calculators/bief/config.json
+++ b/src/app/calculators/bief/config.json
@@ -6,7 +6,8 @@
             {
                 "id": "select_regime",
                 "type": "select",
-                "source": "bief_regime"
+                "property": "regime",
+                "default": "Fluvial"
             }
         ]
     },
@@ -17,13 +18,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -65,9 +66,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "defaultRegime": "Fluvial",
-        "sectionSourceId": "select_section",
-        "regimeSelectId": "select_regime",
+        "selectIds": [ "select_section", "select_regime" ],
         "help": "hsl/bief.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/bief/en.json b/src/app/calculators/bief/en.json
index 056d28730..772347ac1 100644
--- a/src/app/calculators/bief/en.json
+++ b/src/app/calculators/bief/en.json
@@ -8,10 +8,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/bief/fr.json b/src/app/calculators/bief/fr.json
index f22d1f024..a8f1f5489 100644
--- a/src/app/calculators/bief/fr.json
+++ b/src/app/calculators/bief/fr.json
@@ -8,10 +8,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/cloisons/config.json b/src/app/calculators/cloisons/config.json
index 1356c2276..fd387b8de 100644
--- a/src/app/calculators/cloisons/config.json
+++ b/src/app/calculators/cloisons/config.json
@@ -22,19 +22,21 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "Orifice_OrificeSubmerged": "structures/orifice_noye.html",
                     "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html",
                     "SeuilRectangulaire_WeirSubmergedLarinier": "structures/fente_noyee.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "h1",
             "L",
@@ -57,7 +59,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "pab/cloisons.html"
     }
diff --git a/src/app/calculators/courberemous/config.json b/src/app/calculators/courberemous/config.json
index c6508c4a2..710818fc3 100644
--- a/src/app/calculators/courberemous/config.json
+++ b/src/app/calculators/courberemous/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -52,11 +52,12 @@
             {
                 "id": "select_resolution",
                 "type": "select",
-                "source": "remous_methode_resolution",
+                "property": "methodeResolution",
+                "default": "Trapezes",
                 "help": {
-                    "Trapezes": "../methodes_numeriques/integration_trapezes.html",
-                    "RungeKutta4": "../methodes_numeriques/rk4.html",
-                    "EulerExplicite": "../methodes_numeriques/euler_explicite.html"
+                    "0": "../methodes_numeriques/integration_trapezes.html",
+                    "1": "../methodes_numeriques/rk4.html",
+                    "2": "../methodes_numeriques/euler_explicite.html"
                 }
             }
         ]
@@ -68,6 +69,7 @@
             {
                 "id": "select_target",
                 "type": "select",
+                "property": "varCalc",
                 "source": "remous_target",
                 "help": {
                     "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
@@ -93,9 +95,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "sectionSourceId": "select_section",
-        "targetSelectId": "select_target",
-        "methodSelectId": "select_resolution",
+        "selectIds": [ "select_resolution", "select_section", "select_target" ],
         "help": "hsl/courbe_remous.html",
         "resultsHelp": {
             "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
diff --git a/src/app/calculators/courberemous/en.json b/src/app/calculators/courberemous/en.json
index 39ad2d88e..cb5166fe0 100644
--- a/src/app/calculators/courberemous/en.json
+++ b/src/app/calculators/courberemous/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
@@ -43,9 +43,9 @@
     "UNIT_IMP": "N",
     "UNIT_TAU0": "Pa",
 
-    "select_resolution_Trapezes": "Integration by trapezoid",
-    "select_resolution_RungeKutta4": "Runge Kutta fourth order",
-    "select_resolution_EulerExplicite": "Explicit Euler",
+    "select_resolution_0": "Integration by trapezoid",
+    "select_resolution_1": "Runge Kutta fourth order",
+    "select_resolution_2": "Explicit Euler",
 
     "fs_target_data": "Data to compute",
     "select_target": "Choice of the data to compute",
diff --git a/src/app/calculators/courberemous/fr.json b/src/app/calculators/courberemous/fr.json
index 6c6d61121..3d9bfd7ee 100644
--- a/src/app/calculators/courberemous/fr.json
+++ b/src/app/calculators/courberemous/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
@@ -42,9 +42,9 @@
     "UNIT_IMP": "N",
     "UNIT_TAU0": "Pa",
 
-    "select_resolution_Trapezes": "Intégration par trapèzes",
-    "select_resolution_RungeKutta4": "Runge Kutta d'ordre 4",
-    "select_resolution_EulerExplicite": "Euler explicite",
+    "select_resolution_0": "Intégration par trapèzes",
+    "select_resolution_1": "Runge Kutta d'ordre 4",
+    "select_resolution_2": "Euler explicite",
 
     "fs_target_data": "Donnée à calculer",
     "select_target": "Choix de la donnée à calculer",
diff --git a/src/app/calculators/dever/config.json b/src/app/calculators/dever/config.json
index b76d28c55..dc68b2e26 100644
--- a/src/app/calculators/dever/config.json
+++ b/src/app/calculators/dever/config.json
@@ -20,17 +20,19 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "SeuilRectangulaire_WeirFree": "structures/kivi.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "ZDV",
             "L",
@@ -52,7 +54,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "structures/dever.html"
     }
diff --git a/src/app/calculators/grille/config.json b/src/app/calculators/grille/config.json
index ed3784d4b..5b074f9fd 100644
--- a/src/app/calculators/grille/config.json
+++ b/src/app/calculators/grille/config.json
@@ -17,12 +17,12 @@
     {
         "id": "fs_plan",
         "type": "fieldset",
-        "defaultGridType": "Conventional",
         "fields": [
             {
                 "id": "select_grid_type",
                 "type": "select",
-                "source": "grille_type",
+                "property": "gridType",
+                "default": "Conventional",
                 "help": {
                     "0": "devalaison/grille.html#grille-conventionnelle",
                     "1": "devalaison/grille.html#grille-orientee",
@@ -44,12 +44,12 @@
     {
         "id": "fs_grille",
         "type": "fieldset",
-        "defaultGridProfile": "Rectangular",
         "fields": [
             {
                 "id": "select_grid_profile",
                 "type": "select",
-                "source": "grille_profile",
+                "property": "gridProfile",
+                "default": "Rectangular",
                 "help": "devalaison/grille.html#profil-des-barreaux"
             },
             {
@@ -91,8 +91,7 @@
     },
     {
         "type": "options",
-        "gridTypeSelectId": "select_grid_type",
-        "gridProfileSelectId": "select_grid_profile",
+        "selectIds": [ "select_grid_type", "select_grid_profile" ],
         "help": "devalaison/grille.html",
         "resultsHelp": {
             "VAPDG": "devalaison/grille.html#vitesse-dapproche-moyenne-pour-le-debit-maximum-turbine-en-soustrayant-la-partie-superieure-eventuellement-obturee",
diff --git a/src/app/calculators/lechaptcalmon/config.json b/src/app/calculators/lechaptcalmon/config.json
index 87cf30bd5..663588dff 100644
--- a/src/app/calculators/lechaptcalmon/config.json
+++ b/src/app/calculators/lechaptcalmon/config.json
@@ -7,7 +7,8 @@
             {
                 "id": "select_material",
                 "type": "select",
-                "source": "lechapt_calmon_material"
+                "property": "material",
+                "default": "UnlinedCastIronCoarseConcrete"
             },
             "L",
             "M",
@@ -28,7 +29,7 @@
     {
         "type": "options",
         "idCal": "J",
-        "lcMaterialSelectId": "select_material",
+        "selectIds": [ "select_material" ],
         "help": "hyd_en_charge/lechapt-calmon.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/macrorugocompound/config.json b/src/app/calculators/macrorugocompound/config.json
index 5ecdf13e0..db7b7d8fe 100644
--- a/src/app/calculators/macrorugocompound/config.json
+++ b/src/app/calculators/macrorugocompound/config.json
@@ -35,7 +35,7 @@
             {
                 "id": "select_pass_type",
                 "type": "select",
-                "source": "mrc_pass_type"
+                "property": "inclinedApron"
             },
             "ZRR",
             "ZRL",
@@ -61,7 +61,7 @@
     {
         "type": "options",
         "idCal": "Q",
-        "apronTypeSelectId": "select_pass_type",
+        "selectIds": [ "select_pass_type" ],
         "help": "pam/macrorugo_complexe.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/parallelstructure/config.json b/src/app/calculators/parallelstructure/config.json
index b469be78c..d9fdec718 100644
--- a/src/app/calculators/parallelstructure/config.json
+++ b/src/app/calculators/parallelstructure/config.json
@@ -19,11 +19,14 @@
             {
                 "id": "select_structure",
                 "type": "select",
+                "property": "structureType",
                 "source": "device_structure_type"
             },
             {
                 "id": "select_loidebit",
                 "type": "select",
+                "property": "loiDebit",
+                "source": "device_loi_debit",
                 "help": {
                     "SeuilRectangulaire_KIVI": "structures/kivi.html",
                     "SeuilRectangulaire_WeirVillemonte": "structures/kivi.html",
@@ -38,8 +41,7 @@
                     "SeuilRectangulaire_WeirFree": "structures/kivi.html",
                     "SeuilTriangulaire_TriangularWeirFree": "structures/dever_triang.html",
                     "SeuilTriangulaireTrunc_TriangularTruncWeirFree": "structures/dever_triang_tronque.html"
-                },
-                "source": "device_loi_debit"
+                }
             },
             "S",
             "ZDV",
@@ -69,7 +71,7 @@
     },
     {
         "type": "options",
-        "ouvrageSelectId": "select_structure",
+        "selectIds": [ "select_structure", "select_loidebit" ],
         "idCal": "Q",
         "help": "structures/lois_ouvrages.html",
         "resultsHelp": {
diff --git a/src/app/calculators/regimeuniforme/config.json b/src/app/calculators/regimeuniforme/config.json
index 0961e0c64..b78ebf54f 100644
--- a/src/app/calculators/regimeuniforme/config.json
+++ b/src/app/calculators/regimeuniforme/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurFond",
             "Fruit",
@@ -44,8 +44,8 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
+        "selectIds": [ "select_section" ],
         "idCal": "Q",
-        "sectionSourceId": "fs_section",
         "help": "hsl/regime_uniforme.html",
         "resultsHelp": {
             "V": "hsl/var_hydrauliques.html#vitesse-moyenne-v"
diff --git a/src/app/calculators/regimeuniforme/en.json b/src/app/calculators/regimeuniforme/en.json
index 4e52b0ab8..e27ce7d4a 100644
--- a/src/app/calculators/regimeuniforme/en.json
+++ b/src/app/calculators/regimeuniforme/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/regimeuniforme/fr.json b/src/app/calculators/regimeuniforme/fr.json
index c3c20571c..7d44f4775 100644
--- a/src/app/calculators/regimeuniforme/fr.json
+++ b/src/app/calculators/regimeuniforme/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/sectionparametree/config.json b/src/app/calculators/sectionparametree/config.json
index e4a901ed9..dc3d8f78c 100644
--- a/src/app/calculators/sectionparametree/config.json
+++ b/src/app/calculators/sectionparametree/config.json
@@ -6,13 +6,13 @@
             {
                 "id": "select_section",
                 "type": "select",
+                "property": "nodeType",
                 "help": {
-                    "SectionRectangle": "hsl/types_sections.html#section-rectangulaire",
-                    "SectionCercle": "hsl/types_sections.html#section-circulaire",
-                    "SectionTrapeze": "hsl/types_sections.html#section-trapezoidale",
-                    "SectionPuissance": "hsl/types_sections.html#section-parabolique"
-                },
-                "source": "acsection_section"
+                    "1": "hsl/types_sections.html#section-rectangulaire",
+                    "0": "hsl/types_sections.html#section-circulaire",
+                    "2": "hsl/types_sections.html#section-trapezoidale",
+                    "3": "hsl/types_sections.html#section-parabolique"
+                }
             },
             "LargeurBerge",
             "LargeurFond",
@@ -44,8 +44,7 @@
     {
         "type": "options",
         "defaultNodeType": "SectionRectangle",
-        "sectionSourceId": "select_section",
-        "targetSelectId": "select_target",
+        "selectIds": [ "select_section" ],
         "help": "hsl/section_parametree.html",
         "resultsHelp": {
             "B": "hsl/var_hydrauliques.html#largeur-au-miroir-b",
diff --git a/src/app/calculators/sectionparametree/en.json b/src/app/calculators/sectionparametree/en.json
index 915cdb505..29699a3a1 100644
--- a/src/app/calculators/sectionparametree/en.json
+++ b/src/app/calculators/sectionparametree/en.json
@@ -2,10 +2,10 @@
     "fs_section": "Type of section",
     "select_section": "Choice of section type",
 
-    "select_section_SectionTrapeze": "Trapezoidal",
-    "select_section_SectionRectangle": "Rectangular",
-    "select_section_SectionCercle": "Circular",
-    "select_section_SectionPuissance": "Parabolic",
+    "select_section_2": "Trapezoidal",
+    "select_section_1": "Rectangular",
+    "select_section_0": "Circular",
+    "select_section_3": "Parabolic",
 
     "LargeurFond": "Width at bottom",
     "Fruit": "Bank slope",
diff --git a/src/app/calculators/sectionparametree/fr.json b/src/app/calculators/sectionparametree/fr.json
index c9065310f..12e016363 100644
--- a/src/app/calculators/sectionparametree/fr.json
+++ b/src/app/calculators/sectionparametree/fr.json
@@ -2,10 +2,10 @@
     "fs_section": "Type de section",
     "select_section": "Choix du type de section",
 
-    "select_section_SectionTrapeze": "Trapézoïdale",
-    "select_section_SectionRectangle": "Rectangulaire",
-    "select_section_SectionCercle": "Circulaire",
-    "select_section_SectionPuissance": "Parabolique",
+    "select_section_2": "Trapézoïdale",
+    "select_section_1": "Rectangulaire",
+    "select_section_0": "Circulaire",
+    "select_section_3": "Parabolique",
 
     "LargeurFond": "Largeur au fond",
     "Fruit": "Fruit des berges",
diff --git a/src/app/calculators/spp/config.json b/src/app/calculators/spp/config.json
index 0c3c24272..1a20f3cf1 100644
--- a/src/app/calculators/spp/config.json
+++ b/src/app/calculators/spp/config.json
@@ -2,12 +2,12 @@
     {
         "id": "fs_spp",
         "type": "fieldset",
-        "defaultOperation": "SUM",
         "fields": [
             {
                 "id": "select_spp_operation",
                 "type": "select",
-                "source": "spp_operation"
+                "property": "sppOperation",
+                "default": "SUM"
             },
             "Y"
         ]
@@ -32,7 +32,7 @@
     {
         "type": "options",
         "idCal": "Y",
-        "operationSelectId": "select_spp_operation",
-        "_help": "util/trigo.html"
+        "selectIds": [ "select_spp_operation" ],
+        "_help": "util/spp.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/calculators/trigo/config.json b/src/app/calculators/trigo/config.json
index 6dbb51a8c..806076c83 100644
--- a/src/app/calculators/trigo/config.json
+++ b/src/app/calculators/trigo/config.json
@@ -2,18 +2,18 @@
     {
         "id": "fs_trigo",
         "type": "fieldset",
-        "defaultOperation": "COS",
-        "defaultUnit": "DEG",
         "fields": [
             {
                 "id": "select_operation",
                 "type": "select",
-                "source": "trigo_operation"
+                "property": "trigoOperation",
+                "default": "COS"
             },
             {
                 "id": "select_unit",
                 "type": "select",
-                "source": "trigo_unit"
+                "property": "trigoUnit",
+                "default": "DEG"
             }
         ]
     },
@@ -25,8 +25,7 @@
     {
         "type": "options",
         "idCal": "Y",
-        "operationSelectId": "select_operation",
-        "unitSelectId": "select_unit",
+        "selectIds": [ "select_operation", "select_unit" ],
         "_help": "util/trigo.html"
     }
 ]
\ No newline at end of file
diff --git a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
index 948a63d4b..1d9a14069 100644
--- a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
+++ b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.ts
@@ -1,6 +1,6 @@
 import { Component, ViewChild, DoCheck } from "@angular/core";
 
-import { Result, cLog, Message, MessageCode, MessageSeverity, MacrorugoCompound } from "jalhyd";
+import { Result, cLog, Message, MessageCode, MessageSeverity, MRCInclination } from "jalhyd";
 
 import { fv } from "../../../app/util";
 
@@ -321,7 +321,7 @@ export class MacrorugoCompoundResultsComponent implements DoCheck {
             this.mrcResults
             && this.mrcResults.result
             && this.mrcResults.result.sourceNub
-            && this.mrcResults.result.sourceNub.properties.getPropValue("inclinedApron")
+            && this.mrcResults.result.sourceNub.properties.getPropValue("inclinedApron") === MRCInclination.INCLINED
         );
     }
 
diff --git a/src/app/components/modules-diagram/modules-diagram.component.ts b/src/app/components/modules-diagram/modules-diagram.component.ts
index 093e5b332..a1081c578 100644
--- a/src/app/components/modules-diagram/modules-diagram.component.ts
+++ b/src/app/components/modules-diagram/modules-diagram.component.ts
@@ -12,7 +12,7 @@ import {
     Session,
     ParamValueMode,
     CalculatorType,
-    ComputeNodeType,
+    SectionType,
     LoiDebit,
     Nub,
     MacrorugoCompound,
@@ -232,7 +232,7 @@ export class ModulesDiagramComponent implements AfterContentInit, AfterViewCheck
         let type = CalculatorType[n.calcType];
         const nt = n.properties.getPropValue("nodeType");
         if (nt) {
-            type = ComputeNodeType[nt];
+            type = SectionType[nt];
         } else {
             const ld = n.properties.getPropValue("loiDebit");
             if (ld !== undefined) {
diff --git a/src/app/formulaire/definition/form-bief.ts b/src/app/formulaire/definition/form-bief.ts
deleted file mode 100644
index 46b7ffad6..000000000
--- a/src/app/formulaire/definition/form-bief.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { IObservable, SectionNub, Session, BiefRegime } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
-
-export class FormulaireBief extends FormulaireSection {
-
-    /** id du select configurant le régime */
-    private _regimeSelectId: string;
-
-    constructor() {
-        super();
-        // default properties
-        this._props["regime"] = BiefRegime.Fluvial;
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id du select configurant la méthode de résolution
-        this._regimeSelectId = this.getOption(json, "regimeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de méthode de résolution
-        if (this._regimeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._regimeSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-
-        super.update(sender, data);
-
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_water_line":
-                    this.reset();
-                    // Either Z1 or Z2 is calculable, depending on Regime
-                    this.getFieldsetById("fs_condlim").updateFields();
-                    break;
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-courbe-remous.ts b/src/app/formulaire/definition/form-courbe-remous.ts
index 38d112690..11c22edd0 100644
--- a/src/app/formulaire/definition/form-courbe-remous.ts
+++ b/src/app/formulaire/definition/form-courbe-remous.ts
@@ -1,9 +1,8 @@
-import { IObservable, MethodeResolution, SectionNub, Session, Result, CourbeRemous, CourbeRemousParams, acSection } from "jalhyd";
+import { Result, CourbeRemous, CourbeRemousParams, acSection } from "jalhyd";
 
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
 import { RemousResults } from "../../results/remous-results";
 import { CalculatorResults } from "../../results/calculator-results";
+import { FormulaireSection } from "./form-section";
 
 export class FormulaireCourbeRemous extends FormulaireSection {
 
@@ -14,36 +13,12 @@ export class FormulaireCourbeRemous extends FormulaireSection {
 
     private resultYc: Result;
 
-    /**
-     * id du select configurant la méthode de résolution
-     */
-    private _resolveMethSelectId: string;
-
     constructor() {
         super();
         this._remousResults = new RemousResults();
-        // default properties
-        this._props["methodeResolution"] = MethodeResolution.Trapezes;
         this._props["varCalc"] = ""; // important
     }
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id du select configurant la méthode de résolution
-        this._resolveMethSelectId = this.getOption(json, "methodSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de méthode de résolution
-        if (this._resolveMethSelectId) {
-            const sel = fs.getFormulaireNodeById(this._resolveMethSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     protected compute() {
         this.reaffectResultComponents();
     }
@@ -91,32 +66,4 @@ export class FormulaireCourbeRemous extends FormulaireSection {
         this._remousResults.helpLinks = this.helpLinks;
         return [ this._remousResults ];
     }
-
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-
-        super.update(sender, data);
-
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_param_calc":
-                case "fs_target_data":
-                    this.reset();
-                    break;
-            }
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index f6cf46ffc..4c55719f1 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -1,4 +1,15 @@
-import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, SectionNub, acSection, ParamDefinition, Result } from "jalhyd";
+import {
+    CalculatorType,
+    SectionType,
+    Nub,
+    Props,
+    Observer,
+    Session,
+    SectionNub,
+    acSection,
+    ParamDefinition,
+    Result
+} from "jalhyd";
 
 import { FormulaireElement } from "../elements/formulaire-element";
 import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
@@ -73,7 +84,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         return props["calcType"];
     }
 
-    public get nodeType(): ComputeNodeType {
+    public get nodeType(): SectionType {
         const props = this._currentNub === undefined ? this.defaultProperties : (this._currentNub.properties as Props).props;
         return props["nodeType"];
     }
@@ -145,7 +156,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
     protected parseOptions(json: {}) {
         const dnt = json["defaultNodeType"];
         if (dnt !== undefined) {
-            this._defaultNodeType = ComputeNodeType[dnt];
+            this._defaultNodeType = SectionType[dnt];
         }
         this._helpLink = json["help"];
         this._resultsHelpLinks = json["resultsHelp"];
@@ -156,7 +167,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this.helpLinks = this._resultsHelpLinks;
     }
 
-    public getOption(json: {}, option: string): string {
+    public getOption(json: {}, option: string): any {
         if (json["type"] === "options") {
             return json[option];
         }
diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts
index 9a5f38b9d..b2051ccba 100644
--- a/src/app/formulaire/definition/form-fixedvar.ts
+++ b/src/app/formulaire/definition/form-fixedvar.ts
@@ -4,14 +4,18 @@ import { VarResults } from "../../results/var-results";
 import { ChartType } from "../../results/chart-type";
 import { CalculatorResults } from "../../results/calculator-results";
 import { ParamRadioConfig, NgParameter } from "../elements/ngparam";
+import { FieldSet } from "../elements/fieldset";
 
-import { Nub } from "jalhyd";
+import { Nub, IObservable } from "jalhyd";
 
 export class FormulaireFixedVar extends FormulaireDefinition {
 
     protected _fixedResults: FixedResults;
     protected _varResults: VarResults;
 
+    /** ids of select fields */
+    private _selectIds: string[] = [];
+
     constructor() {
         super();
         this._fixedResults = new FixedResults();
@@ -26,6 +30,10 @@ export class FormulaireFixedVar extends FormulaireDefinition {
         return this._varResults;
     }
 
+    public get selectids(): string[] {
+        return this._selectIds;
+    }
+
     public resetFormResults() {
         this._fixedResults.reset();
         this._varResults.reset();
@@ -61,6 +69,24 @@ export class FormulaireFixedVar extends FormulaireDefinition {
         return res;
     }
 
+    public afterParseFieldset(fs: FieldSet) {
+        // observe all select fields @see this.update()
+        if (this._selectIds.length > 0) {
+            for (const sId of this._selectIds) {
+                const sel = fs.getFormulaireNodeById(sId);
+                if (sel) {
+                    fs.properties.addObserver(this);
+                }
+            }
+        }
+    }
+
+    protected parseOptions(json: {}) {
+        super.parseOptions(json);
+        // get ids of all select fields
+        this._selectIds = this.getOption(json, "selectIds") || [];
+    }
+
     protected compute() {
         this.runNubCalc(this.currentNub);
         this.reaffectResultComponents();
@@ -90,4 +116,18 @@ export class FormulaireFixedVar extends FormulaireDefinition {
             this.varResults.update();
         }
     }
+
+    // interface Observer
+
+    public update(sender: IObservable, data: any) {
+        super.update(sender, data);
+        // whenever a select field is touched, reset results
+        if (data.action === "propertyChange") {
+            this.reset();
+            // reflect changes in GUI (who knows ?), for ex. show / hide dependent fields
+            for (const fs of this.allFieldsets) {
+                fs.updateFields();
+            }
+        }
+    }
 }
diff --git a/src/app/formulaire/definition/form-grille.ts b/src/app/formulaire/definition/form-grille.ts
index c66630c1a..67aa6e692 100644
--- a/src/app/formulaire/definition/form-grille.ts
+++ b/src/app/formulaire/definition/form-grille.ts
@@ -1,6 +1,3 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireFixedVar } from "./form-fixedvar";
 
 /**
@@ -8,12 +5,6 @@ import { FormulaireFixedVar } from "./form-fixedvar";
  */
 export class FormulaireGrille extends FormulaireFixedVar {
 
-    /** id of select configuring grid profile */
-    private _gridProfileSelectId: string;
-
-    /** id of select configuring grid type */
-    private _gridTypeSelectId: string;
-
     constructor() {
         super();
         // custom variables order for results tables
@@ -25,44 +16,4 @@ export class FormulaireGrille extends FormulaireFixedVar {
         ];
     }
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._gridProfileSelectId = this.getOption(json, "gridProfileSelectId");
-        this._gridTypeSelectId = this.getOption(json, "gridTypeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._gridTypeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._gridTypeSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-        if (this._gridProfileSelectId) {
-            const sel = fs.getFormulaireNodeById(this._gridProfileSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            if (data.name === "gridType") {
-                this.reset();
-                // Inclined grids have more input fields (OEntH and cIncl)
-                this.getFieldsetById("fs_grille").updateFields();
-                // Alpha and Beta are not always shown
-                this.getFieldsetById("fs_plan").updateFields();
-            }
-            if (data.name === "gridProfile") {
-                this.reset();
-                // Shape coefficients a and c are not always shown
-                this.getFieldsetById("fs_grille").updateFields();
-            }
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-lechapt-calmon.ts b/src/app/formulaire/definition/form-lechapt-calmon.ts
deleted file mode 100644
index cedc683c5..000000000
--- a/src/app/formulaire/definition/form-lechapt-calmon.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireFixedVar } from "./form-fixedvar";
-
-/**
- * Formulaire pour Lechapt et Calmon
- */
-export class FormulaireLechaptCalmon extends FormulaireFixedVar {
-
-    /** id of select configuring material */
-    private _lcMaterialSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._lcMaterialSelectId = this.getOption(json, "lcMaterialSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._lcMaterialSelectId) {
-            const sel = fs.getFormulaireNodeById(this._lcMaterialSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            if (data.name === "material") {
-                this.reset();
-            }
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts
index 8c38f31ec..663da1f96 100644
--- a/src/app/formulaire/definition/form-macrorugo-compound.ts
+++ b/src/app/formulaire/definition/form-macrorugo-compound.ts
@@ -1,4 +1,4 @@
-import { IObservable, Nub, MacrorugoCompound, Result } from "jalhyd";
+import { IObservable, Nub, MacrorugoCompound, Result, MRCInclination } from "jalhyd";
 
 import { FieldSet } from "../elements/fieldset";
 import { FieldsetContainer } from "../elements/fieldset-container";
@@ -13,32 +13,13 @@ import { CalculatorResults } from "../../results/calculator-results";
  */
 export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
 
-    /** id of select configuring apron type */
-    private _apronTypeSelectId: string;
-
     protected _mrcResults: MacrorugoCompoundResults;
 
     constructor() {
         super();
         this._mrcResults = new MacrorugoCompoundResults();
         // default properties
-        this._props["inclinedApron"] = false;
-    }
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._apronTypeSelectId = this.getOption(json, "apronTypeSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // if Fieldset contains apron type selector
-        if (this._apronTypeSelectId) {
-            const sel = fs.getFormulaireNodeById(this._apronTypeSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
+        this._props["inclinedApron"] = MRCInclination.NOT_INCLINED;
     }
 
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
@@ -105,7 +86,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
     /**
      * Reflect inclinedApron property state in GUI
      */
-    public updateApronState(inclined: boolean) {
+    public updateApronState(inclined: MRCInclination) {
         for (const fs of this.allFieldsets) {
             // show / hide dependent fields (read from model)
             fs.updateFields();
@@ -113,12 +94,12 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset {
         // show / hide children list (GUI only)
         for (const elt of this.allFormElements) {
             if (elt instanceof FieldsetContainer) {
-                elt.isDisplayed = (! inclined);
+                elt.isDisplayed = (inclined === MRCInclination.NOT_INCLINED);
             }
         }
         // when switching to multiple aprons, remove all fieldset container
         // instances and reinstanciate for every MacroRugo child
-        if (! inclined) {
+        if (inclined === MRCInclination.NOT_INCLINED) {
             for (const elt of this.allFormElements) {
                 if (elt instanceof FieldsetContainer) {
                     elt.clearKids();
diff --git a/src/app/formulaire/definition/form-parallel-structures.ts b/src/app/formulaire/definition/form-parallel-structures.ts
index fa8a481f9..6e238dd76 100644
--- a/src/app/formulaire/definition/form-parallel-structures.ts
+++ b/src/app/formulaire/definition/form-parallel-structures.ts
@@ -10,29 +10,6 @@ import { FormulaireRepeatableFieldset } from "./form-repeatable-fieldset";
 
 export class FormulaireParallelStructure extends FormulaireRepeatableFieldset {
 
-    /**
-     * id du select configurant le type d'ouvrage
-     */
-    private __ouvrageSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-
-        // id du select configurant le type d'ouvrage
-        this.__ouvrageSelectId = this.getOption(json, "ouvrageSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        // si le FieldSet contient le select de type d'ouvrage
-        if (this.__ouvrageSelectId) {
-            const sel = fs.getFormulaireNodeById(this.__ouvrageSelectId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     /**
      * construit un identifiant de type { uid: "abcdef", symbol: "X" }
      * avec "abcdef" l'index de l'ouvrage et "X" son paramètre
diff --git a/src/app/formulaire/definition/form-regime-uniforme.ts b/src/app/formulaire/definition/form-regime-uniforme.ts
deleted file mode 100644
index f1630343a..000000000
--- a/src/app/formulaire/definition/form-regime-uniforme.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { IObservable, Observer, Session, SectionNub } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireSection } from "./form-section";
-
-export class FormulaireRegimeUniforme extends FormulaireSection implements Observer {
-
-    update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        // changement de propriété du FieldSet contenant le select de choix du type de section
-        if (sender instanceof FieldSet && sender.id === "fs_section" && data.action === "propertyChange") {
-            // replace underlying section without replacing whole Nub
-            const newSect = Session.getInstance().createSection(data.value);
-            (this._currentNub as SectionNub).setSection(newSect);
-            // reflect changes in GUI
-            for (const fs of this.allFieldsets) {
-                // show / hide dependent fields
-                fs.updateFields();
-            }
-            this.reset();
-        }
-    }
-}
diff --git a/src/app/formulaire/definition/form-section-parametree.ts b/src/app/formulaire/definition/form-section-parametree.ts
index a18349a53..922edddb8 100644
--- a/src/app/formulaire/definition/form-section-parametree.ts
+++ b/src/app/formulaire/definition/form-section-parametree.ts
@@ -1,9 +1,8 @@
-import { IObservable, Nub, Session, SectionNub, ParamDefinition, Result, SectionParametree, acSection } from "jalhyd";
+import { Nub, ParamDefinition, Result, SectionParametree, acSection } from "jalhyd";
 
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireSection } from "./form-section";
 import { SectionResults } from "../../results/section-results";
-import { ParamRadioConfig } from "../elements/ngparam";
+import { ParamRadioConfig, NgParameter } from "../elements/ngparam";
 import { CalculatorResults } from "../../results/calculator-results";
 
 export class FormulaireSectionParametree extends FormulaireSection {
@@ -78,30 +77,7 @@ export class FormulaireSectionParametree extends FormulaireSection {
         return res;
     }
 
-    // interface Observer
-
-    update(sender: IObservable, data: any) {
-        super.update(sender, data);
-
-        // changement de propriété du FieldSet contenant le select de choix du type de section
-        if (sender instanceof FieldSet && data.action === "propertyChange") {
-            switch (sender.id) {
-                case "fs_section":
-                    // replace underlying section without replacing whole Nub
-                    const newSect = Session.getInstance().createSection(data.value);
-                    (this._currentNub as SectionNub).setSection(newSect);
-                    // reflect changes in GUI
-                    for (const fs of this.allFieldsets) {
-                        // show / hide dependent fields
-                        fs.updateFields();
-                    }
-                    this.reset();
-                    break;
-
-                case "fs_computed_var":
-                    this.reset();
-                    break;
-            }
-        }
+    public getSectionVariatedParameters(): NgParameter[] {
+        return this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
     }
 }
diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts
index e645b98ac..bd1685b44 100644
--- a/src/app/formulaire/definition/form-section.ts
+++ b/src/app/formulaire/definition/form-section.ts
@@ -1,43 +1,24 @@
-import { NgParameter, ParamRadioConfig } from "../elements/ngparam";
-import { FieldSet } from "../elements/fieldset";
 import { FormulaireFixedVar } from "./form-fixedvar";
+import { FieldSet } from "../elements/fieldset";
 
-export abstract class FormulaireSection extends FormulaireFixedVar {
-
-    /** id de l'élément configurant le type de section */
-    private _sectionSourceId: string;
-
-    private get hasSectionNodeTypeSource(): boolean {
-        return this._sectionSourceId !== undefined;
-    }
-
-    public getSectionVariatedParameters(): NgParameter[] {
-        return this.getDisplayedParamListFromState(ParamRadioConfig.VAR);
-    }
-
-    public getSectionComputedParam(): { symbol: string, label: string } {
-        const symbol = this.getSelectedValue("select_target");
-        const label = this.getSelectedLabel("select_target");
-        return { symbol, label };
-    }
+import { IObservable, Session, SectionNub } from "jalhyd";
 
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        // id de l'élément configurant le type de section
-        this._sectionSourceId = this.getOption(json, "sectionSourceId");
-    }
+export class FormulaireSection extends FormulaireFixedVar {
 
-    /**
-     * appelé après la création d'un FieldSet
-     * @param fs nouveau FieldSet
-     */
-    public afterParseFieldset(fs: FieldSet) {
-        if (this.hasSectionNodeTypeSource) { // s'il existe un menu de choix de section dans le module de calcul
-            const sel = fs.getFormulaireNodeById(this._sectionSourceId);
-            if (sel) {
-                // on abonne le formulaire aux propriétés du FieldSet pour MAJ du nub, reset du formulaire, ...
-                fs.properties.addObserver(this);
+    update(sender: IObservable, data: any) {
+        super.update(sender, data);
+        // changement de propriété du FieldSet contenant le select de choix du type de section
+        if (sender instanceof FieldSet && sender.id === "fs_section" && data.action === "propertyChange") {
+            // replace underlying section without replacing whole Nub
+            const newSect = Session.getInstance().createSection(data.value);
+            (this._currentNub as SectionNub).setSection(newSect);
+            // reflect changes in GUI
+            for (const fs of this.allFieldsets) {
+                // show / hide dependent fields
+                fs.updateFields();
             }
+            this.reset();
         }
     }
+
 }
diff --git a/src/app/formulaire/definition/form-spp.ts b/src/app/formulaire/definition/form-spp.ts
index e7ddf4e1a..6ca1be15e 100644
--- a/src/app/formulaire/definition/form-spp.ts
+++ b/src/app/formulaire/definition/form-spp.ts
@@ -3,30 +3,13 @@ import { FieldSet } from "../elements/fieldset";
 import { FormulaireNode } from "../elements/formulaire-node";
 import { FieldsetContainer } from "../elements/fieldset-container";
 
-import { Nub, IObservable } from "jalhyd";
+import { Nub } from "jalhyd";
 
 /**
  * Formulaire pour "somme / produit de puissances"
  */
 export class FormulaireSPP extends FormulaireRepeatableFieldset {
 
-    /** id of select configuring operation */
-    private _operationSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._operationSelectId = this.getOption(json, "operationSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._operationSelectId) {
-            const sel = fs.getFormulaireNodeById(this._operationSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
     public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         if (json["calcType"] === "YAXN") {
             // indice après lequel insérer le nouveau FieldSet
@@ -63,13 +46,4 @@ export class FormulaireSPP extends FormulaireRepeatableFieldset {
         }
         return n as FieldsetContainer;
     }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            this.reset();
-        }
-    }
 }
diff --git a/src/app/formulaire/definition/form-trigo.ts b/src/app/formulaire/definition/form-trigo.ts
deleted file mode 100644
index 332325710..000000000
--- a/src/app/formulaire/definition/form-trigo.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { IObservable } from "jalhyd";
-
-import { FieldSet } from "../elements/fieldset";
-import { FormulaireFixedVar } from "./form-fixedvar";
-
-/**
- * Formulaire pour les fonctions trigonométriques
- */
-export class FormulaireTrigo extends FormulaireFixedVar {
-
-    /** id of select configuring operation */
-    private _operationSelectId: string;
-
-    /** id of select configuring unit */
-    private _unitSelectId: string;
-
-    protected parseOptions(json: {}) {
-        super.parseOptions(json);
-        this._operationSelectId = this.getOption(json, "operationSelectId");
-        this._unitSelectId = this.getOption(json, "unitSelectId");
-    }
-
-    public afterParseFieldset(fs: FieldSet) {
-        if (this._operationSelectId) {
-            const sel = fs.getFormulaireNodeById(this._operationSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-        if (this._unitSelectId) {
-            const sel = fs.getFormulaireNodeById(this._unitSelectId);
-            if (sel) {
-                fs.properties.addObserver(this);
-            }
-        }
-    }
-
-    // interface Observer
-
-    public update(sender: IObservable, data: any) {
-        super.update(sender, data);
-        if (data.action === "propertyChange") {
-            this.reset();
-        }
-    }
-}
diff --git a/src/app/formulaire/elements/fieldset-template.ts b/src/app/formulaire/elements/fieldset-template.ts
index de8c1e2d8..3c9071131 100644
--- a/src/app/formulaire/elements/fieldset-template.ts
+++ b/src/app/formulaire/elements/fieldset-template.ts
@@ -1,5 +1,5 @@
 import { FieldSet } from "./fieldset";
-import { CalculatorType, ComputeNodeType, LoiDebit, Nub, StructureType } from "jalhyd";
+import { CalculatorType, LoiDebit, Nub, StructureType, SectionType } from "jalhyd";
 import { FormulaireDefinition } from "../definition/form-definition";
 import { FieldsetContainer } from "./fieldset-container";
 
@@ -19,9 +19,9 @@ export class FieldsetTemplate {
         return CalculatorType[ct];
     }
 
-    public get defaultNodeTypeFromConfig(): ComputeNodeType {
+    public get defaultNodeTypeFromConfig(): SectionType {
         const nt: string = this._jsonConfig["defaultNodeType"];
-        return ComputeNodeType[nt];
+        return SectionType[nt];
     }
 
     public get defaultStructTypeFromConfig(): StructureType {
diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts
index 5e36142cc..0472fdc52 100644
--- a/src/app/formulaire/elements/fieldset.ts
+++ b/src/app/formulaire/elements/fieldset.ts
@@ -1,51 +1,33 @@
 import {
     CalculatorType,
     ParamDefinition,
-    LCMaterial,
-    LoiDebit,
     Props,
     Observer,
     Nub,
-    MethodeResolution,
-    GrilleType,
-    GrilleProfile,
-    BiefRegime,
-    TrigoOperation,
-    TrigoUnit,
-    SPPOperation,
+    Session,
 } from "jalhyd";
 
 import { FormulaireElement } from "./formulaire-element";
 import { Field } from "./field";
 import { SelectField } from "./select-field";
 import { NgParameter, ParamRadioConfig } from "./ngparam";
-import { FormulaireDefinition } from "../definition/form-definition";
 import { StringMap } from "../../stringmap";
-import { FormulaireNode } from "./formulaire-node";
 import { FieldsetContainer } from "./fieldset-container";
 import { SelectFieldNub } from "./select-field-nub";
 import { SelectFieldParameter } from "./select-field-parameter";
+import { FormulaireFixedVar } from "../definition/form-fixedvar";
 
 export class FieldSet extends FormulaireElement implements Observer {
-    /**
-     * Nub associé
-     */
+
+    /** Nub associé */
     private _nub: Nub;
 
-    /**
-     * dictionnaire de traduction
-     */
+    /** dictionnaire de traduction */
     private _localisation: StringMap;
 
-    /**
-     * fichier de configuration
-     */
+    /** fichier de configuration */
     private _jsonConfig: {};
 
-    constructor(parent: FormulaireNode) {
-        super(parent);
-    }
-
     public get nub(): Nub {
         return this._nub;
     }
@@ -185,6 +167,9 @@ export class FieldSet extends FormulaireElement implements Observer {
     }
 
     private parseFields() {
+        // clear everything so that parseFields() is idempotent
+        this.clearFields();
+        // parse children fields from config
         const fields = this._jsonConfig["fields"];
         for (const field_index in fields) {
             let field = fields[field_index];
@@ -245,60 +230,16 @@ export class FieldSet extends FormulaireElement implements Observer {
      * Reflects all properties values in the interface, through the values of the <select> fields
      */
     public updateFields() {
-        this.clearFields();
         this.parseFields();
         this.updateLocalisation();
 
-        // MAJ des selects avec les valeurs actuelles des propriétés
-        // spécifique à chaque modul de calcul, à revoir
-        switch (this._confId) {
-
-            case "fs_ouvrage":
-                this.setSelectValueFromProperty("select_structure", "structureType");
-                this.setSelectValueFromProperty("select_loidebit", "loiDebit");
-                break;
-
-            case "fs_section":
-                // property nodeType is stored in the section, not in the parent Nub
-                this.setSelectValueFromProperty("select_section", "nodeType", true);
-                break;
-
-            case "fs_param_calc":
-                this.setSelectValueFromProperty("select_resolution", "methodeResolution");
-                break;
-
-            case "fs_materiau":
-                this.setSelectValueFromProperty("select_material", "material");
-                break;
-
-            case "fs_target_data": // courbe de remous
-                this.setSelectValueFromProperty("select_target", "varCalc");
-                break;
-
-            case "fs_pass_type": // macro-rugo complexe
-                this.setSelectValueFromProperty("select_pass_type", "inclinedApron");
-                break;
-
-            case "fs_plan": // Grille
-                this.setSelectValueFromProperty("select_grid_type", "gridType");
-                break;
-
-            case "fs_grille": // Grille
-                this.setSelectValueFromProperty("select_grid_profile", "gridProfile");
-                break;
-
-            case "fs_water_line": // Bief
-                this.setSelectValueFromProperty("select_regime", "regime");
-                break;
-
-            case "fs_trigo": // Trigo
-                this.setSelectValueFromProperty("select_operation", "trigoOperation");
-                this.setSelectValueFromProperty("select_unit", "trigoUnit");
-                break;
-
-            case "fs_spp": // SPP
-                this.setSelectValueFromProperty("select_spp_operation", "sppOperation");
-                break;
+        // for all select fields known by the form, set selected value
+        // from associated property
+        if (this.parentForm instanceof FormulaireFixedVar) {
+            const selectIds = this.parentForm.selectids;
+            for (const sId of selectIds) {
+                this.setSelectValueFromProperty(sId, (this._confId === "fs_section"));
+            }
         }
     }
 
@@ -306,10 +247,10 @@ export class FieldSet extends FormulaireElement implements Observer {
      * Reflects a property value in the interface, through the value of a <select> field, if this select exists
      * @param inSection if true, will look for the required property in the Nub's section (children[0])
      */
-    private setSelectValueFromProperty(selectId: string, propertyKey: string, inSection: boolean = false) {
+    private setSelectValueFromProperty(selectId: string, inSection: boolean = false) {
         const selectField: SelectField = this.getFormulaireNodeById(selectId) as SelectField;
         if (selectField) {
-            let propVal: any = this.getPropValue(propertyKey, inSection);
+            let propVal: any = this.getPropValue(selectField.associatedProperty, inSection);
             if (propVal === undefined) {
                 propVal = ""; // clodo bullet-proof loading
             }
@@ -317,26 +258,13 @@ export class FieldSet extends FormulaireElement implements Observer {
             try {
                 selectField.setValue(selectElement);
             } catch (e) {
-                console.error(`setSelectValueFromProperty: cannot set value ${propVal} on <select> ${selectId}`);
+                // silent fail, to avoid errors being thrown in Structure Nubs when
+                // trying to apply same LoiDebit on new StructureType
+                // 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 === undefined)) {
-            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)
@@ -348,23 +276,39 @@ export class FieldSet extends FormulaireElement implements Observer {
         this._confId = json["id"];
         this._helpLink = json["help"];
 
-        const parentForm = this.parentForm as FormulaireDefinition;
         const ct: string = json["calcType"];
         const currentCt = this.properties.getPropValue("calcType");
-        const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : parentForm.calculatorType);
+        const calc_type: CalculatorType = currentCt ? currentCt : (ct ? CalculatorType[ct] : this.parentForm.calculatorType);
         this.setPropValue("calcType", calc_type);
 
-        this.setPropertyValueFromConfig(json, "defaultStructType", "structureType");
-        this.setPropertyValueFromConfig(json, "defaultLoiDebit", "loiDebit", LoiDebit);
-        this.setPropertyValueFromConfig(json, "methodeResolution", "methodeResolution", MethodeResolution);
-        this.setPropertyValueFromConfig(json, "defaultMaterial", "material", LCMaterial);
-        this.setPropertyValueFromConfig(json, "defaultGridProfile", "gridProfile", GrilleProfile);
-        this.setPropertyValueFromConfig(json, "defaultGridType", "gridType", GrilleType);
-        this.setPropertyValueFromConfig(json, "defaultRegime", "regime", BiefRegime);
-        this.setPropertyValueFromConfig(json, "varCalc", "varCalc");
-        this.setPropertyValueFromConfig(json, "defaultOperation", "trigoOperation", TrigoOperation);
-        this.setPropertyValueFromConfig(json, "defaultUnit", "trigoUnit", TrigoUnit);
-        this.setPropertyValueFromConfig(json, "defaultOperation", "sppOperation", SPPOperation);
+        // parse fields once, so that SelectField elements are present
+        // when setting default properties below
+        this.parseFields();
+
+        // for all select fields known by the form, apply default value
+        // to associated property, usually from associated enum
+        if (this.parentForm instanceof FormulaireFixedVar) {
+            const selectIds = this.parentForm.selectids;
+            for (const sId of selectIds) {
+                // find select element in parent form
+                const fe = this.getFormulaireNodeById(sId);
+                if (fe) {
+                    const prop = (fe as SelectField).associatedProperty;
+                    const defaultValue = (fe as SelectField).defaultValue;
+                    // Sets Nub default property, unless this property is already set
+                    const currentValue = this.properties.getPropValue(prop);
+                    if (defaultValue !== undefined && currentValue === undefined) {
+                        let formalValue = defaultValue;
+                        // !! property names must be unique throughout JaLHyd !!
+                        const enumClass = Session.enumFromProperty[prop];
+                        if (enumClass) {
+                            formalValue = enumClass[defaultValue];
+                        }
+                        this.setPropValue(prop, formalValue);
+                    }
+                }
+            }
+        }
 
         this.updateFields();
     }
@@ -416,57 +360,36 @@ export class FieldSet extends FormulaireElement implements Observer {
             switch (data.action) {
                 case "select":
                     const senderId: string = sender.id.replace(/\d+$/, "");
-                    switch (senderId) {
-                        case "select_section": // sections paramétrées, courbes de remous, régimes uniformes
-                            // "nodeType" is a property of the section child, not of the parent
-                            const oldNodeType = this.nub.getChildren()[0].properties.getPropValue("nodeType");
-                            if (oldNodeType !== data.value.value) { // avoid infinite loops
-                                // manually notify parent so that it replaces the child Nub @WARNING clodo trick
-                                this.parentForm.update(this, {
-                                    action: "propertyChange",
-                                    name: "nodeType",
-                                    value: data.value.value
-                                });
+                    if (senderId === "select_section") {
+                        // sections paramétrées, courbes de remous, régimes uniformes
+                        // "nodeType" is a property of the section child, not of the parent
+                        const oldNodeType = this.nub.getChildren()[0].properties.getPropValue("nodeType");
+                        if (oldNodeType !== data.value.value) { // avoid infinite loops
+                            // manually notify parent so that it replaces the child Nub @WARNING clodo trick
+                            this.parentForm.update(this, {
+                                action: "propertyChange",
+                                name: "nodeType",
+                                value: data.value.value
+                            });
+                        }
+                    } else {
+                        // for all select fields known by the form, apply received value
+                        // to associated property
+                        if (this.parentForm instanceof FormulaireFixedVar) {
+                            const selectIds = this.parentForm.selectids;
+                            for (const sId of selectIds) {
+                                if (senderId === sId) {
+                                    // find select element in parent form
+                                    const fe = this.parentForm.getFieldById(sId);
+                                    if (fe) {
+                                        const prop = (fe as SelectField).associatedProperty;
+                                        this.setPropValue(prop, data.value.value);
+                                    }
+                                }
                             }
-                            break;
-                        case "select_structure": // ouvrages parallèles
-                            this.setPropValue("structureType", data.value.value);
-                            break;
-                        case "select_loidebit": // ouvrages parallèles et dérivés
-                            this.setPropValue("loiDebit", data.value.value);
-                            break;
-                        case "select_resolution": // courbes de remous, méthode de résolution
-                            this.setPropValue("methodeResolution", data.value.value);
-                            break;
-                        case "select_target": // courbes de remous, variable à calculer
-                            this.setPropValue("varCalc", data.value.value);
-                            break;
-                        case "select_material": // Lechapt-Calmon, matériau
-                            this.setPropValue("material", data.value.value);
-                            break;
-                        case "select_pass_type": // macro-rugo complexe
-                            this.setPropValue("inclinedApron", data.value.value);
-                            break;
-                        case "select_grid_type": // Grille
-                            this.setPropValue("gridType", data.value.value);
-                            break;
-                        case "select_grid_profile": // Grille
-                            this.setPropValue("gridProfile", data.value.value);
-                            break;
-                        case "select_regime": // Bief
-                            this.setPropValue("regime", data.value.value);
-                            break;
-                        case "select_operation": // Trigo
-                            this.setPropValue("trigoOperation", data.value.value);
-                            break;
-                        case "select_unit": // Trigo
-                            this.setPropValue("trigoUnit", data.value.value);
-                            break;
-                        case "select_spp_operation": // SPP
-                            this.setPropValue("sppOperation", data.value.value);
-                            break;
+                        }
                     }
-                    break;
+                    break; // switch (data.action)
             }
         }
     }
diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts
index 0d98274bb..cfd54a582 100644
--- a/src/app/formulaire/elements/select-field.ts
+++ b/src/app/formulaire/elements/select-field.ts
@@ -1,17 +1,11 @@
 import {
-    BiefRegime,
-    LechaptCalmon,
     acSection,
     CourbeRemous,
     Nub,
     ParallelStructure,
     StructureType,
     LoiDebit,
-    GrilleType,
-    GrilleProfile,
-    TrigoUnit,
-    TrigoOperation,
-    SPPOperation
+    Session
  } from "jalhyd";
 
 import { Field } from "./field";
@@ -29,6 +23,12 @@ export class SelectField extends Field {
 
     protected _selectedEntry: SelectEntry;
 
+    /** name of the Nub property associated to this field, if any */
+    protected _associatedProperty: string;
+
+    /** default value for this field */
+    protected _defaultValue: string;
+
     constructor(parent: FormulaireNode) {
         super(parent);
         this.clearEntries();
@@ -42,6 +42,14 @@ export class SelectField extends Field {
         return this._entries;
     }
 
+    public get associatedProperty(): string {
+        return this._associatedProperty;
+    }
+
+    public get defaultValue(): string {
+        return this._defaultValue;
+    }
+
     public clearEntries() {
         this._entries = [];
     }
@@ -123,34 +131,14 @@ export class SelectField extends Field {
         this._confId = field["id"];
         this._entriesBaseId = this._confId + "_";
         this._helpLink = field["help"];
+        this._associatedProperty = field["property"];
+        this._defaultValue = field["default"];
         const source = field["source"];
+
         const nub: Nub = (this.parentForm as FormulaireDefinition).currentNub;
         // ad-hoc cases
         switch (source) {
-
-            case "lechapt_calmon_material":
-                let i = 0;
-                for (const mat of LechaptCalmon.materials) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + (i + 1), i);
-                    this.addEntry(e);
-                    i++;
-                }
-                break;
-
-            case "acsection_section":
-                for (const sec of acSection.availableSectionTypes) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + sec.id, sec.value);
-                    this.addEntry(e);
-                }
-                break;
-
-            case "remous_methode_resolution":
-                for (const mr of CourbeRemous.availableMethodeResolution) {
-                    const e: SelectEntry = new SelectEntry(this._entriesBaseId + mr.id, mr.value);
-                    this.addEntry(e);
-                }
-                break;
-
+            // driven by string[], not enum (easier for variable names)
             case "remous_target":
                 this.addEntry(new SelectEntry(this._entriesBaseId + "none", ""));
                 for (const at of CourbeRemous.availableTargets) {
@@ -159,6 +147,7 @@ export class SelectField extends Field {
                 }
                 break;
 
+            // possible values depend on CalcType
             case "device_structure_type":
                 for (const st in (nub as ParallelStructure).getLoisAdmissibles()) {
                     const e: SelectEntry = new SelectEntry(this._entriesBaseId + st, StructureType[st]);
@@ -166,6 +155,7 @@ export class SelectField extends Field {
                 }
                 break;
 
+            // possible values depend on CalcType
             case "device_loi_debit":
                 // get current structure type from appropriate Nub child
                 const child = nub.getChildren()[this.parent.indexAsKid()];
@@ -178,43 +168,16 @@ export class SelectField extends Field {
                 }
                 break;
 
-            case "mrc_pass_type": // macrorugo complexe: type de radier
-                this.addEntry(new SelectEntry(this._entriesBaseId + "0", false));
-                this.addEntry(new SelectEntry(this._entriesBaseId + "1", true));
-                break;
-
-            case "grille_type": // Grille: type de grille
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Conventional, GrilleType.Conventional));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Oriented, GrilleType.Oriented));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleType.Inclined, GrilleType.Inclined));
-                break;
-
-            case "grille_profile": // Grille: profil des barreaux
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Rectangular, GrilleProfile.Rectangular));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Hydrodynamic, GrilleProfile.Hydrodynamic));
-                this.addEntry(new SelectEntry(this._entriesBaseId + GrilleProfile.Custom, GrilleProfile.Custom));
-                break;
-
-            case "bief_regime": // Bief: type de régime
-                this.addEntry(new SelectEntry(this._entriesBaseId + BiefRegime.Fluvial, BiefRegime.Fluvial));
-                this.addEntry(new SelectEntry(this._entriesBaseId + BiefRegime.Torrentiel, BiefRegime.Torrentiel));
-                break;
-
-            case "trigo_operation": // Trigo: opération (cos, sin…)
-                for (let j = 0; j < Object.keys(TrigoOperation).length / 2; j++) {
-                    this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
+            // general case : property values taken from an enum
+            default:
+                // find enum associated to property
+                const enumClass = Session.enumFromProperty[this._associatedProperty];
+                if (enumClass !== undefined) {
+                    // add one select entry per enum entry, in the enum order
+                    for (let j = 0; j < Object.keys(enumClass).length / 2; j++) {
+                        this.addEntry(new SelectEntry(this._entriesBaseId + j, j));
+                    }
                 }
-                break;
-
-            case "trigo_unit": // Trigo: unité (degrés, radians)
-                this.addEntry(new SelectEntry(this._entriesBaseId + TrigoUnit.DEG, TrigoUnit.DEG));
-                this.addEntry(new SelectEntry(this._entriesBaseId + TrigoUnit.RAD, TrigoUnit.RAD));
-                break;
-
-            case "spp_operation": // SPP: opération (somme, produit)
-                this.addEntry(new SelectEntry(this._entriesBaseId + SPPOperation.SUM, SPPOperation.SUM));
-                this.addEntry(new SelectEntry(this._entriesBaseId + SPPOperation.PRODUCT, SPPOperation.PRODUCT));
-                break;
         }
 
         this.afterParseConfig();
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index c4dc4ab45..101572ca1 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -29,20 +29,17 @@ import { SelectField } from "../formulaire/elements/select-field";
 import { StringMap } from "../stringmap";
 import { FormulaireSectionParametree } from "../formulaire/definition/form-section-parametree";
 import { FormulaireCourbeRemous } from "../formulaire/definition/form-courbe-remous";
-import { FormulaireRegimeUniforme } from "../formulaire/definition/form-regime-uniforme";
 import { FormulaireParallelStructure } from "../formulaire/definition/form-parallel-structures";
 import { NgParameter } from "../formulaire/elements/ngparam";
 import { FieldsetContainer } from "../formulaire/elements/fieldset-container";
 import { FormulairePab } from "../formulaire/definition/form-pab";
 import { FormulaireMacrorugoCompound } from "../formulaire/definition/form-macrorugo-compound";
-import { FormulaireLechaptCalmon } from "../formulaire/definition/form-lechapt-calmon";
 import { FormulaireGrille } from "../formulaire/definition/form-grille";
-import { FormulaireBief } from "../formulaire/definition/form-bief";
 import { FormulaireSolveur } from "../formulaire/definition/form-solveur";
 import { AppComponent } from "../app.component";
 import { FormulaireSPP } from "../formulaire/definition/form-spp";
-import { FormulaireTrigo } from "../formulaire/definition/form-trigo";
 import { FormulaireFixedVar } from "../formulaire/definition/form-fixedvar";
+import { FormulaireSection } from "../formulaire/definition/form-section";
 
 @Injectable()
 export class FormulaireService extends Observable {
@@ -275,22 +272,15 @@ export class FormulaireService extends Observable {
                 f = new FormulaireSectionParametree();
                 break;
 
+            case CalculatorType.Bief:
             case CalculatorType.RegimeUniforme:
-                f = new FormulaireRegimeUniforme();
+                f = new FormulaireSection();
                 break;
 
             case CalculatorType.CourbeRemous:
                 f = new FormulaireCourbeRemous();
                 break;
 
-            case CalculatorType.Bief:
-                f = new FormulaireBief();
-                break;
-
-            case CalculatorType.LechaptCalmon:
-                f = new FormulaireLechaptCalmon();
-                break;
-
             case CalculatorType.ParallelStructure:
             case CalculatorType.Dever:
             case CalculatorType.Cloisons:
@@ -317,10 +307,6 @@ export class FormulaireService extends Observable {
                 f = new FormulaireSPP();
                 break;
 
-            case CalculatorType.Trigo:
-                f = new FormulaireTrigo();
-                break;
-
             default:
                 f = new FormulaireFixedVar();
         }
-- 
GitLab


From e1630ab2f2f367eb97baf62a0dbfd543507d7f25 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Tue, 28 Jan 2020 11:10:05 +0100
Subject: [PATCH 2/2] update jalhyd_branch

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

diff --git a/jalhyd_branch b/jalhyd_branch
index 1f7391f92..47b2c5e06 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-master
+normalize-for-gui-forms
-- 
GitLab