Commit 0a2ea9bf authored by Dorchies David's avatar Dorchies David
Browse files

Merge branch 'devel' into 'master'

Release version 4.15.0

See merge request !133
parents 828dc263 ec828fee
Pipeline #35730 passed with stages
in 17 minutes and 24 seconds
......@@ -4,28 +4,42 @@ stages:
- test
- build
- clean-stale-branches
- deploy
- deploy-stable
- deploy-dev
- deploy-prod
- releases-nightly
- releases-version
variables:
# from Gitlab CI/CD environment variables :
# - development server :
# DEV_HOST : deployment server hostname
# DEV_LOGIN : user on deployment server
# DEV_PATH : path base on deployment server
# - production server :
# PROD_HOST : deployment server hostname
# PROD_LOGIN : user on deployment server
# PROD_PASS : password for user on deployment server
# PROD_PATH : path base on deployment server
LC_ALL: C.UTF-8
ANDROID_HOME: "/usr/local/android-sdk" # should already be defined in the Docker image
ANDROID_SDK_ROOT: "/usr/local/android-sdk" # should already be defined in the Docker image
DEPLOY_HOST_LOGIN: "nghyd@aubes"
DEPLOY_URL: "/var/www/html/cassiopee"
DEPLOY_STABLE_URL: "/var/www/cassiopee-production"
RELEASES_URL: "$DEPLOY_STABLE_URL/cassiopee-releases"
RELEASES_PATH: "$PROD_PATH/cassiopee-releases"
before_script:
# load private key from GitLab CI variable, to deploy on Aubes server
# load private key from GitLab CI variable to deploy on Aubes server
- eval $(ssh-agent -s)
- ssh-add <(echo "$AUBES_B64_AUTHORIZED_SSH_PRIVATE_KEY" | base64 -d)
# load private key from GitLab CI variable to deploy on OVH server
- ssh-add <(echo "$OVH_B64_AUTHORIZED_SSH_PRIVATE_KEY" | base64 -d)
# disable console prompt for host checking
- mkdir -p ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
cache:
key:
files:
- jalhyd_branch
- package.json
paths:
- node_modules/
......@@ -91,10 +105,10 @@ clean-stale-branches:
- tags
- web
script:
- ./scripts/remove-stale-branches.sh $DEPLOY_HOST_LOGIN $DEPLOY_URL
- ./scripts/remove-stale-branches.sh $DEV_LOGIN@$DEV_HOST $DEV_PATH
deploy:
stage: deploy
deploy-dev:
stage: deploy-dev
only:
- pushes
- tags
......@@ -103,32 +117,28 @@ deploy:
- build
script:
# Copie de la branche / du tag
- rsync -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_URL/$CI_COMMIT_REF_NAME"
- ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH
deploy-stable:
stage: deploy-stable
deploy-prod:
stage: deploy-prod
only:
variables:
- $CI_COMMIT_REF_NAME == "stable"
dependencies:
- build
script:
# Copie de la branche production
- rsync -a "dist/" "$DEPLOY_HOST_LOGIN:$DEPLOY_STABLE_URL/"
# Modification du dossier base href
- ssh $DEPLOY_HOST_LOGIN "sed -i 's:/cassiopee/stable/:/:g' $DEPLOY_STABLE_URL/index.html"
- ./scripts/deploy-version.sh stable $PROD_LOGIN $PROD_HOST $PROD_PATH $PROD_PASS
releases-nightly:
stage: releases-nightly
only:
- schedules
except:
# exclude master to apply releases-nightly on devel only
- master
dependencies: []
script:
- npm run release-all
- find release -name "fr.irstea.cassiopee_*.deb" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/linux-nightly.deb \;
- find release -name "Cassio*Setup*.exe" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/windows-nightly.exe \;
- find release -name "Cassio*-mac.zip" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/macos-nightly.zip \;
- find release -name "cassiopee-*.apk" -exec scp "{}" $DEPLOY_HOST_LOGIN:$RELEASES_URL/android-nightly.apk \;
- ./scripts/release-version.sh nightly $PROD_LOGIN $PROD_HOST $RELEASES_PATH
releases-version:
stage: releases-version
......@@ -137,4 +147,4 @@ releases-version:
- $CI_COMMIT_REF_NAME =~ /^[0-9]+\.[0-9]+\.[0-9]+$/ # version tag
dependencies: []
script:
- ./scripts/release-version.sh $CI_COMMIT_REF_NAME $DEPLOY_HOST_LOGIN $RELEASES_URL
- ./scripts/release-version.sh $CI_COMMIT_REF_NAME $PROD_LOGIN $PROD_HOST $RELEASES_PATH
......@@ -10,7 +10,10 @@
"name": "Launch Chrome (local webserver)",
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}",
"runtimeExecutable": "/usr/bin/chromium-browser"
"runtimeExecutable": "/usr/bin/chromium",
"runtimeArgs": [
"--preserve-symlinks"
]
},
{
"name": "Launch Firefox (local webserver)",
......@@ -19,6 +22,23 @@
"reAttach": true,
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}"
},
{
"name": "Launch e2e current file",
"type": "node",
"request": "launch",
"stopOnEntry": false,
"program": "${workspaceRoot}/node_modules/protractor/bin/protractor",
"args": [
"${workspaceRoot}/protractor.conf.js",
"--specs=${file}"
],
"cwd": "${workspaceRoot}",
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/dist/out-tsc-e2e/*.js"
],
"skipSourceMapSupport": true
}
]
}
\ No newline at end of file
}
# Historique des versions
### 4.15.0 - 2022-05-04 (Salmo trutta)
#### Nouvelles fonctionnalités
* PAB : Variation du débit d'attrait ([nghyd#431](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/431))
* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300),[nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507))
* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298),[nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484))
#### Changements
* Fente Larinier : laisser le coefficient de débit vide ([nghyd#515](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/515))
* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306),[nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516))
#### Correction de bogues
* Courbe de remous: crash de l'application sur données erronées ([jalhyd#307](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/307),[nghyd#532](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/532))
Deux bugs en un, l'appli crashe quand :
- la hauteur de berge dépasse une certaine valeur avec des paramètres corrects pour effectuer un calcul (par exemple les valeurs par défaut)
- les deux cotes de l'eau se situent sous les cotes de fond amont et aval
* Sections : non convergence du calcul du tirant d'eau critique ([jalhyd#301](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/301),[nghyd#528](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/528))
* Remettre le paramètre dans son état initial quand le dialogue "Varier" est annulé ([nghyd#508](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/508))
* Prébarrages: les champs ne sont pas vides lors des ajouts de bassins et cloisons ([nghyd#503](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/503))
* Mode "champs vides par défaut" : changer le type d'un ouvrage (ex: dans Cloisons) remplit les champs ([nghyd#480](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/480))
* PréBarrages : perte du focus lorsqu'on édite un paramètre d'un enfant (cloison ou bassin) ([nghyd#469](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/469))
#### Documentation
* Cloisons : il manque l'aide contextuelle pour les lois de débit ([nghyd#529](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/529))
* Documentation : corrections ([nghyd#498](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/498))
#### Changements internes
* Nightly build: clean folder before installation ([nghyd#495](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/495))
* Transfert du site de production sur OVH ([nghyd#505](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/505))
* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530),[nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531))
- Les champs des exemples chargés sont vides lorsque le mode "champ vides" est activé.
- Les tests e2e plantent par manque de temporisation
* CI : les jobs build en schedule de master et devel plantent ([nghyd#527](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/527))
* CI : affiner la gestion du cache ([nghyd#526](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/526))
### 4.14.2 - 2021-03-25
#### Nouvelles fonctionnalités
......
......@@ -104,7 +104,12 @@
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ngHyd:build",
"aot": true
"aot": true,
"sourceMap": {
"scripts": true,
"styles": true,
"vendor": true
}
},
"configurations": {
"production": {
......@@ -193,4 +198,4 @@
"cli": {
"analytics": false
}
}
\ No newline at end of file
}
......@@ -3,7 +3,7 @@
This module calculates the hydraulic quantities associated to:
- a section with a defined geometrical shape ([See section types managed by Cassiopée](types_sections.md))
- a draft \(y\) in m
- a water depth \(y\) in m
- a flow \(Q\) in m<sup>3</sup>/s
- a bottom slope \(I_f\) in m/m
- a roughness expressed with the Strickler's coefficient \(K\) in m<sup>1/3</sup>/s
......@@ -23,7 +23,7 @@ The calculated hydraulic quantities are:
- Critical depth (m)
- Critical head (m)
- Corresponding depth (m)
- Impulsion (kg⋅m⋅s<sup>-1</sup>)
- Impulsion (N)
- Conjugate depth
- Tractive force (Pa)
......@@ -122,15 +122,15 @@ We use Newton's method by posing \(y_{k+1} = y_k - \frac{f(y_k)}{f'(y_k)}\) with
<div style="position: relative"><div style="position: relative"><a id="la-charge-critique-m" style="position: absolute; top: -100px;" style="position: absolute; top: -60px;"></a></div></div>
## Critical head (m)
This is the head calculated for a draft equal to the critical depth. \(H_c = H(y_c)\).
This is the head calculated for a water depth equal to the critical depth. \(H_c = H(y_c)\).
<div style="position: relative"><a id="le-tirant-deau-correspondant-m" style="position: absolute; top: -60px;"></a></div>
## Corresponing depth (m)
## Corresponding depth (m)
For a fluvial (respectively torrential draft) \(y\), corresponding depth is the torrential (respectively fluvial) draft for the which \(H(y) = H(y_{cor})\).
For a fluvial (respectively torrential water depth) \(y\), corresponding depth is the torrential (respectively fluvial) water depth for which \(H(y) = H(y_{cor})\).
<div style="position: relative"><a id="limpulsion-hydraulique-kgms-1" style="position: absolute; top: -60px;"></a></div>
## Hydraulic impulsion (kg⋅m⋅s<sup>-1</sup>)
<div style="position: relative"><a id="limpulsion-hydraulique-N" style="position: absolute; top: -60px;"></a></div>
## Hydraulic impulsion (N)
The impulsion \(I\) is the sum of the amount of movement and the resultant of the pressure force in a section:
......@@ -145,7 +145,7 @@ The distance from the centre of gravity of the section to the free surface \(y_g
$$S.y_g = \int_{0}^{y} (y-z)B(z)dz$$
With \(y\) the depth and \(B(z)\) the width at mirror for a draft \(z\)
With \(y\) the depth and \(B(z)\) the width at mirror for a water depth \(z\)
Formulas of \(S.y_g\) for the different section shapes are :
......@@ -157,7 +157,7 @@ Formulas of \(S.y_g\) for the different section shapes are :
<div style="position: relative"><a id="le-tirant-deau-conjugue-m" style="position: absolute; top: -60px;"></a></div>
## Conjugate depth (m)
For a fluvial (respectively torrential draft) \(y\), conjugate depth is the torrential (respectively fluvial) draft for the which \(I(y) = I(y_{con})\).
For a fluvial (respectively torrential water depth) \(y\), conjugate depth is the torrential (respectively fluvial) water depth for which \(I(y) = I(y_{con})\).
<div style="position: relative"><a id="la-force-tractrice-pa" style="position: absolute; top: -60px;"></a></div>
## Tractive force (Pa)
......
......@@ -23,7 +23,7 @@ Les grandeurs hydrauliques calculées sont&nbsp;:
- Le tirant d'eau critique (m)
- La charge critique (m)
- Le tirant d'eau correspondant (m)
- L'impulsion (kg⋅m⋅s<sup>-1</sup>)
- L'impulsion (N)
- Le tirant d'eau conjugué
- La force tractrice (Pa)
......@@ -117,7 +117,7 @@ C'est la charge calculée pour un tirant d'eau égal au tirant d'eau critique \(
Pour un tirant d'eau fluvial (respectivement torrentiel) \(y\), le tirant correspondant est le tirant d'eau torrentiel (respectivement fluvial) pour lequel \(H(y) = H(y_{cor})\).
## L'impulsion hydraulique (kg⋅m⋅s<sup>-1</sup>)
## L'impulsion hydraulique (N)
L'impulsion \(I\) est la somme de la quantité de mouvement et de la résultante de la force de pression dans une section :
......
......@@ -49,7 +49,7 @@ Table: Matériaux et coefficients utilisés dans la formule de Lechapt et Calmon
$$ J_S = K_S \frac{V^2}{2g}$$
Avec&nbsp:
Avec&nbsp;:
- \(K_S\)&nbsp;: le coefficient de perte de charge singulière
- \(V\)&nbsp;: la vitesse de l'eau dans la conduite (\(V = 4 Q / \pi / D^2\))
......@@ -60,4 +60,4 @@ $$ K_L = \frac{2g J_L}{V^2} $$
## Coefficient de perte de charge de Darcy
$$ f_D = \frac{2g J D}{l_T V^2}
$$ f_D = \frac{2g J D}{l_T V^2} $$
......@@ -2,6 +2,8 @@ import { ListPage } from "./list.po";
import { CalculatorPage } from "./calculator.po";
import { Navbar } from "./navbar.po";
import { browser, by, element } from "protractor";
import { PreferencesPage } from "./preferences.po";
import { SideNav } from "./sidenav.po";
/**
* Calculate all modules of all examples
......@@ -11,30 +13,50 @@ describe("ngHyd − example sessions −", async () => {
let listPage: ListPage;
let calcPage: CalculatorPage;
let navbar: Navbar;
let prefPage: PreferencesPage;
let sideNav: SideNav;
beforeAll(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000;
});
it("calcul de tous les modules de tous les exemples −", async () => {
listPage = new ListPage();
calcPage = new CalculatorPage();
navbar = new Navbar();
listPage = new ListPage();
prefPage = new PreferencesPage();
sideNav = new SideNav();
});
it("calcul de tous les modules de tous les exemples −", async () => {
// disable evil option "empty fields on module creation"
await prefPage.navigateTo();
await prefPage.disableEvilEmptyFields();
await browser.sleep(200);
// for each calculator
let lastExampleFound = true;
let i = 0;
while (lastExampleFound) {
await listPage.navigateTo();
if (i == 0) {
// start page
await navbar.clickNewCalculatorButton();
await browser.sleep(200);
}
else {
// empty session
await navbar.clickMenuButton();
await browser.sleep(200);
await sideNav.clickNewSessionButton();
await browser.sleep(1000);
}
const examples = await element.all(by.css("#examples-list .load-example"));
await browser.sleep(200);
if (examples.length > i) {
// click example #i
await examples[i].click();
await browser.sleep(50);
await browser.sleep(200);
const nbModules = await navbar.getCalculatorEntriesCount();
await browser.sleep(200);
for (let j = 0; j < nbModules; j++) {
// select module
await navbar.openNthCalculator(j);
......
......@@ -67,6 +67,10 @@ export class CalculatorPage {
return element(by.css("fieldset-container .hyd-window-btns button.add-structure"));
}
getCopyStructureButton() {
return element(by.css("fieldset-container .hyd-window-btns button.copy-structure"));
}
getAllLinkButtons() {
return element.all(by.css("mat-button-toggle.radio_link"));
}
......
......@@ -3,6 +3,7 @@ import { CalculatorPage } from "./calculator.po";
import { Navbar } from "./navbar.po";
import { SideNav } from "./sidenav.po";
import { browser } from "protractor";
import { PreferencesPage } from "./preferences.po";
/**
* Load a session containing 3 calculators, having linked parameters
......@@ -16,12 +17,14 @@ describe("ngHyd − compute then reset chained results − ", () => {
let calcPage: CalculatorPage;
let navbar: Navbar;
let sidenav: SideNav;
let prefPage: PreferencesPage;
function init() {
startPage = new AppPage();
calcPage = new CalculatorPage();
navbar = new Navbar();
sidenav = new SideNav();
prefPage = new PreferencesPage();
}
beforeEach(init);
......@@ -128,8 +131,16 @@ describe("ngHyd − compute then reset chained results − ", () => {
});
it("when loading session-results-invalidation.json, results reset should not be triggered on calculation", async () => {
// disable evil option "empty fields on module creation"
await prefPage.navigateTo();
await prefPage.disableEvilEmptyFields();
await browser.sleep(200);
// start page
await navbar.clickNewCalculatorButton();
await browser.sleep(200);
// load session file
await startPage.navigateTo();
await navbar.clickMenuButton();
await browser.sleep(200);
await sidenav.clickLoadSessionButton();
......
import { browser, by, element } from "protractor";
import { CalculatorPage } from "./calculator.po";
import { ListPage } from "./list.po";
import { Navbar } from "./navbar.po";
import { PreferencesPage } from "./preferences.po"
/**
* check that fields are empty on creation
*/
describe("ngHyd - Check that examples fields are not empty with 'empty fields on calculator creation' is enabled - ", () => {
let prefPage: PreferencesPage;
let navBar: Navbar;
let calcPage: CalculatorPage;
beforeEach(async () => {
prefPage = new PreferencesPage();
navBar = new Navbar();
calcPage = new CalculatorPage();
// enable evil option "empty fields on module creation"
await prefPage.navigateTo();
await browser.sleep(200);
await prefPage.enableEvilEmptyFields();
await browser.sleep(200);
});
/**
* check that a input set is in a given (empty/filled) state
* @param inputIds id of the inputs to check
* @param emptys empty/not empty state array
*/
async function checkFields(inputIds: string[], emptys: boolean[]) {
let n = 0;
for (const id of inputIds) {
const inp = await calcPage.getInputById(id);
const txt = await inp.getAttribute("value");
expect(txt === "").toEqual(emptys[n]);
n++;
}
}
it("when a standard fish ladder calculator is created", async () => {
// start page
await navBar.clickNewCalculatorButton();
await browser.sleep(200);
// open 1st example
const examples = await element.all(by.css("#examples-list .load-example"));
await examples[0].click();
await browser.sleep(50);
// select wall module
await navBar.openNthCalculator(4);
await browser.sleep(50);
// check fields are not empty
const inputIds = ["Z1", "LB", "PB", "0_L", "0_CdWSL"];
const emptys = [false, false, false, false, false];
await checkFields(inputIds, emptys);
});
it("calculated parameter initial value when discharge law is modified", async () => {
// start page
await navBar.clickNewCalculatorButton();
await browser.sleep(200);
// open 1st example
const examples = await element.all(by.css("#examples-list .load-example"));
await examples[0].click();
await browser.sleep(50);
// select wall module
await navBar.openNthCalculator(4);
await browser.sleep(50);
// modify 1st structure discharge law
const dischargeSelect = calcPage.getSelectById("select_loidebit");
await calcPage.changeSelectValue(dischargeSelect, 1);
await browser.sleep(200);
// open initial dialog
const initDlgButton = element(by.className("param-computed-more"));
await initDlgButton.click();
await browser.sleep(200);
// check input value is not null
const input = calcPage.getInputById("initval-input");
const underlyingInput = input.element(by.id("0_h1"));
const txt = await underlyingInput.getAttribute("value");
expect(txt === "").toEqual(false);
});
});
describe("ngHyd - Check that examples work with 'empty fields on calculator creation' enabled - ", () => {
let prefPage: PreferencesPage;
let navBar: Navbar;
let calcPage: CalculatorPage;
beforeEach(async () => {
prefPage = new PreferencesPage();
navBar = new Navbar();
calcPage = new CalculatorPage();
// enable evil option "empty fields on module creation"
await prefPage.navigateTo();
await browser.sleep(200);
await prefPage.enableEvilEmptyFields();
await browser.sleep(200);
});
it("when calculation is run on a generated fish ladder calculator", async () => {
debugger
// start page
await navBar.clickNewCalculatorButton();
await browser.sleep(200);
// open 1st example
const examples = await element.all(by.css("#examples-list .load-example"));
await examples[0].click();
await browser.sleep(50);
// select wall module
await navBar.openNthCalculator(4);
await browser.sleep(50);
// run calculation
const calcButton = calcPage.getCalculateButton();
await calcButton.click();
await browser.sleep(200);
// click "generate PAB" button
const genButton = calcPage.getGeneratePabButton();
await genButton.click();
await browser.sleep(200);
// write "6" in basin count input
const nbBassins = calcPage.getInputById("generatePabNbBassins");
await nbBassins.sendKeys("6");
await browser.sleep(50);
// click "Generate PAB"
await element(by.css("dialog-generate-pab button#do-generate")).click();
await browser.sleep(1000);
// calculate PAB
const calcButtonPAB = calcPage.getCalculateButton();
await calcButtonPAB.click();
await browser.sleep(200);
// check that result is not empty
const hasResults = await calcPage.hasResults();
expect(hasResults).toBe(true);
});
});
......@@ -34,6 +34,10 @@ describe("ngHyd − load session with multiple linked parameters − ", () => {
await prefPage.navigateTo();
await prefPage.changeLanguage(1); // fr
await browser.sleep(200);
// disable evil option "empty fields on module creation"
await prefPage.disableEvilEmptyFields();
await browser.sleep(200);
// start page
await navbar.clickNewCalculatorButton();
});
......
import { ListPage } from "./list.po";
import { browser, by, element } from "protractor";
import { CalculatorPage } from "./calculator.po";
import { AppPage } from "./app.po";
import { PreferencesPage } from "./preferences.po";
import { Navbar } from "./navbar.po";
/**
* Check that created/cloned structures have empty fields when
* "empty fields on calculator creation" is enabled
*/
describe("ngHyd - check that created/cloned structures have empty fields - ", () => {
let prefPage: PreferencesPage;
let listPage: ListPage;
let calcPage: CalculatorPage;
let navBar: Navbar;
beforeAll(() => {
prefPage = new PreferencesPage();