-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api-ui): add Inflow Structure form in Hydro (#1919)
Merge pull request #1919 from AntaresSimulatorTeam/feature/983-add-inflow-pattern-form
- Loading branch information
Showing
11 changed files
with
403 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
tests/integration/study_data_blueprint/test_hydro_inflow_structure.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
from http import HTTPStatus | ||
from unittest.mock import ANY | ||
|
||
import pytest | ||
from starlette.testclient import TestClient | ||
|
||
|
||
@pytest.mark.unit_test | ||
class TestHydroInflowStructure: | ||
""" | ||
Test the end points related to hydraulic inflow-structure. | ||
Those tests use the "examples/studies/STA-mini.zip" Study, | ||
which contains the following areas: ["de", "es", "fr", "it"]. | ||
""" | ||
|
||
def test_get_inflow_structure( | ||
self, | ||
client: TestClient, | ||
user_access_token: str, | ||
study_id: str, | ||
): | ||
user_header = {"Authorization": f"Bearer {user_access_token}"} | ||
area_id = "fr" | ||
|
||
# ==================== | ||
# Use case : RAW study | ||
# ==================== | ||
|
||
# Check that the default values are returned | ||
res = client.get( | ||
f"/v1/studies/{study_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
actual = res.json() | ||
expected = {"interMonthlyCorrelation": 0.5} | ||
assert actual == expected | ||
|
||
# Update the values | ||
obj = {"interMonthlyCorrelation": 0.8} | ||
res = client.put( | ||
f"/v1/studies/{study_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
json=obj, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
|
||
# Check that the right values are returned | ||
res = client.get( | ||
f"/v1/studies/{study_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
actual = res.json() | ||
expected = {"interMonthlyCorrelation": 0.8} | ||
assert actual == expected | ||
|
||
# ======================== | ||
# Use case : Variant study | ||
# ======================== | ||
|
||
# Create a managed study from the RAW study. | ||
res = client.post( | ||
f"/v1/studies/{study_id}/copy", | ||
headers={"Authorization": f"Bearer {user_access_token}"}, | ||
params={"dest": "Clone", "with_outputs": False, "use_task": False}, | ||
) | ||
res.raise_for_status() | ||
managed_id = res.json() | ||
assert managed_id is not None | ||
|
||
# Create a variant from the managed study. | ||
res = client.post( | ||
f"/v1/studies/{managed_id}/variants", | ||
headers={"Authorization": f"Bearer {user_access_token}"}, | ||
params={"name": "Variant"}, | ||
) | ||
res.raise_for_status() | ||
variant_id = res.json() | ||
assert variant_id is not None | ||
|
||
# Check that the return values match the RAW study values | ||
res = client.get( | ||
f"/v1/studies/{variant_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
actual = res.json() | ||
expected = {"interMonthlyCorrelation": 0.8} | ||
assert actual == expected | ||
|
||
# Update the values | ||
obj = {"interMonthlyCorrelation": 0.9} | ||
res = client.put( | ||
f"/v1/studies/{variant_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
json=obj, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
|
||
# Check that the right values are returned | ||
res = client.get( | ||
f"/v1/studies/{variant_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
actual = res.json() | ||
expected = {"interMonthlyCorrelation": 0.9} | ||
assert actual == expected | ||
|
||
# Check the variant commands | ||
res = client.get( | ||
f"/v1/studies/{variant_id}/commands", | ||
headers=user_header, | ||
) | ||
assert res.status_code == HTTPStatus.OK, res.json() | ||
actual = res.json() | ||
assert len(actual) == 2 | ||
expected = { | ||
"id": ANY, | ||
"action": "update_config", | ||
"args": { | ||
"target": "input/hydro/prepro/fr/prepro/prepro", | ||
"data": {"intermonthly-correlation": 0.9}, | ||
}, | ||
"version": 1, | ||
} | ||
assert actual[1] == expected | ||
|
||
def test_update_inflow_structure__invalid_values( | ||
self, | ||
client: TestClient, | ||
user_access_token: str, | ||
study_id: str, | ||
): | ||
user_header = {"Authorization": f"Bearer {user_access_token}"} | ||
area_id = "fr" | ||
|
||
# Update the values with invalid values | ||
obj = {"interMonthlyCorrelation": 1.1} | ||
res = client.put( | ||
f"/v1/studies/{study_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
json=obj, | ||
) | ||
assert res.status_code == HTTPStatus.UNPROCESSABLE_ENTITY, res.json() | ||
|
||
obj = {"interMonthlyCorrelation": -0.1} | ||
res = client.put( | ||
f"/v1/studies/{study_id}/areas/{area_id}/hydro/inflow-structure", | ||
headers=user_header, | ||
json=obj, | ||
) | ||
assert res.status_code == HTTPStatus.UNPROCESSABLE_ENTITY, res.json() |
67 changes: 67 additions & 0 deletions
67
...src/components/App/Singlestudy/explore/Modelization/Areas/Hydro/InflowStructure/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { useOutletContext } from "react-router"; | ||
import { StudyMetadata } from "../../../../../../../../common/types"; | ||
import useAppSelector from "../../../../../../../../redux/hooks/useAppSelector"; | ||
import { getCurrentAreaId } from "../../../../../../../../redux/selectors"; | ||
import Form from "../../../../../../../common/Form"; | ||
import { | ||
type InflowStructureFields, | ||
getInflowStructureFields, | ||
updateInflowStructureFields, | ||
} from "./utils"; | ||
import NumberFE from "../../../../../../../common/fieldEditors/NumberFE"; | ||
import { SubmitHandlerPlus } from "../../../../../../../common/Form/types"; | ||
import { useTranslation } from "react-i18next"; | ||
|
||
function InflowStructure() { | ||
const [t] = useTranslation(); | ||
const { study } = useOutletContext<{ study: StudyMetadata }>(); | ||
const areaId = useAppSelector(getCurrentAreaId); | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Event handlers | ||
//////////////////////////////////////////////////////////////// | ||
|
||
const handleSubmit = (data: SubmitHandlerPlus<InflowStructureFields>) => { | ||
return updateInflowStructureFields(study.id, areaId, data.values); | ||
}; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// JSX | ||
//////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<Form | ||
key={study.id + areaId} | ||
config={{ | ||
defaultValues: () => getInflowStructureFields(study.id, areaId), | ||
}} | ||
onSubmit={handleSubmit} | ||
miniSubmitButton | ||
enableUndoRedo | ||
sx={{ display: "flex", alignItems: "center", ".Form__Footer": { p: 0 } }} | ||
> | ||
{({ control }) => ( | ||
<NumberFE | ||
label="Inter-Monthly Correlation" | ||
name="interMonthlyCorrelation" | ||
control={control} | ||
rules={{ | ||
min: { | ||
value: 0, | ||
message: t("form.field.minValue", { 0: 0 }), | ||
}, | ||
max: { | ||
value: 1, | ||
message: t("form.field.maxValue", { 0: 1 }), | ||
}, | ||
}} | ||
inputProps={{ step: 0.1 }} | ||
size="small" | ||
sx={{ width: 180 }} | ||
/> | ||
)} | ||
</Form> | ||
); | ||
} | ||
|
||
export default InflowStructure; |
34 changes: 34 additions & 0 deletions
34
.../src/components/App/Singlestudy/explore/Modelization/Areas/Hydro/InflowStructure/utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { type StudyMetadata } from "../../../../../../../../common/types"; | ||
import client from "../../../../../../../../services/api/client"; | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Types | ||
//////////////////////////////////////////////////////////////// | ||
|
||
export interface InflowStructureFields { | ||
interMonthlyCorrelation: number; | ||
} | ||
|
||
//////////////////////////////////////////////////////////////// | ||
// Utils | ||
//////////////////////////////////////////////////////////////// | ||
|
||
function makeRequestURL(studyId: StudyMetadata["id"], areaId: string): string { | ||
return `v1/studies/${studyId}/areas/${areaId}/hydro/inflow-structure`; | ||
} | ||
|
||
export async function getInflowStructureFields( | ||
studyId: StudyMetadata["id"], | ||
areaId: string, | ||
): Promise<InflowStructureFields> { | ||
const res = await client.get(makeRequestURL(studyId, areaId)); | ||
return res.data; | ||
} | ||
|
||
export function updateInflowStructureFields( | ||
studyId: StudyMetadata["id"], | ||
areaId: string, | ||
values: InflowStructureFields, | ||
): Promise<void> { | ||
return client.put(makeRequestURL(studyId, areaId), values); | ||
} |
Oops, something went wrong.