From 0cad1a969fd14e81cf502aecb821df4b2d7abcb6 Mon Sep 17 00:00:00 2001 From: belthlemar Date: Thu, 31 Aug 2023 16:35:38 +0200 Subject: [PATCH 1/9] fix(raw): allow NaN in matrices --- antarest/study/web/raw_studies_blueprint.py | 9 ++++++++- .../raw_studies_blueprint/test_fetch_raw_data.py | 9 +++++---- tests/integration/test_integration_xpansion.py | 10 ++++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/antarest/study/web/raw_studies_blueprint.py b/antarest/study/web/raw_studies_blueprint.py index a62a08b207..7f60c1c587 100644 --- a/antarest/study/web/raw_studies_blueprint.py +++ b/antarest/study/web/raw_studies_blueprint.py @@ -136,7 +136,14 @@ def get_study( # because it's better to avoid raising an exception. return Response(content=output, media_type="application/octet-stream") - return JSONResponse(content=output) + json_response = json.dumps( + output, + ensure_ascii=False, + allow_nan=True, + indent=None, + separators=(",", ":"), + ).encode("utf-8") + return Response(content=json_response, media_type="application/json") @bp.post( "/studies/{uuid}/raw", diff --git a/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py b/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py index 96366c6e44..3090dddc5a 100644 --- a/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py +++ b/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py @@ -41,6 +41,7 @@ def test_get_study( with db(): study: RawStudy = db.session.get(Study, study_id) study_dir = pathlib.Path(study.path) + headers = {"Authorization": f"Bearer {user_access_token}"} shutil.copytree( ASSETS_DIR.joinpath("user"), @@ -55,7 +56,7 @@ def test_get_study( query_string = urlencode({"path": f"/{rel_path}", "depth": 1}) res = client.get( f"/v1/studies/{study_id}/raw?{query_string}", - headers={"Authorization": f"Bearer {user_access_token}"}, + headers=headers, ) res.raise_for_status() if file_path.suffix == ".json": @@ -81,7 +82,7 @@ def test_get_study( query_string = urlencode({"path": f"/{rel_path.as_posix()}", "depth": 1}) res = client.get( f"/v1/studies/{study_id}/raw?{query_string}", - headers={"Authorization": f"Bearer {user_access_token}"}, + headers=headers, ) res.raise_for_status() actual = res.content @@ -95,7 +96,7 @@ def test_get_study( query_string = urlencode({"path": f"/{rel_path.as_posix()}", "depth": 1}) res = client.get( f"/v1/studies/{study_id}/raw?{query_string}", - headers={"Authorization": f"Bearer {user_access_token}"}, + headers=headers, ) assert res.status_code == http.HTTPStatus.UNPROCESSABLE_ENTITY @@ -104,7 +105,7 @@ def test_get_study( query_string = urlencode({"path": "/input/areas/list", "depth": 1}) res = client.get( f"/v1/studies/{study_id}/raw?{query_string}", - headers={"Authorization": f"Bearer {user_access_token}"}, + headers=headers, ) res.raise_for_status() assert res.json() == ["DE", "ES", "FR", "IT"] diff --git a/tests/integration/test_integration_xpansion.py b/tests/integration/test_integration_xpansion.py index f4f4648605..bd52a9d9ca 100644 --- a/tests/integration/test_integration_xpansion.py +++ b/tests/integration/test_integration_xpansion.py @@ -1,18 +1,16 @@ import io from pathlib import Path -from fastapi import FastAPI from starlette.testclient import TestClient from antarest.study.business.area_management import AreaType from antarest.study.business.xpansion_management import XpansionCandidateDTO -def test_integration_xpansion(app: FastAPI, tmp_path: Path): - client = TestClient(app, raise_server_exceptions=False) - res = client.post("/v1/login", json={"username": "admin", "password": "admin"}) - admin_credentials = res.json() - headers = {"Authorization": f'Bearer {admin_credentials["access_token"]}'} +def test_integration_xpansion( + client: TestClient, tmp_path: Path, admin_access_token: str +): + headers = {"Authorization": f"Bearer {admin_access_token}"} created = client.post( "/v1/studies?name=foo", From 29b1f71856463542dcc0170fe97bc6832ec4a72a Mon Sep 17 00:00:00 2001 From: belthlemar Date: Thu, 31 Aug 2023 17:12:14 +0200 Subject: [PATCH 2/9] feat(tests): add a test to ensure GET /raw endpoint reads NaN values --- .../raw_studies_blueprint/test_fetch_raw_data.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py b/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py index 3090dddc5a..7b5bc4e38e 100644 --- a/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py +++ b/tests/integration/raw_studies_blueprint/test_fetch_raw_data.py @@ -4,6 +4,7 @@ import shutil from urllib.parse import urlencode +import numpy as np import pytest from starlette.testclient import TestClient @@ -109,3 +110,11 @@ def test_get_study( ) res.raise_for_status() assert res.json() == ["DE", "ES", "FR", "IT"] + + # asserts that the GET /raw endpoint is able to read matrix containing NaN values + res = client.get( + f"/v1/studies/{study_id}/raw?path=output/20201014-1427eco/economy/mc-all/areas/de/id-monthly", + headers=headers, + ) + assert res.status_code == 200 + assert np.isnan(res.json()["data"][0]).any() From 7394248821ad5e2e8e5b51d389896c745740225d Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Tue, 5 Sep 2023 18:26:01 +0200 Subject: [PATCH 3/9] fix(api): allow `NaN`, `+Infinity`, and `-Infinity` values in JSON response --- antarest/study/web/raw_studies_blueprint.py | 4 ++++ tests/integration/test_integration_xpansion.py | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/antarest/study/web/raw_studies_blueprint.py b/antarest/study/web/raw_studies_blueprint.py index 7f60c1c587..1105a5f74a 100644 --- a/antarest/study/web/raw_studies_blueprint.py +++ b/antarest/study/web/raw_studies_blueprint.py @@ -136,6 +136,10 @@ def get_study( # because it's better to avoid raising an exception. return Response(content=output, media_type="application/octet-stream") + # We want to allow `NaN`, `+Infinity`, and `-Infinity` values in the JSON response + # even though they are not standard JSON values because they are supported in JavaScript. + # Additionally, we cannot use `orjson` because, despite its superior performance, it converts + # `NaN` and other values to `null`, even when using a custom encoder. json_response = json.dumps( output, ensure_ascii=False, diff --git a/tests/integration/test_integration_xpansion.py b/tests/integration/test_integration_xpansion.py index bd52a9d9ca..0aa0579734 100644 --- a/tests/integration/test_integration_xpansion.py +++ b/tests/integration/test_integration_xpansion.py @@ -7,9 +7,7 @@ from antarest.study.business.xpansion_management import XpansionCandidateDTO -def test_integration_xpansion( - client: TestClient, tmp_path: Path, admin_access_token: str -): +def test_integration_xpansion(client: TestClient, tmp_path: Path, admin_access_token: str): headers = {"Authorization": f"Bearer {admin_access_token}"} created = client.post( From 83e17c4dd8e212da8a8cfc2b23c1b1eb93cca9c4 Mon Sep 17 00:00:00 2001 From: Hatim Dinia Date: Tue, 3 Oct 2023 17:47:47 +0200 Subject: [PATCH 4/9] feat(ui-outputs): add outputs synthesis view (#1737) --- webapp/public/locales/fr/main.json | 2 +- .../explore/Results/ResultDetails/index.tsx | 217 +++++++++++------- .../explore/Results/ResultDetails/utils.ts | 24 ++ 3 files changed, 155 insertions(+), 88 deletions(-) diff --git a/webapp/public/locales/fr/main.json b/webapp/public/locales/fr/main.json index d60556d964..eee1289e74 100644 --- a/webapp/public/locales/fr/main.json +++ b/webapp/public/locales/fr/main.json @@ -198,7 +198,7 @@ "study.timeLimitHelper": "Limite de temps en heures (max: {{max}}h)", "study.nbCpu": "Nombre de coeurs", "study.clusterLoad": "Charge du cluster", - "study.synthesis": "Synthesis", + "study.synthesis": "Synthèse", "study.level": "Niveau", "study.years": "Années", "study.type": "Type", diff --git a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx index abc29e9b4b..a28e7359af 100644 --- a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx @@ -1,6 +1,7 @@ import { Box, Button, + Paper, Skeleton, ToggleButton, ToggleButtonGroup, @@ -32,7 +33,13 @@ import PropertiesView from "../../../../../common/PropertiesView"; import SplitLayoutView from "../../../../../common/SplitLayoutView"; import ListElement from "../../common/ListElement"; import SelectionDrawer, { SelectionDrawerProps } from "./SelectionDrawer"; -import { createPath, DataType, OutputItemType, Timestep } from "./utils"; +import { + createPath, + DataType, + OutputItemType, + SYNTHESIS_ITEMS, + Timestep, +} from "./utils"; import UsePromiseCond, { mergeResponses, } from "../../../../../common/utils/UsePromiseCond"; @@ -57,6 +64,7 @@ function ResultDetails() { const [itemType, setItemType] = useState(OutputItemType.Areas); const [selectedItemId, setSelectedItemId] = useState(""); const [searchValue, setSearchValue] = useState(""); + const isSynthesis = itemType === OutputItemType.Synthesis; const { t } = useTranslation(); const navigate = useNavigate(); @@ -67,10 +75,12 @@ function ResultDetails() { ) as Array<{ id: string; name: string; label?: string }>; const filteredItems = useMemo(() => { - return items.filter((item) => - isSearchMatching(searchValue, item.label || item.name) - ); - }, [items, searchValue]); + return isSynthesis + ? SYNTHESIS_ITEMS + : items.filter((item) => + isSearchMatching(searchValue, item.label || item.name) + ); + }, [isSynthesis, items, searchValue]); const selectedItem = filteredItems.find( (item) => item.id === selectedItemId @@ -92,7 +102,7 @@ function ResultDetails() { const matrixRes = usePromise( async () => { - if (output && selectedItem) { + if (output && selectedItem && !isSynthesis) { const path = createPath({ output: { ...output, id: outputId as string }, item: selectedItem, @@ -120,6 +130,20 @@ function ResultDetails() { } ); + const { data: synthesis } = usePromise( + async () => { + if (outputId && selectedItem && isSynthesis) { + const path = `output/${outputId}/economy/mc-all/grid/${selectedItem.id}`; + const res = await getStudyData(study.id, path); + return res; + } + return null; + }, + { + deps: [study.id, outputId, selectedItem], + } + ); + //////////////////////////////////////////////////////////////// // Event Handlers //////////////////////////////////////////////////////////////// @@ -171,6 +195,7 @@ function ResultDetails() { value={itemType} exclusive size="small" + orientation="vertical" fullWidth onChange={handleItemTypeChange} > @@ -180,6 +205,9 @@ function ResultDetails() { {t("study.links")} + + {t("study.synthesis")} + - - {[ - [ - `${t("study.results.mc")}:`, - year > 0 ? `${t("study.results.mc.year")} ${year}` : "all", - ], - [`${t("study.results.display")}:`, dataType], - [`${t("study.results.temporality")}:`, timestep], - ].map(([label, value]) => ( - - - {label} - - {value} - - ))} - - - - - - ( - - )} - ifResolved={([, matrix]) => - matrix && ( - - ) - } - ifRejected={(err) => ( - {synthesis} + + ) : ( + <> + + {[ + [ + `${t("study.results.mc")}:`, + year > 0 + ? `${t("study.results.mc.year")} ${year}` + : "all", + ], + [`${t("study.results.display")}:`, dataType], + [`${t("study.results.temporality")}:`, timestep], + ].map(([label, value]) => ( + + + {label} + + {value} + + ))} + + + + + ( + )} - - )} - /> - + ifResolved={([, matrix]) => + matrix && ( + + ) + } + ifRejected={(err) => ( + + {axios.isAxiosError(err) && + err.response?.status === 404 ? ( + <> + + {t("study.results.noData")} + + ) : ( + t("data.error.matrix") + )} + + )} + /> + + + )} } /> diff --git a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/utils.ts b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/utils.ts index 6b2c53913b..a2bcdd4af9 100644 --- a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/utils.ts +++ b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/utils.ts @@ -3,6 +3,7 @@ import { Area, LinkElement, Simulation } from "../../../../../../common/types"; export enum OutputItemType { Areas = "areas", Links = "links", + Synthesis = "synthesis", } export enum DataType { @@ -43,3 +44,26 @@ export function createPath(params: Params): string { return `output/${id}/${mode}/${periodFolder}/${itemType}/${itemFolder}/${dataType}-${timestep}`; } + +export const SYNTHESIS_ITEMS = [ + { + id: "areas", + name: "Areas", + label: "Areas synthesis", + }, + { + id: "links", + name: "Links", + label: "Links synthesis", + }, + { + id: "digest", + name: "Digest", + label: "Digest", + }, + { + id: "thermal", + name: "Thermal", + label: "Thermal synthesis", + }, +]; From 71fa15fb4719323b065a026a92d7061a3bc6e01b Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Wed, 4 Oct 2023 09:04:44 +0200 Subject: [PATCH 5/9] build: prepare next bug fix release v2.15.1 (2023-10-04) --- antarest/__init__.py | 4 ++-- docs/CHANGELOG.md | 21 +++++++++++++++++++++ setup.py | 2 +- sonar-project.properties | 2 +- webapp/package-lock.json | 2 +- webapp/package.json | 2 +- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/antarest/__init__.py b/antarest/__init__.py index bd53e7a23c..4a6d2e3638 100644 --- a/antarest/__init__.py +++ b/antarest/__init__.py @@ -7,9 +7,9 @@ # Standard project metadata -__version__ = "2.15.0" +__version__ = "2.15.1" __author__ = "RTE, Antares Web Team" -__date__ = "2023-09-30" +__date__ = "2023-10-04" # noinspection SpellCheckingInspection __credits__ = "(c) Réseau de Transport de l’Électricité (RTE)" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index cd2ae9ff87..151671ecb1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,27 @@ Antares Web Changelog ===================== +v2.15.1 (2023-10-04) +-------------------- + +### Features + +* **ui-outputs:** add outputs synthesis view [`#1737`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1737) + + +### Bug Fixes + +* **raw:** impossible to see matrix containing NaN values [`#1714`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1714) +* **raw:** allow NaN in matrices [`0cad1a9`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/0cad1a969fd14e81cf502aecb821df4b2d7abcb6) +* **api:** allow `NaN`, `+Infinity`, and `-Infinity` values in JSON response [`7394248`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/7394248821ad5e2e8e5b51d389896c745740225d) + + +### Tests + +* **tests:** add a test to ensure GET `/raw` endpoint reads NaN values [`29b1f71`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/29b1f71856463542dcc0170fe97bc6832ec4a72a) + + + v2.15.0 (2023-09-30) -------------------- diff --git a/setup.py b/setup.py index 323d8deb7b..92e4e34f98 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="AntaREST", - version="2.15.0", + version="2.15.1", description="Antares Server", long_description=Path("README.md").read_text(encoding="utf-8"), long_description_content_type="text/markdown", diff --git a/sonar-project.properties b/sonar-project.properties index 3fb85c7559..9bf66c1c14 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -6,5 +6,5 @@ sonar.exclusions=antarest/gui.py,antarest/main.py sonar.python.coverage.reportPaths=coverage.xml sonar.python.version=3.8 sonar.javascript.lcov.reportPaths=webapp/coverage/lcov.info -sonar.projectVersion=2.15.0 +sonar.projectVersion=2.15.1 sonar.coverage.exclusions=antarest/gui.py,antarest/main.py,antarest/singleton_services.py,antarest/worker/archive_worker_service.py,webapp/**/* \ No newline at end of file diff --git a/webapp/package-lock.json b/webapp/package-lock.json index af03a6bde3..7d2f92946c 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -1,6 +1,6 @@ { "name": "antares-web", - "version": "2.15.0", + "version": "2.15.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/webapp/package.json b/webapp/package.json index 3a5251d7f8..74a8fd65f0 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -1,6 +1,6 @@ { "name": "antares-web", - "version": "2.15.0", + "version": "2.15.1", "private": true, "engines": { "node": "18.16.1" From 7d70db47c0434a2d199f0fce396a4371afb21fa1 Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:41:06 +0200 Subject: [PATCH 6/9] feat(ui-results): move filters on top of matrices (#1751) --- webapp/public/locales/en/main.json | 1 - webapp/public/locales/fr/main.json | 3 +- .../Results/ResultDetails/SelectionDrawer.tsx | 124 ------ .../explore/Results/ResultDetails/index.tsx | 378 ++++++++++-------- 4 files changed, 219 insertions(+), 287 deletions(-) delete mode 100644 webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/SelectionDrawer.tsx diff --git a/webapp/public/locales/en/main.json b/webapp/public/locales/en/main.json index f7651f99b1..e966640063 100644 --- a/webapp/public/locales/en/main.json +++ b/webapp/public/locales/en/main.json @@ -479,7 +479,6 @@ "study.modelization.bindingConst.question.deleteConstraintTerm": "Are you sure you want to delete this constraint term?", "study.modelization.bindingConst.question.deleteBindingConstraint": "Are you sure you want to delete this binding constraint?", "study.results.mc": "Monte-Carlo", - "study.results.mc.year": "Year", "study.results.display": "Display", "study.results.temporality": "Temporality", "study.results.noData": "No data available", diff --git a/webapp/public/locales/fr/main.json b/webapp/public/locales/fr/main.json index eee1289e74..90a338597b 100644 --- a/webapp/public/locales/fr/main.json +++ b/webapp/public/locales/fr/main.json @@ -110,7 +110,7 @@ "form.submit.inProgress": "Le formulaire est en cours de soumission. Etes-vous sûr de vouloir quitter la page ?", "form.asyncDefaultValues.error": "Impossible d'obtenir les valeurs", "form.field.required": "Champ requis", - "form.field.duplicate": "Cette valeur existe déjà: {{0}}", + "form.field.duplicate": "Cette valeur existe déjà: {{0}}", "form.field.minLength": "{{0}} caractère(s) minimum", "form.field.minValue": "La valeur minimum est {{0}}", "form.field.maxValue": "La valeur maximum est {{0}}", @@ -479,7 +479,6 @@ "study.modelization.bindingConst.question.deleteConstraintTerm": "Êtes-vous sûr de vouloir supprimer ce terme ?", "study.modelization.bindingConst.question.deleteBindingConstraint": "Êtes-vous sûr de vouloir supprimer cette contrainte couplante ?", "study.results.mc": "Monte-Carlo", - "study.results.mc.year": "année", "study.results.display": "Affichage", "study.results.temporality": "Temporalité", "study.results.noData": "Aucune donnée disponible", diff --git a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/SelectionDrawer.tsx b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/SelectionDrawer.tsx deleted file mode 100644 index da3aef3229..0000000000 --- a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/SelectionDrawer.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { Box, Button, Drawer, RadioGroup } from "@mui/material"; -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import BooleanFE from "../../../../../common/fieldEditors/BooleanFE"; -import NumberFE from "../../../../../common/fieldEditors/NumberFE"; -import RadioFE from "../../../../../common/fieldEditors/RadioFE"; -import Fieldset from "../../../../../common/Fieldset"; -import { DataType, MAX_YEAR, Timestep } from "./utils"; - -export interface SelectionDrawerProps { - open: boolean; - onClose: () => void; - values: { - dataType: DataType; - timestep: Timestep; - year: number; - }; - maxYear?: number; - onSelection: (values: SelectionDrawerProps["values"]) => void; -} - -function SelectionDrawer(props: SelectionDrawerProps) { - const { open, onClose, values, maxYear = MAX_YEAR, onSelection } = props; - const [dataTypeTmp, setDataTypeTmp] = useState(values.dataType); - const [timestepTmp, setTimestepTemp] = useState(values.timestep); - const [yearTmp, setYearTmp] = useState(values.year); - const { t } = useTranslation(); - - useEffect(() => { - setDataTypeTmp(values.dataType); - setTimestepTemp(values.timestep); - setYearTmp(values.year); - }, [values.dataType, values.timestep, values.year]); - - //////////////////////////////////////////////////////////////// - // Event Handlers - //////////////////////////////////////////////////////////////// - - const handleSelection = () => { - onSelection({ - dataType: dataTypeTmp, - timestep: timestepTmp, - year: yearTmp, - }); - onClose(); - }; - - const handleClose = () => { - setDataTypeTmp(values.dataType); - setTimestepTemp(values.timestep); - setYearTmp(values.year); - onClose(); - }; - - //////////////////////////////////////////////////////////////// - // JSX - //////////////////////////////////////////////////////////////// - - return ( - - -
- { - setYearTmp(event?.target.value ? -1 : 1); - }} - /> - {yearTmp > 0 && ( - { - const value = Number(event.target.value); - setYearTmp(value > maxYear ? maxYear : value); - }} - /> - )} -
-
- setDataTypeTmp(value as DataType)} - > - - - - - -
-
- setTimestepTemp(value as Timestep)} - > - - - - - - -
-
- - - -
- ); -} - -export default SelectionDrawer; diff --git a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx index a28e7359af..f89b584035 100644 --- a/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Results/ResultDetails/index.tsx @@ -32,10 +32,10 @@ import EditableMatrix from "../../../../../common/EditableMatrix"; import PropertiesView from "../../../../../common/PropertiesView"; import SplitLayoutView from "../../../../../common/SplitLayoutView"; import ListElement from "../../common/ListElement"; -import SelectionDrawer, { SelectionDrawerProps } from "./SelectionDrawer"; import { createPath, DataType, + MAX_YEAR, OutputItemType, SYNTHESIS_ITEMS, Timestep, @@ -46,6 +46,9 @@ import UsePromiseCond, { import useStudySynthesis from "../../../../../../redux/hooks/useStudySynthesis"; import { downloadMatrix } from "../../../../../../utils/matrixUtils"; import ButtonBack from "../../../../../common/ButtonBack"; +import BooleanFE from "../../../../../common/fieldEditors/BooleanFE"; +import SelectFE from "../../../../../common/fieldEditors/SelectFE"; +import NumberFE from "../../../../../common/fieldEditors/NumberFE"; function ResultDetails() { const { study } = useOutletContext<{ study: StudyMetadata }>(); @@ -60,7 +63,6 @@ function ResultDetails() { const [dataType, setDataType] = useState(DataType.General); const [timestep, setTimeStep] = useState(Timestep.Hourly); const [year, setYear] = useState(-1); - const [showFilter, setShowFilter] = useState(false); const [itemType, setItemType] = useState(OutputItemType.Areas); const [selectedItemId, setSelectedItemId] = useState(""); const [searchValue, setSearchValue] = useState(""); @@ -86,6 +88,8 @@ function ResultDetails() { (item) => item.id === selectedItemId ) as (Area & { id: string }) | LinkElement | undefined; + const maxYear = output?.nbyears ?? MAX_YEAR; + useEffect( () => { const isValidSelectedItem = @@ -104,7 +108,7 @@ function ResultDetails() { async () => { if (output && selectedItem && !isSynthesis) { const path = createPath({ - output: { ...output, id: outputId as string }, + output, item: selectedItem, dataType, timestep, @@ -126,7 +130,7 @@ function ResultDetails() { { resetDataOnReload: true, resetErrorOnReload: true, - deps: [study.id, output, selectedItem], + deps: [study.id, output, selectedItem, dataType, timestep, year], } ); @@ -155,16 +159,6 @@ function ResultDetails() { setItemType(value); }; - const handleSelection: SelectionDrawerProps["onSelection"] = ({ - dataType, - timestep, - year, - }) => { - setDataType(dataType); - setTimeStep(timestep); - setYear(year); - }; - const handleDownload = (matrixData: MatrixType, fileName: string): void => { downloadMatrix(matrixData, fileName); }; @@ -174,53 +168,53 @@ function ResultDetails() { //////////////////////////////////////////////////////////////// return ( - <> - + navigate("..")} /> + + } + mainContent={ + <> + - navigate("..")} /> - - } - mainContent={ - <> - - - {t("study.areas")} - - - {t("study.links")} - - - {t("study.synthesis")} - - - setSelectedItemId(item.id)} - /> - - } - onSearchFilterChange={setSearchValue} - /> - } - right={ + + {t("study.areas")} + + + {t("study.links")} + + + {t("study.synthesis")} + + + setSelectedItemId(item.id)} + /> + + } + onSearchFilterChange={setSearchValue} + /> + } + right={ + isSynthesis ? ( - {isSynthesis ? ( - - {synthesis} - - ) : ( - <> + + {synthesis} + + + ) : ( + + + {( + [ + [ + `${t("study.results.mc")}:`, + () => ( + <> + { + setYear(event?.target.value ? -1 : 1); + }} + /> + {year > 0 && ( + { + setYear(Number(event.target.value)); + }} + /> + )} + + ), + ], + [ + `${t("study.results.display")}:`, + () => ( + { + setDataType(event?.target.value as DataType); + }} + /> + ), + ], + [ + `${t("study.results.temporality")}:`, + () => ( + { + setTimeStep(event?.target.value as Timestep); + }} + /> + ), + ], + ] as const + ).map(([label, Field]) => ( - {[ - [ - `${t("study.results.mc")}:`, - year > 0 - ? `${t("study.results.mc.year")} ${year}` - : "all", - ], - [`${t("study.results.display")}:`, dataType], - [`${t("study.results.temporality")}:`, timestep], - ].map(([label, value]) => ( - - - {label} - - {value} - - ))} - - + + {label} + + - - ( - - )} - ifResolved={([, matrix]) => - matrix && ( - - ) - } - ifRejected={(err) => ( - - {axios.isAxiosError(err) && - err.response?.status === 404 ? ( - <> - - {t("study.results.noData")} - - ) : ( - t("data.error.matrix") - )} - + ))} + + + + ( + + )} + ifResolved={([, matrix]) => + matrix && ( + + ) + } + ifRejected={(err) => ( + + {axios.isAxiosError(err) && err.response?.status === 404 ? ( + <> + + {t("study.results.noData")} + + ) : ( + t("data.error.matrix") )} - /> - - - )} + + )} + /> + - } - /> - setShowFilter(false)} - values={{ dataType, timestep, year }} - maxYear={output?.nbyears} - onSelection={handleSelection} - /> - + ) + } + /> ); } From f9ef1bc63e8f52fc726fbebda58f383ba05731b7 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Wed, 4 Oct 2023 13:26:10 +0200 Subject: [PATCH 7/9] build: update CHANGELOG.md for release v2.15.1 (2023-10-04) --- docs/CHANGELOG.md | 1 + webapp/package-lock.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 151671ecb1..1a0cb92ec2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,7 @@ v2.15.1 (2023-10-04) ### Features +* **ui-results:** move filters on top of matrices [`#1751`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1751) * **ui-outputs:** add outputs synthesis view [`#1737`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1737) diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 7d2f92946c..9a4f7cd401 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "antares-web", - "version": "2.14.4", + "version": "2.15.1", "dependencies": { "@emotion/react": "11.10.6", "@emotion/styled": "11.10.6", From 71f7129f83f15e6670fbf14f18844afcc5c7b67f Mon Sep 17 00:00:00 2001 From: Hatim Dinia Date: Thu, 5 Oct 2023 13:21:03 +0200 Subject: [PATCH 8/9] fix(ui-xpansion): display issue in form (#1754) --- .../Xpansion/Settings/SettingsForm.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/webapp/src/components/App/Singlestudy/explore/Xpansion/Settings/SettingsForm.tsx b/webapp/src/components/App/Singlestudy/explore/Xpansion/Settings/SettingsForm.tsx index b03440c7b4..b8fe5b9076 100644 --- a/webapp/src/components/App/Singlestudy/explore/Xpansion/Settings/SettingsForm.tsx +++ b/webapp/src/components/App/Singlestudy/explore/Xpansion/Settings/SettingsForm.tsx @@ -180,22 +180,22 @@ function SettingsForm(props: PropType) { label={t("xpansion.solver")} data={currentSettings.solver || ""} handleChange={handleChange} + optional sx={{ minWidth: "100%", }} - optional - /> - - handleChange("batch_size", parseInt(e.target.value, 10)) - } - sx={{ mb: 1 }} /> + + handleChange("batch_size", parseInt(e.target.value, 10)) + } + sx={{ mb: 1 }} + /> Date: Thu, 5 Oct 2023 14:17:50 +0200 Subject: [PATCH 9/9] build: update CHANGELOG.md for release v2.15.1 (2023-10-05) --- antarest/__init__.py | 2 +- docs/CHANGELOG.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/antarest/__init__.py b/antarest/__init__.py index 4a6d2e3638..4023e2ca7b 100644 --- a/antarest/__init__.py +++ b/antarest/__init__.py @@ -9,7 +9,7 @@ __version__ = "2.15.1" __author__ = "RTE, Antares Web Team" -__date__ = "2023-10-04" +__date__ = "2023-10-05" # noinspection SpellCheckingInspection __credits__ = "(c) Réseau de Transport de l’Électricité (RTE)" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1a0cb92ec2..e6d96180aa 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,7 +1,7 @@ Antares Web Changelog ===================== -v2.15.1 (2023-10-04) +v2.15.1 (2023-10-05) -------------------- ### Features @@ -12,9 +12,10 @@ v2.15.1 (2023-10-04) ### Bug Fixes +* **api:** allow `NaN`, `+Infinity`, and `-Infinity` values in JSON response [`7394248`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/7394248821ad5e2e8e5b51d389896c745740225d) +* **ui-xpansion:** display issue in form [`#1754`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1754) * **raw:** impossible to see matrix containing NaN values [`#1714`](https://github.com/AntaresSimulatorTeam/AntaREST/pull/1714) * **raw:** allow NaN in matrices [`0cad1a9`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/0cad1a969fd14e81cf502aecb821df4b2d7abcb6) -* **api:** allow `NaN`, `+Infinity`, and `-Infinity` values in JSON response [`7394248`](https://github.com/AntaresSimulatorTeam/AntaREST/commit/7394248821ad5e2e8e5b51d389896c745740225d) ### Tests