diff --git a/.gitignore b/.gitignore index 5bd2d8af3276d30225062d5cddfe237c0578176d..d484f6a04277b6d27baea18c96717919acad33b7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /src/assets/docs /release /build +/docs/pdf_build # dependencies /node_modules diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed146e000f40c2e3b3874a3c1241896787708e44..92811cedb1fad95a05865e51acd895e050f929ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,19 +79,34 @@ test: script: - npm run e2e -build: +.build: stage: build - only: - - pushes - - tags - - schedules - - web artifacts: expire_in: 10 min paths: - dist/ script: - - npm run build + # -baseref option is used by npm to set the npm_config_basehref environment variable + # used in package.json + - npm run build-href -basehref=$BASEHREF + +build-dev: + extends: .build + only: + - tags + - pushes + - schedules + - web + variables: + BASEHREF: "/cassiopee/$CI_COMMIT_REF_NAME/" + +build-prod: + extends: .build + only: + - tags + - devel + variables: + BASEHREF: "/" clean-stale-branches: stage: clean-stale-branches @@ -109,7 +124,7 @@ deploy-dev: - tags - web dependencies: - - build + - build-dev script: # Copie de la branche / du tag - ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH @@ -120,7 +135,7 @@ deploy-ovh-dev: only: - devel dependencies: - - build + - build-prod script: # Copie de la branche / du tag - ./scripts/deploy-version.sh prod-devel $PROD_LOGIN $PROD_HOST $PROD_DEV_PATH @@ -131,7 +146,7 @@ deploy-prod: variables: - $CI_COMMIT_REF_NAME == "stable" dependencies: - - build + - build-prod script: - ./scripts/deploy-version.sh prod $PROD_LOGIN $PROD_HOST $PROD_PATH diff --git a/README.md b/README.md index 5750c79b6ba0413eaaf5bd25fba416d4790817f8..0fc8a9725a79ebaa03c2684ef07a93917538361a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Requirements for developping Cassiopee can be achieved by manually install the r * npm * python3 * pandoc ^2 (optional, for PDF documentation only) - * texlive (optional, for PDF documentation only) + * texlive, texlive-bibtex-extra, texlive-latex-extra, latexmk (optional, for PDF documentation only) Building the HTML documentation requires MkDocs and some extensions: diff --git a/e2e/calculate-linked-params.e2e-spec.ts b/e2e/calculate-linked-params.e2e-spec.ts index 12e68d423b9cdda3373f74cabd60824086cfb91e..7c54f5af436fb313519b1919e95a5a6a923afd8a 100644 --- a/e2e/calculate-linked-params.e2e-spec.ts +++ b/e2e/calculate-linked-params.e2e-spec.ts @@ -5,6 +5,7 @@ import { Navbar } from "./navbar.po"; import { SideNav } from "./sidenav.po"; import { browser, by } from "protractor"; import { PreferencesPage } from "./preferences.po"; +import { changeSelectValue } from "./util.po"; /** * Uses an example configuration to calculate : @@ -62,7 +63,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y = calcPage.getInputById("Y"); await calcPage.setParamMode(Y, "link"); const sel = await calcPage.getLinkedValueSelect(Y); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); await computeAndCheckPresenceOfResults(); }); @@ -79,7 +80,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y = calcPage.getInputById("Y"); await calcPage.setParamMode(Y, "link"); const sel = await calcPage.getLinkedValueSelect(Y); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); // vary W const W = calcPage.getInputById("W"); await calcPage.setParamMode(W, "var"); @@ -102,7 +103,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y2 = calcPage.getInputById("Y"); await calcPage.setParamMode(Y2, "link"); const sel = await calcPage.getLinkedValueSelect(Y2); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); await computeAndCheckPresenceOfResults(); }); @@ -122,7 +123,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y2 = calcPage.getInputById("Y"); await calcPage.setParamMode(Y2, "link"); const sel = await calcPage.getLinkedValueSelect(Y2); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); await computeAndCheckPresenceOfResults(); }); @@ -142,7 +143,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y2 = calcPage.getInputById("Y"); await calcPage.setParamMode(Y2, "link"); const sel = await calcPage.getLinkedValueSelect(Y2); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); // vary W const W = calcPage.getInputById("W"); await calcPage.setParamMode(W, "var"); @@ -168,7 +169,7 @@ describe("ngHyd − calculate with linked parameters", () => { const Y2 = calcPage.getInputById("Y"); await calcPage.setParamMode(Y2, "link"); const sel = await calcPage.getLinkedValueSelect(Y2); - await calcPage.changeSelectValue(sel, 0); + await changeSelectValue(sel, 0); await computeAndCheckPresenceOfResults(); }); diff --git a/e2e/calculator.po.ts b/e2e/calculator.po.ts index af1e1803ce378ba967def9837500ece6da58a434..12c5a8de42cace9dad88a7905d233e0091842aeb 100644 --- a/e2e/calculator.po.ts +++ b/e2e/calculator.po.ts @@ -331,13 +331,6 @@ export class CalculatorPage { return calcButton; } - async changeSelectValue(elt: ElementFinder, index: number) { - await elt.click(); - const optionId = ".cdk-overlay-container mat-option:nth-of-type(" + (index + 1) + ")"; - const option = element(by.css(optionId)); - await option.click(); - } - // find parent element of elt having class "container" async findParentContainer(elt: ElementFinder): Promise<ElementFinder> { let i = 8; // garde fous diff --git a/e2e/cloisons.e2e-spec.ts b/e2e/cloisons.e2e-spec.ts index 2febdc57e4263fb9d97e1466736b8e2699942cf9..f251afabc8b8c7d4c8c81773ea3c8bcc8c56d277 100644 --- a/e2e/cloisons.e2e-spec.ts +++ b/e2e/cloisons.e2e-spec.ts @@ -3,6 +3,7 @@ import { CalculatorPage } from "./calculator.po"; import { browser } from "protractor"; import { Navbar } from "./navbar.po"; import { PreferencesPage } from "./preferences.po"; +import { changeSelectValue } from "./util.po"; /** * Cloisons - différents tests qui n'ont pas tant de rapport que ça avec les cloisons :) @@ -44,7 +45,7 @@ describe("ngHyd − cloisons", () => { await browser.sleep(300); // 4. change LoiDebit - await calcPage.changeSelectValue(calcPage.getSelectById("select_loidebit"), 1); + await changeSelectValue(calcPage.getSelectById("select_loidebit"), 1); await browser.sleep(300); // 5. check number of inputs in CALC mode diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts index 038a90e661a28a6526a9b143f407842f3bed4329..a63f565b0fb43630cb3c5f88fb4b91926629e528 100644 --- a/e2e/clone-calc.e2e-spec.ts +++ b/e2e/clone-calc.e2e-spec.ts @@ -4,7 +4,7 @@ import { CalculatorPage } from "./calculator.po"; import { Navbar } from "./navbar.po"; import { browser } from "protractor"; import { PreferencesPage } from "./preferences.po"; -import { scrollPageToTop } from "./util.po"; +import { changeSelectValue, scrollPageToTop } from "./util.po"; /** * Clone calculators @@ -54,7 +54,7 @@ describe("ngHyd − clone a calculator", () => { k: 0.6, Ks: 42 }; - await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique" + await changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique" await calcPage.getInputById("k").clear(); await calcPage.getInputById("k").sendKeys(sourceValues["k"]); await calcPage.getInputById("Ks").clear(); @@ -63,7 +63,7 @@ describe("ngHyd − clone a calculator", () => { const debitSP = calcPage.getInputById("Q"); await calcPage.setParamMode(debitSP, "link"); await browser.sleep(500); - await calcPage.changeSelectValue(calcPage.getSelectById("linked_Q"), 1); // "Courbe de remous" + await changeSelectValue(calcPage.getSelectById("linked_Q"), 1); // "Courbe de remous" await browser.sleep(500); // otherwise clickCloneCalcButton() fails with "Element is not clickable at point" diff --git a/e2e/examples-empty-fields.e2e-spec.ts b/e2e/examples-empty-fields.e2e-spec.ts index 08f40c467f44678244027dbcd7487e56c16dc6aa..3a8d3942cd6594c7bc3e367d9128597809980e77 100644 --- a/e2e/examples-empty-fields.e2e-spec.ts +++ b/e2e/examples-empty-fields.e2e-spec.ts @@ -3,6 +3,7 @@ import { CalculatorPage } from "./calculator.po"; import { ListPage } from "./list.po"; import { Navbar } from "./navbar.po"; import { PreferencesPage } from "./preferences.po" +import { changeSelectValue } from "./util.po"; /** * check that fields are empty on creation @@ -60,7 +61,7 @@ describe("ngHyd - Check that examples fields are not empty with 'empty fields on // modify 1st structure discharge law const dischargeSelect = calcPage.getSelectById("select_loidebit"); - await calcPage.changeSelectValue(dischargeSelect, 1); + await changeSelectValue(dischargeSelect, 1); await browser.sleep(200); // open initial dialog diff --git a/e2e/lechapt-calmon.e2e-spec.ts b/e2e/lechapt-calmon.e2e-spec.ts index 91dea3194e5d9ffa11790e9d417080e556ea8ab2..f3be14a59a0fde635a339a8cc469c8048ffb23a5 100644 --- a/e2e/lechapt-calmon.e2e-spec.ts +++ b/e2e/lechapt-calmon.e2e-spec.ts @@ -3,6 +3,7 @@ import { browser, by } from "protractor"; import { CalculatorPage } from "./calculator.po"; import { PreferencesPage } from "./preferences.po"; import { Navbar } from "./navbar.po"; +import { changeSelectValue } from "./util.po"; /** * Check that created/cloned structures have empty fields when @@ -45,7 +46,7 @@ describe("Lechapt&Calmon - ", () => { // select last material type const materialSelect = calcPage.getSelectById("select_material"); - await calcPage.changeSelectValue(materialSelect, 8); + await changeSelectValue(materialSelect, 8); await browser.sleep(200); // run calculation @@ -58,7 +59,7 @@ describe("Lechapt&Calmon - ", () => { const pl1 = await res1.all(by.css("td")).get(1).getText(); // select first material type - await calcPage.changeSelectValue(materialSelect, 0); + await changeSelectValue(materialSelect, 0); await browser.sleep(200); // run calculation diff --git a/e2e/linked-parameter-section-type.e2e-spec.ts b/e2e/linked-parameter-section-type.e2e-spec.ts index b42c13d0f8ad8249514e3880592938bd726888bb..a863f273ed3f66ba5c4e19eeb2f14b02e2fd5134 100644 --- a/e2e/linked-parameter-section-type.e2e-spec.ts +++ b/e2e/linked-parameter-section-type.e2e-spec.ts @@ -3,6 +3,7 @@ import { ListPage } from "./list.po"; import { Navbar } from "./navbar.po"; import { PreferencesPage } from "./preferences.po"; import { CalculatorPage } from "./calculator.po"; +import { changeSelectValue } from "./util.po"; describe("linked parameter in calculator with section - ", () => { let listPage: ListPage; @@ -42,7 +43,7 @@ describe("linked parameter in calculator with section - ", () => { await calcPage.setParamMode(inputQ, "link"); // change section type - await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique" + await changeSelectValue(calcPage.getSelectById("select_section"), 3); // mode "parabolique" // check Q is still in linked mode expect(await calcPage.inputIsInLinkedMode(inputQ)).toBe(true); diff --git a/e2e/load-save-session.e2e-spec.ts b/e2e/load-save-session.e2e-spec.ts index 436058e6f6ffc4d54e716b1680c22b6b8dc9de18..8689c6f13a7510026cff21608aefa1ff663ee5cd 100644 --- a/e2e/load-save-session.e2e-spec.ts +++ b/e2e/load-save-session.e2e-spec.ts @@ -5,7 +5,7 @@ import { Navbar } from "./navbar.po"; import { SideNav } from "./sidenav.po"; import { browser, by, element } from "protractor"; import { PreferencesPage } from "./preferences.po"; -import { expectNumber } from "./util.po"; +import { changeSelectValue, expectNumber } from "./util.po"; const fs = require("fs"); const path = require("path"); @@ -122,7 +122,7 @@ describe("ngHyd − save and load sessions", () => { await listPage.clickMenuEntryForCalcType(2); // Section paramétrée await browser.sleep(500); - await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); // mode "trapezoidal" + await changeSelectValue(calcPage.getSelectById("select_section"), 2); // mode "trapezoidal" await calcPage.getInputById("Ks").clear(); // coefficient de Strickler await browser.sleep(1000); @@ -190,7 +190,7 @@ describe("ngHyd − save and load sessions", () => { // select next select option (optionally looping) const nextInd = (ind + 1) % optionCount; - await calcPage.changeSelectValue(sel, nextInd); + await changeSelectValue(sel, nextInd); await browser.sleep(200); // save session diff --git a/e2e/ouvrages-empty-fields.e2e-spec.ts b/e2e/ouvrages-empty-fields.e2e-spec.ts index 4a28316f8c5a2001f778241fd31c211da1d00fec..918107e2c8a980f573a5cced40dbfe6dbfa2ed67 100644 --- a/e2e/ouvrages-empty-fields.e2e-spec.ts +++ b/e2e/ouvrages-empty-fields.e2e-spec.ts @@ -4,6 +4,7 @@ import { CalculatorPage } from "./calculator.po"; import { AppPage } from "./app.po"; import { PreferencesPage } from "./preferences.po"; import { Navbar } from "./navbar.po"; +import { changeSelectValue } from "./util.po"; /** * Check that created/cloned structures have empty fields when @@ -51,7 +52,7 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () // change 1st structure type to rectangular weir const structSelect = calcPage.getSelectById("select_structure"); - await calcPage.changeSelectValue(structSelect, 1); + await changeSelectValue(structSelect, 1); await browser.sleep(200); // check 1st structure empty fields @@ -91,7 +92,7 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () // change 1st structure type to rectangular weir const structSelect = calcPage.getSelectById("select_structure"); - await calcPage.changeSelectValue(structSelect, 1); + await changeSelectValue(structSelect, 1); await browser.sleep(200); // copy structure @@ -102,7 +103,7 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () // change 2nd structure type to rectangular gate const selects = await element.all(by.css("mat-select#select_structure")); const structSelect2 = selects[1]; - await calcPage.changeSelectValue(structSelect2, 5); + await changeSelectValue(structSelect2, 5); await browser.sleep(200); // check empty fields @@ -135,12 +136,12 @@ describe("ngHyd - check that created/cloned structures have empty fields - ", () // change 1st structure type to rectangular weir const structSelect = calcPage.getSelectById("select_structure"); - await calcPage.changeSelectValue(structSelect, 1); + await changeSelectValue(structSelect, 1); await browser.sleep(200); // change discharge law to Larinier const dischargeSelect = calcPage.getSelectById("select_loidebit"); - await calcPage.changeSelectValue(dischargeSelect, 3); + await changeSelectValue(dischargeSelect, 3); await browser.sleep(200); // check empty fields diff --git a/e2e/pab.e2e-spec.ts b/e2e/pab.e2e-spec.ts index 866f67fb57da855a5c8ce10d407efd3da5616ffc..edcdd97504ef4be2502413318d40266a8680beb5 100644 --- a/e2e/pab.e2e-spec.ts +++ b/e2e/pab.e2e-spec.ts @@ -5,7 +5,7 @@ import { browser, by, element } from "protractor"; import { AppPage } from "./app.po"; import { SideNav } from "./sidenav.po"; import { PreferencesPage } from "./preferences.po"; -import { scrollPageToTop } from "./util.po"; +import { changeSelectValue, scrollPageToTop } from "./util.po"; /** * Clone calculators @@ -297,7 +297,7 @@ describe("ngHyd − Passe à Bassins", () => { // change iteration const pve = calcPage.getSelectById("pab-variating-element"); - calcPage.changeSelectValue(pve, 3); + await changeSelectValue(pve, 3); await browser.sleep(300); // check absence of logs expect(await calcPage.nbLogEntries()).toBe(2); diff --git a/e2e/preferences.po.ts b/e2e/preferences.po.ts index 264ebb84fdc7f9ab570bb8524e7f61ccd26adb02..39604b8cbc5cf02b2644a058c342b032d61813da 100644 --- a/e2e/preferences.po.ts +++ b/e2e/preferences.po.ts @@ -1,4 +1,5 @@ import { browser, by, element, ElementFinder } from "protractor"; +import { changeSelectValue } from "./util.po"; export class PreferencesPage { navigateTo() { @@ -43,10 +44,7 @@ export class PreferencesPage { async changeLanguage(index: number) { const select = this.getLanguageSelect(); - await select.click(); - const optionId = ".cdk-overlay-container mat-option#mat-option-" + index; - const option = element(by.css(optionId)); - await option.click(); + await changeSelectValue(select, index); } async enableEvilEmptyFields() { @@ -65,6 +63,23 @@ export class PreferencesPage { } } + /** + * enable/disable option "empty fields on module creation" + * @param b true to enable "empty fields on module creation" option, false to disable it (fill fields with default values) + */ + async setEmptyFields(b: boolean) { + await this.navigateTo(); + await browser.sleep(200); + + if (b) { + await this.enableEvilEmptyFields(); + } + else { + await this.disableEvilEmptyFields(); + } + await browser.sleep(200); + } + async setIterationCount(n: number) { const input = this.getInputFromName("nmi"); input.clear(); diff --git a/e2e/pressure-loss-empty-fields.e2e-spec.ts b/e2e/pressure-loss-empty-fields.e2e-spec.ts index c4516a88bdeeb74f95eed96b4897f2641dd4f6a5..59eb87c641d01eeae71004f1b2cd07b5523625a5 100644 --- a/e2e/pressure-loss-empty-fields.e2e-spec.ts +++ b/e2e/pressure-loss-empty-fields.e2e-spec.ts @@ -3,6 +3,7 @@ import { Navbar } from "./navbar.po"; import { browser } from "protractor"; import { CalculatorPage } from "./calculator.po"; import { PreferencesPage } from "./preferences.po"; +import { changeSelectValue } from "./util.po"; describe("Check fields are empty in 'pressure loss' calculator when created with 'empty fields' option -", () => { let listPage: ListPage; @@ -32,7 +33,7 @@ describe("Check fields are empty in 'pressure loss' calculator when created with // select Lechapt-Calmon pressure loss law const materialSelect = calcPage.getSelectById("select_pressurelosstype"); - await calcPage.changeSelectValue(materialSelect, 0); + await changeSelectValue(materialSelect, 0); await browser.sleep(200); expect(calcPage.checkEmptyOrFilledFields(["Q", "D", "Lg", "Kloc"], [true, true, true, true])); diff --git a/e2e/remous.e2e-spec.ts b/e2e/remous.e2e-spec.ts index d13ccd48bd73cfea28a4b94f39b7243579f7b073..342d35edb63c03d52c0d0b8a60c86fcc00730d2d 100644 --- a/e2e/remous.e2e-spec.ts +++ b/e2e/remous.e2e-spec.ts @@ -4,6 +4,7 @@ import { browser } from "protractor"; import { Navbar } from "./navbar.po"; import { PreferencesPage } from "./preferences.po"; import { SideNav } from "./sidenav.po"; +import { changeSelectValue } from "./util.po"; /** * Remous @@ -59,7 +60,7 @@ describe("ngHyd − remous", () => { await browser.sleep(300); // 2. Set to trapezoidal section with bank slope of 2m/m and 20 meter width bed - await calcPage.changeSelectValue(calcPage.getSelectById("select_section"), 2); + await changeSelectValue(calcPage.getSelectById("select_section"), 2); await browser.sleep(300); await calcPage.getInputById("LargeurFond").clear(); await browser.sleep(300); diff --git a/e2e/solveur.e2e-spec.ts b/e2e/solveur.e2e-spec.ts index 89ca70d6ed4b357ddf9999ae61b08f9b4c4e5a9c..afe88721eb9b32753d9db0ec05fb40e0727c0a82 100644 --- a/e2e/solveur.e2e-spec.ts +++ b/e2e/solveur.e2e-spec.ts @@ -5,7 +5,7 @@ import { Navbar } from "./navbar.po"; import { browser, by, element } from "protractor"; import { SideNav } from "./sidenav.po"; import { PreferencesPage } from "./preferences.po"; -import { scrollPageToTop } from "./util.po"; +import { changeSelectValue, scrollPageToTop } from "./util.po"; /** * Clone calculators @@ -76,7 +76,7 @@ describe("Solveur - ", () => { expect(hasResults).toBe(true); // change targetted Nub, check that targetted result changes too - await calcPage.changeSelectValue(ntc, 0); + await changeSelectValue(ntc, 0); const nttV2 = await calcPage.getSelectValueText(ntt); expect(nttV2).not.toContain("Puissance dissipée (PV)"); }); @@ -111,9 +111,9 @@ describe("Solveur - ", () => { // Go back to Solveur await navbar.clickCalculatorTab(0); - await calcPage.changeSelectValue(calcPage.getSelectById("select_target_nub"), 1); // "Puissance / PV" + await changeSelectValue(calcPage.getSelectById("select_target_nub"), 1); // "Puissance / PV" await browser.sleep(500); - await calcPage.changeSelectValue(calcPage.getSelectById("select_searched_param"), 2); // "Chute / Z2" + await changeSelectValue(calcPage.getSelectById("select_searched_param"), 2); // "Chute / Z2" await browser.sleep(500); await calcPage.getInputById("Ytarget").sendKeys("318"); @@ -159,7 +159,7 @@ describe("Solveur - ", () => { // modify searched parameter const sel = calcPage.getSelectById("select_searched_param"); - await calcPage.changeSelectValue(sel, 11); + await changeSelectValue(sel, 11); await browser.sleep(300); const selText = await calcPage.getSelectValueText(sel); diff --git a/e2e/translation.e2e-spec.ts b/e2e/translation.e2e-spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0118eac98d93955aed19f0d537b59320f505001 --- /dev/null +++ b/e2e/translation.e2e-spec.ts @@ -0,0 +1,97 @@ +import { ListPage } from "./list.po"; +import { Navbar } from "./navbar.po"; +import { browser, by } from "protractor"; +import { CalculatorPage } from "./calculator.po"; +import { PreferencesPage } from "./preferences.po"; +import { SideNav } from "./sidenav.po"; + +describe("Check translation", () => { + let listPage: ListPage; + let navBar: Navbar; + let calcPage: CalculatorPage; + let prefPage: PreferencesPage; + let sideNav: SideNav; + + beforeAll(async () => { + listPage = new ListPage(); + navBar = new Navbar(); + calcPage = new CalculatorPage(); + prefPage = new PreferencesPage(); + sideNav = new SideNav(); + }); + + beforeEach(async () => { + prefPage.setEmptyFields(false); + }); + + it("variables in results", async () => { + // *** results in french *** + + prefPage.changeLanguage(1); // fr + await browser.sleep(200); + + // open "fish ladder: fall" calculator + await navBar.clickNewCalculatorButton(); + await listPage.clickMenuEntryForCalcType(12); + await browser.sleep(200); + + // set Z2 to variated mode + const inpZ2 = calcPage.getInputById("Z2"); + await calcPage.setParamMode(inpZ2, "var"); + + // run calculation + await calcPage.getCalculateButton().click(); + await browser.sleep(500); + + // "variable for X axis" select label + const selXaxis = calcPage.getSelectById("selectX"); + expect(await calcPage.getMatselectCurrentOptionText(selXaxis)).toEqual("Cote aval"); + + // "variable for Y axis" select label + const selYaxis = calcPage.getSelectById("selectY"); + expect(await calcPage.getMatselectCurrentOptionText(selYaxis)).toEqual("DH : Chute (m)"); + + // fixed results variables + const frr = calcPage.getAllFixedResultsRows(); + let lbl1 = await frr.all(by.css("td")).get(0).getText(); + expect(lbl1).toEqual("Cote amont (m)"); + + // variated results headers + const vrh = calcPage.getAllVariatedResultsTableHeaders(); + let lbl2 = await vrh.get(0).getText(); + expect(lbl2).toEqual("Cote aval"); + let lbl3 = await vrh.get(1).getText(); + expect(lbl3).toEqual("Chute (m)"); + + // *** results in english *** + + // setup -> english + await navBar.clickMenuButton(); + await browser.sleep(200); + const setupBtn = await sideNav.getSetupButton(); + await setupBtn.click(); + await browser.sleep(200); + await prefPage.changeLanguage(0); // en + await browser.sleep(200); + + // back to calculator + await navBar.clickCalculatorTab(0); + await browser.sleep(200); + + // "variable for X axis" select label + expect(await calcPage.getMatselectCurrentOptionText(selXaxis)).toEqual("Downstream elevation"); + + // "variable for Y axis" select label + expect(await calcPage.getMatselectCurrentOptionText(selYaxis)).toEqual("DH : Fall (m)"); + + // fixed results variables + lbl1 = await frr.all(by.css("td")).get(0).getText(); + expect(lbl1).toEqual("Upstream elevation (m)"); + + // variated results headers + lbl2 = await vrh.get(0).getText(); + expect(lbl2).toEqual("Downstream elevation"); + lbl3 = await vrh.get(1).getText(); + expect(lbl3).toEqual("Fall (m)"); + }); +}); diff --git a/e2e/util.po.ts b/e2e/util.po.ts index e772a28ce9c01e0c54f85d0bce84a01df90e7ac5..aded71c166c96b6914bff75af3f3fa4fe409185f 100644 --- a/e2e/util.po.ts +++ b/e2e/util.po.ts @@ -1,4 +1,4 @@ -import { ElementFinder, browser } from "protractor"; +import { ElementFinder, browser, by, element } from "protractor"; /** * scroll page to make element visible @@ -27,3 +27,11 @@ export function expectNumber(msg: string, val: number, expected: number) { } expect(val).toEqual(expected); } + +export async function changeSelectValue(elt: ElementFinder, index: number) { + await elt.click(); + const optionId = ".cdk-overlay-container mat-option:nth-of-type(" + (index + 1) + ")"; + const option = element(by.css(optionId)); + await option.click(); + await browser.sleep(200); +} diff --git a/package.json b/package.json index 47e5d03490ed4a741f99a9d11dc7693f057d9ff7..b7cf7d4e8781930a18da8e1cc310cc48ecc3db55 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "preprocess": "mkdir -p build; node scripts/preprocessors.js; npm run service-worker-version; bash scripts/fix-chartjs-plugin-zoom-2.0.0.sh", "start": "npm run preprocess && npm run mkdocs && npm run ng serve -- --host 0.0.0.0 --poll 5000", "build-no-pdf": "npm run preprocess && npm run mkdocs && npm run ng build -- --configuration production", - "build": "npm run preprocess && npm run mkdocs && npm run ng build -- --configuration production && npm run mkdocs2pdf", + "build": "npm run build-href -basehref=/", + "build-href": "npm run preprocess && npm run mkdocs && npm run ng build -- --configuration production --base-href=$npm_config_basehref && npm run mkdocs2pdf", "update-dist-index-mimetypes": "node scripts/update-dist-index-mimetypes.js", "electron": "npm run update-dist-index-mimetypes && \"node_modules/.bin/electron\" .", "release-linux-nocompile": "npm run update-dist-index-mimetypes && \"node_modules/.bin/electron-builder\"", diff --git a/scripts/deploy-version.sh b/scripts/deploy-version.sh index 4221e281bf9a84801c54b96417c6fb24955543e7..4d5bd0687b2b11ebc1bce1b92ee80aa979e0f399 100755 --- a/scripts/deploy-version.sh +++ b/scripts/deploy-version.sh @@ -35,10 +35,6 @@ echo "$(basename $0): deploying version $VERSION in $LOGIN@$HOST:$DIR" if [[ $VERSION == "prod" || $VERSION == "prod-devel" ]]; then display_local_href - # Modification du dossier base href -> / - echo "updating index.html base href to /" - sed -i '/<base/s/href="[^"]*"/href="\/"/' $LOCAL_DIR/index.html - # Copie de la branche production rsync -a --delete --exclude=cassiopee-releases -e "ssh -o StrictHostKeyChecking=no" $LOCAL_DIR/ ${LOGIN}@${HOST}:${DIR}/ @@ -46,10 +42,6 @@ if [[ $VERSION == "prod" || $VERSION == "prod-devel" ]]; then else display_local_href - # Modification du dossier base href -> /cassiopee/version/ - echo "updating index.html base href to /cassiopee/$VERSION/" - sed -i "/<base/s/href=\"[^\"]*\"/href=\"\/cassiopee\/$VERSION\/\"/" $LOCAL_DIR/index.html - # Copie de la branche / du tag rsync -a --delete --exclude=cassiopee-releases -e "ssh -o StrictHostKeyChecking=no" $LOCAL_DIR/ "$LOGIN@$HOST:$DIR/$VERSION" diff --git a/scripts/mkdocs2pdf.py b/scripts/mkdocs2pdf.py index 6e3cf68040aa15e43debd48019a955e3e13d9b2a..37deb6a8f52ef1d99b61ccf8f1b618790e3fa4a2 100644 --- a/scripts/mkdocs2pdf.py +++ b/scripts/mkdocs2pdf.py @@ -20,6 +20,9 @@ import yaml import re import shutil +# verbose output +verbose = False + baseDir = os.getcwd() buildDir = os.path.join(baseDir, 'build') latexSourceDir = os.path.join(baseDir, 'docs/latex') @@ -38,6 +41,21 @@ def runCommand(cmd): if os.waitstatus_to_exitcode(os.system(cmd)) != 0: raise RuntimeError("error executing:",cmd) +# Create a symbolic link +def createLink(src): + # check if destination already exists + dest = os.path.basename(src) + if os.path.exists(dest): + if not os.path.islink(dest): + raise Exception('{} exists but is not a symbolic link'.format(dest)) + else: + runCommand('ln -s {}'.format(src)) + +def createEmptyDir(path): + if os.path.exists(path): + shutil.rmtree(path) + os.makedirs(path) + # Reads an MkDocs configuration file def readConfig(sYAML): f = open(sYAML, 'r') @@ -130,9 +148,14 @@ def convertMdToTex(filePath): def getLatexModel(): # Clone Git repository os.chdir(pdfBuildDir) - runCommand( - 'git clone {} {}'.format(latexModelRepository, latexModelDir) - ) + if os.path.isdir(latexModelDir): + # git directory exists, update it + os.chdir(latexModelDir) + runCommand('git pull') + # platform independent "cd .." + os.chdir(os.path.dirname(os.getcwd())) + else: + runCommand('git clone {} {}'.format(latexModelRepository, latexModelDir)) # back to original working drectory os.chdir(baseDir) @@ -146,35 +169,17 @@ def injectContentIntoModel(mergedDocFilenameTex, lang): # Symlink necessary resources os.chdir(modelDir) relPathToMergedTexDoc = os.path.join('..', mergedDocFilenameTex) - runCommand( - 'ln -s {} .'.format(relPathToMergedTexDoc) - ) + createLink(relPathToMergedTexDoc) latexTemplate = filenamePrefix + lang + '.tex' relPathToLatexTemplate = os.path.join(latexSourceDir, latexTemplate) - runCommand( - 'ln -s {}'.format(relPathToLatexTemplate) - ) - runCommand( - 'ln -s {}'.format(os.path.join(latexSourceDir, 'logo_pole.png')) - ) - runCommand( - 'ln -s {}/schema_rugosite_fond.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')) - ) - runCommand( - 'ln -s {}/bloc_cylindre.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')) - ) - runCommand( - 'ln -s {}/bloc_face_arrondie.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')) - ) - runCommand( - 'ln -s {}/bloc_base_carree.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')) - ) - runCommand( - 'rm rapport_inrae/logos.tex' - ) - runCommand( - 'ln -s {} rapport_inrae/'.format(os.path.join(latexSourceDir, 'logos.tex')) - ) + createLink(relPathToLatexTemplate) + createLink(os.path.join(latexSourceDir, 'logo_pole.png')) + createLink('{}/schema_rugosite_fond.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))) + createLink('{}/bloc_cylindre.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))) + createLink('{}/bloc_face_arrondie.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))) + createLink('{}/bloc_base_carree.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))) + runCommand('rm rapport_inrae/logos.tex') + createLink('{} rapport_inrae/'.format(os.path.join(latexSourceDir, 'logos.tex'))) # back to original working drectory os.chdir(baseDir) @@ -189,9 +194,11 @@ def buildPDF(lang): cvt = os.path.join(buildDir, 'cassiopee_version.tex') shutil.copy(cvt, modelDir) - os.system( - 'latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null 2>&1'.format(sourceTexFile) - ) + if verbose: + os.system('latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null'.format(sourceTexFile)) + else: + os.system('latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null 2>&1'.format(sourceTexFile)) + # copy generated PDF to release directory shutil.copy(outputPdfFile, outputDir) # back to original working drectory @@ -201,9 +208,9 @@ def buildPDF(lang): def buildDocForLang(lang): # Prepare temporary build directory - os.makedirs(pdfBuildDir, exist_ok=True) + createEmptyDir(pdfBuildDir) # Prepare output directory - os.makedirs(outputDir, exist_ok=True) + createEmptyDir(outputDir) # Read config yamlPath = 'mkdocs/mkdocs-' + lang + '.yml' diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d11194ecab2f9f8c1b5ed14ec25d6a671bc1bf23..0e1044ac651ec31ebd7d38d288ab52741aaea25c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -22,7 +22,7 @@ import { DialogSaveSessionComponent } from "./components/dialog-save-session/dia import { QuicknavComponent } from "./components/quicknav/quicknav.component"; import { NotificationsService } from "./services/notifications.service"; -import { decodeHtml } from "./util"; +import { decodeHtml } from "./util/util"; import { HotkeysService, Hotkey } from "angular2-hotkeys"; @@ -33,6 +33,8 @@ import { saveAs } from "file-saver"; import * as XLSX from "xlsx"; import * as pako from "pako"; +import { DialogConfirmComponent } from "./components/dialog-confirm/dialog-confirm.component"; +import { UserConfirmationService } from "./services/user-confirmation.service"; import { ServiceWorkerUpdateService } from "./services/service-worker-update.service"; @Component({ @@ -85,13 +87,16 @@ export class AppComponent implements OnInit, OnDestroy, Observer { private confirmCloseCalcDialog: MatDialog, private hotkeysService: HotkeysService, private matomoTracker: MatomoTracker, - private serviceWorkerUpdateService: ServiceWorkerUpdateService + private confirmDialog: MatDialog, + private serviceWorkerUpdateService: ServiceWorkerUpdateService, + private userConfirmationService: UserConfirmationService ) { ServiceFactory.httpService = httpService; ServiceFactory.applicationSetupService = appSetupService; ServiceFactory.i18nService = intlService; ServiceFactory.formulaireService = formulaireService; ServiceFactory.notificationsService = notificationsService; + ServiceFactory.serviceWorkerUpdateService = serviceWorkerUpdateService; if (!isDevMode()) { // évite de mettre en place un bandeau RGPD @@ -218,10 +223,24 @@ export class AppComponent implements OnInit, OnDestroy, Observer { ngOnInit() { this.formulaireService.addObserver(this); this._innerWidth = window.innerWidth; + this.logRevisionInfo(); + + // Initialise communication with UserConfirmationService. + // When receiving a message from it, open a dialog to ask user to confirm. + // Will then reply to UserConfirmationService with a message holding confirmation status. + this.userConfirmationService.subscribe(this); + this.userConfirmationService.addHandler(this, { + next: (data) => this.displayConfirmationDialog(data["title"], data["body"]), + error: () => { }, + complete: () => { }, + }); } ngOnDestroy() { this.formulaireService.removeObserver(this); + + // cancel communication link with UserConfirmationService + this.userConfirmationService.unsubscribe(this); } @HostListener("window:resize", ["$event"]) @@ -670,6 +689,12 @@ export class AppComponent implements OnInit, OnDestroy, Observer { }; } + private logRevisionInfo() { + const ri = this.revisionInfo; + console.log("JaLHyd", ri.jalhyd.date, ri.jalhyd.version); + console.log("ngHyd", ri.nghyd.date, ri.nghyd.version); + } + /** * sauvegarde du/des formulaires * @param form formulaire à sélectionner par défaut dans la liste @@ -809,4 +834,24 @@ export class AppComponent implements OnInit, OnDestroy, Observer { } } } + + /** + * display a confirmation display upon request from UserConfirmationService + */ + private displayConfirmationDialog(title: string, text: string) { + const dialogRef = this.confirmDialog.open( + DialogConfirmComponent, + { + data: { + title: title, + text: text + }, + disableClose: true + } + ); + dialogRef.afterClosed().subscribe(result => { + // reply to UserConfirmationService + this.userConfirmationService.postConfirmation(this, { "confirm": result }); + }); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 15eac95408a49c29f830397b606d7f95990029fc..5c912764c5e680f134109936abe3681c7d0de46d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -96,6 +96,7 @@ import { JetTrajectoryChartComponent } from "./components/jet-trajectory-chart/j import { SessionPropertiesComponent } from "./components/session-properties/session-properties.component"; import { VerificateurResultsComponent } from "./components/verificateur-results/verificateur-results.component"; +import { DialogConfirmComponent } from "./components/dialog-confirm/dialog-confirm.component"; import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-close-calc/dialog-confirm-close-calc.component"; import { DialogEditPabComponent } from "./components/dialog-edit-pab/dialog-edit-pab.component"; @@ -127,6 +128,7 @@ import { SelectSectionDetailsComponent } from "./components/select-section-detai import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; import { ServiceWorkerUpdateService } from "./services/service-worker-update.service"; +import { UserConfirmationService } from "./services/user-confirmation.service"; const appRoutes: Routes = [ { path: "list/search", component: CalculatorListComponent }, @@ -208,6 +210,7 @@ const appRoutes: Routes = [ CalculatorResultsComponent, DialogConfirmCloseCalcComponent, DialogConfirmEmptySessionComponent, + DialogConfirmComponent, DialogEditPabComponent, DialogEditParamComputedComponent, DialogEditParamValuesComponent, @@ -282,7 +285,8 @@ const appRoutes: Routes = [ provide: ErrorStateMatcher, useClass: ImmediateErrorStateMatcher }, - ServiceWorkerUpdateService + ServiceWorkerUpdateService, + UserConfirmationService ], schemas: [NO_ERRORS_SCHEMA], bootstrap: [AppComponent] diff --git a/src/app/components/dialog-confirm/dialog-confirm.component.html b/src/app/components/dialog-confirm/dialog-confirm.component.html new file mode 100644 index 0000000000000000000000000000000000000000..1de1a1bae3d8e2d2cee34ed52dd36424283dc39f --- /dev/null +++ b/src/app/components/dialog-confirm/dialog-confirm.component.html @@ -0,0 +1,12 @@ +<h1 mat-dialog-title [innerHTML]="uitextTitle"></h1> +<div mat-dialog-content> + <p [innerHTML]="uitextBody"></p> +</div> +<div mat-dialog-actions [attr.align]="'end'"> + <button id="cancel" mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial> + {{ uitextNo }} + </button> + <button id="confirm" mat-raised-button color="warn" [mat-dialog-close]="true"> + {{ uitextYes }} + </button> +</div> diff --git a/src/app/components/dialog-confirm/dialog-confirm.component.ts b/src/app/components/dialog-confirm/dialog-confirm.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8cefaa2526ec20077f992157001690ec99e5c16 --- /dev/null +++ b/src/app/components/dialog-confirm/dialog-confirm.component.ts @@ -0,0 +1,38 @@ +import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; +import { Inject, Component } from "@angular/core"; +import { I18nService } from "../../services/internationalisation.service"; + +@Component({ + selector: "dialog-confirm", + templateUrl: "dialog-confirm.component.html", +}) +export class DialogConfirmComponent { + + private _title: string; + private _text: string; + + constructor( + public dialogRef: MatDialogRef<DialogConfirmComponent>, + private intlService: I18nService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { + this._title = data.title; + this._text = data.text; + } + + public get uitextYes() { + return this.intlService.localizeText("INFO_OPTION_YES"); + } + + public get uitextNo() { + return this.intlService.localizeText("INFO_OPTION_NO"); + } + + public get uitextTitle() { + return this._title; + } + + public get uitextBody() { + return this._text; + } +} diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts index 16768e9c0715efc77bbf7b50d2c4d6b45d3e64ea..47790963b1c2fd3b83d065621b01b1c2326a026a 100644 --- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts +++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.ts @@ -10,7 +10,7 @@ import { sprintf } from "sprintf-js"; import { ParamValueMode, ExtensionStrategy } from "jalhyd"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; import { ServiceFactory } from "app/services/service-factory"; @Component({ diff --git a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts index b7aaf61d72def9cd99d15fec5b95d62666de2614..554bc994357a9496566c3ad921f6ec8f4b8176f1 100644 --- a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts +++ b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts @@ -3,7 +3,7 @@ import { Inject, Component } from "@angular/core"; import { I18nService } from "../../services/internationalisation.service"; import { MultiDimensionResults } from "../../results/multidimension-results"; -import { fv, longestVarParam } from "../../util"; +import { fv, longestVarParam } from "../../util/util"; @Component({ selector: "dialog-generate-par-simulation", diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts index 448d40a7dc63bfcd47dbec4e10bdb29ba884e857..62b39960f24fd4f2e18e1d4c95c9e5b8dda162c1 100644 --- a/src/app/components/field-set/field-set.component.ts +++ b/src/app/components/field-set/field-set.component.ts @@ -16,7 +16,7 @@ import { I18nService } from "../../services/internationalisation.service"; import { sprintf } from "sprintf-js"; import { capitalize } from "jalhyd"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; @Component({ selector: "field-set", diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts index 042df751799ed61418e5b9a869e2277cb627110d..e07c6514d5088587c89b402db5c6cca6088bc7e7 100644 --- a/src/app/components/fieldset-container/fieldset-container.component.ts +++ b/src/app/components/fieldset-container/fieldset-container.component.ts @@ -6,7 +6,7 @@ import { FieldSet } from "../../formulaire/elements/fieldset"; import { FormulaireDefinition } from "../../formulaire/definition/form-definition"; import { I18nService } from "../../services/internationalisation.service"; import { ApplicationSetupService } from "../../services/app-setup.service"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; import { ParamValueMode } from "jalhyd"; @Component({ diff --git a/src/app/components/fixedvar-results/results.component.ts b/src/app/components/fixedvar-results/results.component.ts index ae9747dbe0e9f0b4843d4ccb9292105cf295e86f..18b08975073117647fc2b4e3fbfd1e94e5e81a1c 100644 --- a/src/app/components/fixedvar-results/results.component.ts +++ b/src/app/components/fixedvar-results/results.component.ts @@ -2,7 +2,7 @@ import screenfull from "screenfull"; import { NgParameter } from "../../formulaire/elements/ngparam"; import { ServiceFactory } from "../../services/service-factory"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; import { CalculatorResults } from "../../results/calculator-results"; import { Directive, HostListener } from "@angular/core"; diff --git a/src/app/components/fixedvar-results/var-results.component.ts b/src/app/components/fixedvar-results/var-results.component.ts index 7493401d2776c1760fbe9c616232aa62ceefecea..f48623acc22a3df02f2a972a5ba0a7b227c93683 100644 --- a/src/app/components/fixedvar-results/var-results.component.ts +++ b/src/app/components/fixedvar-results/var-results.component.ts @@ -1,14 +1,14 @@ -import { Component, ViewChild, ElementRef, Input } from "@angular/core"; +import { Component, ViewChild, ElementRef, Input, OnInit } from "@angular/core"; import { MatDialog } from "@angular/material/dialog"; import { VarResults } from "../../results/var-results"; -import { ResultElement, Message, MessageSeverity } from "jalhyd"; +import { ResultElement, Message, MessageSeverity, Observer } from "jalhyd"; import { I18nService } from "../../services/internationalisation.service"; import { ResultsComponentDirective } from "./results.component"; import { DialogLogEntriesDetailsComponent } from "../dialog-log-entries-details/dialog-log-entries-details.component"; import { AppComponent } from "../../app.component"; -import { longestVarParam } from "../../../app/util"; +import { longestVarParam } from "../../../app/util/util"; @Component({ selector: "var-results", @@ -17,7 +17,7 @@ import { longestVarParam } from "../../../app/util"; "./var-results.component.scss" ] }) -export class VarResultsComponent extends ResultsComponentDirective { +export class VarResultsComponent extends ResultsComponentDirective implements Observer, OnInit { /** size of the longest variated parameter */ public size: number; @@ -42,12 +42,17 @@ export class VarResultsComponent extends ResultsComponentDirective { protected logEntriesDetailsDialog: MatDialog ) { super(); + this.intlService.addObserver(this); } /** Refreshes results and builds the dataset */ @Input() public set results(r: VarResults) { this._varResults = r; + this.updateResults(); + } + + private updateResults() { this._results = []; this._headers = []; this._messages = []; @@ -190,4 +195,16 @@ export class VarResultsComponent extends ResultsComponentDirective { } ); } + + ngOnInit(): void { + this._varResults.updateCalculatedParameterHeader(); + } + + // Observer interface + + update(sender: any, data: any): void { + if (sender instanceof I18nService) { + this._varResults.update(); + } + } } diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 49e81d946b6216bb123c23a0c64dea8c32cbe730..23f71a54d7850d590d8c0aff6729585eccb0ee69 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -28,7 +28,7 @@ import { ParallelStructure } from "jalhyd"; -import { generateValuesCombination, getUnformattedIthResult, getUnformattedIthValue } from "../../util"; +import { generateValuesCombination, getUnformattedIthResult, getUnformattedIthValue } from "../../util/util"; import { AppComponent } from "../../app.component"; import { FormulaireService } from "../../services/formulaire.service"; @@ -62,7 +62,7 @@ import { sprintf } from "sprintf-js"; import * as XLSX from "xlsx"; import { ServiceFactory } from "app/services/service-factory"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; import { FormulaireCourbeRemous } from "app/formulaire/definition/form-courbe-remous"; import { RemousResults } from "app/results/remous-results"; @@ -1259,7 +1259,7 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe const form = this._formulaire as FormulaireFixedVar; const nub = (form.currentNub as Espece); nub.loadPredefinedSpecies(result.selected); - form.refreshFieldsets(); + form.refreshFieldsets(false); } }); } diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts index d95168143cb67edb5fff3ffe00586e65fe60ad4f..281a11332a7c288641ab2719a9f18a1d11c9ccf2 100644 --- a/src/app/components/generic-input/generic-input.component.ts +++ b/src/app/components/generic-input/generic-input.component.ts @@ -5,7 +5,7 @@ import { FormulaireDefinition } from "../../formulaire/definition/form-definitio import { NgParameter } from "../../formulaire/elements/ngparam"; import { I18nService } from "../../services/internationalisation.service"; import { ApplicationSetupService } from "../../services/app-setup.service"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; /** * classe de gestion générique d'un champ de saisie avec titre, validation et message d'erreur diff --git a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts index 5bd87e2bb12d5177c109a493bcc92517bef823ce..bf4e084e134588c955fd4da70e1a8de96b82808c 100644 --- a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts +++ b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.ts @@ -5,7 +5,7 @@ import { BaseChartDirective } from "ng2-charts"; import { I18nService } from "../../services/internationalisation.service"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { IYSeries } from "../../results/y-series"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; import { AppComponent } from "../../app.component"; import { Jet, Result } from "jalhyd"; 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 f388647dafbcf7d653fcffd263b87d3dfff40718..039681e3c0195eb26e976b2d3b6ab31fd3189534 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 @@ -2,7 +2,7 @@ import { Component, Input } from "@angular/core"; import { Result, cLog, Message, MessageCode, MessageSeverity, MRCInclination } from "jalhyd"; -import { fv } from "../../../app/util"; +import { fv } from "../../../app/util/util"; import { CalculatorResults } from "../../results/calculator-results"; import { NgParameter } from "../../formulaire/elements/ngparam"; diff --git a/src/app/components/modules-diagram/modules-diagram.component.ts b/src/app/components/modules-diagram/modules-diagram.component.ts index 0b607e51e10e25cb2f5505c3e1bdf0993dfcffe5..0ec435a0739a6691b60d18390aab60a0f4227fdc 100644 --- a/src/app/components/modules-diagram/modules-diagram.component.ts +++ b/src/app/components/modules-diagram/modules-diagram.component.ts @@ -33,7 +33,7 @@ import * as SvgPanZoom from "svg-pan-zoom"; import { MatomoTracker } from "@ngx-matomo/tracker"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; @Component({ selector: "modules-diagram", diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts index ee664e43ad59b3c77bd6e000921cbb11d8c32ea6..11aca1b4046fb5c4b0119cf4a5c87b4a56f41b20 100644 --- a/src/app/components/pab-profile-chart/pab-profile-chart.component.ts +++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.ts @@ -6,7 +6,7 @@ import { I18nService } from "../../services/internationalisation.service"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { PabResults } from "../../results/pab-results"; import { IYSeries } from "../../results/y-series"; -import { fv, longestVarParam } from "../../util"; +import { fv, longestVarParam } from "../../util/util"; import { AppComponent } from "../../app.component"; import { CloisonAval, Cloisons, LoiDebit } from "jalhyd"; diff --git a/src/app/components/pab-results/pab-results-table.component.ts b/src/app/components/pab-results/pab-results-table.component.ts index b541cdc52e332f6cde19abc74c9c9730db870fd8..b2b36a8368d34de4fa186b699152db63e9602442 100644 --- a/src/app/components/pab-results/pab-results-table.component.ts +++ b/src/app/components/pab-results/pab-results-table.component.ts @@ -6,7 +6,7 @@ import { PabResults } from "../../results/pab-results"; import { I18nService } from "../../services/internationalisation.service"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { AppComponent } from "../../app.component"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; @Component({ selector: "pab-results-table", diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index f06c1b536c27ea4cd2c0d434cd3d416723c16f1a..a3919284b434408c8eee278ea30c551f93d90996 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -28,7 +28,7 @@ import { PabTable } from "../../formulaire/elements/pab-table"; import { DialogEditPabComponent } from "../dialog-edit-pab/dialog-edit-pab.component"; import { AppComponent } from "../../app.component"; import { NgParameter, ParamRadioConfig } from "../../formulaire/elements/ngparam"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; /** * The big editable data grid for calculator type "Pab" (component) diff --git a/src/app/components/pb-results/pb-cloison-results.component.ts b/src/app/components/pb-results/pb-cloison-results.component.ts index 0a59b6a8b1f0581e7ff07e706f24459e6e7df5ce..da3aae4ba32983e163a9096fdf1db300ea78aab3 100644 --- a/src/app/components/pb-results/pb-cloison-results.component.ts +++ b/src/app/components/pb-results/pb-cloison-results.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from "@angular/core"; import { FixedResultsComponent } from "../fixedvar-results/fixed-results.component"; import { NgParameter } from "../../formulaire/elements/ngparam"; -import { getIthValue } from "../../util"; +import { getIthValue } from "../../util/util"; import { PbCloisonResults } from "../../results/pb-cloison-results"; import { Result, ResultElement } from "jalhyd"; diff --git a/src/app/components/pb-results/pb-results-table.component.ts b/src/app/components/pb-results/pb-results-table.component.ts index 79084192dd3b7b5e0477157ea06f3e8a09b1e5c9..9e1315d86f6d1f8608f728389431494d1065d239 100644 --- a/src/app/components/pb-results/pb-results-table.component.ts +++ b/src/app/components/pb-results/pb-results-table.component.ts @@ -5,7 +5,7 @@ import { PreBarrage, PbBassin } from "jalhyd"; import { I18nService } from "../../services/internationalisation.service"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { AppComponent } from "../../app.component"; -import { fv, getIthValue } from "../../util"; +import { fv, getIthValue } from "../../util/util"; import { PrebarrageResults } from "../../results/prebarrage-results"; @Component({ diff --git a/src/app/components/pb-schema/pb-schema.component.ts b/src/app/components/pb-schema/pb-schema.component.ts index 6de70eecd8ddf7c49d2c45a200a9ae6a6cf0a009..ef424b22fd24c3c88efd3680c3d0250f38ba1512 100644 --- a/src/app/components/pb-schema/pb-schema.component.ts +++ b/src/app/components/pb-schema/pb-schema.component.ts @@ -18,9 +18,9 @@ import { GenericCalculatorComponent } from "../generic-calculator/calculator.com import { FormulairePrebarrage } from "../../formulaire/definition/form-prebarrage"; import { AppComponent } from "../../app.component"; -import { fv } from "app/util"; +import { fv } from "app/util/util"; import { ServiceFactory } from "app/services/service-factory"; -import { DefinedBoolean } from "app/definedvalue/definedboolean"; +import { DefinedBoolean } from "../../util/definedvalue/definedboolean"; import { PrebarrageService, PrebarrageServiceEvents } from "app/services/prebarrage.service"; /** diff --git a/src/app/components/remous-results/remous-results.component.ts b/src/app/components/remous-results/remous-results.component.ts index 1f5ea4b720bfcb4bbf0ccbd85f42bde4dc582540..2fd73ae1e13f3ecb6b1b9444b07e0800ca6435f8 100644 --- a/src/app/components/remous-results/remous-results.component.ts +++ b/src/app/components/remous-results/remous-results.component.ts @@ -9,7 +9,7 @@ import { FormulaireService } from "../../services/formulaire.service"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { AppComponent } from "../../app.component"; import { LineData, ChartData } from "./line-and-chart-data"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; import { VarResults } from "../../results/var-results"; import { BaseChartDirective } from "ng2-charts"; diff --git a/src/app/components/results-chart/chart-type.component.ts b/src/app/components/results-chart/chart-type.component.ts index 39839c3a96cb2feea1c220ebbf415e2855263880..123657c5173e1f09900f327f140c4cdd6eb3dc65 100644 --- a/src/app/components/results-chart/chart-type.component.ts +++ b/src/app/components/results-chart/chart-type.component.ts @@ -4,7 +4,7 @@ import { I18nService } from "../../services/internationalisation.service"; import { ChartType } from "../../results/chart-type"; import { SelectFieldChartType } from "app/formulaire/elements/select/select-field-charttype"; import { SelectEntry } from "app/formulaire/elements/select/select-entry"; -import { decodeHtml } from "../../util"; +import { decodeHtml } from "../../util/util"; @Component({ selector: "chart-type", diff --git a/src/app/components/results-chart/results-chart.component.ts b/src/app/components/results-chart/results-chart.component.ts index 0b33967f3c45ae7766943a382b9db32fc3593ed7..a52719212a258e15957e4f8d27e586345f77474a 100644 --- a/src/app/components/results-chart/results-chart.component.ts +++ b/src/app/components/results-chart/results-chart.component.ts @@ -11,7 +11,7 @@ import { ChartType } from "../../results/chart-type"; import { ResultsComponentDirective } from "../fixedvar-results/results.component"; import { IYSeries } from "../../results/y-series"; import { VarResults } from "../../results/var-results"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; import { AppComponent } from "../../app.component"; import zoomPlugin from 'chartjs-plugin-zoom'; @@ -182,6 +182,10 @@ export class ResultsChartComponent extends ResultsComponentDirective implements } public ngOnChanges() { + if (this._results instanceof VarResults) { + this._results.updateCalculatedParameterHeader(); + } + // redessiner le graphique chaque fois qu'une entrée change this.drawChart(); } diff --git a/src/app/components/select-field-line/select-field-line.component.ts b/src/app/components/select-field-line/select-field-line.component.ts index c6b2474a0f08e795ac58514bb58486d127e4ecdb..7c4b067efcece001ba65882f713c0e286d660f48 100644 --- a/src/app/components/select-field-line/select-field-line.component.ts +++ b/src/app/components/select-field-line/select-field-line.component.ts @@ -4,7 +4,7 @@ import { SelectField } from "../../formulaire/elements/select/select-field"; import { SelectEntry } from "../../formulaire/elements/select/select-entry"; import { I18nService } from "../../services/internationalisation.service"; import { ApplicationSetupService } from "../../services/app-setup.service"; -import { decodeHtml } from "../../util"; +import { decodeHtml } from "../../util/util"; @Component({ selector: "select-field-line", diff --git a/src/app/components/select-section-details/select-section-details.component.ts b/src/app/components/select-section-details/select-section-details.component.ts index 55c21b523cead45096bfc15f39d2d733043aad92..278ce4bdca3d2ead89a5354807f4266b1f4171a0 100644 --- a/src/app/components/select-section-details/select-section-details.component.ts +++ b/src/app/components/select-section-details/select-section-details.component.ts @@ -3,7 +3,7 @@ import { Router } from '@angular/router'; import { FormulaireDefinition } from 'app/formulaire/definition/form-definition'; import { FormulaireService } from 'app/services/formulaire.service'; import { I18nService } from 'app/services/internationalisation.service'; -import { fv } from 'app/util'; +import { fv } from 'app/util/util'; import { formattedValue } from 'jalhyd'; /** diff --git a/src/app/components/variable-results-selector/variable-results-selector.component.ts b/src/app/components/variable-results-selector/variable-results-selector.component.ts index 0d68b44573e4177fb943019a8516944fdbc94162..50c4a0d968df136c66c0f25f9391c0c2a5688820 100644 --- a/src/app/components/variable-results-selector/variable-results-selector.component.ts +++ b/src/app/components/variable-results-selector/variable-results-selector.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnChanges } from "@angular/core"; import { I18nService } from "../../services/internationalisation.service"; -import { fv, longestVarParam } from "../../util"; +import { fv, longestVarParam } from "../../util/util"; import { MultiDimensionResults } from "../../results/multidimension-results"; import { VariatedDetails } from "jalhyd"; import { CalculatorResults } from "../../results/calculator-results"; diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 9acb17e78dea09b3bf132dd208e12ffecbf7a4cb..c6b05ea1ba0dd4a3fe92354006e6d8eeb4a95a5d 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -346,11 +346,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs } /** - * Trouve le Ngparameter correspondant au symbole "symbol", parmi tous les - * éléments du formulaire - * @param symbol string + * Trouve le NgParameter correspondant au paramètre Nub parmi tous les éléments du formulaire + * @param param paramètre critère de recherche */ - public getParamFromSymbol(param: ParamDefinition): NgParameter { + private getNgparamFromNubParam(param: ParamDefinition): NgParameter { for (const p of this.allFormElements) { if (p instanceof NgParameter) { if (p.symbol === param.symbol && p.paramDefinition.parentNub.uid === param.parentNub.uid) { @@ -360,6 +359,14 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs } } + public getOrCreateParam(nubParam: ParamDefinition, parent: FormulaireNode): NgParameter { + const res = this.getNgparamFromNubParam(nubParam); + if (res === undefined) { + return new NgParameter(nubParam, parent); + } + return res; + } + public getFieldById(id: string): Field { const res = this.getFormulaireNodeById(id); if (res instanceof Field) { @@ -532,14 +539,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs protected getComputedParameter(): NgParameter { const cpd = this.currentNub.calculatedParam; - let ngparam: NgParameter; if (cpd !== undefined) { - ngparam = this.getParamFromSymbol(cpd); - if (ngparam === undefined) { // calculated parameter is not displayed on screen - ngparam = new NgParameter(cpd, this); - } + return this.getOrCreateParam(cpd, this); } - return ngparam; + return undefined; } /** find variated (possibly linked) parameters from model, and get their values at the same time */ @@ -552,7 +555,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs const fixedParams: ParamDefinition[] = this._currentNub.findFixedParams(); let fnp: NgParameter[] = []; for (const fp of fixedParams) { - fnp.push(this.getParamFromSymbol(fp)); + fnp.push(this.getNgparamFromNubParam(fp)); } fnp = fnp.filter((e) => e !== undefined); return fnp; diff --git a/src/app/formulaire/definition/form-fixedvar.ts b/src/app/formulaire/definition/form-fixedvar.ts index 8eb6917e75496d210925a4bd8ab355c6ece3e107..f20ce41fef290508de47d54f63fb72b826792e4d 100644 --- a/src/app/formulaire/definition/form-fixedvar.ts +++ b/src/app/formulaire/definition/form-fixedvar.ts @@ -82,8 +82,7 @@ export class FormulaireFixedVar extends FormulaireDefinition { protected compute() { this.runNubCalc(this.currentNub); - this.refreshFieldsets(); // important: before reaffectResultComponents() or it will break results components localization - // this.reaffectResultComponents(); // seems useless since called from runNubCalc() + this.reaffectResultComponents(); } protected reaffectResultComponents() { @@ -115,9 +114,9 @@ export class FormulaireFixedVar extends FormulaireDefinition { /** * Forces all fieldsets to update all their fields */ - public refreshFieldsets() { + public refreshFieldsets(forceClear: boolean) { for (const fs of this.allFieldsets) { - fs.updateFields(); + fs.updateFields(forceClear); } this.completeParse(false); // re-add observers that were destroyed by updateFields() } @@ -130,7 +129,7 @@ export class FormulaireFixedVar extends FormulaireDefinition { if (data.action === "propertyChange") { this.reset(); // reflect changes in GUI (who knows ?), for ex. show / hide dependent fields - this.refreshFieldsets(); + this.refreshFieldsets(true); } } } diff --git a/src/app/formulaire/definition/form-macrorugo-compound.ts b/src/app/formulaire/definition/form-macrorugo-compound.ts index 306332cb56def101c15cd82afcb095fb06aa4fb3..5dd33e865c4dada32d3de547e0f9d7696423b6a3 100644 --- a/src/app/formulaire/definition/form-macrorugo-compound.ts +++ b/src/app/formulaire/definition/form-macrorugo-compound.ts @@ -84,7 +84,7 @@ export class FormulaireMacrorugoCompound extends FormulaireRepeatableFieldset { */ public updateApronState(inclined: MRCInclination) { // show / hide dependent fields (read from model) - this.refreshFieldsets(); + this.refreshFieldsets(false); // show / hide children list (GUI only) for (const elt of this.allFormElements) { if (elt instanceof FieldsetContainer) { diff --git a/src/app/formulaire/definition/form-pab.ts b/src/app/formulaire/definition/form-pab.ts index 85f423501196014b5198c27d9e5a6a243524e796..d27a620927df68c68c2789250112d8889d7dbd93 100644 --- a/src/app/formulaire/definition/form-pab.ts +++ b/src/app/formulaire/definition/form-pab.ts @@ -3,7 +3,7 @@ import { Pab, Result, VariatedDetails } from "jalhyd"; import { FormulaireDefinition } from "./form-definition"; import { PabResults } from "../../results/pab-results"; import { NgParameter } from "../elements/ngparam"; -import { longestVarParam } from "../../util"; +import { longestVarParam } from "../../util/util"; import { PabTable } from "../elements/pab-table"; /** diff --git a/src/app/formulaire/definition/form-prebarrage.ts b/src/app/formulaire/definition/form-prebarrage.ts index c9a0d9e0db35efb7ff665b637520798032944bf6..fbccdec66c8b788bb59508949aa2bd2b7c5413a5 100644 --- a/src/app/formulaire/definition/form-prebarrage.ts +++ b/src/app/formulaire/definition/form-prebarrage.ts @@ -9,7 +9,7 @@ import { FieldsetContainer } from "../elements/fieldset-container"; import { CalculatorResults } from "../../results/calculator-results"; import { PrebarrageResults } from "../../results/prebarrage-results"; import { NgParameter } from "../elements/ngparam"; -import { longestVarParam } from "../../util"; +import { longestVarParam } from "../../util/util"; import { FormulaireNode } from "../elements/formulaire-node"; /** @@ -239,7 +239,7 @@ export class FormulairePrebarrage extends FormulaireFixedVar { protected compute() { this.runNubCalc(this.currentNub); - this.refreshFieldsets(); // important: before reaffectResultComponents() or it will break results components localization + this.refreshFieldsets(false); // important: before reaffectResultComponents() or it will break results components localization // reset variable index to avoid trying to access an index > 0 when nothing varies this._pbResults.variableIndex = 0; diff --git a/src/app/formulaire/definition/form-pressureloss.ts b/src/app/formulaire/definition/form-pressureloss.ts index 26c862355f9b7d5f572d022379d73c0f27e4e982..9260bc79ae47f9098291a57b6ef35efb2d3c3409 100644 --- a/src/app/formulaire/definition/form-pressureloss.ts +++ b/src/app/formulaire/definition/form-pressureloss.ts @@ -36,16 +36,23 @@ export class FormulairePressureLoss extends FormulaireFixedVar { } public update(sender: IObservable, data: any) { - // changement de propriété du FieldSet contenant le select de choix du type de perte de charge - if (sender instanceof FieldSet && sender.id === "fs_pressureloss_law" && data.action === "propertyChange") { - // replace underlying pressure loss law without replacing whole Nub - const newPLL = Session.getInstance().createPressureLossLaw(data.value, undefined, this.currentNub.getPropValue(Prop_NullParameters)); - (this._currentNub as PressureLoss).setLaw(newPLL); - // show / hide dependent fields - this.refreshFieldsets(); - this.reset(); + // if (sender instanceof FieldSet && sender.id === "fs_pressureloss_law" && data.action === "propertyChange") { + if (data.action === "propertyChange") { + if (data.name === "pressurelosstype") { + // changement de propriété du FieldSet contenant le select de choix du type de perte de charge + + // replace underlying pressure loss law without replacing whole Nub + const newPLL = Session.getInstance().createPressureLossLaw(data.value, undefined, this.currentNub.getPropValue(Prop_NullParameters)); + (this._currentNub as PressureLoss).setLaw(newPLL); + // show / hide dependent fields + this.refreshFieldsets(true); + this.reset(); + } + else if (data.name === "material") { + // changement de propriété du FieldSet contenant le select de choix du type de matériau + this.refreshFieldsets(false); + this.reset(); + } } - else - super.update(sender, data); } } diff --git a/src/app/formulaire/definition/form-section-parametree.ts b/src/app/formulaire/definition/form-section-parametree.ts index 7f91f2fca963c76ba3e5bae49cfa8adc511afa8b..7ddfdefaf792c204256e0ec9cfebfc86e9d9588a 100644 --- a/src/app/formulaire/definition/form-section-parametree.ts +++ b/src/app/formulaire/definition/form-section-parametree.ts @@ -23,10 +23,6 @@ export class FormulaireSectionParametree extends FormulaireSection { this.reaffectResultComponents(); } - protected runNubCalc(nub: Nub, computedParam?: ParamDefinition): Result { - return nub.CalcSerie(); - } - protected reaffectResultComponents() { this.resetFormResults(); // to avoid adding fixed parameters more than once (see below) const sectNub: SectionParametree = this.currentNub as SectionParametree; diff --git a/src/app/formulaire/definition/form-section.ts b/src/app/formulaire/definition/form-section.ts index bf06c16b257e578889469d86dc696f6ea15249a0..d2aa08b33f532607425315ddbf139662708d15bb 100644 --- a/src/app/formulaire/definition/form-section.ts +++ b/src/app/formulaire/definition/form-section.ts @@ -47,12 +47,7 @@ export class FormulaireSection extends FormulaireFixedVar { 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(); - } - // show / hide dependent fields - this.refreshFieldsets(); + this.refreshFieldsets(true); this.reset(); } } diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 0a3d446efac3a99a2fa2165f3b0916462fcfeb5a..ce7be1797a493253662eb914bf8a6ae1d3495d82 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -63,7 +63,7 @@ export class FormulaireSolveur extends FormulaireFixedVar { // refresh targetted result selector const trSel = this.getFormulaireNodeById(this._targettedResultSelectId) as SelectField; if (trSel) { - (trSel.parent as FieldSet).updateFields(); + (trSel.parent as FieldSet).updateFields(true); // trick to re-set observers this.completeParse(false); } diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index c1678a93ba7bbc72b6bbba20953523941dc1cf8f..7b709eb764cb73580a7f56d1c2b24ed17b2a4c97 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -10,7 +10,7 @@ import { import { FormulaireElement } from "./formulaire-element"; import { Field } from "./field"; import { SelectField } from "./select/select-field"; -import { NgParameter, ParamRadioConfig } from "./ngparam"; +import { NgParameter } from "./ngparam"; import { FieldsetContainer } from "./fieldset-container"; import { SelectFieldFactory } from "./select/select-field-factory"; import { FormulaireFixedVar } from "../definition/form-fixedvar"; @@ -38,9 +38,8 @@ export class FieldSet extends FormulaireElement implements IProperties { public setNub(sn: Nub, update: boolean = true) { this._nub = sn; - this.setParentNubForAllFields(); if (update) { - this.updateFields(); + this.updateFields(true); } } @@ -48,7 +47,9 @@ export class FieldSet extends FormulaireElement implements IProperties { if (!f) { throw new Error("FieldSet.addField() : argument incorrect (undefined)"); } - this.kids.push(f); + if (this.kids.indexOf(f) === -1) { + this.kids.push(f); + } } /** @@ -106,6 +107,15 @@ export class FieldSet extends FormulaireElement implements IProperties { } } + private getOrCreateSelect(json: {}): SelectField { + const id: string = json["id"]; + const res = this.getFormulaireNodeById(id); + if (res === undefined || !(res instanceof SelectField)) { + return SelectFieldFactory.newSelectField(json, this); + } + return res; + } + private parse_select(json: {}): SelectField { let ok: boolean = true; // in case select is associated to a property, check nub has the property @@ -114,7 +124,7 @@ export class FieldSet extends FormulaireElement implements IProperties { ok = this.parentForm.getPropValue(p) !== undefined; } if (ok) { - const res: SelectField = SelectFieldFactory.newSelectField(json, this); + const res: SelectField = this.getOrCreateSelect(json); res.parseConfig(json); res.afterParseConfig(); res.addObserver(this); @@ -135,9 +145,6 @@ export class FieldSet extends FormulaireElement implements IProperties { return this._jsonConfig; } - private setParentNubForAllFields() { - } - /** * crée un input * @param json definition de l'input, extrait du fichier de conf du module de calcul @@ -151,7 +158,7 @@ export class FieldSet extends FormulaireElement implements IProperties { try { nubParam = this.getNubParamFromSymbol(input_id); if (nubParam.visible) { - res = new NgParameter(nubParam, this); + res = this.parentForm.getOrCreateParam(nubParam, this); res.parseConfig(json); } } catch (e) { @@ -161,8 +168,6 @@ export class FieldSet extends FormulaireElement implements IProperties { } 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) { @@ -207,7 +212,10 @@ export class FieldSet extends FormulaireElement implements IProperties { /** * Reloads the model values and properties, and reloads localisation strings */ - public updateFields() { + public updateFields(forceClear: boolean) { + if (forceClear) { + this.clearFields(); + } this.parseFields(); this.updateLocalisation(); @@ -261,6 +269,7 @@ export class FieldSet extends FormulaireElement implements IProperties { // parse fields once, so that SelectField elements are present // when setting default properties below + this.clearFields(); this.parseFields(); // for all select fields known by the form, apply default value @@ -280,32 +289,6 @@ export class FieldSet extends FormulaireElement implements IProperties { } } - public getNodeParameter(symbol: string): NgParameter { - for (const p of this.kids) { - if (p instanceof NgParameter) { - if (p.isDisplayed && p.symbol === symbol) { - return p; - } - } - } - } - - public getNodeParameterValue(symbol: string): number { - const p = this.getNodeParameter(symbol); - if (!p) { - throw new Error(`FieldSet.getNodeParameterValue() : pas de paramètre ${symbol} trouvé`); - } - - switch (p.radioState) { - case ParamRadioConfig.FIX: - return p.getValue(); - - case ParamRadioConfig.VAR: - case ParamRadioConfig.CAL: - return undefined; - } - } - /** * retourne la valeur actuellement sélectionnée d'un SelectField (qui doit être affiché) * @param selectFieldId id du SelectField diff --git a/src/app/formulaire/elements/ngparam.ts b/src/app/formulaire/elements/ngparam.ts index e4dc902cd4034702c761634d145c30781db189b2..a579f014146807fe4e091f7a7dd6b1d0050faa18 100644 --- a/src/app/formulaire/elements/ngparam.ts +++ b/src/app/formulaire/elements/ngparam.ts @@ -8,7 +8,7 @@ import { sprintf } from "sprintf-js"; import { InputField } from "./input-field"; import { ServiceFactory } from "../../services/service-factory"; import { FormulaireNode } from "./formulaire-node"; -import { fv } from "../../util"; +import { fv } from "../../util/util"; export enum ParamRadioConfig { /** pas de radio, paramètre modifiable à la main uniquement */ diff --git a/src/app/formulaire/elements/select/select-field-searched-param.ts b/src/app/formulaire/elements/select/select-field-searched-param.ts index 339acbfe5702e623c3cc8041b2860ad7ef0fe3f6..8811ef81f441628e39164f0f46404fa8cf1a1d4c 100644 --- a/src/app/formulaire/elements/select/select-field-searched-param.ts +++ b/src/app/formulaire/elements/select/select-field-searched-param.ts @@ -1,5 +1,5 @@ import { ServiceFactory } from "app/services/service-factory"; -import { decodeHtml } from "app/util"; +import { decodeHtml } from "app/util/util"; import { acSection, Nub, Solveur } from "jalhyd"; import { SelectEntry } from "./select-entry"; import { SelectField } from "./select-field"; diff --git a/src/app/formulaire/elements/select/select-field-solveur-target.ts b/src/app/formulaire/elements/select/select-field-solveur-target.ts index b98546e221fc7bf13c782ca43440e24df9f34320..3d752aa4368a5c45c5b0c4a4d36375ff8cb0d8b2 100644 --- a/src/app/formulaire/elements/select/select-field-solveur-target.ts +++ b/src/app/formulaire/elements/select/select-field-solveur-target.ts @@ -5,7 +5,7 @@ */ import { ServiceFactory } from "app/services/service-factory"; -import { decodeHtml } from "../../../util"; +import { decodeHtml } from "../../../util/util"; import { Session, Solveur } from "jalhyd"; import { SelectEntry } from "./select-entry"; import { SelectField } from "./select-field"; diff --git a/src/app/formulaire/elements/select/select-field-target-pass.ts b/src/app/formulaire/elements/select/select-field-target-pass.ts index 6383c02ffc159a14afa7f6a11dce014769c48af9..8438e0a0fe2c50a5b5b1c8b937543249def5a423 100644 --- a/src/app/formulaire/elements/select/select-field-target-pass.ts +++ b/src/app/formulaire/elements/select/select-field-target-pass.ts @@ -1,5 +1,5 @@ import { ServiceFactory } from "app/services/service-factory"; -import { decodeHtml } from "app/util"; +import { decodeHtml } from "app/util/util"; import { CalculatorType, FishPass, Session, Verificateur } from "jalhyd"; import { FormulaireElement } from "../formulaire-element"; import { FormulaireNode } from "../formulaire-node"; diff --git a/src/app/formulaire/elements/select/select-field.ts b/src/app/formulaire/elements/select/select-field.ts index 2b9b65aa97fc770e1548718791597698decb7a09..b45f59c42d2581d536dc40659295cb86ed57cc62 100644 --- a/src/app/formulaire/elements/select/select-field.ts +++ b/src/app/formulaire/elements/select/select-field.ts @@ -1,6 +1,6 @@ import { Field } from "../field"; import { SelectEntry } from "./select-entry"; -import { arraysAreEqual } from "../../../util"; +import { arraysAreEqual } from "../../../util/util"; import { FormulaireNode } from "../formulaire-node"; import { ServiceFactory } from "app/services/service-factory"; import { FormulaireDefinition } from "../../definition/form-definition"; diff --git a/src/app/results/param-calc-results.ts b/src/app/results/param-calc-results.ts index eaca087d32dee78357630328c0c72508f7b00e44..9e22d98b4928284d5b72a4712e233bb551649a7c 100644 --- a/src/app/results/param-calc-results.ts +++ b/src/app/results/param-calc-results.ts @@ -12,7 +12,7 @@ export abstract class CalculatedParamResults extends CalculatorResults { protected _calculatedParam: NgParameter; /** titre de la colonne du paramètre calculé */ - public calculatedParameterHeader: string; + private _calculatedParameterHeader: string; /** résultat du calcul sur le paramètre calculé */ public result: Result; @@ -22,7 +22,7 @@ export abstract class CalculatedParamResults extends CalculatorResults { public reset() { this._calculatedParam = undefined; - this.calculatedParameterHeader = undefined; + this._calculatedParameterHeader = undefined; this.result = undefined; } @@ -32,7 +32,17 @@ export abstract class CalculatedParamResults extends CalculatorResults { public set calculatedParameter(p: NgParameter) { this._calculatedParam = p; - this.calculatedParameterHeader = CalculatorResults.paramLabel(this._calculatedParam, true); + this.updateCalculatedParameterHeader(); + } + + public updateCalculatedParameterHeader() { + if (this._calculatedParam !== undefined) { + this._calculatedParameterHeader = CalculatorResults.paramLabel(this._calculatedParam, true); + } + } + + public get calculatedParameterHeader(): string { + return this._calculatedParameterHeader; } public get hasResults(): boolean { diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts index 37ff757b971936d696f0b040060cc6b54f2688f7..c8c814d89776af9760d03c5e524297446330f92a 100644 --- a/src/app/results/var-results.ts +++ b/src/app/results/var-results.ts @@ -2,7 +2,7 @@ import { CalculatedParamResults } from "./param-calc-results"; import { ServiceFactory } from "../services/service-factory"; import { PlottableData } from "./plottable-data"; import { ChartType } from "./chart-type"; -import { longestVarParam } from "../util"; +import { longestVarParam } from "../util/util"; import { FormulaireDefinition } from "../formulaire/definition/form-definition"; import { sprintf } from "sprintf-js"; diff --git a/src/app/services/internationalisation.service.ts b/src/app/services/internationalisation.service.ts index ea1bec8c3d563f2e11b1a8cfdbf45ae95c67100f..deee494fecb63836be93eeb253b8253ed708742f 100644 --- a/src/app/services/internationalisation.service.ts +++ b/src/app/services/internationalisation.service.ts @@ -5,7 +5,7 @@ import { Message, MessageCode, Observable, Observer, Nub, CalculatorType, PreBar import { StringMap } from "../stringmap"; import { ApplicationSetupService } from "./app-setup.service"; import { HttpService } from "./http.service"; -import { fv, decodeHtml } from "../util"; +import { fv, decodeHtml } from "../util/util"; import { ServiceFactory } from "./service-factory"; import { FormulaireService } from "./formulaire.service"; diff --git a/src/app/services/service-factory.ts b/src/app/services/service-factory.ts index e3ea55cae3c7ce504924688dac8ae1517f3268ba..668d5aea18b12ed1295f44b2885fdec97a1eeb56 100644 --- a/src/app/services/service-factory.ts +++ b/src/app/services/service-factory.ts @@ -4,6 +4,7 @@ import { I18nService } from "./internationalisation.service"; import { HttpService } from "./http.service"; import { NotificationsService } from "./notifications.service"; import { PrebarrageService } from "./prebarrage.service"; +import { ServiceWorkerUpdateService } from "./service-worker-update.service"; /** * A "Singleton" the TS way, that holds pointers to all services, to be accessed @@ -17,11 +18,13 @@ export const ServiceFactory: { httpService: HttpService; notificationsService: NotificationsService; prebarrageService: PrebarrageService; + serviceWorkerUpdateService: ServiceWorkerUpdateService; } = { applicationSetupService: undefined, formulaireService: undefined, i18nService: undefined, httpService: undefined, notificationsService: undefined, - prebarrageService: undefined + prebarrageService: undefined, + serviceWorkerUpdateService: undefined }; diff --git a/src/app/services/service-worker-update.service.ts b/src/app/services/service-worker-update.service.ts index 96b84426ac85dc1c4666d7d6b55ecc7e4aa46f29..163fd4a12e45f941abec56a389479a73c68b291c 100644 --- a/src/app/services/service-worker-update.service.ts +++ b/src/app/services/service-worker-update.service.ts @@ -1,36 +1,74 @@ -import { Injectable } from "@angular/core"; +import { Injectable, NgZone } from "@angular/core"; import { SwUpdate } from '@angular/service-worker'; import { I18nService } from "./internationalisation.service"; import { NotificationsService } from "./notifications.service"; +import { UserConfirmationService } from "./user-confirmation.service"; +import { interval } from "rxjs"; @Injectable() export class ServiceWorkerUpdateService { constructor( private swUpdate: SwUpdate, private notificationService: NotificationsService, - private i18nService: I18nService + private i18nService: I18nService, + private userConfirmationService: UserConfirmationService, + private ngZone: NgZone ) { - swUpdate.versionUpdates.subscribe(evt => { + if (this.swUpdate.isEnabled) { + this.ngZone.runOutsideAngular(() => + interval(1000 * 60 * 60).subscribe(val => { + console.log('ServiceWorkerUpdateService: checking for updates...') + swUpdate.checkForUpdate().then(b => { + console.log("ServiceWorkerUpdateService: " + (b ? "new version found" : "no new version")); + }); + }) + ); + } else { + console.log("ServiceWorkerUpdateService: SwUpdate is disabled"); + } + + this.swUpdate.versionUpdates.subscribe(evt => { switch (evt.type) { case 'VERSION_DETECTED': - let ver = evt.version.appData["version"]; - let msg = i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_DETECTED", { "ver": ver }); - notificationService.notify(msg, 10000); + let ver = (evt as any).version?.appData?.version ?? "<NA>"; + console.log("ServiceWorkerUpdateService: VERSION_DETECTED", ver); + notificationService.notify(i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_DETECTED", { "ver": ver }), 10000); break; case 'VERSION_READY': - const newVer = evt.latestVersion.appData["version"]; - // const currVer = evt.currentVersion.appData["version"]; - msg = i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_READY", { "ver": newVer }); - notificationService.notify(msg, 10000); + const currVer = (evt as any).currentVersion?.appData?.version ?? "<NA>"; + const newVer = (evt as any).latestVersion?.appData?.version ?? "<NA>"; + console.log("ServiceWorkerUpdateService: VERSION_READY", currVer, "->", newVer); + + notificationService.notify(i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_READY", { "ver": newVer }), 10000); + // PLANTE si on stocke le message dans une variable !!!! + // const msg = i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_READY", { "ver": newVer }); + // notificationService.notify(msg, 10000); + // -> ReferenceError: can't access lexical declaration 'xxx' before initialization + // avec xxx qui varie d'une fois à l'autre !!! + + userConfirmationService.askUserConfirmation("Confirmation", + i18nService.localizeText("INFO_SERVICE_WORKER_VERSION_READY", { "ver": newVer })).then(data => { + if (data["confirm"]) { + console.log("ServiceWorkerUpdateService: application update confirmed"); + window.location.reload(); + } + else { + console.log("ServiceWorkerUpdateService: application update canceled"); + } + }); break; case 'VERSION_INSTALLATION_FAILED': - ver = evt.version.appData["version"]; - msg = i18nService.localizeText("ERROR_SERVICE_WORKER_INSTALL_FAILED", { "ver": ver }); - notificationService.notify(msg, 10000); + ver = (evt as any).version?.appData?.version ?? "NA"; + console.log("ServiceWorkerUpdateService: VERSION_INSTALLATION_FAILED", ver); + notificationService.notify(i18nService.localizeText("ERROR_SERVICE_WORKER_INSTALL_FAILED", { "ver": ver }), 10000); break; } }); + swUpdate.unrecoverable.subscribe(event => { + console.log("SwUpdate.unrecoverable reason", event.reason, "type", event.type); + notificationService.notify("SwUpdate: unrecoverable state. Reason=" + event.reason + ", type=" + event.type, 10000); + }); } } diff --git a/src/app/services/user-confirmation.service.ts b/src/app/services/user-confirmation.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..d33beecbbcb3516620ad36170922baeeca54a8b3 --- /dev/null +++ b/src/app/services/user-confirmation.service.ts @@ -0,0 +1,69 @@ +import { Injectable } from "@angular/core"; + +import { BidirectionalSubject } from "app/util/bidir_subject"; +import { Observer } from "rxjs"; + +/** + * This service enables any class (even another service) to display a confirmation dialog on GUI ans get the user answer + */ +@Injectable() +export class UserConfirmationService { + + // used to communicate with UI component in charge of displaying confirmation dialog + // direction 0 : this + // direction 1 : UI + private _userConfirm: BidirectionalSubject<{}>; + + public constructor() { + this._userConfirm = new BidirectionalSubject<{}>(); + + // we choose communication canal 0, UI will use 1 + this._userConfirm.selectPostingChannel(this, 0); + } + + /** + * add subscription from UI + * @param source + */ + public subscribe(source: any) { + this._userConfirm.selectPostingChannel(source, 1); + } + + /** + * remove UI subscription + * @param source + */ + public unsubscribe(source: any) { + this._userConfirm.unselectPostingChannel(source); + } + + /** + * add a handler (provided bu UI) to confirmation request + * @param source normally, UI component + * @param obs processing function + */ + public addHandler(source: any, obs: Observer<boolean>) { + this._userConfirm.addHandler(source, obs) + } + + /** + * forward user confirmation from UI to requesting object + * @param confirm user confirmation status + */ + public postConfirmation(source: any, confirm: {}) { + this._userConfirm.post(source, confirm); + } + + /** + * forward to UI a request from source to ask a user confirmation with a dialog + * @param source object requesting confirmation + * @param title confirmation dialog title + * @param text confirmation dialog body text + * @returns a Promise resolving to a boolean holding user confirmation status + */ + public askUserConfirmation(title: string, text: string): Promise<{}> { + const ret = this._userConfirm.getReceivePromise(this); + this._userConfirm.post(this, { title: title, body: text }); // false or true, we don't care + return ret; + } +} diff --git a/src/app/util/bidir_subject.ts b/src/app/util/bidir_subject.ts new file mode 100644 index 0000000000000000000000000000000000000000..069e004e83e7040dff2b273fad42ba9aef3ddd0c --- /dev/null +++ b/src/app/util/bidir_subject.ts @@ -0,0 +1,131 @@ +import { Observer, Subject, firstValueFrom, lastValueFrom } from "rxjs"; + +/** + * bi-directional subject (see RxJS Subject) + * Allows two objects to exchange messages in both directions. Each object has to choose a posting channel + * (messages will receive from the other one). + * + * source1 ----post-----> | channel 0 | --subscribe--> source2 + * <--subscribe-- | channel 1 | <-----post---- + * + * EventEmitter is not used since it is reserved to properties in Angular component with @Output annotation + */ +export class BidirectionalSubject<T> { + + // communication channels + private _channel0: Subject<T>; + private _channel1: Subject<T>; + + // array of "who chose which posting channel" + private _channel0Posters: any[] = []; + private _channel1Posters: any[] = []; + + constructor() { + this._channel0 = new Subject(); + this._channel1 = new Subject(); + } + + /** + * get posting channel index + * @param source object that chose one of the channels + */ + private getPostingChannelIndex(source: any) { + if (this._channel0Posters.indexOf(source) !== -1) { + return 0; + } + if (this._channel1Posters.indexOf(source) !== -1) { + return 1; + } + return -1; + } + + /** + * choose a posting channel + * @param source object that chooses the channel + * @param chan channel number + */ + public selectPostingChannel(source: any, chan: number) { + switch (chan) { + case 0: + if (this.getPostingChannelIndex(source) !== -1) { + throw new Error("object already has a selected channel"); + } + this._channel0Posters.push(source); + break; + + case 1: + if (this.getPostingChannelIndex(source) !== -1) { + throw new Error("object already has a selected channel"); + } + this._channel1Posters.push(source); + break; + + default: + throw new Error(`invalid channel number ${chan}`); + } + } + + /** + * remove a source from its channel + */ + public unselectPostingChannel(source: any) { + this._channel0Posters = this._channel0Posters.filter(o => o != source); + this._channel1Posters = this._channel1Posters.filter(o => o != source); + } + + /** + * used by a source to post a message to communication channel + */ + public post(source: any, msg: T) { + switch (this.getPostingChannelIndex(source)) { + case 0: + this._channel0.next(msg); + break; + + case 1: + this._channel1.next(msg); + break; + + case -1: + throw new Error("must select a channel first"); + } + } + + /** + * create a Promise representing a received message (when posted by another source) + * @param source object that will use the Promise + */ + public getReceivePromise(source: any): Promise<T> { + switch (this.getPostingChannelIndex(source)) { + case 0: + return firstValueFrom(this._channel1); + + case 1: + return firstValueFrom(this._channel0); + + case -1: + throw new Error("must select a channel first"); + } + } + + /** + * Add a message handler (provided by source) to process received messages + * (alternative to getReceivePromise()) + * @param source object providing handler + * @param handler message processing function + */ + public addHandler(source: any, handler: Observer<T>) { + switch (this.getPostingChannelIndex(source)) { + case 0: + this._channel1.subscribe(handler); + break; + + case 1: + this._channel0.subscribe(handler); + break; + + case -1: + throw new Error("must select a channel first"); + } + } +} diff --git a/src/app/definedvalue/definedboolean.ts b/src/app/util/definedvalue/definedboolean.ts similarity index 100% rename from src/app/definedvalue/definedboolean.ts rename to src/app/util/definedvalue/definedboolean.ts diff --git a/src/app/definedvalue/definedvalue.ts b/src/app/util/definedvalue/definedvalue.ts similarity index 100% rename from src/app/definedvalue/definedvalue.ts rename to src/app/util/definedvalue/definedvalue.ts diff --git a/src/app/util.ts b/src/app/util/util.ts similarity index 97% rename from src/app/util.ts rename to src/app/util/util.ts index 763a425cbebe0a5b95596c0ae707666bfea8df12..06db46788e2d96870913a5efd1faf8c49db487dd 100644 --- a/src/app/util.ts +++ b/src/app/util/util.ts @@ -1,5 +1,5 @@ -import { NgParameter } from "./formulaire/elements/ngparam"; -import { ServiceFactory } from "./services/service-factory"; +import { NgParameter } from "../formulaire/elements/ngparam"; +import { ServiceFactory } from "../services/service-factory"; import { formattedValue, Nub, VariatedDetails, ParamDefinition, ParamValueMode, Result } from "jalhyd"; @@ -13,7 +13,7 @@ export function logObject(obj: {}, m?: string) { } export function isNumber(s: string): boolean { - return Number(s) !== NaN; + return !Number.isNaN(Number(s)); } /** diff --git a/src/main.ts b/src/main.ts index 066830176864449a04f0ba173614afdd06bde81e..28da08b5bff46969e78ef8737919a9ee7b67fc3e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,5 +11,9 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.log(err)); +platformBrowserDynamic().bootstrapModule(AppModule).then(() => { + if ('serviceWorker' in navigator && environment.production) { + console.log("Registering ngsw-worker.js..."); + navigator.serviceWorker.register('ngsw-worker.js'); + } +}).catch(err => console.log(err));