From 8512d0f7eebb57450f0fd17fd07403dd17b3989d Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Fri, 6 Sep 2019 10:42:02 +0200
Subject: [PATCH] Fix #165 load standard example ssessions

---
 src/app/app.component.ts                      | 38 +++++++++-------
 .../calculator-list.component.html            | 26 ++++++++---
 .../calculator-list.component.scss            | 27 ++++++++++-
 .../calculator-list.component.ts              | 45 ++++++++++++++++++-
 src/app/examples/pab-complete-chain.json      |  1 +
 .../services/formulaire/formulaire.service.ts |  2 +-
 src/app/services/http/http.service.ts         |  7 +++
 src/locale/messages.en.json                   |  3 ++
 src/locale/messages.fr.json                   |  3 ++
 9 files changed, 124 insertions(+), 28 deletions(-)
 create mode 100644 src/app/examples/pab-complete-chain.json

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index f212678cb..81c408864 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -444,7 +444,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
     this.router.navigate(["/list"]);
   }
 
-  private toCalc(id: string) {
+  public toCalc(id: string) {
     this.router.navigate(["/calculator", id]);
     this.setActiveCalc(id);
   }
@@ -484,23 +484,27 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
         if (result.emptySession) {
           this.doEmptySession();
         }
-        this.formulaireService.loadSession(result.file, result.calculators)
-          .then((data) => {
-            if (data.hasErrors) {
-              this.notificationsService.notify(this.intlService.localizeText("ERROR_PROBLEM_LOADING_SESSION"), 3500);
-            } else {
-              if (data.loaded && data.loaded.length > 0) {
-                this.toCalc(data.loaded[0]);
-              }
-            }
-          })
-          .catch((err) => {
-            this.notificationsService.notify(this.intlService.localizeText("ERROR_LOADING_SESSION"), 3500);
-            console.error("error loading session - ", err);
-            // rollback to ensure session is clean
-            this.doEmptySession();
-          });
+        this.loadSessionFile(result.file, result.calculators);
+      }
+    });
+  }
+
+  public loadSessionFile(f: File, info?: any) {
+    this.formulaireService.loadSession(f, info)
+    .then((data) => {
+      if (data.hasErrors) {
+        this.notificationsService.notify(this.intlService.localizeText("ERROR_PROBLEM_LOADING_SESSION"), 3500);
+      } else {
+        if (data.loaded && data.loaded.length > 0) {
+          this.toCalc(data.loaded[0]);
+        }
       }
+    })
+    .catch((err) => {
+      this.notificationsService.notify(this.intlService.localizeText("ERROR_LOADING_SESSION"), 3500);
+      console.error("error loading session - ", err);
+      // rollback to ensure session is clean
+      this.doEmptySession();
     });
   }
 
diff --git a/src/app/components/calculator-list/calculator-list.component.html b/src/app/components/calculator-list/calculator-list.component.html
index 65ea10765..c6422b960 100644
--- a/src/app/components/calculator-list/calculator-list.component.html
+++ b/src/app/components/calculator-list/calculator-list.component.html
@@ -14,12 +14,6 @@
 
         <a href="https://g-eau.fr" target="_blank"><img mat-card-image src="assets/images/logo_geau_m.png"></a>
 
-        <mat-card-actions>
-            <div class="container" fxLayout="column" fxLayoutAlign="left" fxLayoutGap="10px">
-                <button mat-raised-button color="accent" class="theme-calculator"></button>
-            </div>
-        </mat-card-actions>
-
     </mat-card>
 
     <mat-card *ngFor="let theme of items" class="compute-nodes-theme">
@@ -52,4 +46,24 @@
 
     </mat-card>
 
+    <mat-card class="examples-card" *ngIf="nbOpenCalculators === 0">
+
+        <mat-card-header>
+            <mat-card-title>{{ uitextExamplesTitle }}</mat-card-title>
+            <mat-card-subtitle>{{ uitextExamplesSubtitle }}</mat-card-subtitle>
+        </mat-card-header>
+
+        <mat-card-content>
+            <mat-list id="examples-list" role="list">
+              <mat-list-item role="listitem" *ngFor="let f of exampleFiles">
+                <mat-icon color="primary">folder_open</mat-icon>
+                <a class="load-example" (click)="loadExample(f.path)">
+                    {{ f.label }}
+                </a>
+              </mat-list-item>
+            </mat-list>
+        </mat-card-content>
+
+    </mat-card>
+
 </div>
diff --git a/src/app/components/calculator-list/calculator-list.component.scss b/src/app/components/calculator-list/calculator-list.component.scss
index d3dc4658f..368a9971c 100644
--- a/src/app/components/calculator-list/calculator-list.component.scss
+++ b/src/app/components/calculator-list/calculator-list.component.scss
@@ -1,4 +1,4 @@
-mat-card.compute-nodes-theme, mat-card.welcome-card {
+mat-card.compute-nodes-theme, mat-card.welcome-card, mat-card.examples-card {
     width: 300px;
     margin: 1em;
 
@@ -48,10 +48,33 @@ mat-card.compute-nodes-theme, mat-card.welcome-card {
     }
 }
 
-mat-card.welcome-card {
+mat-card.welcome-card, mat-card.examples-card {
 
     .mat-card-content {
         line-height: 1.4em;
         margin-bottom: 3em;
     }
 }
+
+a.load-example {
+    cursor: pointer;
+    padding-top: 1px;
+}
+
+#examples-list {
+    padding-top: 0;
+
+    .mat-list-item {
+        height: 32px;
+        font-size: .9em;
+
+        ::ng-deep .mat-list-item-content {
+            padding-left: 0;
+
+            mat-icon {
+                transform: scale(0.8);
+                margin-right: 5px;
+            }
+        }
+    }
+}
diff --git a/src/app/components/calculator-list/calculator-list.component.ts b/src/app/components/calculator-list/calculator-list.component.ts
index d58d2758e..eb454f10a 100644
--- a/src/app/components/calculator-list/calculator-list.component.ts
+++ b/src/app/components/calculator-list/calculator-list.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from "@angular/core";
+import { Component, OnInit, Inject, forwardRef } from "@angular/core";
 import { Router } from "@angular/router";
 
 import { CalculatorType, EnumEx, Session } from "jalhyd";
@@ -9,6 +9,10 @@ import { I18nService } from "../../services/internationalisation/internationalis
 import { FormulaireParallelStructure } from "../../formulaire/definition/concrete/form-parallel-structures";
 import { FieldsetContainer } from "../../formulaire/fieldset-container";
 import { FormulairePab } from "../../formulaire/definition/concrete/form-pab";
+import { HttpService } from "../../services/http/http.service";
+import { NotificationsService } from "../../services/notifications/notifications.service";
+import { FormulaireService } from "../../services/formulaire/formulaire.service";
+import { AppComponent } from "../../app.component";
 
 
 @Component({
@@ -19,7 +23,14 @@ import { FormulairePab } from "../../formulaire/definition/concrete/form-pab";
 export class CalculatorListComponent implements OnInit {
     private _items: any[];
 
-    constructor(private router: Router) {
+    constructor(
+        @Inject(forwardRef(() => AppComponent)) private appComponent: AppComponent,
+        private router: Router,
+        private httpService: HttpService,
+        private intlService: I18nService,
+        private notificationsService: NotificationsService,
+        private formulaireService: FormulaireService
+    ) {
         ServiceFactory.instance.i18nService.addObserver(this);
         ServiceFactory.instance.applicationSetupService.addObserver(this);
     }
@@ -130,6 +141,28 @@ export class CalculatorListComponent implements OnInit {
         return this._items;
     }
 
+    /**
+     * IMPORTANT: keep in sync with app/examples folder contents
+     */
+    public get exampleFiles() {
+        return [
+            {
+                label: this.intlService.localizeText("INFO_EXAMPLE_LABEL_PAB_COMPLETE"),
+                path: "pab-complete-chain.json"
+            }
+        ];
+    }
+
+    public loadExample(path: string) {
+        const realPath = "app/examples/" + path;
+        this.httpService.httpGetBlobRequestPromise(realPath).then((d) => {
+            const f = new File([d], "fake_filename", { type: "application/json", lastModified: Date.now() });
+            this.appComponent.loadSessionFile(f);
+        }).catch((e) => {
+            console.error("could not load session file", e);
+        });
+    }
+
     public get uitextWelcomeTitle() {
         return "Cassiopée";
     }
@@ -142,6 +175,14 @@ export class CalculatorListComponent implements OnInit {
         return ServiceFactory.instance.i18nService.localizeText("INFO_WELCOME_CONTENT");
     }
 
+    public get uitextExamplesTitle() {
+        return ServiceFactory.instance.i18nService.localizeText("INFO_EXAMPLES_TITLE");
+    }
+
+    public get uitextExamplesSubtitle() {
+        return ServiceFactory.instance.i18nService.localizeText("INFO_EXAMPLES_SUBTITLE");
+    }
+
     public onKC() {
         for (const i of this.items) {
             i.image.path = "assets/images/themes/sp.jpg";
diff --git a/src/app/examples/pab-complete-chain.json b/src/app/examples/pab-complete-chain.json
new file mode 100644
index 000000000..ee99ec0c8
--- /dev/null
+++ b/src/app/examples/pab-complete-chain.json
@@ -0,0 +1 @@
+{"header":{"source":"jalhyd","format_version":"1.1","created":"2019-09-06T08:40:17.092Z"},"session":[{"uid":"NjdmM3","props":{"calcType":"PabChute","nodeType":"None"},"meta":{"title":"PAB : chute"},"children":[],"parameters":[{"symbol":"Z1","mode":"SINGLE","value":29.99},{"symbol":"Z2","mode":"SINGLE","value":26.81},{"symbol":"DH","mode":"CALCUL"}]},{"uid":"eWNjdG","props":{"calcType":"PabNombre","nodeType":"None"},"meta":{"title":"PAB : nombre"},"children":[],"parameters":[{"symbol":"DHT","mode":"LINK","targetNub":"NjdmM3","targetParam":"DH"},{"symbol":"N","mode":"SINGLE","value":14},{"symbol":"DH","mode":"CALCUL"}]},{"uid":"dXM4em","props":{"calcType":"PabPuissance","nodeType":"None"},"meta":{"title":"PAB : puissance"},"children":[],"parameters":[{"symbol":"DH","mode":"LINK","targetNub":"eWNjdG","targetParam":"DH"},{"symbol":"Q","mode":"SINGLE","value":1.8},{"symbol":"V","mode":"CALCUL"},{"symbol":"PV","mode":"SINGLE","value":140}]},{"uid":"bzNlaX","props":{"calcType":"PabDimensions","nodeType":"None"},"meta":{"title":"PAB : dimensions"},"children":[],"parameters":[{"symbol":"L","mode":"SINGLE","value":5},{"symbol":"W","mode":"SINGLE","value":3.6},{"symbol":"Y","mode":"CALCUL"},{"symbol":"V","mode":"LINK","targetNub":"dXM4em","targetParam":"V"}]},{"uid":"cGI5d3","props":{"calcType":"Cloisons","nodeType":"None"},"meta":{"title":"Cloisons"},"children":[{"uid":"ZzZzbD","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"h1","mode":"CALCUL"},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"Q","mode":"LINK","targetNub":"dXM4em","targetParam":"Q"},{"symbol":"Z1","mode":"SINGLE","value":30.14},{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"LINK","targetNub":"bzNlaX","targetParam":"W"},{"symbol":"PB","mode":"SINGLE","value":2.5},{"symbol":"DH","mode":"LINK","targetNub":"eWNjdG","targetParam":"DH"}]},{"uid":"Y3k4bj","props":{"calcType":"Pab"},"meta":{"title":"PAB"},"children":[{"uid":"ampiN3","props":{"calcType":"Cloisons","nodeType":"None"},"children":[{"uid":"Yzgxa2","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":28.085},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":27.413},{"symbol":"ZRAM","mode":"SINGLE","value":27.526},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"c3RmMz","props":{"calcType":"Cloisons","nodeType":"None"},"children":[{"uid":"dmwyem","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.858},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":27.186},{"symbol":"ZRAM","mode":"SINGLE","value":27.299},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"cTlydj","props":{"calcType":"Cloisons","nodeType":"None"},"children":[{"uid":"cWQ5aX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.631},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.959},{"symbol":"ZRAM","mode":"SINGLE","value":27.072},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"emRkMX","props":{"calcType":"Cloisons","nodeType":"None"},"children":[{"uid":"aG1xbj","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.404},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.731},{"symbol":"ZRAM","mode":"SINGLE","value":26.845},{"symbol":"QA","mode":"SINGLE","value":0}]},{"uid":"eG9hdT","props":{"calcType":"Cloisons","nodeType":"None"},"children":[{"uid":"M3Z5ZX","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":27.177},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"LB","mode":"SINGLE","value":4.5},{"symbol":"BB","mode":"SINGLE","value":3.6},{"symbol":"ZRMB","mode":"SINGLE","value":26.504},{"symbol":"ZRAM","mode":"SINGLE","value":26.618},{"symbol":"QA","mode":"SINGLE","value":0}]}],"parameters":[{"symbol":"Q","mode":"SINGLE","value":1.8},{"symbol":"Z1","mode":"CALCUL"},{"symbol":"Z2","mode":"SINGLE","value":28.778}],"downWall":{"uid":"bWExN2","props":{"calcType":"CloisonAval"},"children":[{"uid":"bm0zcD","props":{"calcType":"Structure","structureType":"SeuilRectangulaire","loiDebit":"WeirSubmergedLarinier","nodeType":"None"},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":26.95},{"symbol":"L","mode":"SINGLE","value":0.5},{"symbol":"CdWSL","mode":"SINGLE","value":0.83}]}],"parameters":[{"symbol":"ZRAM","mode":"SINGLE","value":26.391}]}}]}
\ No newline at end of file
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
index 50007ca1d..ceca2ccfb 100644
--- a/src/app/services/formulaire/formulaire.service.ts
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -556,7 +556,7 @@ export class FormulaireService extends Observable {
      * @param f fichier session
      * @param formInfos infos sur les modules de calcul @see DialogLoadSessionComponent.calculators
      */
-    public async loadSession(f: File, formInfos: any[]): Promise<{ hasErrors: boolean, loaded: string[] }> {
+    public async loadSession(f: File, formInfos: any[] = []): Promise<{ hasErrors: boolean, loaded: string[] }> {
         try {
             const s = await this.readSingleFile(f);
             const uids: string[] = [];
diff --git a/src/app/services/http/http.service.ts b/src/app/services/http/http.service.ts
index a103cc5a1..c40b39c95 100644
--- a/src/app/services/http/http.service.ts
+++ b/src/app/services/http/http.service.ts
@@ -31,6 +31,13 @@ export class HttpService {
         return res$.toPromise();
     }
 
+    /**
+     * Lance une requête GET et renvoie une Promise contenant un Blob (File)
+     */
+    public httpGetBlobRequestPromise(path: string): Promise<Blob> {
+        return this.http.get<any>(encodeURI(path), { responseType: "blob" as "json" }).toPromise();
+    }
+
     /**
      * Lance une requête GET (version callbacks)
      * @param processDataCallback callback en cas de succès
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 1729ef3d6..11c625f6d 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -404,6 +404,9 @@
     "INFO_TITREJOURNAL_GLOBAL": "Calculation log synthesis",
     "INFO_WELCOME_CONTENT": "<p>The Cassiopée software was developed by <a href=\"https://www.afbiodiversite.fr\" target=\"_blank\">AFB</a> (French Agency for Biodiversity) and <a href=\"http://g-eau.fr/index.php/en/\" target=\"_blank\">UMR G-EAU</a> (Joint Research Unit \"Water Management, Actors, Territories\").</p><p>It includes tools for designing fish passes, and hydraulic calculation tools useful for environmental and agricultural engineering.</p><p>For more information, consult <a href=\"assets/docs-fr/mentions_legales.html\" target=\"_blank\">legal notice</a> and <a href=\"assets/docs-fr/index.html\" target=\"_blank\">documentation</a>.</p>",
     "INFO_WELCOME_SUBTITLE": "Hydraulic calculators",
+    "INFO_EXAMPLE_LABEL_PAB_COMPLETE": "Standard fish ladder",
+    "INFO_EXAMPLES_TITLE": "Examples",
+    "INFO_EXAMPLES_SUBTITLE": "Load standard examples",
     "WARNING_REMOUS_ARRET_CRITIQUE": "Calculation stopped: critical elevation reached at abscissa %x%",
     "WARNING_STRUCTUREKIVI_HP_TROP_ELEVE": "h/p must not be greater than 2.5. h/p is forced to 2.5",
     "WARNING_STRUCTUREKIVI_PELLE_TROP_FAIBLE": "Threshold height should be greater than 0.1 m. Beta coefficient is forced to 0",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 3234683eb..ed8d1b7f6 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -403,6 +403,9 @@
     "INFO_TITREJOURNAL_GLOBAL": "Synthèse du journal de calcul",
     "INFO_WELCOME_CONTENT": "<p>Le logiciel Cassiopée a été développé par l'<a href=\"https://www.afbiodiversite.fr\" target=\"_blank\">AFB</a> (Agence Française pour la Biodiversité) et <a href=\"http://g-eau.fr\" target=\"_blank\">L'UMR G-EAU</a> (UMR Gestion de l'Eau, Acteurs, Usages).</p><p>Il regroupe des outils d'aide à la conception de passes à poissons et des outils de calcul hydraulique utiles pour l'ingénierie en environnement et agriculture.</p><p>Pour plus d'informations, consulter les <a href=\"assets/docs-fr/mentions_legales.html\" target=\"_blank\">mentions légales</a> et la <a href=\"assets/docs-fr/index.html\" target=\"_blank\">documentation</a>.</p>",
     "INFO_WELCOME_SUBTITLE": "Modules de calcul d'hydraulique",
+    "INFO_EXAMPLE_LABEL_PAB_COMPLETE": "Passe à bassins type",
+    "INFO_EXAMPLES_TITLE": "Exemples",
+    "INFO_EXAMPLES_SUBTITLE": "Charger des exemples types",
     "WARNING_REMOUS_ARRET_CRITIQUE": "Arrêt du calcul&nbsp;: hauteur critique atteinte à l'abscisse %x%",
     "WARNING_STRUCTUREKIVI_HP_TROP_ELEVE": "h/p ne doit pas être supérieur à 2,5. h/p est forcé à 2,5",
     "WARNING_STRUCTUREKIVI_PELLE_TROP_FAIBLE": "La pelle du seuil doit mesurer au moins 0,1 m. Le coefficient béta est forcé à 0",
-- 
GitLab