From e0e957be4cf1f02d9a508c718e171a32abeb74a2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Mar 2026 09:05:37 +0000 Subject: [PATCH 01/11] refactor: use generic VoltageLevelCreationForm from commons-ui Refactor the voltage level creation form to use the generic VoltageLevelCreationForm from @gridsuite/commons-ui. The study-specific form (StudyVoltageLevelCreationForm) now wraps the generic form and adds: - Substation autocomplete with create-inline option - Bus bar count, section count, coupling omnibus, switches between sections - Attachment point mode support The dialog is updated to use commons-ui field constants (FieldConstants.EQUIPMENT_ID instead of the local EQUIPMENT_ID) for consistency with the generic form's field naming convention. https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level-creation-dialog.tsx | 129 ++++++----- .../creation/voltage-level-creation-form.tsx | 219 ++++++------------ 2 files changed, 141 insertions(+), 207 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 1884cbc5f4..2f3f6b04b8 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -24,6 +24,12 @@ import { DeepNullable, sanitizeString, FieldConstants, + VL_SUBSTATION_ID, + VL_NOMINAL_V, + VL_LOW_VOLTAGE_LIMIT, + VL_HIGH_VOLTAGE_LIMIT, + VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT, + VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, } from '@gridsuite/commons-ui'; import { yupResolver } from '@hookform/resolvers/yup'; import EquipmentSearchDialog from 'components/dialogs/equipment-search-dialog'; @@ -35,18 +41,12 @@ import { BUS_BAR_SECTION_ID2, COUPLING_OMNIBUS, EQUIPMENT_ID, - HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, - HIGH_VOLTAGE_LIMIT, ID, IS_ATTACHMENT_POINT_CREATION, - LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - LOW_VOLTAGE_LIMIT, NAME, - NOMINAL_V, SECTION_COUNT, SUBSTATION_CREATION, SUBSTATION_CREATION_ID, - SUBSTATION_ID, SUBSTATION_NAME, SWITCH_KIND, SWITCH_KINDS, @@ -58,7 +58,7 @@ import { FC, useCallback, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; -import VoltageLevelCreationForm from './voltage-level-creation-form'; +import StudyVoltageLevelCreationForm from './voltage-level-creation-form'; import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; import { useIntl } from 'react-intl'; import { FORM_LOADING_DELAY } from 'components/network/constants'; @@ -82,18 +82,18 @@ interface VoltageLevelCreationFormData { [BUS_BAR_COUNT]: number; [FieldConstants.COUNTRY]: string | null; [COUPLING_OMNIBUS]: CreateCouplingDeviceDialogSchemaForm[]; - [EQUIPMENT_ID]: string; + [FieldConstants.EQUIPMENT_ID]: string; [FieldConstants.EQUIPMENT_NAME]: string; - [HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [HIGH_VOLTAGE_LIMIT]: number | null; + [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; + [VL_HIGH_VOLTAGE_LIMIT]: number | null; [IS_ATTACHMENT_POINT_CREATION]: boolean; - [LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [LOW_VOLTAGE_LIMIT]: number | null; - [NOMINAL_V]: number | null; + [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; + [VL_LOW_VOLTAGE_LIMIT]: number | null; + [VL_NOMINAL_V]: number | null; [SECTION_COUNT]: number; [SUBSTATION_CREATION]: Properties; [SUBSTATION_CREATION_ID]: string | null; - [SUBSTATION_ID]: string | null; + [VL_SUBSTATION_ID]: string | null; [SUBSTATION_NAME]: string | null; [SWITCHES_BETWEEN_SECTIONS]: string; [SWITCH_KINDS]: SwitchKindFormData[]; @@ -116,7 +116,7 @@ interface VoltageLevelCreationDialogProps { } /** - * Dialog to create a load in the network + * Dialog to create a voltage level in the network * @param currentNode The node we are currently working on * @param studyUuid the study we are currently working on * @param editData the data to edit @@ -127,14 +127,14 @@ interface VoltageLevelCreationDialogProps { */ const emptyFormData: VoltageLevelCreationFormData = { - [EQUIPMENT_ID]: '', + [FieldConstants.EQUIPMENT_ID]: '', [FieldConstants.EQUIPMENT_NAME]: '', - [SUBSTATION_ID]: null, - [NOMINAL_V]: null, - [LOW_VOLTAGE_LIMIT]: null, - [HIGH_VOLTAGE_LIMIT]: null, - [LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: null, - [HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: null, + [VL_SUBSTATION_ID]: null, + [VL_NOMINAL_V]: null, + [VL_LOW_VOLTAGE_LIMIT]: null, + [VL_HIGH_VOLTAGE_LIMIT]: null, + [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: null, + [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: null, [BUS_BAR_COUNT]: 1, [SECTION_COUNT]: 1, [SWITCHES_BETWEEN_SECTIONS]: '', @@ -152,13 +152,16 @@ const emptyFormData: VoltageLevelCreationFormData = { const formSchema = yup .object() .shape({ - [EQUIPMENT_ID]: yup + [FieldConstants.EQUIPMENT_ID]: yup .string() .required() .when([ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => !addSubstationCreation, then: (schema) => - schema.notOneOf([yup.ref(SUBSTATION_ID), null], 'CreateSubstationInVoltageLevelIdenticalId'), + schema.notOneOf( + [yup.ref(VL_SUBSTATION_ID), null], + 'CreateSubstationInVoltageLevelIdenticalId' + ), }) .when([ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => addSubstationCreation, @@ -170,7 +173,7 @@ const formSchema = yup }), [FieldConstants.EQUIPMENT_NAME]: yup.string().nullable(), [ADD_SUBSTATION_CREATION]: yup.boolean().required(), - [SUBSTATION_ID]: yup + [VL_SUBSTATION_ID]: yup .string() .nullable() .when([ADD_SUBSTATION_CREATION], { @@ -178,7 +181,10 @@ const formSchema = yup then: (schema) => schema .required() - .notOneOf([yup.ref(EQUIPMENT_ID), null], 'CreateSubstationInVoltageLevelIdenticalId'), + .notOneOf( + [yup.ref(FieldConstants.EQUIPMENT_ID), null], + 'CreateSubstationInVoltageLevelIdenticalId' + ), }), [SUBSTATION_CREATION_ID]: yup .string() @@ -188,34 +194,37 @@ const formSchema = yup then: (schema) => schema .required() - .notOneOf([yup.ref(EQUIPMENT_ID), null], 'CreateSubstationInVoltageLevelIdenticalId'), + .notOneOf( + [yup.ref(FieldConstants.EQUIPMENT_ID), null], + 'CreateSubstationInVoltageLevelIdenticalId' + ), }), [SUBSTATION_NAME]: yup.string().nullable(), [FieldConstants.COUNTRY]: yup.string().nullable(), [SUBSTATION_CREATION]: creationPropertiesSchema, - [NOMINAL_V]: yup + [VL_NOMINAL_V]: yup .number() .nullable() .when([IS_ATTACHMENT_POINT_CREATION], { is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, then: (schema) => schema.min(0, 'mustBeGreaterOrEqualToZero').required(), }), - [LOW_VOLTAGE_LIMIT]: yup + [VL_LOW_VOLTAGE_LIMIT]: yup .number() .nullable() .min(0, 'mustBeGreaterOrEqualToZero') - .max(yup.ref(HIGH_VOLTAGE_LIMIT), 'voltageLevelNominalVoltageMaxValueError'), - [HIGH_VOLTAGE_LIMIT]: yup.number().nullable().min(0, 'mustBeGreaterOrEqualToZero'), - [LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: yup + .max(yup.ref(VL_HIGH_VOLTAGE_LIMIT), 'voltageLevelNominalVoltageMaxValueError'), + [VL_HIGH_VOLTAGE_LIMIT]: yup.number().nullable().min(0, 'mustBeGreaterOrEqualToZero'), + [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: yup .number() .nullable() .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .max(yup.ref(HIGH_SHORT_CIRCUIT_CURRENT_LIMIT), 'ShortCircuitCurrentLimitMinMaxError'), - [HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: yup + .max(yup.ref(VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT), 'ShortCircuitCurrentLimitMinMaxError'), + [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: yup .number() .nullable() .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .when([LOW_SHORT_CIRCUIT_CURRENT_LIMIT], { + .when([VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT], { is: (lowShortCircuitCurrentLimit: number | null) => lowShortCircuitCurrentLimit != null, then: (schema) => schema.required(), }), @@ -298,11 +307,11 @@ const VoltageLevelCreationDialog: FC = ({ const isSubstationCreation = (!fromCopy && voltageLevel.substationCreation?.equipmentId != null) || isAttachmentPointModification; const shortCircuitLimits = { - [LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( + [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMin : voltageLevel.ipMin ), - [HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( + [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMax : voltageLevel.ipMax ), @@ -316,22 +325,24 @@ const VoltageLevelCreationDialog: FC = ({ ?.map((switchKind: string) => intl.formatMessage({ id: switchKind })) .join(' / ') || ''; + // Read from external data using API field names (equipmentId, id, name) const equipmentId = (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[ID]) + (fromCopy ? '(1)' : ''); const equipmentName = voltageLevel[FieldConstants.EQUIPMENT_NAME] ?? voltageLevel[NAME]; - const substationId = isSubstationCreation ? null : (voltageLevel[SUBSTATION_ID] ?? null); + const substationId = isSubstationCreation ? null : (voltageLevel[VL_SUBSTATION_ID] ?? null); const properties = fromCopy ? copyEquipmentPropertiesForCreation(voltageLevel) : getPropertiesFromModification(voltageLevel.properties); reset( { - [EQUIPMENT_ID]: equipmentId, + // Set form fields using commons-ui field names + [FieldConstants.EQUIPMENT_ID]: equipmentId, [FieldConstants.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], + [VL_SUBSTATION_ID]: substationId, + [VL_NOMINAL_V]: voltageLevel[VL_NOMINAL_V], + [VL_LOW_VOLTAGE_LIMIT]: voltageLevel[VL_LOW_VOLTAGE_LIMIT], + [VL_HIGH_VOLTAGE_LIMIT]: voltageLevel[VL_HIGH_VOLTAGE_LIMIT], ...shortCircuitLimits, [BUS_BAR_COUNT]: voltageLevel[BUS_BAR_COUNT] ?? 1, [SECTION_COUNT]: voltageLevel[SECTION_COUNT] ?? 1, @@ -373,26 +384,26 @@ const VoltageLevelCreationDialog: FC = ({ useEffect(() => { // Watch HIGH_VOLTAGE_LIMIT changed const unsubscribeHighVoltageLimit = subscribe({ - name: [`${HIGH_VOLTAGE_LIMIT}`], + name: [VL_HIGH_VOLTAGE_LIMIT], formState: { values: true, }, callback: ({ isSubmitted }: { isSubmitted?: boolean }) => { if (isSubmitted) { - trigger(`${LOW_VOLTAGE_LIMIT}`).then(); + trigger(VL_LOW_VOLTAGE_LIMIT).then(); } }, }); // Watch EQUIPMENT_ID changed const unsubscribeEquipmentId = subscribe({ - name: [EQUIPMENT_ID], + name: [FieldConstants.EQUIPMENT_ID], formState: { values: true, }, callback: () => { - if (getValues(SUBSTATION_ID)) { - trigger(SUBSTATION_ID); + if (getValues(VL_SUBSTATION_ID)) { + trigger(VL_SUBSTATION_ID); } if (getValues(SUBSTATION_CREATION_ID)) { trigger(SUBSTATION_CREATION_ID); @@ -402,13 +413,13 @@ const VoltageLevelCreationDialog: FC = ({ // Watch SUBSTATION_ID or SUBSTATION_CREATION_ID changed const unsubscribeSubstationIds = subscribe({ - name: [SUBSTATION_ID, SUBSTATION_CREATION_ID], + name: [VL_SUBSTATION_ID, SUBSTATION_CREATION_ID], formState: { values: true, }, callback: () => { - if (getValues(EQUIPMENT_ID)) { - trigger(EQUIPMENT_ID); + if (getValues(FieldConstants.EQUIPMENT_ID)) { + trigger(FieldConstants.EQUIPMENT_ID); } }, }); @@ -442,20 +453,20 @@ const VoltageLevelCreationDialog: FC = ({ onCreateVoltageLevel({ studyUuid: studyUuid as UUID, nodeUuid: currentNodeUuid, - equipmentId: voltageLevel[EQUIPMENT_ID], + equipmentId: voltageLevel[FieldConstants.EQUIPMENT_ID], equipmentName: sanitizeString(voltageLevel[FieldConstants.EQUIPMENT_NAME]) ?? undefined, - substationId: substationCreation === null ? voltageLevel[SUBSTATION_ID] : null, + substationId: substationCreation === null ? voltageLevel[VL_SUBSTATION_ID] : null, substationCreation: substationCreation, - nominalV: voltageLevel[NOMINAL_V], - lowVoltageLimit: voltageLevel[LOW_VOLTAGE_LIMIT], - highVoltageLimit: voltageLevel[HIGH_VOLTAGE_LIMIT], + nominalV: voltageLevel[VL_NOMINAL_V], + lowVoltageLimit: voltageLevel[VL_LOW_VOLTAGE_LIMIT], + highVoltageLimit: voltageLevel[VL_HIGH_VOLTAGE_LIMIT], ipMin: convertOutputValue( FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[LOW_SHORT_CIRCUIT_CURRENT_LIMIT] + voltageLevel[VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT] ), ipMax: convertOutputValue( FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[HIGH_SHORT_CIRCUIT_CURRENT_LIMIT] + voltageLevel[VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT] ), busbarCount: voltageLevel[BUS_BAR_COUNT], sectionCount: voltageLevel[SECTION_COUNT], @@ -496,7 +507,7 @@ const VoltageLevelCreationDialog: FC = ({ isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - { +}: StudyVoltageLevelCreationFormProps) => { const intl = useIntl(); const { setValue, getValues } = useFormContext(); const [substations, setSubstations] = useState([]); @@ -94,10 +85,6 @@ const VoltageLevelCreationForm = ({ } }, [studyUuid, currentNodeUuid, currentRootNetworkUuid]); - const voltageLevelIdField = ( - - ); - function getCustomPaper(children: React.ReactNode) { return ( @@ -109,7 +96,7 @@ const VoltageLevelCreationForm = ({ sx={{ justifyContent: 'flex-start', fontSize: 'medium', marginLeft: '2%', width: '100%' }} onMouseDown={handleAddButton} > - {`${intl.formatMessage({ id: 'CreateSubstation' })} : ${getValues(SUBSTATION_ID)}`} + {`${intl.formatMessage({ id: 'CreateSubstation' })} : ${getValues(VL_SUBSTATION_ID)}`} @@ -117,68 +104,9 @@ const VoltageLevelCreationForm = ({ } const handleAddButton = useCallback(() => { - setValue(SUBSTATION_CREATION_ID, getValues(SUBSTATION_ID)); + setValue(SUBSTATION_CREATION_ID, getValues(VL_SUBSTATION_ID)); setValue(ADD_SUBSTATION_CREATION, true); }, [setValue, getValues]); - const voltageLevelNameField = ( - - ); - - const substationField = ( - getCustomPaper(children)} - noOptionsText={''} - allowNewValue - /> - ); - - const nominalVoltageField = ; - - const lowVoltageLimitField = ( - - ); - - const highVoltageLimitField = ( - - ); - - const lowShortCircuitCurrentLimitField = ( - - ); - - const highShortCircuitCurrentLimitField = ( - - ); - - const busBarCountField = ; - - const sectionCountField = ; - - const displayOmnibus = watchBusBarCount > 1 || watchSectionCount > 1; - - const couplingOmnibusForm = ; - - const substationCreationIdField = ; - const substationCreationNameField = ; - - const substationCreationCountryField = ( - - ); const handleDeleteButton = useCallback(() => { setValue(ADD_SUBSTATION_CREATION, false); @@ -188,86 +116,81 @@ const VoltageLevelCreationForm = ({ setValue(FieldConstants.COUNTRY, null); }, [setValue]); - return ( - <> + const customSubstationSection = watchAddSubstationCreation ? ( + + + - {voltageLevelIdField} - {voltageLevelNameField} - - - {watchAddSubstationCreation ? ( - - - - - - {substationCreationIdField} - - - {substationCreationNameField} - - - {substationCreationCountryField} - - {!watchIsAttachmentPointCreation && ( - - - - - - - - )} - - - - - + + - ) : ( - - - {substationField} - + + - )} - - - {!watchIsAttachmentPointCreation && {nominalVoltageField}} - {lowVoltageLimitField} - {highVoltageLimitField} + + + + {!watchIsAttachmentPointCreation && ( + + + + + + + + )} - + + + + + + ) : undefined; + + const displayOmnibus = watchBusBarCount > 1 || watchSectionCount > 1; + + const topologySection = !watchIsAttachmentPointCreation ? ( + <> + - {lowShortCircuitCurrentLimitField} - {highShortCircuitCurrentLimitField} - + + + + + + + - {!watchIsAttachmentPointCreation && ( + {displayOmnibus && ( <> - - - {busBarCountField} - {sectionCountField} - + + + + + - {displayOmnibus && ( - <> - - - {couplingOmnibusForm} - - - )} )} - + ) : null; + + return ( + getCustomPaper(children), + noOptionsText: '', + }} + customSubstationSection={customSubstationSection} + hideNominalVoltage={watchIsAttachmentPointCreation} + > + {topologySection} + ); }; -export default VoltageLevelCreationForm; +export default StudyVoltageLevelCreationForm; From 8f8c4ca829ad84787646d47c8f5aeb2eadd44055 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Mar 2026 11:04:21 +0000 Subject: [PATCH 02/11] refactor: use generic VoltageLevelCreationForm from commons-ui - Rewrite VL creation dialog to use FieldConstants from commons-ui - Simplify VL creation form using generic VoltageLevelCreationForm - Use SubstationCreationSection from commons-ui for inline substation creation - Import SwitchesBetweenSections from commons-ui in topology creation form - Remove old local coupling-omnibus and switches-between-sections components - Remove unused voltage-level-creation-utils.js https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../coupling-omnibus-creation.tsx | 66 ---- .../coupling-omnibus-form.tsx | 57 ---- .../voltage-level-creation-dialog.tsx | 288 +++++++++--------- .../creation/voltage-level-creation-form.tsx | 110 +------ .../create-switches-dialog-submit-button.tsx | 27 -- .../create-switches-dialog-utils.ts | 28 -- .../create-switches-dialog.tsx | 76 ----- .../create-switches-form.tsx | 57 ---- .../switches-between-sections.tsx | 121 -------- .../create-voltage-level-topology-form.tsx | 2 +- .../voltage-level-creation-utils.js | 46 --- 11 files changed, 153 insertions(+), 725 deletions(-) delete mode 100644 src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-creation.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-form.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-submit-button.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-utils.ts delete mode 100644 src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-form.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/switches-between-sections/switches-between-sections.tsx delete mode 100644 src/components/dialogs/network-modifications/voltage-level/voltage-level-creation-utils.js diff --git a/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-creation.tsx b/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-creation.tsx deleted file mode 100644 index 7c37d4f286..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-creation.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { AutocompleteInput, Option } from '@gridsuite/commons-ui'; -import { BUS_BAR_SECTION_ID1, BUS_BAR_SECTION_ID2, COUPLING_OMNIBUS } from 'components/utils/field-constants'; -import GridItem from '../../../commons/grid-item'; -import { useEffect } from 'react'; -import { useFormContext } from 'react-hook-form'; - -interface CouplingOmnibusCreationProps { - index: number; - sectionOptions: Option[]; -} - -// TODO should use "name" props instead of `${COUPLING_OMNIBUS}.(...)` -export const CouplingOmnibusCreation = ({ index, sectionOptions }: CouplingOmnibusCreationProps) => { - const { getValues, trigger, subscribe } = useFormContext(); - // Watch BUS_BAR_SECTION_ID1 changed - useEffect(() => { - const unsubscribe = subscribe({ - name: [`${COUPLING_OMNIBUS}.${index}.${BUS_BAR_SECTION_ID1}`], - formState: { - values: true, - }, - callback: () => { - // force trigger validation on BUS_BAR_SECTION_ID2 if it has a value - if (getValues(`${COUPLING_OMNIBUS}.${index}.${BUS_BAR_SECTION_ID2}`)) { - trigger(`${COUPLING_OMNIBUS}.${index}.${BUS_BAR_SECTION_ID2}`); - } - }, - }); - return () => unsubscribe(); - }, [subscribe, trigger, getValues, index]); - - const busBarSectionId1Field = ( - - ); - const busBarSectionId2Field = ( - - ); - - return ( - <> - {busBarSectionId1Field} - {busBarSectionId2Field} - - ); -}; diff --git a/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-form.tsx b/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-form.tsx deleted file mode 100644 index d22023d6a0..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/coupling-omnibus/coupling-omnibus-form.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { - BUS_BAR_COUNT, - BUS_BAR_SECTION_ID1, - BUS_BAR_SECTION_ID2, - COUPLING_OMNIBUS, - EQUIPMENT_ID, - SECTION_COUNT, -} from 'components/utils/field-constants'; -import { CouplingOmnibusCreation } from './coupling-omnibus-creation'; -import { useEffect, useMemo } from 'react'; -import { useFormContext, useWatch } from 'react-hook-form'; -import { buildNewBusbarSections } from 'components/utils/utils'; -import { ExpandableInput } from '@gridsuite/commons-ui'; - -export const CouplingOmnibusForm = () => { - const { setValue } = useFormContext(); - - const couplingOmnibusCreation = { - [BUS_BAR_SECTION_ID1]: null, - [BUS_BAR_SECTION_ID2]: null, - }; - - const watchVoltageLevelID = useWatch({ name: EQUIPMENT_ID }); - const watchBusBarCount = useWatch({ name: BUS_BAR_COUNT }); - const watchSectionCount = useWatch({ name: SECTION_COUNT }); - - const sectionOptions = useMemo(() => { - if (watchVoltageLevelID && watchBusBarCount && watchSectionCount) { - return buildNewBusbarSections(watchVoltageLevelID, watchSectionCount, watchBusBarCount).map((section) => { - return typeof section === 'string' ? section : section.id; - }); - } - return []; - }, [watchVoltageLevelID, watchBusBarCount, watchSectionCount]); - - useEffect(() => { - // the cleanup function is triggered every time sectionOptions changes and when unmounting - return () => setValue(COUPLING_OMNIBUS, []); - }, [sectionOptions, setValue]); - - return ( - - ); -}; diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 2f3f6b04b8..0c4e7a7f57 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -11,48 +11,25 @@ import { copyEquipmentPropertiesForCreation, creationPropertiesSchema, CustomFormProvider, + DeepNullable, emptyProperties, EquipmentType, + FieldConstants, FieldType, getPropertiesFromModification, MODIFICATION_TYPES, Properties, Property, + sanitizeString, snackWithFallback, + SwitchKindFormData, toModificationProperties, useSnackMessage, - DeepNullable, - sanitizeString, - FieldConstants, - VL_SUBSTATION_ID, - VL_NOMINAL_V, - VL_LOW_VOLTAGE_LIMIT, - VL_HIGH_VOLTAGE_LIMIT, - VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, } from '@gridsuite/commons-ui'; import { yupResolver } from '@hookform/resolvers/yup'; import EquipmentSearchDialog from 'components/dialogs/equipment-search-dialog'; import { useFormSearchCopy } from 'components/dialogs/commons/use-form-search-copy'; -import { - ADD_SUBSTATION_CREATION, - BUS_BAR_COUNT, - BUS_BAR_SECTION_ID1, - BUS_BAR_SECTION_ID2, - COUPLING_OMNIBUS, - EQUIPMENT_ID, - ID, - IS_ATTACHMENT_POINT_CREATION, - NAME, - SECTION_COUNT, - SUBSTATION_CREATION, - SUBSTATION_CREATION_ID, - SUBSTATION_NAME, - SWITCH_KIND, - SWITCH_KINDS, - SWITCHES_BETWEEN_SECTIONS, - TOPOLOGY_KIND, -} from 'components/utils/field-constants'; +import { EQUIPMENT_ID } from 'components/utils/field-constants'; import yup from 'components/utils/yup-config'; import { FC, useCallback, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; @@ -74,35 +51,33 @@ import { import { CurrentTreeNode } from '../../../../graph/tree-node.type'; import { CreateCouplingDeviceDialogSchemaForm } from '../../coupling-device/coupling-device-dialog.type'; -export type SwitchKindFormData = { [SWITCH_KIND]: string }; - -interface VoltageLevelCreationFormData { +interface StudyVoltageLevelCreationFormData { [FieldConstants.ADDITIONAL_PROPERTIES]?: Property[]; - [ADD_SUBSTATION_CREATION]: boolean; - [BUS_BAR_COUNT]: number; + [FieldConstants.ADD_SUBSTATION_CREATION]: boolean; + [FieldConstants.BUS_BAR_COUNT]: number; [FieldConstants.COUNTRY]: string | null; - [COUPLING_OMNIBUS]: CreateCouplingDeviceDialogSchemaForm[]; + [FieldConstants.COUPLING_OMNIBUS]: CreateCouplingDeviceDialogSchemaForm[]; [FieldConstants.EQUIPMENT_ID]: string; [FieldConstants.EQUIPMENT_NAME]: string; - [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [VL_HIGH_VOLTAGE_LIMIT]: number | null; - [IS_ATTACHMENT_POINT_CREATION]: boolean; - [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [VL_LOW_VOLTAGE_LIMIT]: number | null; - [VL_NOMINAL_V]: number | null; - [SECTION_COUNT]: number; - [SUBSTATION_CREATION]: Properties; - [SUBSTATION_CREATION_ID]: string | null; - [VL_SUBSTATION_ID]: string | null; - [SUBSTATION_NAME]: string | null; - [SWITCHES_BETWEEN_SECTIONS]: string; - [SWITCH_KINDS]: SwitchKindFormData[]; - [TOPOLOGY_KIND]: string | null; + [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; + [FieldConstants.HIGH_VOLTAGE_LIMIT]: number | null; + [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: boolean; + [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; + [FieldConstants.LOW_VOLTAGE_LIMIT]: number | null; + [FieldConstants.NOMINAL_V]: number | null; + [FieldConstants.SECTION_COUNT]: number; + [FieldConstants.SUBSTATION_CREATION]: Properties; + [FieldConstants.SUBSTATION_CREATION_ID]: string | null; + [FieldConstants.SUBSTATION_ID]: string | null; + [FieldConstants.SUBSTATION_NAME]: string | null; + [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: string; + [FieldConstants.SWITCH_KINDS]: SwitchKindFormData[]; + [FieldConstants.TOPOLOGY_KIND]: string | null; uuid?: UUID; } interface VoltageLevelCreationDialogProps { - editData?: VoltageLevelCreationFormData; + editData?: StudyVoltageLevelCreationFormData; currentNode: CurrentTreeNode; studyUuid: string; currentRootNetworkUuid: UUID; @@ -126,27 +101,27 @@ interface VoltageLevelCreationDialogProps { * @param editDataFetchStatus indicates the status of fetching EditData */ -const emptyFormData: VoltageLevelCreationFormData = { +const emptyFormData: StudyVoltageLevelCreationFormData = { [FieldConstants.EQUIPMENT_ID]: '', [FieldConstants.EQUIPMENT_NAME]: '', - [VL_SUBSTATION_ID]: null, - [VL_NOMINAL_V]: null, - [VL_LOW_VOLTAGE_LIMIT]: null, - [VL_HIGH_VOLTAGE_LIMIT]: null, - [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: null, - [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: null, - [BUS_BAR_COUNT]: 1, - [SECTION_COUNT]: 1, - [SWITCHES_BETWEEN_SECTIONS]: '', - [COUPLING_OMNIBUS]: [], - [SWITCH_KINDS]: [], - [ADD_SUBSTATION_CREATION]: false, - [SUBSTATION_CREATION_ID]: null, - [SUBSTATION_NAME]: null, + [FieldConstants.SUBSTATION_ID]: null, + [FieldConstants.NOMINAL_V]: null, + [FieldConstants.LOW_VOLTAGE_LIMIT]: null, + [FieldConstants.HIGH_VOLTAGE_LIMIT]: null, + [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: null, + [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: null, + [FieldConstants.BUS_BAR_COUNT]: 1, + [FieldConstants.SECTION_COUNT]: 1, + [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: '', + [FieldConstants.COUPLING_OMNIBUS]: [], + [FieldConstants.SWITCH_KINDS]: [], + [FieldConstants.ADD_SUBSTATION_CREATION]: false, + [FieldConstants.SUBSTATION_CREATION_ID]: null, + [FieldConstants.SUBSTATION_NAME]: null, [FieldConstants.COUNTRY]: null, - [IS_ATTACHMENT_POINT_CREATION]: false, - [TOPOLOGY_KIND]: null, - [SUBSTATION_CREATION]: emptyProperties, + [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: false, + [FieldConstants.TOPOLOGY_KIND]: null, + [FieldConstants.SUBSTATION_CREATION]: emptyProperties, }; const formSchema = yup @@ -155,28 +130,28 @@ const formSchema = yup [FieldConstants.EQUIPMENT_ID]: yup .string() .required() - .when([ADD_SUBSTATION_CREATION], { + .when([FieldConstants.ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => !addSubstationCreation, then: (schema) => schema.notOneOf( - [yup.ref(VL_SUBSTATION_ID), null], + [yup.ref(FieldConstants.SUBSTATION_ID), null], 'CreateSubstationInVoltageLevelIdenticalId' ), }) - .when([ADD_SUBSTATION_CREATION], { + .when([FieldConstants.ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => addSubstationCreation, then: (schema) => schema.notOneOf( - [yup.ref(SUBSTATION_CREATION_ID), null], + [yup.ref(FieldConstants.SUBSTATION_CREATION_ID), null], 'CreateSubstationInVoltageLevelIdenticalId' ), }), [FieldConstants.EQUIPMENT_NAME]: yup.string().nullable(), - [ADD_SUBSTATION_CREATION]: yup.boolean().required(), - [VL_SUBSTATION_ID]: yup + [FieldConstants.ADD_SUBSTATION_CREATION]: yup.boolean().required(), + [FieldConstants.SUBSTATION_ID]: yup .string() .nullable() - .when([ADD_SUBSTATION_CREATION], { + .when([FieldConstants.ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => !addSubstationCreation, then: (schema) => schema @@ -186,10 +161,10 @@ const formSchema = yup 'CreateSubstationInVoltageLevelIdenticalId' ), }), - [SUBSTATION_CREATION_ID]: yup + [FieldConstants.SUBSTATION_CREATION_ID]: yup .string() .nullable() - .when([ADD_SUBSTATION_CREATION], { + .when([FieldConstants.ADD_SUBSTATION_CREATION], { is: (addSubstationCreation: boolean) => addSubstationCreation, then: (schema) => schema @@ -199,71 +174,74 @@ const formSchema = yup 'CreateSubstationInVoltageLevelIdenticalId' ), }), - [SUBSTATION_NAME]: yup.string().nullable(), + [FieldConstants.SUBSTATION_NAME]: yup.string().nullable(), [FieldConstants.COUNTRY]: yup.string().nullable(), - [SUBSTATION_CREATION]: creationPropertiesSchema, - [VL_NOMINAL_V]: yup + [FieldConstants.SUBSTATION_CREATION]: creationPropertiesSchema, + [FieldConstants.NOMINAL_V]: yup .number() .nullable() - .when([IS_ATTACHMENT_POINT_CREATION], { + .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, then: (schema) => schema.min(0, 'mustBeGreaterOrEqualToZero').required(), }), - [VL_LOW_VOLTAGE_LIMIT]: yup + [FieldConstants.LOW_VOLTAGE_LIMIT]: yup .number() .nullable() .min(0, 'mustBeGreaterOrEqualToZero') - .max(yup.ref(VL_HIGH_VOLTAGE_LIMIT), 'voltageLevelNominalVoltageMaxValueError'), - [VL_HIGH_VOLTAGE_LIMIT]: yup.number().nullable().min(0, 'mustBeGreaterOrEqualToZero'), - [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: yup + .max(yup.ref(FieldConstants.HIGH_VOLTAGE_LIMIT), 'voltageLevelNominalVoltageMaxValueError'), + [FieldConstants.HIGH_VOLTAGE_LIMIT]: yup.number().nullable().min(0, 'mustBeGreaterOrEqualToZero'), + [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: yup .number() .nullable() .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .max(yup.ref(VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT), 'ShortCircuitCurrentLimitMinMaxError'), - [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: yup + .max(yup.ref(FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT), 'ShortCircuitCurrentLimitMinMaxError'), + [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: yup .number() .nullable() .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .when([VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT], { + .when([FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT], { is: (lowShortCircuitCurrentLimit: number | null) => lowShortCircuitCurrentLimit != null, then: (schema) => schema.required(), }), - [BUS_BAR_COUNT]: yup + [FieldConstants.BUS_BAR_COUNT]: yup .number() .nullable() - .when([IS_ATTACHMENT_POINT_CREATION], { + .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, then: (schema) => schema.min(1, 'BusBarCountMustBeGreaterThanOrEqualToOne').required(), }), - [SECTION_COUNT]: yup + [FieldConstants.SECTION_COUNT]: yup .number() .nullable() - .when([IS_ATTACHMENT_POINT_CREATION], { + .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, then: (schema) => schema.min(1, 'SectionCountMustBeGreaterThanOrEqualToOne').required(), }), - [SWITCHES_BETWEEN_SECTIONS]: yup + [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: yup .string() .nullable() - .when([SECTION_COUNT], { + .when([FieldConstants.SECTION_COUNT], { is: (sectionCount: number) => sectionCount > 1, then: (schema) => schema.required(), }), - [SWITCH_KINDS]: yup.array().of( + [FieldConstants.SWITCH_KINDS]: yup.array().of( yup.object().shape({ - [SWITCH_KIND]: yup.string().required(), + [FieldConstants.SWITCH_KIND]: yup.string().required(), }) ), - [IS_ATTACHMENT_POINT_CREATION]: yup.boolean().required(), - [TOPOLOGY_KIND]: yup.string().nullable(), - [COUPLING_OMNIBUS]: yup.array().of( + [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: yup.boolean().required(), + [FieldConstants.TOPOLOGY_KIND]: yup.string().nullable(), + [FieldConstants.COUPLING_OMNIBUS]: yup.array().of( yup.object().shape({ - [BUS_BAR_SECTION_ID1]: yup.string().nullable().required(), - [BUS_BAR_SECTION_ID2]: yup + [FieldConstants.BUS_BAR_SECTION_ID1]: yup.string().nullable().required(), + [FieldConstants.BUS_BAR_SECTION_ID2]: yup .string() .nullable() .required() - .notOneOf([yup.ref(BUS_BAR_SECTION_ID1), null], 'CreateCouplingDeviceIdenticalBusBar'), + .notOneOf( + [yup.ref(FieldConstants.BUS_BAR_SECTION_ID1), null], + 'CreateCouplingDeviceIdenticalBusBar' + ), }) ), }) @@ -286,9 +264,13 @@ const VoltageLevelCreationDialog: FC = ({ const currentNodeUuid = currentNode.id; const { snackError, snackWarning } = useSnackMessage(); - const defaultValues = useMemo((): VoltageLevelCreationFormData => { + const defaultValues = useMemo((): StudyVoltageLevelCreationFormData => { if (isAttachmentPointModification) { - return { ...emptyFormData, [ADD_SUBSTATION_CREATION]: true, [IS_ATTACHMENT_POINT_CREATION]: true }; + return { + ...emptyFormData, + [FieldConstants.ADD_SUBSTATION_CREATION]: true, + [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: true, + }; } else { return emptyFormData; } @@ -307,69 +289,72 @@ const VoltageLevelCreationDialog: FC = ({ const isSubstationCreation = (!fromCopy && voltageLevel.substationCreation?.equipmentId != null) || isAttachmentPointModification; const shortCircuitLimits = { - [VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( + [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMin : voltageLevel.ipMin ), - [VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( + [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, fromCopy ? voltageLevel.identifiableShortCircuit?.ipMax : voltageLevel.ipMax ), }; const switchKinds: SwitchKindFormData[] = voltageLevel.switchKinds?.map((switchKind: string) => ({ - [SWITCH_KIND]: switchKind, + [FieldConstants.SWITCH_KIND]: switchKind, })) || []; const switchesBetweenSections = voltageLevel.switchKinds ?.map((switchKind: string) => intl.formatMessage({ id: switchKind })) .join(' / ') || ''; - // Read from external data using API field names (equipmentId, id, name) - const equipmentId = (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[ID]) + (fromCopy ? '(1)' : ''); - const equipmentName = voltageLevel[FieldConstants.EQUIPMENT_NAME] ?? voltageLevel[NAME]; - const substationId = isSubstationCreation ? null : (voltageLevel[VL_SUBSTATION_ID] ?? null); + // Read from external data using API field names (equipmentId with lowercase d, id, name) + const equipmentId = + (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[FieldConstants.ID]) + (fromCopy ? '(1)' : ''); + const equipmentName = + voltageLevel[FieldConstants.EQUIPMENT_NAME] ?? voltageLevel[FieldConstants.NAME]; + const substationId = isSubstationCreation + ? null + : (voltageLevel[FieldConstants.SUBSTATION_ID] ?? null); const properties = fromCopy ? copyEquipmentPropertiesForCreation(voltageLevel) : getPropertiesFromModification(voltageLevel.properties); reset( { - // Set form fields using commons-ui field names [FieldConstants.EQUIPMENT_ID]: equipmentId, [FieldConstants.EQUIPMENT_NAME]: equipmentName, - [TOPOLOGY_KIND]: voltageLevel[TOPOLOGY_KIND], - [VL_SUBSTATION_ID]: substationId, - [VL_NOMINAL_V]: voltageLevel[VL_NOMINAL_V], - [VL_LOW_VOLTAGE_LIMIT]: voltageLevel[VL_LOW_VOLTAGE_LIMIT], - [VL_HIGH_VOLTAGE_LIMIT]: voltageLevel[VL_HIGH_VOLTAGE_LIMIT], + [FieldConstants.TOPOLOGY_KIND]: voltageLevel[FieldConstants.TOPOLOGY_KIND], + [FieldConstants.SUBSTATION_ID]: substationId, + [FieldConstants.NOMINAL_V]: voltageLevel[FieldConstants.NOMINAL_V], + [FieldConstants.LOW_VOLTAGE_LIMIT]: voltageLevel[FieldConstants.LOW_VOLTAGE_LIMIT], + [FieldConstants.HIGH_VOLTAGE_LIMIT]: voltageLevel[FieldConstants.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, - [IS_ATTACHMENT_POINT_CREATION]: isAttachmentPointModification, + [FieldConstants.BUS_BAR_COUNT]: voltageLevel[FieldConstants.BUS_BAR_COUNT] ?? 1, + [FieldConstants.SECTION_COUNT]: voltageLevel[FieldConstants.SECTION_COUNT] ?? 1, + [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: switchesBetweenSections, + [FieldConstants.COUPLING_OMNIBUS]: voltageLevel.couplingDevices ?? [], + [FieldConstants.SWITCH_KINDS]: switchKinds, + [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: isAttachmentPointModification, ...properties, }, { keepDefaultValues: true } ); if (isSubstationCreation) { const substationKeys = [ - [SUBSTATION_CREATION_ID, voltageLevel.substationCreation?.equipmentId], - [SUBSTATION_NAME, voltageLevel.substationCreation?.equipmentName], + [FieldConstants.SUBSTATION_CREATION_ID, voltageLevel.substationCreation?.equipmentId], + [FieldConstants.SUBSTATION_NAME, voltageLevel.substationCreation?.equipmentName], [FieldConstants.COUNTRY, voltageLevel.substationCreation?.country], ]; substationKeys.forEach(([key, value]) => { setValue(key, value); }); setValue( - `${SUBSTATION_CREATION}.${FieldConstants.ADDITIONAL_PROPERTIES}`, + `${FieldConstants.SUBSTATION_CREATION}.${FieldConstants.ADDITIONAL_PROPERTIES}`, voltageLevel.substationCreation?.properties ); - setValue(ADD_SUBSTATION_CREATION, true); + setValue(FieldConstants.ADD_SUBSTATION_CREATION, true); } else { - setValue(ADD_SUBSTATION_CREATION, false); + setValue(FieldConstants.ADD_SUBSTATION_CREATION, false); } if (!voltageLevel.isSymmetrical && fromCopy) { snackWarning({ @@ -382,38 +367,35 @@ const VoltageLevelCreationDialog: FC = ({ // Supervisor watches to trigger validation for interdependent constraints useEffect(() => { - // Watch HIGH_VOLTAGE_LIMIT changed const unsubscribeHighVoltageLimit = subscribe({ - name: [VL_HIGH_VOLTAGE_LIMIT], + name: [FieldConstants.HIGH_VOLTAGE_LIMIT], formState: { values: true, }, callback: ({ isSubmitted }: { isSubmitted?: boolean }) => { if (isSubmitted) { - trigger(VL_LOW_VOLTAGE_LIMIT).then(); + trigger(FieldConstants.LOW_VOLTAGE_LIMIT).then(); } }, }); - // Watch EQUIPMENT_ID changed const unsubscribeEquipmentId = subscribe({ name: [FieldConstants.EQUIPMENT_ID], formState: { values: true, }, callback: () => { - if (getValues(VL_SUBSTATION_ID)) { - trigger(VL_SUBSTATION_ID); + if (getValues(FieldConstants.SUBSTATION_ID)) { + trigger(FieldConstants.SUBSTATION_ID); } - if (getValues(SUBSTATION_CREATION_ID)) { - trigger(SUBSTATION_CREATION_ID); + if (getValues(FieldConstants.SUBSTATION_CREATION_ID)) { + trigger(FieldConstants.SUBSTATION_CREATION_ID); } }, }); - // Watch SUBSTATION_ID or SUBSTATION_CREATION_ID changed const unsubscribeSubstationIds = subscribe({ - name: [VL_SUBSTATION_ID, SUBSTATION_CREATION_ID], + name: [FieldConstants.SUBSTATION_ID, FieldConstants.SUBSTATION_CREATION_ID], formState: { values: true, }, @@ -440,14 +422,16 @@ const VoltageLevelCreationDialog: FC = ({ }, [fromExternalDataToFormValues, editData]); const onSubmit = useCallback( - (voltageLevel: VoltageLevelCreationFormData) => { - const substationCreation: AttachedSubstationCreationInfo | null = getValues(ADD_SUBSTATION_CREATION) + (voltageLevel: StudyVoltageLevelCreationFormData) => { + const substationCreation: AttachedSubstationCreationInfo | null = getValues( + FieldConstants.ADD_SUBSTATION_CREATION + ) ? { type: MODIFICATION_TYPES.SUBSTATION_CREATION.type, - equipmentId: voltageLevel[SUBSTATION_CREATION_ID], - equipmentName: voltageLevel[SUBSTATION_NAME], + equipmentId: voltageLevel[FieldConstants.SUBSTATION_CREATION_ID], + equipmentName: voltageLevel[FieldConstants.SUBSTATION_NAME], country: voltageLevel[FieldConstants.COUNTRY], - properties: toModificationProperties(voltageLevel[SUBSTATION_CREATION]), + properties: toModificationProperties(voltageLevel[FieldConstants.SUBSTATION_CREATION]), } : null; onCreateVoltageLevel({ @@ -455,25 +439,25 @@ const VoltageLevelCreationDialog: FC = ({ nodeUuid: currentNodeUuid, equipmentId: voltageLevel[FieldConstants.EQUIPMENT_ID], equipmentName: sanitizeString(voltageLevel[FieldConstants.EQUIPMENT_NAME]) ?? undefined, - substationId: substationCreation === null ? voltageLevel[VL_SUBSTATION_ID] : null, + substationId: substationCreation === null ? voltageLevel[FieldConstants.SUBSTATION_ID] : null, substationCreation: substationCreation, - nominalV: voltageLevel[VL_NOMINAL_V], - lowVoltageLimit: voltageLevel[VL_LOW_VOLTAGE_LIMIT], - highVoltageLimit: voltageLevel[VL_HIGH_VOLTAGE_LIMIT], + nominalV: voltageLevel[FieldConstants.NOMINAL_V], + lowVoltageLimit: voltageLevel[FieldConstants.LOW_VOLTAGE_LIMIT], + highVoltageLimit: voltageLevel[FieldConstants.HIGH_VOLTAGE_LIMIT], ipMin: convertOutputValue( FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[VL_LOW_SHORT_CIRCUIT_CURRENT_LIMIT] + voltageLevel[FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT] ), ipMax: convertOutputValue( FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[VL_HIGH_SHORT_CIRCUIT_CURRENT_LIMIT] + voltageLevel[FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT] ), - busbarCount: voltageLevel[BUS_BAR_COUNT], - sectionCount: voltageLevel[SECTION_COUNT], - switchKinds: voltageLevel[SWITCH_KINDS].map((e) => { + busbarCount: voltageLevel[FieldConstants.BUS_BAR_COUNT], + sectionCount: voltageLevel[FieldConstants.SECTION_COUNT], + switchKinds: voltageLevel[FieldConstants.SWITCH_KINDS].map((e) => { return e.switchKind as SwitchKind; }), - couplingDevices: voltageLevel[COUPLING_OMNIBUS], + couplingDevices: voltageLevel[FieldConstants.COUPLING_OMNIBUS], isUpdate: !!editData, modificationUuid: editData?.uuid, properties: toModificationProperties(voltageLevel), diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx index db1c7212de..afa107b6de 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx @@ -5,38 +5,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { - ADD_SUBSTATION_CREATION, - BUS_BAR_COUNT, - IS_ATTACHMENT_POINT_CREATION, - SECTION_COUNT, - SUBSTATION_CREATION, - SUBSTATION_CREATION_ID, - SUBSTATION_NAME, -} from 'components/utils/field-constants'; import React, { useCallback, useEffect, useState } from 'react'; import { - CountrySelectionInput, EquipmentType, fetchDefaultCountry, FieldConstants, - IntegerInput, - PropertiesForm, - TextInput, - VL_SUBSTATION_ID, + SubstationCreationSection, VoltageLevelCreationForm, } from '@gridsuite/commons-ui'; -import { Box, Grid, Paper, Tooltip } from '@mui/material'; +import { Box, 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 { 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 DeleteIcon from '@mui/icons-material/Delete'; import LineSeparator from '../../../commons/line-separator'; import { UUID } from 'node:crypto'; @@ -54,13 +36,10 @@ const StudyVoltageLevelCreationForm = ({ const intl = useIntl(); const { setValue, getValues } = useFormContext(); const [substations, setSubstations] = useState([]); - const watchBusBarCount = useWatch({ name: BUS_BAR_COUNT }); - const watchSectionCount = useWatch({ name: SECTION_COUNT }); - const watchAddSubstationCreation = useWatch({ name: ADD_SUBSTATION_CREATION }); - const watchIsAttachmentPointCreation = useWatch({ name: IS_ATTACHMENT_POINT_CREATION }); + const watchAddSubstationCreation = useWatch({ name: FieldConstants.ADD_SUBSTATION_CREATION }); + const watchIsAttachmentPointCreation = useWatch({ name: FieldConstants.IS_ATTACHMENT_POINT_CREATION }); useEffect(() => { - // in new substation mode, set the default country if (watchAddSubstationCreation && !getValues(FieldConstants.COUNTRY)) { fetchDefaultCountry().then((country) => { if (country) { @@ -96,7 +75,7 @@ const StudyVoltageLevelCreationForm = ({ sx={{ justifyContent: 'flex-start', fontSize: 'medium', marginLeft: '2%', width: '100%' }} onMouseDown={handleAddButton} > - {`${intl.formatMessage({ id: 'CreateSubstation' })} : ${getValues(VL_SUBSTATION_ID)}`} + {`${intl.formatMessage({ id: 'CreateSubstation' })} : ${getValues(FieldConstants.SUBSTATION_ID)}`} @@ -104,80 +83,24 @@ const StudyVoltageLevelCreationForm = ({ } const handleAddButton = useCallback(() => { - setValue(SUBSTATION_CREATION_ID, getValues(VL_SUBSTATION_ID)); - setValue(ADD_SUBSTATION_CREATION, true); + setValue(FieldConstants.SUBSTATION_CREATION_ID, getValues(FieldConstants.SUBSTATION_ID)); + setValue(FieldConstants.ADD_SUBSTATION_CREATION, true); }, [setValue, getValues]); const handleDeleteButton = useCallback(() => { - setValue(ADD_SUBSTATION_CREATION, false); - // clear the fields of the new substation - setValue(SUBSTATION_CREATION_ID, null); - setValue(SUBSTATION_NAME, null); + setValue(FieldConstants.ADD_SUBSTATION_CREATION, false); + setValue(FieldConstants.SUBSTATION_CREATION_ID, null); + setValue(FieldConstants.SUBSTATION_NAME, null); setValue(FieldConstants.COUNTRY, null); }, [setValue]); const customSubstationSection = watchAddSubstationCreation ? ( - - - - - - - - - - - - - - {!watchIsAttachmentPointCreation && ( - - - - - - - - )} - - - - - - + ) : undefined; - const displayOmnibus = watchBusBarCount > 1 || watchSectionCount > 1; - - const topologySection = !watchIsAttachmentPointCreation ? ( - <> - - - - - - - - - - - {displayOmnibus && ( - <> - - - - - - - - )} - - ) : null; - return ( - {topologySection} - + hideBusBarSection={watchIsAttachmentPointCreation} + /> ); }; diff --git a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-submit-button.tsx b/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-submit-button.tsx deleted file mode 100644 index 9e06b3b45e..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-submit-button.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { Button } from '@mui/material'; -import { FieldValues, SubmitHandler, useFormContext } from 'react-hook-form'; -import { FormattedMessage } from 'react-intl'; -import { CreateSwitchesFormData } from '../switches-between-sections'; - -interface CreateSwitchesDialogSubmitButtonProps { - handleSave: (data: CreateSwitchesFormData) => void | Promise; -} - -const CreateSwitchesDialogSubmitButton = ({ handleSave }: CreateSwitchesDialogSubmitButtonProps) => { - const { handleSubmit } = useFormContext(); - - return ( - - ); -}; - -export default CreateSwitchesDialogSubmitButton; diff --git a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-utils.ts b/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-utils.ts deleted file mode 100644 index 90e2dc43ae..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog-utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { SWITCH_KINDS, SWITCH_KIND } from 'components/utils/field-constants'; -import yup from 'components/utils/yup-config'; - -export const getCreateSwitchesValidationSchema = (id = SWITCH_KINDS) => { - return { - [id]: yup.array().nullable().of(getSwitchTypeSchema()), - }; -}; - -const createSwitchesEmptyFormData = () => ({ - [SWITCH_KIND]: '', -}); - -export const getSwitchTypeSchema = () => - yup.object().shape({ - [SWITCH_KIND]: yup.string().nullable().required(), - }); - -export const getCreateSwitchesEmptyFormData = (sectionCount: number, id = SWITCH_KINDS) => ({ - [id]: new Array(sectionCount - 1).fill(createSwitchesEmptyFormData()), -}); diff --git a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog.tsx deleted file mode 100644 index bb23a892af..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-dialog.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2022, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { Dialog, DialogActions } from '@mui/material'; -import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import CreateSwitchesDialogSubmitButton from './create-switches-dialog-submit-button'; -import CreateSwitchesForm from './create-switches-form'; -import { getCreateSwitchesEmptyFormData, getCreateSwitchesValidationSchema } from './create-switches-dialog-utils'; -import { SWITCH_KINDS } from 'components/utils/field-constants'; -import yup from 'components/utils/yup-config'; -import React, { useEffect } from 'react'; -import { CancelButton, CustomFormProvider } from '@gridsuite/commons-ui'; -import { CreateSwitchesFormData, SwitchKindData } from '../switches-between-sections'; - -const formSchema = yup.object().shape({ - ...getCreateSwitchesValidationSchema(), -}) as yup.ObjectSchema; - -interface CreateSwitchesDialogProps { - sectionCount: number; - handleCreateSwitchesDialog: (data: CreateSwitchesFormData) => void; - setOpenCreateSwitchesDialog: React.Dispatch>; - openCreateSwitchesDialog: boolean; - switchKinds: SwitchKindData[]; -} - -export const CreateSwitchesDialog = ({ - sectionCount, - handleCreateSwitchesDialog, - setOpenCreateSwitchesDialog, - openCreateSwitchesDialog, - switchKinds, -}: CreateSwitchesDialogProps) => { - const emptyFormData = getCreateSwitchesEmptyFormData(sectionCount); - const formMethods = useForm({ - defaultValues: emptyFormData, - resolver: yupResolver(formSchema), - }); - - const { reset } = formMethods; - - useEffect(() => { - if (switchKinds?.length > 0) { - reset({ - [SWITCH_KINDS]: switchKinds, - }); - } - }, [switchKinds, reset]); - - const handleCloseDialog = () => { - reset(emptyFormData); - setOpenCreateSwitchesDialog(false); - }; - - const handleSave = (data: CreateSwitchesFormData) => { - handleCreateSwitchesDialog(data); - handleCloseDialog(); - }; - - return ( - - - - - - - - - - ); -}; diff --git a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-form.tsx b/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-form.tsx deleted file mode 100644 index d8823335e5..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/create-switches-between-sections/create-switches-form.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { DialogContent, DialogTitle, Grid } from '@mui/material'; -import { SWITCH_TYPE } from 'components/network/constants'; -import EnumInput from 'components/utils/rhf-inputs/enum-input'; -import { SWITCH_KIND } from 'components/utils/field-constants'; -import { useFieldArray } from 'react-hook-form'; -import { FormattedMessage } from 'react-intl'; - -interface CreateSwitchesFormProps { - id: string; -} - -const CreateSwitchesForm = ({ id }: CreateSwitchesFormProps) => { - const { fields: rows } = useFieldArray({ name: `${id}` }); - return ( - <> - - - - - - {rows.map((value, index) => { - return ( - - - - ); - })} - - - - ); -}; - -export default CreateSwitchesForm; diff --git a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/switches-between-sections.tsx b/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/switches-between-sections.tsx deleted file mode 100644 index a72ff2514b..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/switches-between-sections/switches-between-sections.tsx +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { IconButton } from '@mui/material'; -import { TextInput } from '@gridsuite/commons-ui'; -import { SECTION_COUNT, SWITCHES_BETWEEN_SECTIONS, SWITCH_KINDS, SWITCH_KIND } from 'components/utils/field-constants'; -import { ReactElement, useCallback, useEffect, useRef, useState } from 'react'; -import { useFormContext, useWatch } from 'react-hook-form'; -import { useIntl } from 'react-intl'; -import { CreateSwitchesDialog } from './create-switches-between-sections/create-switches-dialog'; -import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; -import GridItem from '../../../commons/grid-item'; - -export interface SwitchKindData { - [SWITCH_KIND]: string; -} - -export interface CreateSwitchesFormData { - [SWITCH_KINDS]: SwitchKindData[]; -} - -export const SwitchesBetweenSections = (): ReactElement => { - const { getValues, setValue } = useFormContext(); - const [openCreateSwitchesDialog, setOpenCreateSwitchesDialog] = useState(false); - - const watchSectionCount: number = useWatch({ name: SECTION_COUNT }); - const watchSwitchesBetweenSections: string = useWatch({ - name: SWITCHES_BETWEEN_SECTIONS, - }); - - const addIconAdornment = useCallback((clickCallback: () => void): ReactElement => { - return ( - - - - ); - }, []); - - const handleClickOpenSwitchesPane = useCallback(() => { - if (watchSectionCount > 1) { - setOpenCreateSwitchesDialog(true); - } - }, [watchSectionCount]); - - const intl = useIntl(); - const setSwitchesKinds = useCallback( - (data: CreateSwitchesFormData) => { - const map = data[SWITCH_KINDS].map((switchData) => { - return intl.formatMessage({ id: switchData[SWITCH_KIND] }); - }); - setValue(SWITCHES_BETWEEN_SECTIONS, map.join(' / '), { - shouldValidate: true, - shouldDirty: true, - }); - setValue(SWITCH_KINDS, data[SWITCH_KINDS]); - }, - [intl, setValue] - ); - - const handleCreateSwitchesDialog = useCallback( - (data: CreateSwitchesFormData) => { - setSwitchesKinds(data); - }, - [setSwitchesKinds] - ); - - const sectionCountRef = useRef(watchSectionCount); - const switchesBetweenSectionsRef = useRef(watchSwitchesBetweenSections); - - useEffect(() => { - // If the user changes the section count, we reset the switches between sections - if ( - sectionCountRef.current !== watchSectionCount && - switchesBetweenSectionsRef.current === watchSwitchesBetweenSections - ) { - const initialKindDisconnector: SwitchKindData = { switchKind: 'DISCONNECTOR' }; - let list = []; - if (watchSectionCount >= 1) { - list = new Array(watchSectionCount - 1).fill(initialKindDisconnector); - } - const data: CreateSwitchesFormData = { switchKinds: list }; - setSwitchesKinds(data); - } - sectionCountRef.current = watchSectionCount; - switchesBetweenSectionsRef.current = watchSwitchesBetweenSections; - }, [watchSectionCount, watchSwitchesBetweenSections, setSwitchesKinds]); - - const switchesBetweenSectionsField = ( - - ); - - if (Number.isNaN(watchSectionCount) || watchSectionCount <= 1) { - return <>; - } else { - return ( - <> - {switchesBetweenSectionsField} - {openCreateSwitchesDialog && ( - - )} - - ); - } -}; diff --git a/src/components/dialogs/network-modifications/voltage-level/topology-creation/create-voltage-level-topology-form.tsx b/src/components/dialogs/network-modifications/voltage-level/topology-creation/create-voltage-level-topology-form.tsx index b023e018a7..7ec6f714a2 100644 --- a/src/components/dialogs/network-modifications/voltage-level/topology-creation/create-voltage-level-topology-form.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/topology-creation/create-voltage-level-topology-form.tsx @@ -17,7 +17,7 @@ import { FormattedMessage, useIntl } from 'react-intl'; import type { UUID } from 'node:crypto'; import { isNodeBuilt } from '../../../../graph/util/model-functions'; import { CurrentTreeNode } from '../../../../graph/tree-node.type'; -import { SwitchesBetweenSections } from '../switches-between-sections/switches-between-sections'; +import { SwitchesBetweenSections } from '@gridsuite/commons-ui'; export interface CreateVoltageLevelTopologyFormProps { voltageLevelId: string; diff --git a/src/components/dialogs/network-modifications/voltage-level/voltage-level-creation-utils.js b/src/components/dialogs/network-modifications/voltage-level/voltage-level-creation-utils.js deleted file mode 100644 index 727710e2d3..0000000000 --- a/src/components/dialogs/network-modifications/voltage-level/voltage-level-creation-utils.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { COUPLING_OMNIBUS, BUS_BAR_SECTION_ID1, BUS_BAR_SECTION_ID2 } from 'components/utils/field-constants'; -import yup from 'components/utils/yup-config'; - -const buildValidationError = (errors, field) => { - return errors.length === 0 - ? true - : { - name: 'ValidationError', - path: `${field}`, - errors: [], - inner: errors, - }; -}; - -/* - * Get BusBarSection indexes linked to itself - */ -const findBusBarSectionIndexesItSelf = (values) => { - const indexes = []; - values?.forEach((value, index) => { - if (value[BUS_BAR_SECTION_ID1] === value[BUS_BAR_SECTION_ID2]) { - indexes.push(index); - } - }); - return indexes; -}; - -export const controlCouplingOmnibusBetweenSections = (values, message) => { - const errors = []; - const indexes = findBusBarSectionIndexesItSelf(values); - if (indexes?.length > 0) { - indexes.forEach((index) => { - errors.push(new yup.ValidationError(message, null, `${COUPLING_OMNIBUS}[${index}].${BUS_BAR_SECTION_ID1}`)); - errors.push(new yup.ValidationError(message, null, `${COUPLING_OMNIBUS}[${index}].${BUS_BAR_SECTION_ID2}`)); - }); - } - - return buildValidationError(errors, COUPLING_OMNIBUS); -}; From eabc3148549f6f0920a1381cdcd847544b7f21a2 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Mar 2026 11:23:35 +0000 Subject: [PATCH 03/11] refactor: use unified VL creation schema from commons-ui - Remove duplicated schema from gridstudy dialog (now in commons-ui) - Use voltageLevelCreationFormSchema, voltageLevelCreationEmptyFormData, voltageLevelCreationFormToDto from commons-ui - Replace IS_ATTACHMENT_POINT_CREATION with HIDE_NOMINAL_VOLTAGE and HIDE_BUS_BAR_SECTION - Simplify onSubmit using commons-ui formToDto - Simplify form wrapper: remove manual SubstationCreationSection toggle (handled by VoltageLevelCreationForm internally) - Keep study-specific logic: substation fetching, custom paper component with CreateSubstation button, default country fetching https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level-creation-dialog.tsx | 261 +++--------------- .../creation/voltage-level-creation-form.tsx | 29 +- 2 files changed, 41 insertions(+), 249 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 0c4e7a7f57..74747a9396 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -7,30 +7,25 @@ import { convertInputValue, - convertOutputValue, copyEquipmentPropertiesForCreation, - creationPropertiesSchema, CustomFormProvider, DeepNullable, - emptyProperties, EquipmentType, FieldConstants, FieldType, getPropertiesFromModification, - MODIFICATION_TYPES, - Properties, - Property, - sanitizeString, snackWithFallback, SwitchKindFormData, - toModificationProperties, useSnackMessage, + VoltageLevelCreationFormData, + voltageLevelCreationEmptyFormData, + voltageLevelCreationFormSchema, + voltageLevelCreationFormToDto, } from '@gridsuite/commons-ui'; import { yupResolver } from '@hookform/resolvers/yup'; import EquipmentSearchDialog from 'components/dialogs/equipment-search-dialog'; import { useFormSearchCopy } from 'components/dialogs/commons/use-form-search-copy'; import { EQUIPMENT_ID } from 'components/utils/field-constants'; -import yup from 'components/utils/yup-config'; import { FC, useCallback, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; @@ -45,34 +40,13 @@ import { FetchStatus } from '../../../../../services/utils'; import { UUID } from 'node:crypto'; import { AttachedSubstationCreationInfo, + CouplingDeviceInfos, SwitchKind, VoltageLevelCreationInfo, } from '../../../../../services/network-modification-types'; import { CurrentTreeNode } from '../../../../graph/tree-node.type'; -import { CreateCouplingDeviceDialogSchemaForm } from '../../coupling-device/coupling-device-dialog.type'; -interface StudyVoltageLevelCreationFormData { - [FieldConstants.ADDITIONAL_PROPERTIES]?: Property[]; - [FieldConstants.ADD_SUBSTATION_CREATION]: boolean; - [FieldConstants.BUS_BAR_COUNT]: number; - [FieldConstants.COUNTRY]: string | null; - [FieldConstants.COUPLING_OMNIBUS]: CreateCouplingDeviceDialogSchemaForm[]; - [FieldConstants.EQUIPMENT_ID]: string; - [FieldConstants.EQUIPMENT_NAME]: string; - [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [FieldConstants.HIGH_VOLTAGE_LIMIT]: number | null; - [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: boolean; - [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: number | null; - [FieldConstants.LOW_VOLTAGE_LIMIT]: number | null; - [FieldConstants.NOMINAL_V]: number | null; - [FieldConstants.SECTION_COUNT]: number; - [FieldConstants.SUBSTATION_CREATION]: Properties; - [FieldConstants.SUBSTATION_CREATION_ID]: string | null; - [FieldConstants.SUBSTATION_ID]: string | null; - [FieldConstants.SUBSTATION_NAME]: string | null; - [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: string; - [FieldConstants.SWITCH_KINDS]: SwitchKindFormData[]; - [FieldConstants.TOPOLOGY_KIND]: string | null; +interface StudyVoltageLevelCreationFormData extends VoltageLevelCreationFormData { uuid?: UUID; } @@ -101,154 +75,6 @@ interface VoltageLevelCreationDialogProps { * @param editDataFetchStatus indicates the status of fetching EditData */ -const emptyFormData: StudyVoltageLevelCreationFormData = { - [FieldConstants.EQUIPMENT_ID]: '', - [FieldConstants.EQUIPMENT_NAME]: '', - [FieldConstants.SUBSTATION_ID]: null, - [FieldConstants.NOMINAL_V]: null, - [FieldConstants.LOW_VOLTAGE_LIMIT]: null, - [FieldConstants.HIGH_VOLTAGE_LIMIT]: null, - [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: null, - [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: null, - [FieldConstants.BUS_BAR_COUNT]: 1, - [FieldConstants.SECTION_COUNT]: 1, - [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: '', - [FieldConstants.COUPLING_OMNIBUS]: [], - [FieldConstants.SWITCH_KINDS]: [], - [FieldConstants.ADD_SUBSTATION_CREATION]: false, - [FieldConstants.SUBSTATION_CREATION_ID]: null, - [FieldConstants.SUBSTATION_NAME]: null, - [FieldConstants.COUNTRY]: null, - [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: false, - [FieldConstants.TOPOLOGY_KIND]: null, - [FieldConstants.SUBSTATION_CREATION]: emptyProperties, -}; - -const formSchema = yup - .object() - .shape({ - [FieldConstants.EQUIPMENT_ID]: yup - .string() - .required() - .when([FieldConstants.ADD_SUBSTATION_CREATION], { - is: (addSubstationCreation: boolean) => !addSubstationCreation, - then: (schema) => - schema.notOneOf( - [yup.ref(FieldConstants.SUBSTATION_ID), null], - 'CreateSubstationInVoltageLevelIdenticalId' - ), - }) - .when([FieldConstants.ADD_SUBSTATION_CREATION], { - is: (addSubstationCreation: boolean) => addSubstationCreation, - then: (schema) => - schema.notOneOf( - [yup.ref(FieldConstants.SUBSTATION_CREATION_ID), null], - 'CreateSubstationInVoltageLevelIdenticalId' - ), - }), - [FieldConstants.EQUIPMENT_NAME]: yup.string().nullable(), - [FieldConstants.ADD_SUBSTATION_CREATION]: yup.boolean().required(), - [FieldConstants.SUBSTATION_ID]: yup - .string() - .nullable() - .when([FieldConstants.ADD_SUBSTATION_CREATION], { - is: (addSubstationCreation: boolean) => !addSubstationCreation, - then: (schema) => - schema - .required() - .notOneOf( - [yup.ref(FieldConstants.EQUIPMENT_ID), null], - 'CreateSubstationInVoltageLevelIdenticalId' - ), - }), - [FieldConstants.SUBSTATION_CREATION_ID]: yup - .string() - .nullable() - .when([FieldConstants.ADD_SUBSTATION_CREATION], { - is: (addSubstationCreation: boolean) => addSubstationCreation, - then: (schema) => - schema - .required() - .notOneOf( - [yup.ref(FieldConstants.EQUIPMENT_ID), null], - 'CreateSubstationInVoltageLevelIdenticalId' - ), - }), - [FieldConstants.SUBSTATION_NAME]: yup.string().nullable(), - [FieldConstants.COUNTRY]: yup.string().nullable(), - [FieldConstants.SUBSTATION_CREATION]: creationPropertiesSchema, - [FieldConstants.NOMINAL_V]: yup - .number() - .nullable() - .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { - is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, - then: (schema) => schema.min(0, 'mustBeGreaterOrEqualToZero').required(), - }), - [FieldConstants.LOW_VOLTAGE_LIMIT]: yup - .number() - .nullable() - .min(0, 'mustBeGreaterOrEqualToZero') - .max(yup.ref(FieldConstants.HIGH_VOLTAGE_LIMIT), 'voltageLevelNominalVoltageMaxValueError'), - [FieldConstants.HIGH_VOLTAGE_LIMIT]: yup.number().nullable().min(0, 'mustBeGreaterOrEqualToZero'), - [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: yup - .number() - .nullable() - .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .max(yup.ref(FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT), 'ShortCircuitCurrentLimitMinMaxError'), - [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: yup - .number() - .nullable() - .min(0, 'ShortCircuitCurrentLimitMustBeGreaterOrEqualToZero') - .when([FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT], { - is: (lowShortCircuitCurrentLimit: number | null) => lowShortCircuitCurrentLimit != null, - then: (schema) => schema.required(), - }), - [FieldConstants.BUS_BAR_COUNT]: yup - .number() - .nullable() - .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { - is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, - then: (schema) => schema.min(1, 'BusBarCountMustBeGreaterThanOrEqualToOne').required(), - }), - [FieldConstants.SECTION_COUNT]: yup - .number() - .nullable() - .when([FieldConstants.IS_ATTACHMENT_POINT_CREATION], { - is: (isAttachmentPointCreation: boolean) => !isAttachmentPointCreation, - then: (schema) => schema.min(1, 'SectionCountMustBeGreaterThanOrEqualToOne').required(), - }), - [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: yup - .string() - .nullable() - .when([FieldConstants.SECTION_COUNT], { - is: (sectionCount: number) => sectionCount > 1, - then: (schema) => schema.required(), - }), - [FieldConstants.SWITCH_KINDS]: yup.array().of( - yup.object().shape({ - [FieldConstants.SWITCH_KIND]: yup.string().required(), - }) - ), - [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: yup.boolean().required(), - [FieldConstants.TOPOLOGY_KIND]: yup.string().nullable(), - [FieldConstants.COUPLING_OMNIBUS]: yup.array().of( - yup.object().shape({ - [FieldConstants.BUS_BAR_SECTION_ID1]: yup.string().nullable().required(), - [FieldConstants.BUS_BAR_SECTION_ID2]: yup - .string() - .nullable() - .required() - .notOneOf( - [yup.ref(FieldConstants.BUS_BAR_SECTION_ID1), null], - 'CreateCouplingDeviceIdenticalBusBar' - ), - }) - ), - }) - .concat(creationPropertiesSchema); - -type VoltageLevelFormInfos = yup.InferType; - const VoltageLevelCreationDialog: FC = ({ editData, currentNode, @@ -267,18 +93,20 @@ const VoltageLevelCreationDialog: FC = ({ const defaultValues = useMemo((): StudyVoltageLevelCreationFormData => { if (isAttachmentPointModification) { return { - ...emptyFormData, + ...voltageLevelCreationEmptyFormData, [FieldConstants.ADD_SUBSTATION_CREATION]: true, - [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: true, + [FieldConstants.HIDE_NOMINAL_VOLTAGE]: true, + [FieldConstants.HIDE_BUS_BAR_SECTION]: true, }; - } else { - return emptyFormData; } + return voltageLevelCreationEmptyFormData; }, [isAttachmentPointModification]); - const formMethods = useForm>({ + type FormSchemaType = ReturnType; + + const formMethods = useForm>({ defaultValues: defaultValues, - resolver: yupResolver>(formSchema), + resolver: yupResolver>(voltageLevelCreationFormSchema), }); const { reset, setValue, getValues, trigger, subscribe } = formMethods; @@ -334,7 +162,8 @@ const VoltageLevelCreationDialog: FC = ({ [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: switchesBetweenSections, [FieldConstants.COUPLING_OMNIBUS]: voltageLevel.couplingDevices ?? [], [FieldConstants.SWITCH_KINDS]: switchKinds, - [FieldConstants.IS_ATTACHMENT_POINT_CREATION]: isAttachmentPointModification, + [FieldConstants.HIDE_NOMINAL_VOLTAGE]: isAttachmentPointModification, + [FieldConstants.HIDE_BUS_BAR_SECTION]: isAttachmentPointModification, ...properties, }, { keepDefaultValues: true } @@ -422,55 +251,37 @@ const VoltageLevelCreationDialog: FC = ({ }, [fromExternalDataToFormValues, editData]); const onSubmit = useCallback( - (voltageLevel: StudyVoltageLevelCreationFormData) => { - const substationCreation: AttachedSubstationCreationInfo | null = getValues( - FieldConstants.ADD_SUBSTATION_CREATION - ) - ? { - type: MODIFICATION_TYPES.SUBSTATION_CREATION.type, - equipmentId: voltageLevel[FieldConstants.SUBSTATION_CREATION_ID], - equipmentName: voltageLevel[FieldConstants.SUBSTATION_NAME], - country: voltageLevel[FieldConstants.COUNTRY], - properties: toModificationProperties(voltageLevel[FieldConstants.SUBSTATION_CREATION]), - } - : null; + (voltageLevel: VoltageLevelCreationFormData) => { + const dto = voltageLevelCreationFormToDto(voltageLevel); onCreateVoltageLevel({ studyUuid: studyUuid as UUID, nodeUuid: currentNodeUuid, - equipmentId: voltageLevel[FieldConstants.EQUIPMENT_ID], - equipmentName: sanitizeString(voltageLevel[FieldConstants.EQUIPMENT_NAME]) ?? undefined, - substationId: substationCreation === null ? voltageLevel[FieldConstants.SUBSTATION_ID] : null, - substationCreation: substationCreation, - nominalV: voltageLevel[FieldConstants.NOMINAL_V], - lowVoltageLimit: voltageLevel[FieldConstants.LOW_VOLTAGE_LIMIT], - highVoltageLimit: voltageLevel[FieldConstants.HIGH_VOLTAGE_LIMIT], - ipMin: convertOutputValue( - FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT] - ), - ipMax: convertOutputValue( - FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, - voltageLevel[FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT] - ), - busbarCount: voltageLevel[FieldConstants.BUS_BAR_COUNT], - sectionCount: voltageLevel[FieldConstants.SECTION_COUNT], - switchKinds: voltageLevel[FieldConstants.SWITCH_KINDS].map((e) => { - return e.switchKind as SwitchKind; - }), - couplingDevices: voltageLevel[FieldConstants.COUPLING_OMNIBUS], + equipmentId: dto.equipmentId, + equipmentName: dto.equipmentName ?? undefined, + substationId: dto.substationId, + substationCreation: dto.substationCreation as AttachedSubstationCreationInfo | null, + nominalV: dto.nominalV, + lowVoltageLimit: dto.lowVoltageLimit, + highVoltageLimit: dto.highVoltageLimit, + ipMin: dto.ipMin, + ipMax: dto.ipMax, + busbarCount: dto.busbarCount, + sectionCount: dto.sectionCount, + switchKinds: dto.switchKinds as SwitchKind[], + couplingDevices: dto.couplingDevices as unknown as CouplingDeviceInfos[], isUpdate: !!editData, modificationUuid: editData?.uuid, - properties: toModificationProperties(voltageLevel), + properties: dto.properties, }).catch((error: Error) => { snackWithFallback(snackError, error, { headerId: 'VoltageLevelCreationError' }); }); }, - [getValues, onCreateVoltageLevel, studyUuid, currentNodeUuid, editData, snackError] + [onCreateVoltageLevel, studyUuid, currentNodeUuid, editData, snackError] ); const clear = useCallback(() => { - reset(emptyFormData); - }, [reset]); + reset(defaultValues); + }, [reset, defaultValues]); const open = useOpenShortWaitFetching({ isDataFetched: @@ -479,7 +290,7 @@ const VoltageLevelCreationDialog: FC = ({ }); return ( - + ([]); const watchAddSubstationCreation = useWatch({ name: FieldConstants.ADD_SUBSTATION_CREATION }); - const watchIsAttachmentPointCreation = useWatch({ name: FieldConstants.IS_ATTACHMENT_POINT_CREATION }); useEffect(() => { if (watchAddSubstationCreation && !getValues(FieldConstants.COUNTRY)) { @@ -64,6 +62,11 @@ const StudyVoltageLevelCreationForm = ({ } }, [studyUuid, currentNodeUuid, currentRootNetworkUuid]); + const handleAddButton = useCallback(() => { + setValue(FieldConstants.SUBSTATION_CREATION_ID, getValues(FieldConstants.SUBSTATION_ID)); + setValue(FieldConstants.ADD_SUBSTATION_CREATION, true); + }, [setValue, getValues]); + function getCustomPaper(children: React.ReactNode) { return ( @@ -82,25 +85,6 @@ const StudyVoltageLevelCreationForm = ({ ); } - const handleAddButton = useCallback(() => { - setValue(FieldConstants.SUBSTATION_CREATION_ID, getValues(FieldConstants.SUBSTATION_ID)); - setValue(FieldConstants.ADD_SUBSTATION_CREATION, true); - }, [setValue, getValues]); - - const handleDeleteButton = useCallback(() => { - setValue(FieldConstants.ADD_SUBSTATION_CREATION, false); - setValue(FieldConstants.SUBSTATION_CREATION_ID, null); - setValue(FieldConstants.SUBSTATION_NAME, null); - setValue(FieldConstants.COUNTRY, null); - }, [setValue]); - - const customSubstationSection = watchAddSubstationCreation ? ( - - ) : undefined; - return ( getCustomPaper(children), noOptionsText: '', }} - customSubstationSection={customSubstationSection} - hideNominalVoltage={watchIsAttachmentPointCreation} - hideBusBarSection={watchIsAttachmentPointCreation} /> ); }; From 532e290453347605605b1cc85358220f4ae2bf79 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Mar 2026 12:49:32 +0000 Subject: [PATCH 04/11] refactor: remove fetchDefaultCountry now handled by commons-ui VL form The fetchDefaultCountry logic has been moved to the generic VoltageLevelCreationForm component in commons-ui. https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../creation/voltage-level-creation-form.tsx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx index 8d5e1441d3..2b352c2895 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx @@ -8,14 +8,13 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EquipmentType, - fetchDefaultCountry, FieldConstants, VoltageLevelCreationForm, } from '@gridsuite/commons-ui'; import { Box, Paper } from '@mui/material'; import { fetchEquipmentsIds } from '../../../../../services/study/network-map'; -import { useFormContext, useWatch } from 'react-hook-form'; +import { useFormContext } from 'react-hook-form'; import IconButton from '@mui/material/IconButton'; import { useIntl } from 'react-intl'; import LineSeparator from '../../../commons/line-separator'; @@ -35,17 +34,6 @@ const StudyVoltageLevelCreationForm = ({ const intl = useIntl(); const { setValue, getValues } = useFormContext(); const [substations, setSubstations] = useState([]); - const watchAddSubstationCreation = useWatch({ name: FieldConstants.ADD_SUBSTATION_CREATION }); - - useEffect(() => { - if (watchAddSubstationCreation && !getValues(FieldConstants.COUNTRY)) { - fetchDefaultCountry().then((country) => { - if (country) { - setValue(FieldConstants.COUNTRY, country); - } - }); - } - }, [setValue, getValues, watchAddSubstationCreation]); useEffect(() => { if (studyUuid && currentNodeUuid && currentRootNetworkUuid) { From bf720532d9ac6057c69be7bdf43e9a4c7f9b7b42 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Mar 2026 08:10:50 +0000 Subject: [PATCH 05/11] refactor: use VoltageLevelCreationFormData from commons-ui, remove FormSchemaType - Replace local FormSchemaType with VoltageLevelCreationFormData from commons-ui - Map coupling device field names from backend to form field names - Simplify type casts now that DTO field names match https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level-creation-dialog.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 74747a9396..371fb67fe7 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -15,7 +15,6 @@ import { FieldType, getPropertiesFromModification, snackWithFallback, - SwitchKindFormData, useSnackMessage, VoltageLevelCreationFormData, voltageLevelCreationEmptyFormData, @@ -102,11 +101,9 @@ const VoltageLevelCreationDialog: FC = ({ return voltageLevelCreationEmptyFormData; }, [isAttachmentPointModification]); - type FormSchemaType = ReturnType; - - const formMethods = useForm>({ + const formMethods = useForm>({ defaultValues: defaultValues, - resolver: yupResolver>(voltageLevelCreationFormSchema), + resolver: yupResolver>(voltageLevelCreationFormSchema), }); const { reset, setValue, getValues, trigger, subscribe } = formMethods; @@ -126,7 +123,7 @@ const VoltageLevelCreationDialog: FC = ({ fromCopy ? voltageLevel.identifiableShortCircuit?.ipMax : voltageLevel.ipMax ), }; - const switchKinds: SwitchKindFormData[] = + const switchKinds = voltageLevel.switchKinds?.map((switchKind: string) => ({ [FieldConstants.SWITCH_KIND]: switchKind, })) || []; @@ -160,7 +157,13 @@ const VoltageLevelCreationDialog: FC = ({ [FieldConstants.BUS_BAR_COUNT]: voltageLevel[FieldConstants.BUS_BAR_COUNT] ?? 1, [FieldConstants.SECTION_COUNT]: voltageLevel[FieldConstants.SECTION_COUNT] ?? 1, [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: switchesBetweenSections, - [FieldConstants.COUPLING_OMNIBUS]: voltageLevel.couplingDevices ?? [], + [FieldConstants.COUPLING_OMNIBUS]: + voltageLevel.couplingDevices?.map( + (device: { busbarSectionId1: string; busbarSectionId2: string }) => ({ + [FieldConstants.BUS_BAR_SECTION_ID1]: device.busbarSectionId1, + [FieldConstants.BUS_BAR_SECTION_ID2]: device.busbarSectionId2, + }) + ) ?? [], [FieldConstants.SWITCH_KINDS]: switchKinds, [FieldConstants.HIDE_NOMINAL_VOLTAGE]: isAttachmentPointModification, [FieldConstants.HIDE_BUS_BAR_SECTION]: isAttachmentPointModification, @@ -268,7 +271,7 @@ const VoltageLevelCreationDialog: FC = ({ busbarCount: dto.busbarCount, sectionCount: dto.sectionCount, switchKinds: dto.switchKinds as SwitchKind[], - couplingDevices: dto.couplingDevices as unknown as CouplingDeviceInfos[], + couplingDevices: dto.couplingDevices as CouplingDeviceInfos[], isUpdate: !!editData, modificationUuid: editData?.uuid, properties: dto.properties, From 2ac16c88c2e3efd199e4a09f6482c38df5f8c3d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Mar 2026 09:16:06 +0000 Subject: [PATCH 06/11] refactor: use voltageLevelCreationDtoToForm from commons-ui in VL dialog Simplify fromExternalDataToFormValues by delegating field mapping to commons-ui's unified conversion function that handles both edit data (VoltageLevelCreationDto) and copy data (VoltageLevelFormInfos). https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level-creation-dialog.tsx | 109 ++++-------------- 1 file changed, 22 insertions(+), 87 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 371fb67fe7..661cf065a2 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -6,17 +6,16 @@ */ import { - convertInputValue, - copyEquipmentPropertiesForCreation, CustomFormProvider, DeepNullable, EquipmentType, FieldConstants, - FieldType, - getPropertiesFromModification, snackWithFallback, useSnackMessage, + VoltageLevelCreationDto, VoltageLevelCreationFormData, + VoltageLevelFormInfos, + voltageLevelCreationDtoToForm, voltageLevelCreationEmptyFormData, voltageLevelCreationFormSchema, voltageLevelCreationFormToDto, @@ -24,14 +23,12 @@ import { import { yupResolver } from '@hookform/resolvers/yup'; import EquipmentSearchDialog from 'components/dialogs/equipment-search-dialog'; import { useFormSearchCopy } from 'components/dialogs/commons/use-form-search-copy'; -import { EQUIPMENT_ID } from 'components/utils/field-constants'; import { FC, useCallback, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; import StudyVoltageLevelCreationForm from './voltage-level-creation-form'; import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; -import { useIntl } from 'react-intl'; import { FORM_LOADING_DELAY } from 'components/network/constants'; import { useOpenShortWaitFetching } from '../../../commons/handle-modification-form'; import { createVoltageLevel } from '../../../../../services/study/network-modifications'; @@ -45,12 +42,12 @@ import { } from '../../../../../services/network-modification-types'; import { CurrentTreeNode } from '../../../../graph/tree-node.type'; -interface StudyVoltageLevelCreationFormData extends VoltageLevelCreationFormData { +interface StudyVoltageLevelCreationDto extends VoltageLevelCreationDto { uuid?: UUID; } interface VoltageLevelCreationDialogProps { - editData?: StudyVoltageLevelCreationFormData; + editData?: StudyVoltageLevelCreationDto; currentNode: CurrentTreeNode; studyUuid: string; currentRootNetworkUuid: UUID; @@ -89,7 +86,7 @@ const VoltageLevelCreationDialog: FC = ({ const currentNodeUuid = currentNode.id; const { snackError, snackWarning } = useSnackMessage(); - const defaultValues = useMemo((): StudyVoltageLevelCreationFormData => { + const defaultValues = useMemo(() => { if (isAttachmentPointModification) { return { ...voltageLevelCreationEmptyFormData, @@ -108,93 +105,31 @@ const VoltageLevelCreationDialog: FC = ({ const { reset, setValue, getValues, trigger, subscribe } = formMethods; - const intl = useIntl(); const fromExternalDataToFormValues = useCallback( - (voltageLevel: Record, fromCopy = true) => { - const isSubstationCreation = - (!fromCopy && voltageLevel.substationCreation?.equipmentId != null) || isAttachmentPointModification; - const shortCircuitLimits = { - [FieldConstants.LOW_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( - FieldType.LOW_SHORT_CIRCUIT_CURRENT_LIMIT, - fromCopy ? voltageLevel.identifiableShortCircuit?.ipMin : voltageLevel.ipMin - ), - [FieldConstants.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT]: convertInputValue( - FieldType.HIGH_SHORT_CIRCUIT_CURRENT_LIMIT, - fromCopy ? voltageLevel.identifiableShortCircuit?.ipMax : voltageLevel.ipMax - ), - }; - const switchKinds = - voltageLevel.switchKinds?.map((switchKind: string) => ({ - [FieldConstants.SWITCH_KIND]: switchKind, - })) || []; - const switchesBetweenSections = - voltageLevel.switchKinds - ?.map((switchKind: string) => intl.formatMessage({ id: switchKind })) - .join(' / ') || ''; + (voltageLevel: VoltageLevelFormInfos | VoltageLevelCreationDto, fromCopy = true) => { + const formData = voltageLevelCreationDtoToForm(voltageLevel); - // Read from external data using API field names (equipmentId with lowercase d, id, name) - const equipmentId = - (voltageLevel[EQUIPMENT_ID] ?? voltageLevel[FieldConstants.ID]) + (fromCopy ? '(1)' : ''); - const equipmentName = - voltageLevel[FieldConstants.EQUIPMENT_NAME] ?? voltageLevel[FieldConstants.NAME]; - const substationId = isSubstationCreation - ? null - : (voltageLevel[FieldConstants.SUBSTATION_ID] ?? null); + if (fromCopy) { + formData[FieldConstants.EQUIPMENT_ID] += '(1)'; + } - const properties = fromCopy - ? copyEquipmentPropertiesForCreation(voltageLevel) - : getPropertiesFromModification(voltageLevel.properties); - reset( - { - [FieldConstants.EQUIPMENT_ID]: equipmentId, - [FieldConstants.EQUIPMENT_NAME]: equipmentName, - [FieldConstants.TOPOLOGY_KIND]: voltageLevel[FieldConstants.TOPOLOGY_KIND], - [FieldConstants.SUBSTATION_ID]: substationId, - [FieldConstants.NOMINAL_V]: voltageLevel[FieldConstants.NOMINAL_V], - [FieldConstants.LOW_VOLTAGE_LIMIT]: voltageLevel[FieldConstants.LOW_VOLTAGE_LIMIT], - [FieldConstants.HIGH_VOLTAGE_LIMIT]: voltageLevel[FieldConstants.HIGH_VOLTAGE_LIMIT], - ...shortCircuitLimits, - [FieldConstants.BUS_BAR_COUNT]: voltageLevel[FieldConstants.BUS_BAR_COUNT] ?? 1, - [FieldConstants.SECTION_COUNT]: voltageLevel[FieldConstants.SECTION_COUNT] ?? 1, - [FieldConstants.SWITCHES_BETWEEN_SECTIONS]: switchesBetweenSections, - [FieldConstants.COUPLING_OMNIBUS]: - voltageLevel.couplingDevices?.map( - (device: { busbarSectionId1: string; busbarSectionId2: string }) => ({ - [FieldConstants.BUS_BAR_SECTION_ID1]: device.busbarSectionId1, - [FieldConstants.BUS_BAR_SECTION_ID2]: device.busbarSectionId2, - }) - ) ?? [], - [FieldConstants.SWITCH_KINDS]: switchKinds, - [FieldConstants.HIDE_NOMINAL_VOLTAGE]: isAttachmentPointModification, - [FieldConstants.HIDE_BUS_BAR_SECTION]: isAttachmentPointModification, - ...properties, - }, - { keepDefaultValues: true } - ); - if (isSubstationCreation) { - const substationKeys = [ - [FieldConstants.SUBSTATION_CREATION_ID, voltageLevel.substationCreation?.equipmentId], - [FieldConstants.SUBSTATION_NAME, voltageLevel.substationCreation?.equipmentName], - [FieldConstants.COUNTRY, voltageLevel.substationCreation?.country], - ]; - substationKeys.forEach(([key, value]) => { - setValue(key, value); - }); - setValue( - `${FieldConstants.SUBSTATION_CREATION}.${FieldConstants.ADDITIONAL_PROPERTIES}`, - voltageLevel.substationCreation?.properties - ); - setValue(FieldConstants.ADD_SUBSTATION_CREATION, true); - } else { - setValue(FieldConstants.ADD_SUBSTATION_CREATION, false); + if (isAttachmentPointModification) { + formData[FieldConstants.HIDE_NOMINAL_VOLTAGE] = true; + formData[FieldConstants.HIDE_BUS_BAR_SECTION] = true; + if (!formData[FieldConstants.ADD_SUBSTATION_CREATION]) { + formData[FieldConstants.ADD_SUBSTATION_CREATION] = true; + } } - if (!voltageLevel.isSymmetrical && fromCopy) { + + reset(formData, { keepDefaultValues: true }); + + if (fromCopy && !('equipmentId' in voltageLevel) && !voltageLevel.isSymmetrical) { snackWarning({ messageId: 'BusBarSectionsCopyingNotSupported', }); } }, - [isAttachmentPointModification, reset, intl, setValue, snackWarning] + [isAttachmentPointModification, reset, snackWarning] ); // Supervisor watches to trigger validation for interdependent constraints From 7a75ced72537662a885b6e08e2010e14b7146c15 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Mar 2026 17:06:08 +0000 Subject: [PATCH 07/11] refactor: use separate DTO and FormInfos conversion functions in VL dialog Split fromExternalDataToFormValues into fromEditDataToFormValues (using voltageLevelCreationDtoToForm for editData/useEffect) and fromSearchCopyToFormValues (using voltageLevelInfosToForm for useFormSearchCopy). Extract shared attachment point logic into applyAttachmentPointOverrides helper. https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level-creation-dialog.tsx | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 661cf065a2..9235ab0ee8 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -16,6 +16,7 @@ import { VoltageLevelCreationFormData, VoltageLevelFormInfos, voltageLevelCreationDtoToForm, + voltageLevelInfosToForm, voltageLevelCreationEmptyFormData, voltageLevelCreationFormSchema, voltageLevelCreationFormToDto, @@ -103,16 +104,10 @@ const VoltageLevelCreationDialog: FC = ({ resolver: yupResolver>(voltageLevelCreationFormSchema), }); - const { reset, setValue, getValues, trigger, subscribe } = formMethods; - - const fromExternalDataToFormValues = useCallback( - (voltageLevel: VoltageLevelFormInfos | VoltageLevelCreationDto, fromCopy = true) => { - const formData = voltageLevelCreationDtoToForm(voltageLevel); - - if (fromCopy) { - formData[FieldConstants.EQUIPMENT_ID] += '(1)'; - } + const { reset, getValues, trigger, subscribe } = formMethods; + const applyAttachmentPointOverrides = useCallback( + (formData: Record) => { if (isAttachmentPointModification) { formData[FieldConstants.HIDE_NOMINAL_VOLTAGE] = true; formData[FieldConstants.HIDE_BUS_BAR_SECTION] = true; @@ -120,16 +115,33 @@ const VoltageLevelCreationDialog: FC = ({ formData[FieldConstants.ADD_SUBSTATION_CREATION] = true; } } + }, + [isAttachmentPointModification] + ); + const fromSearchCopyToFormValues = useCallback( + (voltageLevel: VoltageLevelFormInfos) => { + const formData = voltageLevelInfosToForm(voltageLevel); + formData[FieldConstants.EQUIPMENT_ID] += '(1)'; + applyAttachmentPointOverrides(formData); reset(formData, { keepDefaultValues: true }); - if (fromCopy && !('equipmentId' in voltageLevel) && !voltageLevel.isSymmetrical) { + if (!voltageLevel.isSymmetrical) { snackWarning({ messageId: 'BusBarSectionsCopyingNotSupported', }); } }, - [isAttachmentPointModification, reset, snackWarning] + [applyAttachmentPointOverrides, reset, snackWarning] + ); + + const fromEditDataToFormValues = useCallback( + (editDto: VoltageLevelCreationDto) => { + const formData = voltageLevelCreationDtoToForm(editDto); + applyAttachmentPointOverrides(formData); + reset(formData, { keepDefaultValues: true }); + }, + [applyAttachmentPointOverrides, reset] ); // Supervisor watches to trigger validation for interdependent constraints @@ -180,13 +192,13 @@ const VoltageLevelCreationDialog: FC = ({ }; }, [subscribe, trigger, getValues]); - const searchCopy = useFormSearchCopy(fromExternalDataToFormValues, EQUIPMENT_TYPES.VOLTAGE_LEVEL); + const searchCopy = useFormSearchCopy(fromSearchCopyToFormValues, EQUIPMENT_TYPES.VOLTAGE_LEVEL); useEffect(() => { if (editData) { - fromExternalDataToFormValues(editData, false); + fromEditDataToFormValues(editData); } - }, [fromExternalDataToFormValues, editData]); + }, [fromEditDataToFormValues, editData]); const onSubmit = useCallback( (voltageLevel: VoltageLevelCreationFormData) => { From 0b458926d71d0f35dda640007596770617f93b69 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 05:03:14 +0000 Subject: [PATCH 08/11] feat: pass intl to voltageLevelInfosToForm for translated switch kinds https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../creation/voltage-level-creation-dialog.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 9235ab0ee8..529ced3c51 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -28,6 +28,7 @@ import { FC, useCallback, useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { ModificationDialog } from 'components/dialogs/commons/modificationDialog'; +import { useIntl } from 'react-intl'; import StudyVoltageLevelCreationForm from './voltage-level-creation-form'; import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; import { FORM_LOADING_DELAY } from 'components/network/constants'; @@ -85,6 +86,7 @@ const VoltageLevelCreationDialog: FC = ({ ...dialogProps }) => { const currentNodeUuid = currentNode.id; + const intl = useIntl(); const { snackError, snackWarning } = useSnackMessage(); const defaultValues = useMemo(() => { @@ -121,7 +123,7 @@ const VoltageLevelCreationDialog: FC = ({ const fromSearchCopyToFormValues = useCallback( (voltageLevel: VoltageLevelFormInfos) => { - const formData = voltageLevelInfosToForm(voltageLevel); + const formData = voltageLevelInfosToForm(voltageLevel, intl); formData[FieldConstants.EQUIPMENT_ID] += '(1)'; applyAttachmentPointOverrides(formData); reset(formData, { keepDefaultValues: true }); @@ -132,7 +134,7 @@ const VoltageLevelCreationDialog: FC = ({ }); } }, - [applyAttachmentPointOverrides, reset, snackWarning] + [applyAttachmentPointOverrides, intl, reset, snackWarning] ); const fromEditDataToFormValues = useCallback( From e5760b9f9744d5dd705392cd2388184454c4bd8e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 05:36:00 +0000 Subject: [PATCH 09/11] fix: pass intl to voltageLevelCreationDtoToForm for switch kind translation https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level/creation/voltage-level-creation-dialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index 529ced3c51..e662d5c9a2 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -139,11 +139,11 @@ const VoltageLevelCreationDialog: FC = ({ const fromEditDataToFormValues = useCallback( (editDto: VoltageLevelCreationDto) => { - const formData = voltageLevelCreationDtoToForm(editDto); + const formData = voltageLevelCreationDtoToForm(editDto, intl); applyAttachmentPointOverrides(formData); reset(formData, { keepDefaultValues: true }); }, - [applyAttachmentPointOverrides, reset] + [applyAttachmentPointOverrides, intl, reset] ); // Supervisor watches to trigger validation for interdependent constraints From 631fe0e1a9c888f217443ac67abe08b309aa78aa Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 05:49:33 +0000 Subject: [PATCH 10/11] feat: pass includePreviousValue=true in voltageLevelCreationDtoToForm https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level/creation/voltage-level-creation-dialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx index e662d5c9a2..6d885f7919 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.tsx @@ -139,7 +139,7 @@ const VoltageLevelCreationDialog: FC = ({ const fromEditDataToFormValues = useCallback( (editDto: VoltageLevelCreationDto) => { - const formData = voltageLevelCreationDtoToForm(editDto, intl); + const formData = voltageLevelCreationDtoToForm(editDto, intl, true); applyAttachmentPointOverrides(formData); reset(formData, { keepDefaultValues: true }); }, From 903474d5485139033ccea23e6ca7f857836db305 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 6 Mar 2026 07:05:07 +0000 Subject: [PATCH 11/11] feat: compute and pass showDeleteSubstationButton to VoltageLevelCreationForm Move the showDeleteSubstationButton logic to StudyVoltageLevelCreationForm and pass it as a prop to the shared VoltageLevelCreationForm component. https://claude.ai/code/session_01CUA6hVhwcTV96EMWeQrKFv --- .../voltage-level/creation/voltage-level-creation-form.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx index 2b352c2895..3836fd8497 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.tsx @@ -14,7 +14,7 @@ import { import { Box, Paper } from '@mui/material'; import { fetchEquipmentsIds } from '../../../../../services/study/network-map'; -import { useFormContext } from 'react-hook-form'; +import { useFormContext, useWatch } from 'react-hook-form'; import IconButton from '@mui/material/IconButton'; import { useIntl } from 'react-intl'; import LineSeparator from '../../../commons/line-separator'; @@ -34,6 +34,9 @@ const StudyVoltageLevelCreationForm = ({ const intl = useIntl(); const { setValue, getValues } = useFormContext(); const [substations, setSubstations] = useState([]); + const watchHideNominalVoltage = useWatch({ name: FieldConstants.HIDE_NOMINAL_VOLTAGE }); + const watchHideBusBarSection = useWatch({ name: FieldConstants.HIDE_BUS_BAR_SECTION }); + const showDeleteSubstationButton = !(watchHideNominalVoltage && watchHideBusBarSection); useEffect(() => { if (studyUuid && currentNodeUuid && currentRootNetworkUuid) { @@ -80,6 +83,7 @@ const StudyVoltageLevelCreationForm = ({ PaperComponent: ({ children }: { children: React.ReactNode }) => getCustomPaper(children), noOptionsText: '', }} + showDeleteSubstationButton={showDeleteSubstationButton} /> ); };