diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx index 27d924635a..836880d836 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx @@ -10,6 +10,7 @@ import { convertOutputValue, CustomFormProvider, FieldType, + MODIFICATION_TYPES, useSnackMessage, } from '@gridsuite/commons-ui'; import { yupResolver } from '@hookform/resolvers/yup'; @@ -17,9 +18,12 @@ import { sanitizeString } from 'components/dialogs/dialog-utils'; import EquipmentSearchDialog from 'components/dialogs/equipment-search-dialog'; import { useFormSearchCopy } from 'components/dialogs/form-search-copy-hook'; import { + ADD_SUBSTATION_CREATION, + ADDITIONAL_PROPERTIES, BUS_BAR_COUNT, BUS_BAR_SECTION_ID1, BUS_BAR_SECTION_ID2, + COUNTRY, COUPLING_OMNIBUS, EQUIPMENT_ID, EQUIPMENT_NAME, @@ -31,7 +35,10 @@ import { NAME, NOMINAL_V, SECTION_COUNT, + SUBSTATION_CREATION, + SUBSTATION_CREATION_ID, SUBSTATION_ID, + SUBSTATION_NAME, SWITCH_KIND, SWITCH_KINDS, SWITCHES_BETWEEN_SECTIONS, @@ -84,6 +91,11 @@ const emptyFormData = { [SWITCHES_BETWEEN_SECTIONS]: '', [COUPLING_OMNIBUS]: [], [SWITCH_KINDS]: [], + [ADD_SUBSTATION_CREATION]: false, + [SUBSTATION_CREATION_ID]: null, + [SUBSTATION_NAME]: null, + [COUNTRY]: null, + [SUBSTATION_CREATION]: emptyProperties, ...emptyProperties, }; @@ -92,7 +104,23 @@ const formSchema = yup .shape({ [EQUIPMENT_ID]: yup.string().required(), [EQUIPMENT_NAME]: yup.string().nullable(), - [SUBSTATION_ID]: yup.string().nullable().required(), + [SUBSTATION_ID]: yup + .string() + .nullable() + .when([ADD_SUBSTATION_CREATION], { + is: (addSubstationCreation) => addSubstationCreation === false, + then: (schema) => schema.required(), + }), + [SUBSTATION_CREATION_ID]: yup + .string() + .nullable() + .when([ADD_SUBSTATION_CREATION], { + is: (addSubstationCreation) => addSubstationCreation === true, + then: (schema) => schema.required(), + }), + [SUBSTATION_NAME]: yup.string().nullable(), + [COUNTRY]: yup.string().nullable(), + [SUBSTATION_CREATION]: creationPropertiesSchema, [NOMINAL_V]: yup.number().nullable().required(), [LOW_VOLTAGE_LIMIT]: yup.number().nullable(), [HIGH_VOLTAGE_LIMIT]: yup.number().nullable(), @@ -148,22 +176,12 @@ const VoltageLevelCreationDialog = ({ resolver: yupResolver(formSchema), }); - const { reset } = formMethods; + const { reset, setValue, getValues } = formMethods; const intl = useIntl(); - const fromExternalDataToFormValues = useCallback( (voltageLevel, fromCopy = true) => { - const properties = fromCopy - ? copyEquipmentPropertiesForCreation(voltageLevel) - : getPropertiesFromModification(voltageLevel.properties); - reset({ - [EQUIPMENT_ID]: (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[ID]) + (fromCopy ? '(1)' : ''), - [EQUIPMENT_NAME]: voltageLevel[EQUIPMENT_NAME] ?? voltageLevel[NAME], - [TOPOLOGY_KIND]: voltageLevel[TOPOLOGY_KIND], - [SUBSTATION_ID]: voltageLevel[SUBSTATION_ID], - [NOMINAL_V]: voltageLevel[NOMINAL_V], - [LOW_VOLTAGE_LIMIT]: voltageLevel[LOW_VOLTAGE_LIMIT], - [HIGH_VOLTAGE_LIMIT]: voltageLevel[HIGH_VOLTAGE_LIMIT], + const isSubstationCreation = !fromCopy && voltageLevel.substationCreation?.equipmentId != null; + const shortCircuitLimits = { [LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMin : voltageLevel.ipMin @@ -172,29 +190,67 @@ const VoltageLevelCreationDialog = ({ FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMax : voltageLevel.ipMax ), - [BUS_BAR_COUNT]: voltageLevel[BUS_BAR_COUNT] ?? 1, - [SECTION_COUNT]: voltageLevel[SECTION_COUNT] ?? 1, - [SWITCHES_BETWEEN_SECTIONS]: voltageLevel.switchKinds - ?.map((switchKind) => { - return intl.formatMessage({ id: switchKind }); - }) - .join(' / '), - [COUPLING_OMNIBUS]: voltageLevel.couplingDevices ?? [], - [SWITCH_KINDS]: - voltageLevel.switchKinds != null - ? voltageLevel.switchKinds?.map((switchKind) => ({ - [SWITCH_KIND]: switchKind, - })) - : [], - ...properties, - }); + }; + const switchKinds = + voltageLevel.switchKinds?.map((switchKind) => ({ + [SWITCH_KIND]: switchKind, + })) || []; + + const switchesBetweenSections = + voltageLevel.switchKinds?.map((switchKind) => intl.formatMessage({ id: switchKind })).join(' / ') || ''; + + const equipmentId = (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[ID]) + (fromCopy ? '(1)' : ''); + const equipmentName = voltageLevel[EQUIPMENT_NAME] ?? voltageLevel[NAME]; + const substationId = isSubstationCreation ? null : voltageLevel[SUBSTATION_ID] ?? null; + + const properties = fromCopy + ? copyEquipmentPropertiesForCreation(voltageLevel) + : getPropertiesFromModification(voltageLevel.properties); + reset( + { + [EQUIPMENT_ID]: equipmentId, + [EQUIPMENT_NAME]: equipmentName, + [TOPOLOGY_KIND]: voltageLevel[TOPOLOGY_KIND], + [SUBSTATION_ID]: substationId, + [NOMINAL_V]: voltageLevel[NOMINAL_V], + [LOW_VOLTAGE_LIMIT]: voltageLevel[LOW_VOLTAGE_LIMIT], + [HIGH_VOLTAGE_LIMIT]: voltageLevel[HIGH_VOLTAGE_LIMIT], + [LOW_VOLTAGE_LIMIT]: voltageLevel[LOW_VOLTAGE_LIMIT], + [HIGH_VOLTAGE_LIMIT]: voltageLevel[HIGH_VOLTAGE_LIMIT], + ...shortCircuitLimits, + [BUS_BAR_COUNT]: voltageLevel[BUS_BAR_COUNT] ?? 1, + [SECTION_COUNT]: voltageLevel[SECTION_COUNT] ?? 1, + [SWITCHES_BETWEEN_SECTIONS]: switchesBetweenSections, + [COUPLING_OMNIBUS]: voltageLevel.couplingDevices ?? [], + [SWITCH_KINDS]: switchKinds, + ...properties, + }, + { keepDefaultValues: true } + ); + if (isSubstationCreation) { + const substationKeys = [ + [SUBSTATION_CREATION_ID, voltageLevel.substationCreation?.equipmentId], + [SUBSTATION_NAME, voltageLevel.substationCreation?.equipmentName], + [COUNTRY, voltageLevel.substationCreation?.country], + ]; + substationKeys.forEach(([key, value]) => { + setValue(key, value); + }); + setValue( + `${SUBSTATION_CREATION}.${ADDITIONAL_PROPERTIES}`, + voltageLevel.substationCreation?.properties + ); + setValue(ADD_SUBSTATION_CREATION, true); + } else { + setValue(ADD_SUBSTATION_CREATION, false); + } if (!voltageLevel.isRetrievedBusbarSections && fromCopy) { snackWarning({ messageId: 'BusBarSectionsCopyingNotSupported', }); } }, - [intl, reset, snackWarning] + [setValue, intl, reset, snackWarning] ); const searchCopy = useFormSearchCopy({ @@ -213,12 +269,22 @@ const VoltageLevelCreationDialog = ({ const onSubmit = useCallback( (voltageLevel) => { + const substationCreation = getValues(ADD_SUBSTATION_CREATION) + ? { + type: MODIFICATION_TYPES.SUBSTATION_CREATION.type, + equipmentId: voltageLevel[SUBSTATION_CREATION_ID], + equipmentName: voltageLevel[SUBSTATION_NAME], + country: voltageLevel[COUNTRY], + properties: toModificationProperties(voltageLevel[SUBSTATION_CREATION]), + } + : null; onCreateVoltageLevel({ studyUuid: studyUuid, nodeUuid: currentNodeUuid, voltageLevelId: voltageLevel[EQUIPMENT_ID], voltageLevelName: sanitizeString(voltageLevel[EQUIPMENT_NAME]), - substationId: voltageLevel[SUBSTATION_ID], + substationId: substationCreation === null ? voltageLevel[SUBSTATION_ID] : null, + substationCreation: substationCreation, nominalV: voltageLevel[NOMINAL_V], lowVoltageLimit: voltageLevel[LOW_VOLTAGE_LIMIT], highVoltageLimit: voltageLevel[HIGH_VOLTAGE_LIMIT], @@ -247,7 +313,7 @@ const VoltageLevelCreationDialog = ({ }); }); }, - [onCreateVoltageLevel, studyUuid, currentNodeUuid, editData, snackError] + [getValues, onCreateVoltageLevel, studyUuid, currentNodeUuid, editData, snackError] ); const clear = useCallback(() => { diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx index aa221b626c..3e9ae2d619 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx @@ -6,7 +6,9 @@ */ import { + ADD_SUBSTATION_CREATION, BUS_BAR_COUNT, + COUNTRY, EQUIPMENT_ID, EQUIPMENT_NAME, HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, @@ -15,31 +17,42 @@ import { LOW_VOLTAGE_LIMIT, NOMINAL_V, SECTION_COUNT, + SUBSTATION_CREATION, + SUBSTATION_CREATION_ID, SUBSTATION_ID, + SUBSTATION_NAME, } from 'components/utils/field-constants'; -import { useEffect, useState } from 'react'; -import { VoltageAdornment, KiloAmpereAdornment } from 'components/dialogs/dialog-utils'; -import { FloatInput } from '@gridsuite/commons-ui'; -import { TextInput } from '@gridsuite/commons-ui'; -import { AutocompleteInput } from '@gridsuite/commons-ui'; -import { getObjectId } from 'components/utils/utils'; -import { Box, Grid } from '@mui/material'; -import { IntegerInput } from '@gridsuite/commons-ui'; +import { useCallback, useEffect, useState } from 'react'; +import { KiloAmpereAdornment, VoltageAdornment } from 'components/dialogs/dialog-utils'; +import { AutocompleteInput, FloatInput, IntegerInput, TextInput } from '@gridsuite/commons-ui'; +import { Box, Grid, Paper } from '@mui/material'; import { CouplingOmnibusForm } from '../coupling-omnibus/coupling-omnibus-form'; import { SwitchesBetweenSections } from '../switches-between-sections/switches-between-sections'; import { fetchEquipmentsIds } from '../../../../../services/study/network-map'; import PropertiesForm from '../../common/properties/properties-form'; -import { useWatch } from 'react-hook-form'; +import { useFormContext, useWatch } from 'react-hook-form'; import GridItem from '../../../commons/grid-item'; import GridSection from '../../../commons/grid-section'; +import IconButton from '@mui/material/IconButton'; +import { useIntl } from 'react-intl'; +import CountrySelectionInput from '../../../../utils/rhf-inputs/country-selection-input'; +import DeleteIcon from '@mui/icons-material/Delete'; +import LineSeparator from '../../../commons/line-separator'; const VoltageLevelCreationForm = ({ currentNode, studyUuid }) => { const currentNodeUuid = currentNode?.id; + const intl = useIntl(); + const { setValue } = useFormContext(); const [substations, setSubstations] = useState([]); - + const [isWithSubstationCreation, setIsWithSubstationCreation] = useState(false); const watchBusBarCount = useWatch({ name: BUS_BAR_COUNT }); const watchSectionCount = useWatch({ name: SECTION_COUNT }); + const watchAddSubstationCreation = useWatch({ name: ADD_SUBSTATION_CREATION }); + const [selectedNewSubstation, setSelectedNewSubstation] = useState(''); + useEffect(() => { + setIsWithSubstationCreation(watchAddSubstationCreation); + }, [watchAddSubstationCreation]); useEffect(() => { if (studyUuid && currentNodeUuid) { @@ -53,22 +66,50 @@ const VoltageLevelCreationForm = ({ currentNode, studyUuid }) => { ); + function getCustomPaper(children) { + return ( + + + {children} + + + {`${intl.formatMessage({ id: 'CreateSubstation' })} : ${selectedNewSubstation}`} + + + + ); + } + + const handleAddButton = useCallback(() => { + setValue(SUBSTATION_CREATION_ID, selectedNewSubstation); + setValue(ADD_SUBSTATION_CREATION, true); + setIsWithSubstationCreation(true); + }, [selectedNewSubstation, setValue]); const voltageLevelNameField = ; const substationField = ( (value === null ? '' : value)} outputTransform={(value) => value} size={'small'} formProps={{ margin: 'normal' }} + PaperComponent={({ children }) => getCustomPaper(children)} + onInputChange={(_, value) => { + if (typeof value === 'string') { + setSelectedNewSubstation(value); + } + }} + noOptionsText={''} /> ); @@ -106,14 +147,57 @@ const VoltageLevelCreationForm = ({ currentNode, studyUuid }) => { const couplingOmnibusForm = ; + const substationCreationIdField = ; + const substationCreationNameField = ; + + const substationCreationCountryField = ; + + const handleDeleteButton = useCallback(() => { + setSelectedNewSubstation(''); + setValue(ADD_SUBSTATION_CREATION, false); + setIsWithSubstationCreation(false); + }, [setValue]); + return ( <> - {voltageLevelIdField} - {voltageLevelNameField} - {substationField} + {voltageLevelIdField} + {voltageLevelNameField} - + + {isWithSubstationCreation ? ( + + + + + + {substationCreationIdField} + + + {substationCreationNameField} + + + {substationCreationCountryField} + + + + + + + + + + + + + ) : ( + + + {substationField} + + + )} + {nominalVoltageField} {lowVoltageLimitField} diff --git a/src/components/utils/field-constants.ts b/src/components/utils/field-constants.ts index 517d444ef5..244816de20 100644 --- a/src/components/utils/field-constants.ts +++ b/src/components/utils/field-constants.ts @@ -7,6 +7,10 @@ export const EQUIPMENT_ID = 'equipmentId'; export const EQUIPMENT_NAME = 'equipmentName'; +export const SUBSTATION_NAME = 'substationName'; +export const SUBSTATION_CREATION_ID = 'substationCreationId'; +export const ADD_SUBSTATION_CREATION = 'addSubstationCreationId'; +export const SUBSTATION_CREATION = 'substationCreation'; export const LOAD_TYPE = 'loadType'; export const CONNECTIVITY = 'connectivity'; export const SETPOINTS_LIMITS = 'setpointsLimits'; diff --git a/src/services/network-modification-types.ts b/src/services/network-modification-types.ts index e44d2113c1..0c47763967 100644 --- a/src/services/network-modification-types.ts +++ b/src/services/network-modification-types.ts @@ -286,6 +286,7 @@ export interface VoltageLeveInfo { } export interface VoltageLeveCreationlInfo extends VoltageLeveInfo { + substationCreation?: SubstationCreationInfo | null; ipMin: number | null; ipMax: number | null; } diff --git a/src/services/study/network-modifications.ts b/src/services/study/network-modifications.ts index 1ca88c4af2..0ab6b58ee1 100644 --- a/src/services/study/network-modifications.ts +++ b/src/services/study/network-modifications.ts @@ -1373,6 +1373,7 @@ export function createVoltageLevel({ voltageLevelId, voltageLevelName, substationId, + substationCreation, nominalV, lowVoltageLimit, highVoltageLimit, @@ -1400,6 +1401,7 @@ export function createVoltageLevel({ equipmentId: voltageLevelId, equipmentName: voltageLevelName, substationId: substationId, + substationCreation: substationCreation, nominalV: nominalV, lowVoltageLimit: lowVoltageLimit, highVoltageLimit: highVoltageLimit, diff --git a/src/translations/en.json b/src/translations/en.json index 779adf7108..af6b3b3800 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -663,6 +663,7 @@ "TabularModificationError": "Error while creating tabular modification", "TabularModificationShuntWarning": "Both maximum reactive power (and/or type) and maximum susceptance have been submitted for the same shunt compensator. Maximum susceptance will thus be ignored.", "equipmentId": "ID", + "substationName": "Substation name", "activePower": "p (MW)", "maxActivePower": "Max P (MW)", "maxP": "Max P (MW)", diff --git a/src/translations/fr.json b/src/translations/fr.json index 2f12b55bb8..6c63d5b451 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -663,6 +663,7 @@ "TabularModificationError": "Erreur lors de la modification tabulaire", "TabularModificationShuntWarning": "La modification tabulaire contient des valeurs pour la puissance réactive installée (et/ou le type) et la susceptance installée d'un même MCS. La susceptance installée sera donc ignorée.", "equipmentId": "ID", + "substationName": "Nom du site", "activePower": "p (MW)", "maxActivePower": "P max (MW)", "maxP": "P max (MW)",