diff --git a/src/app/app.component.ts b/src/app/app.component.ts index f212678cbc22fa3da7af19be0df9ea9c2bb4e9d5..81c40886460268f630071911c75dd08461aea709 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 65ea10765799050325d4527513b944282a5db5ab..c6422b9602f65a755c972714ea1f02e1224e3618 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 d3dc4658f07ed98dafd7082a60ea01fa5a99cbd2..368a9971c14e1924ead0e3f41cc5a2bdf9052bdb 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 d58d2758e6b4c99f450a63ce4b63589e60513537..eb454f10a3c1dd1af454c53281dc7ff97aefc4c8 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 0000000000000000000000000000000000000000..ee99ec0c84eb4ae574ea2e265a18a22517ca8d9c --- /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 50007ca1dc17ac258350f177d302c0a58e8d8085..ceca2ccfbccb74207b80379ddf37d8f29831a618 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 a103cc5a11d8e70ecc79386b2b7261e062129fde..c40b39c9517d695d47a987615cc27e773e74b3b4 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 1729ef3d6c8bb4887f8c26f58ed55a31d7434627..11c625f6d4a055e6792b3c2ba152a93cef9eb869 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 3234683ebf4a8fb444a0b9d99f45cd4acbca4993..ed8d1b7f6fd5543f898383d2508350f0b6d04e09 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 : 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",