From c8c9e14120d00ea34adfd5dc7505167d905648fe Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Tue, 11 Aug 2026 15:15:14 +0200 Subject: [PATCH 1/6] migrating voltage level section creation from gridstudy to commons-ui Signed-off-by: benrejebmoh --- .../voltageLevel/index.ts | 1 + .../VoltageLevelSectionCreationForm.tsx | 379 ++++++++++++++++++ .../voltageLevel/section/index.ts | 10 + .../voltageLevelSectionCreation.types.ts | 24 ++ .../voltageLevelSectionCreation.utils.ts | 135 +++++++ src/translations/en/networkModificationsEn.ts | 22 + src/translations/fr/networkModificationsFr.ts | 22 + src/utils/constants/fieldConstants.ts | 9 + 8 files changed, 602 insertions(+) create mode 100644 src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx create mode 100644 src/features/network-modifications/voltageLevel/section/index.ts create mode 100644 src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.types.ts create mode 100644 src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts diff --git a/src/features/network-modifications/voltageLevel/index.ts b/src/features/network-modifications/voltageLevel/index.ts index 664fe6626..e0f09bc34 100644 --- a/src/features/network-modifications/voltageLevel/index.ts +++ b/src/features/network-modifications/voltageLevel/index.ts @@ -7,3 +7,4 @@ export * from './creation'; export * from './voltage-level.type'; export * from './modification'; +export * from './section'; diff --git a/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx new file mode 100644 index 000000000..616e3598d --- /dev/null +++ b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx @@ -0,0 +1,379 @@ +/** + * Copyright (c) 2026, 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 { useCallback, useEffect, useMemo, useState } from 'react'; +import { Box, Button, Grid, Slider, TextField, Tooltip, Typography } from '@mui/material'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { InfoOutlined } from '@mui/icons-material'; +import { useFormContext, useWatch } from 'react-hook-form'; +import { AutocompleteInput, SelectInput, SwitchInput, useCustomFormContext } from '../../../../components/ui'; +import { areIdsEqual, FieldConstants, getObjectId, Option } from '../../../../utils'; +import { GridSection } from '../../../../components/composite/grid/grid-section'; +import { filledTextField } from '../../common'; +import { SWITCH_TYPE } from '../creation'; +import { BusBarSections } from './voltageLevelSectionCreation.types'; +import { POSITION_NEW_SECTION_SIDE } from './voltageLevelSectionCreation.utils'; + +const getArrayPosition = (data: BusBarSections, selectedOptionId: string) => { + if (!selectedOptionId || !data) { + return { position: -1, length: 0 }; + } + + const matchingArray = Object.values(data).find( + (array) => Array.isArray(array) && array.indexOf(selectedOptionId) !== -1 + ); + if (matchingArray) { + return { position: matchingArray.indexOf(selectedOptionId), length: matchingArray.length }; + } + return { position: -1, length: 0 }; +}; + +type OptionWithDisabled = Option & { disabled?: boolean }; + +type PositionDiagramPaneType = React.ComponentType<{ + open: boolean; + onClose: () => void; + voltageLevelId: string; +}>; + +export interface VoltageLevelSectionCreationFormProps { + busBarSectionInfos?: BusBarSections; + allBusbarSectionsList?: string[]; + isSymmetricalNbBusBarSections?: boolean; + isNotFoundOrNotSupported?: boolean; + PositionDiagramPane?: PositionDiagramPaneType; +} + +export function VoltageLevelSectionCreationForm({ + busBarSectionInfos, + allBusbarSectionsList, + isSymmetricalNbBusBarSections = false, + isNotFoundOrNotSupported = false, + PositionDiagramPane, +}: Readonly) { + const intl = useIntl(); + const { isNodeBuilt, isUpdate } = useCustomFormContext(); + const [isDiagramPaneOpen, setIsDiagramPaneOpen] = useState(false); + const [busBarSectionsIdOptions, setBusBarSectionsIdOptions] = useState([]); + const [isNotRequiredSwitchBefore, setIsNotRequiredSwitchBefore] = useState(false); + const [isNotRequiredSwitchAfter, setIsNotRequiredSwitchAfter] = useState(false); + const { setValue } = useFormContext(); + const voltageLevelId = useWatch({ name: FieldConstants.EQUIPMENT_ID }); + const busbarIndex = useWatch({ name: FieldConstants.BUS_BAR_INDEX }); + const selectedOption = useWatch({ name: FieldConstants.BUSBAR_SECTION_ID }); + const selectedPositionOption = useWatch({ name: FieldConstants.IS_AFTER_BUSBAR_SECTION_ID }); + // free input mode (no suggestions) is used when no network busbar section data is available, + // e.g. when this form is used outside of a study (GridExplore) + const isFreeInputMode = !busBarSectionInfos; + + const voltageLevelIdField = ( + + ); + const switchValue = useWatch({ name: FieldConstants.NEW_SWITCH_STATES }); + + useEffect(() => { + if (busBarSectionInfos && busbarIndex) { + const selectedKey = busbarIndex?.id; + setValue(FieldConstants.ALL_BUS_BAR_SECTIONS, false); + if (selectedKey === 'all') { + setValue(FieldConstants.ALL_BUS_BAR_SECTIONS, true); + if (allBusbarSectionsList && Array.isArray(allBusbarSectionsList)) { + const options = allBusbarSectionsList + .filter((id): id is string => Boolean(id)) + .map((id) => ({ + id, + label: id, + })); + setBusBarSectionsIdOptions(options); + } else { + setBusBarSectionsIdOptions([]); + } + return; + } + const sections = busBarSectionInfos[selectedKey]; + if (!sections || !Array.isArray(sections)) { + setBusBarSectionsIdOptions([]); + return; + } + const options = sections + .filter((id): id is string => Boolean(id)) + .map((id) => ({ + id, + label: id, + })); + setBusBarSectionsIdOptions(options); + } else { + setBusBarSectionsIdOptions([]); + } + }, [allBusbarSectionsList, busBarSectionInfos, intl, busbarIndex, setValue]); + + const arrayPosition = useMemo( + () => busBarSectionInfos && getArrayPosition(busBarSectionInfos, selectedOption?.id), + [busBarSectionInfos, selectedOption?.id] + ); + + useEffect(() => { + if (selectedOption && selectedPositionOption && busBarSectionInfos && arrayPosition) { + const selectedSectionIndex = arrayPosition.position; + const busBarSections = arrayPosition.length - 1; + if (selectedSectionIndex === 0 && selectedPositionOption === POSITION_NEW_SECTION_SIDE.BEFORE.id) { + setValue(FieldConstants.SWITCH_BEFORE_NOT_REQUIRED, true); + setIsNotRequiredSwitchBefore(true); + } else { + setValue(FieldConstants.SWITCH_BEFORE_NOT_REQUIRED, false); + setIsNotRequiredSwitchBefore(false); + } + if ( + busBarSections === selectedSectionIndex && + selectedPositionOption === POSITION_NEW_SECTION_SIDE.AFTER.id + ) { + setValue(FieldConstants.SWITCH_AFTER_NOT_REQUIRED, true); + setIsNotRequiredSwitchAfter(true); + } else { + setValue(FieldConstants.SWITCH_AFTER_NOT_REQUIRED, false); + setIsNotRequiredSwitchAfter(false); + } + } + if (isUpdate && isNodeBuilt) { + setValue(FieldConstants.SWITCH_AFTER_NOT_REQUIRED, true); + setValue(FieldConstants.SWITCH_BEFORE_NOT_REQUIRED, true); + } + }, [selectedOption, setValue, busBarSectionInfos, selectedPositionOption, arrayPosition, isUpdate, isNodeBuilt]); + + const busBarIndexOptions = useMemo((): OptionWithDisabled[] => { + if (busBarSectionInfos) { + const sortedOptions = Object.keys(busBarSectionInfos || {}) + .sort((a, b) => parseInt(a, 10) - parseInt(b, 10)) + .map((key) => ({ + id: key, + label: key, + })); + const allOption = { + id: 'all', + label: intl.formatMessage({ id: 'allBusbarSections' }), + disabled: !isSymmetricalNbBusBarSections, + } as Option & { disabled?: boolean }; + + return [...sortedOptions, allOption]; + } + return []; + }, [busBarSectionInfos, intl, isSymmetricalNbBusBarSections]); + + const getOptionLabel = (object: string | { id: string | number; label: string | number }) => { + if (typeof object === 'string') { + return object; + } + if (object?.id === 'all') { + return intl.formatMessage({ id: 'allBusbarSections' }) ?? ''; + } + return String(object?.id ?? ''); + }; + + const isOptionEqualToValue = (val1: Option, val2: Option) => { + const getId = (option: Option) => { + return typeof option === 'string' ? option : String(option?.id ?? ''); + }; + + return getId(val1) === getId(val2); + }; + + const handleChangeBusbarIndex = useCallback(() => { + setValue(FieldConstants.BUSBAR_SECTION_ID, null); + }, [setValue]); + + const freeInputOutputTransform = useCallback( + (value: Option | null) => (typeof value === 'string' ? { id: value, label: value } : value), + [] + ); + + const busbarCountField = ( + { + const allOptionsDisabled = (option as any).id === 'all' && (option as any)?.disabled; + const { key, ...otherProps } = props; + return ( +
  • +
    +
    {getOptionLabel(option)}
    + {allOptionsDisabled && ( +
    + {intl.formatMessage({ id: 'allOptionHelperText' })} +
    + )} +
    +
  • + ); + }} + getOptionDisabled={(option) => (option as any)?.disabled} + size="small" + disabled={isNotFoundOrNotSupported} + /> + ); + + const busbarSectionsField = ( + + ); + + const positionSideNewSectionField = ( + + ); + + const switchBeforeField = ( + + ); + const switchAfterField = ( + + ); + const newSwitchState = ( + + ); + const getLabelDescription = useCallback(() => { + return intl.formatMessage({ id: 'newSection' }); + }, [intl]); + const newSectionField = ( + + ); + const handleCloseDiagramPane = useCallback(() => { + setIsDiagramPaneOpen(false); + }, []); + const handleClickOpenDiagramPane = useCallback(() => { + setIsDiagramPaneOpen(true); + }, []); + const diagramToolTip = ( + + + + ); + return ( + + + + + {voltageLevelIdField} + {PositionDiagramPane && isNodeBuilt && ( + + + {diagramToolTip} + + )} + + + {isNotFoundOrNotSupported && ( + + + + + + )} + + + + + {busbarCountField} + {busbarSectionsField} + {positionSideNewSectionField} + + + + + + {switchBeforeField} + {newSectionField} + {switchAfterField} + {newSwitchState} + + {PositionDiagramPane && ( + + )} + + ); +} diff --git a/src/features/network-modifications/voltageLevel/section/index.ts b/src/features/network-modifications/voltageLevel/section/index.ts new file mode 100644 index 000000000..c86af48a6 --- /dev/null +++ b/src/features/network-modifications/voltageLevel/section/index.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2026, 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/. + */ + +export * from './VoltageLevelSectionCreationForm'; +export * from './voltageLevelSectionCreation.types'; +export * from './voltageLevelSectionCreation.utils'; diff --git a/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.types.ts b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.types.ts new file mode 100644 index 000000000..cfc8833fc --- /dev/null +++ b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.types.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2026, 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 { UUID } from 'node:crypto'; +import { ModificationType } from '../../../../utils'; + +export type BusBarSections = Record; + +export interface VoltageLevelSectionCreationDto { + type: ModificationType; + uuid?: UUID; + voltageLevelId: string; + busbarIndex: string | null; + busbarSectionId: string | null; + allBusbars: boolean; + afterBusbarSectionId: boolean; + leftSwitchKind: string | null; + rightSwitchKind: string | null; + switchOpen: boolean; +} diff --git a/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts new file mode 100644 index 000000000..5b67b1937 --- /dev/null +++ b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2026, 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 { boolean, InferType, object, string } from 'yup'; +import { DeepNullable, FieldConstants, ModificationType } from '../../../../utils'; +import { BusBarSections, VoltageLevelSectionCreationDto } from './voltageLevelSectionCreation.types'; + +export const POSITION_NEW_SECTION_SIDE = { + BEFORE: { id: 'BEFORE', label: 'Before' }, + AFTER: { id: 'AFTER', label: 'After' }, +} as const; + +export const voltageLevelSectionCreationFormSchema = object() + .shape({ + [FieldConstants.EQUIPMENT_ID]: string().required(), + [FieldConstants.BUS_BAR_INDEX]: object() + .nullable() + .required() + .shape({ + [FieldConstants.ID]: string().nullable().required(), + }), + [FieldConstants.BUSBAR_SECTION_ID]: object() + .nullable() + .required() + .shape({ + [FieldConstants.ID]: string().nullable().required(), + }), + [FieldConstants.IS_AFTER_BUSBAR_SECTION_ID]: string().nullable().required(), + [FieldConstants.SWITCHES_BEFORE_SECTIONS]: string() + .nullable() + .when([FieldConstants.IS_AFTER_BUSBAR_SECTION_ID, FieldConstants.SWITCH_BEFORE_NOT_REQUIRED], { + is: (isAfterBusBarSectionId: string, switchBeforeNotRequired: boolean) => + isAfterBusBarSectionId === POSITION_NEW_SECTION_SIDE.BEFORE.id && switchBeforeNotRequired, + then: (schema) => schema.notRequired(), + otherwise: (schema) => schema.required(), + }), + [FieldConstants.SWITCHES_AFTER_SECTIONS]: string() + .nullable() + .when([FieldConstants.IS_AFTER_BUSBAR_SECTION_ID, FieldConstants.SWITCH_AFTER_NOT_REQUIRED], { + is: (isAfterBusBarSectionId: string, switchAfterNotRequired: boolean) => + isAfterBusBarSectionId === POSITION_NEW_SECTION_SIDE.AFTER.id && switchAfterNotRequired, + then: (schema) => schema.notRequired(), + otherwise: (schema) => schema.required(), + }), + [FieldConstants.ALL_BUS_BAR_SECTIONS]: boolean(), + [FieldConstants.NEW_SWITCH_STATES]: boolean(), + [FieldConstants.SWITCH_BEFORE_NOT_REQUIRED]: boolean(), + [FieldConstants.SWITCH_AFTER_NOT_REQUIRED]: boolean(), + }) + .required(); + +export type VoltageLevelSectionCreationFormData = InferType; + +export const voltageLevelSectionCreationEmptyFormData: DeepNullable = { + equipmentID: '', + busbarIndex: null, + busbarSectionId: null, + isAfterBusBarSectionId: null, + switchesBeforeSections: null, + switchesAfterSections: null, + allBusbarSections: false, + newSwitchStates: true, + switchBeforeNotRequired: false, + switchAfterNotRequired: false, +}; + +const getBusBarIndexValue = ({ + busbarIndex, + allBusbars, +}: { + busbarIndex: string | null; + allBusbars: boolean; +}): { id: string } => { + if (allBusbars) { + return { id: 'all' }; + } + return { id: busbarIndex ?? '' }; +}; + +const getBusBarSectionValue = ({ busbarSectionId }: { busbarSectionId: string | null }): { id: string } => { + return { id: busbarSectionId ?? '' }; +}; + +const findBusbarKeyForSection = ( + busBarSectionInfos: BusBarSections | undefined, + sectionId: string | null | undefined +): string | null => { + if (!sectionId) { + return null; + } + return Object.keys(busBarSectionInfos || {}).find((key) => busBarSectionInfos?.[key]?.includes(sectionId)) ?? null; +}; + +export const voltageLevelSectionCreationDtoToForm = ( + dto: VoltageLevelSectionCreationDto +): VoltageLevelSectionCreationFormData => { + return { + equipmentID: dto.voltageLevelId, + busbarIndex: getBusBarIndexValue({ + busbarIndex: dto.busbarIndex, + allBusbars: dto.allBusbars, + }), + allBusbarSections: dto.allBusbars ?? false, + busbarSectionId: getBusBarSectionValue({ busbarSectionId: dto.busbarSectionId }), + isAfterBusBarSectionId: dto.afterBusbarSectionId + ? POSITION_NEW_SECTION_SIDE.AFTER.id + : POSITION_NEW_SECTION_SIDE.BEFORE.id, + switchesBeforeSections: dto.leftSwitchKind ?? null, + switchesAfterSections: dto.rightSwitchKind ?? null, + newSwitchStates: !(dto.switchOpen ?? true), + }; +}; + +export const voltageLevelSectionCreationFormToDto = ( + form: VoltageLevelSectionCreationFormData, + busBarSectionInfos?: BusBarSections +): VoltageLevelSectionCreationDto => { + return { + type: ModificationType.CREATE_VOLTAGE_LEVEL_SECTION, + voltageLevelId: form.equipmentID, + busbarIndex: form.allBusbarSections + ? findBusbarKeyForSection(busBarSectionInfos, form.busbarSectionId?.id) + : (form.busbarIndex?.id ?? null), + busbarSectionId: form.busbarSectionId?.id ?? null, + allBusbars: form.allBusbarSections ?? false, + afterBusbarSectionId: form.isAfterBusBarSectionId === POSITION_NEW_SECTION_SIDE.AFTER.id, + leftSwitchKind: form.switchesBeforeSections ?? null, + rightSwitchKind: form.switchesAfterSections ?? null, + switchOpen: !form.newSwitchStates, + }; +}; diff --git a/src/translations/en/networkModificationsEn.ts b/src/translations/en/networkModificationsEn.ts index 837e2e891..0f5a27bd6 100644 --- a/src/translations/en/networkModificationsEn.ts +++ b/src/translations/en/networkModificationsEn.ts @@ -301,6 +301,28 @@ export const networkModificationsEn = { G: 'Magnetizing conductance', B: 'Magnetizing susceptance', + // Voltage level section creation + CreateVoltageLevelSection: 'Add busbar section', + VoltageLevelSectionCreationError: 'Error while creating a section', + VoltageLevelId: 'Voltage level ID', + BusBarSectionsReference: 'Busbar reference section', + CreateCouplingDeviceDiagramButton: 'Show voltage level', + builtNodeTooltipForDiagram: 'Current diagram taking into account all applied modifications', + notValidVoltageLevel: 'Invalid voltage level to add busbar section. Please re-create the voltage level.', + SectionPosition: 'Position', + isAfterBusBarSectionId: 'New section side', + Switch: 'Switch', + newSection: 'New section', + switchesAfterSections: 'Switch after', + switchesBeforeSections: 'Switch before', + Busbar: 'Busbar', + Before: 'Before', + After: 'After', + allBusbarSections: 'All', + allOptionHelperText: 'Busbars have different sections (number or index)', + areSwitchesOpen: 'Open', + areSwitchesClosed: 'Closed', + // Tabs SubstationTab: 'Substation', ConnectivityTab: 'Connectivity', diff --git a/src/translations/fr/networkModificationsFr.ts b/src/translations/fr/networkModificationsFr.ts index 398747a37..f130ed235 100644 --- a/src/translations/fr/networkModificationsFr.ts +++ b/src/translations/fr/networkModificationsFr.ts @@ -307,6 +307,28 @@ export const networkModificationsFr = { G: 'Conductance magnétisante', B: 'Susceptance magnétisante', + // Voltage level section creation + CreateVoltageLevelSection: 'Ajouter un tronçon ou une section', + VoltageLevelSectionCreationError: "Erreur lors de la création d'une section", + VoltageLevelId: 'ID Poste', + BusBarSectionsReference: 'Section de jeu de barres de référence', + CreateCouplingDeviceDiagramButton: 'Voir le poste', + builtNodeTooltipForDiagram: 'Diagramme courant prenant en compte toutes les modifications réalisées', + notValidVoltageLevel: "Poste invalide pour l'ajout de section/tronçon. Veuillez re-créer le poste.", + SectionPosition: 'Position', + isAfterBusBarSectionId: 'Côté de la nouvelle section', + Switch: 'Organes de coupure', + newSection: 'Nouvelle section', + switchesAfterSections: 'OC après', + switchesBeforeSections: 'OC avant', + Busbar: 'Jeu de barres', + Before: 'Avant', + After: 'Après', + allBusbarSections: 'Tous', + allOptionHelperText: "Tous les jeux de barres n'ont pas les memes sections (index et nombre)", + areSwitchesOpen: 'Ouverts', + areSwitchesClosed: 'Fermés', + // Tabs SubstationTab: 'Site', ConnectivityTab: 'Connectivité', diff --git a/src/utils/constants/fieldConstants.ts b/src/utils/constants/fieldConstants.ts index 8850c70d9..05a34dd45 100644 --- a/src/utils/constants/fieldConstants.ts +++ b/src/utils/constants/fieldConstants.ts @@ -10,12 +10,15 @@ export enum FieldConstants { ADDED = 'added', ADDITIONAL_PROPERTIES = 'AdditionalProperties', AG_GRID_ROW_UUID = 'agGridRowUuid', + ALL_BUS_BAR_SECTIONS = 'allBusbarSections', API_CALL = 'apiCall', APPLY_SEGMENTS_LIMITS = 'applySegmentsLimits', APPLICABILITY_FIELD = 'applicability', ASSIGNMENTS = 'assignments', B1 = 'b1', B2 = 'b2', + BUS_BAR_INDEX = 'busbarIndex', + BUSBAR_SECTION_ID = 'busbarSectionId', BUS_OR_BUSBAR_SECTION = 'busOrBusbarSection', CASE_FILE = 'caseFile', CASE_FORMAT = 'caseFormat', @@ -63,6 +66,7 @@ export enum FieldConstants { G2 = 'g2', HVDC_LINE_LCC_DELETION_SPECIFIC_TYPE = 'HVDC_LINE_WITH_LCC', ID = 'id', + IS_AFTER_BUSBAR_SECTION_ID = 'isAfterBusBarSectionId', LOADFLOW_PARAMETERS = 'loadflowParameters', LOAD_TYPE = 'loadType', MARGINAL_COST = 'marginalCost', @@ -79,6 +83,7 @@ export enum FieldConstants { MODIFICATIONS = 'modifications', MINIMUM_ACTIVE_POWER = 'minimumActivePower', NAME = 'name', + NEW_SWITCH_STATES = 'newSwitchStates', NOMINAL_VOLTAGE_1 = 'nominalVoltage1', NOMINAL_VOLTAGE_2 = 'nominalVoltage2', NOMINAL_VOLTAGE_3 = 'nominalVoltage3', @@ -173,6 +178,10 @@ export enum FieldConstants { SUBSTATION_CREATION_ID = 'substationCreationId', SUBSTATION_ID = 'substationId', SUBSTATION_NAME = 'substationName', + SWITCH_AFTER_NOT_REQUIRED = 'switchAfterNotRequired', + SWITCH_BEFORE_NOT_REQUIRED = 'switchBeforeNotRequired', + SWITCHES_AFTER_SECTIONS = 'switchesAfterSections', + SWITCHES_BEFORE_SECTIONS = 'switchesBeforeSections', SWITCHES_BETWEEN_SECTIONS = 'switchesBetweenSections', TEMPORARY_LIMITS = 'temporaryLimits', TEMPORARY_LIMIT_NAME = 'name', From 131aac790d526c22ea6b6609e9f782d74606f35f Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Thu, 13 Aug 2026 10:54:47 +0200 Subject: [PATCH 2/6] merge with main Signed-off-by: benrejebmoh --- src/translations/en/networkModificationsEn.ts | 41 ++++++++----------- src/translations/fr/networkModificationsFr.ts | 41 ++++++++----------- src/utils/constants/fieldConstants.ts | 9 ---- 3 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/translations/en/networkModificationsEn.ts b/src/translations/en/networkModificationsEn.ts index 67c46928d..380d6f510 100644 --- a/src/translations/en/networkModificationsEn.ts +++ b/src/translations/en/networkModificationsEn.ts @@ -301,28 +301,6 @@ export const networkModificationsEn = { G: 'Magnetizing conductance', B: 'Magnetizing susceptance', - // Voltage level section creation - CreateVoltageLevelSection: 'Add busbar section', - VoltageLevelSectionCreationError: 'Error while creating a section', - VoltageLevelId: 'Voltage level ID', - BusBarSectionsReference: 'Busbar reference section', - CreateCouplingDeviceDiagramButton: 'Show voltage level', - builtNodeTooltipForDiagram: 'Current diagram taking into account all applied modifications', - notValidVoltageLevel: 'Invalid voltage level to add busbar section. Please re-create the voltage level.', - SectionPosition: 'Position', - isAfterBusBarSectionId: 'New section side', - Switch: 'Switch', - newSection: 'New section', - switchesAfterSections: 'Switch after', - switchesBeforeSections: 'Switch before', - Busbar: 'Busbar', - Before: 'Before', - After: 'After', - allBusbarSections: 'All', - allOptionHelperText: 'Busbars have different sections (number or index)', - areSwitchesOpen: 'Open', - areSwitchesClosed: 'Closed', - // Tabs SubstationTab: 'Substation', ConnectivityTab: 'Connectivity', @@ -336,7 +314,7 @@ export const networkModificationsEn = { copyLink: 'Copy link', linkCopied: 'Link copied', linkCopyError: 'Error while attempting to copy link', - // Voltage level topology creation + // Voltage level creation CreateVoltageLevelTopology: 'Adding a busbar', CreateVoltageLevelTopologyError: 'Error while creating a voltage level topology', CreateCouplingDeviceDiagramButton: 'Show voltage level', @@ -344,4 +322,21 @@ export const networkModificationsEn = { AtLeastOneSectionAdded: 'At least one busbar section must be added', SectionCount: 'Section count', VoltageLevelId: 'Voltage level ID', + CreateVoltageLevelSection: 'Add busbar section', + VoltageLevelSectionCreationError: 'Error while creating a section', + BusBarSectionsReference: 'Busbar reference section', + notValidVoltageLevel: 'Invalid voltage level to add busbar section. Please re-create the voltage level.', + SectionPosition: 'Position', + isAfterBusBarSectionId: 'New section side', + Switch: 'Switch', + newSection: 'New section', + switchesAfterSections: 'Switch after', + switchesBeforeSections: 'Switch before', + Busbar: 'Busbar', + Before: 'Before', + After: 'After', + allBusbarSections: 'All', + allOptionHelperText: 'Busbars have different sections (number or index)', + areSwitchesOpen: 'Open', + areSwitchesClosed: 'Closed', }; diff --git a/src/translations/fr/networkModificationsFr.ts b/src/translations/fr/networkModificationsFr.ts index 203e0cabe..dbe394eea 100644 --- a/src/translations/fr/networkModificationsFr.ts +++ b/src/translations/fr/networkModificationsFr.ts @@ -307,28 +307,6 @@ export const networkModificationsFr = { G: 'Conductance magnétisante', B: 'Susceptance magnétisante', - // Voltage level section creation - CreateVoltageLevelSection: 'Ajouter un tronçon ou une section', - VoltageLevelSectionCreationError: "Erreur lors de la création d'une section", - VoltageLevelId: 'ID Poste', - BusBarSectionsReference: 'Section de jeu de barres de référence', - CreateCouplingDeviceDiagramButton: 'Voir le poste', - builtNodeTooltipForDiagram: 'Diagramme courant prenant en compte toutes les modifications réalisées', - notValidVoltageLevel: "Poste invalide pour l'ajout de section/tronçon. Veuillez re-créer le poste.", - SectionPosition: 'Position', - isAfterBusBarSectionId: 'Côté de la nouvelle section', - Switch: 'Organes de coupure', - newSection: 'Nouvelle section', - switchesAfterSections: 'OC après', - switchesBeforeSections: 'OC avant', - Busbar: 'Jeu de barres', - Before: 'Avant', - After: 'Après', - allBusbarSections: 'Tous', - allOptionHelperText: "Tous les jeux de barres n'ont pas les memes sections (index et nombre)", - areSwitchesOpen: 'Ouverts', - areSwitchesClosed: 'Fermés', - // Tabs SubstationTab: 'Site', ConnectivityTab: 'Connectivité', @@ -342,7 +320,7 @@ export const networkModificationsFr = { copyLink: 'Copier le lien', linkCopied: 'Lien copié', linkCopyError: 'Erreur lors de la copie du lien', - // Voltage level topology creation + // Voltage level CreateVoltageLevelTopology: 'Ajouter un jeu de barre', CreateVoltageLevelTopologyError: "Erreur lors de la création d'une topologie de poste", CreateCouplingDeviceDiagramButton: 'Voir le poste', @@ -350,4 +328,21 @@ export const networkModificationsFr = { AtLeastOneSectionAdded: 'Il faut ajouter au moins une section de jeu de barre', SectionCount: 'Nombre de sections', VoltageLevelId: 'ID Poste', + CreateVoltageLevelSection: 'Ajouter un tronçon ou une section', + VoltageLevelSectionCreationError: "Erreur lors de la création d'une section", + BusBarSectionsReference: 'Section de jeu de barres de référence', + notValidVoltageLevel: "Poste invalide pour l'ajout de section/tronçon. Veuillez re-créer le poste.", + SectionPosition: 'Position', + isAfterBusBarSectionId: 'Côté de la nouvelle section', + Switch: 'Organes de coupure', + newSection: 'Nouvelle section', + switchesAfterSections: 'OC après', + switchesBeforeSections: 'OC avant', + Busbar: 'Jeu de barres', + Before: 'Avant', + After: 'Après', + allBusbarSections: 'Tous', + allOptionHelperText: "Tous les jeux de barres n'ont pas les memes sections (index et nombre)", + areSwitchesOpen: 'Ouverts', + areSwitchesClosed: 'Fermés', }; diff --git a/src/utils/constants/fieldConstants.ts b/src/utils/constants/fieldConstants.ts index a75d6a3cf..760d2c370 100644 --- a/src/utils/constants/fieldConstants.ts +++ b/src/utils/constants/fieldConstants.ts @@ -10,15 +10,12 @@ export enum FieldConstants { ADDED = 'added', ADDITIONAL_PROPERTIES = 'AdditionalProperties', AG_GRID_ROW_UUID = 'agGridRowUuid', - ALL_BUS_BAR_SECTIONS = 'allBusbarSections', API_CALL = 'apiCall', APPLY_SEGMENTS_LIMITS = 'applySegmentsLimits', APPLICABILITY_FIELD = 'applicability', ASSIGNMENTS = 'assignments', B1 = 'b1', B2 = 'b2', - BUS_BAR_INDEX = 'busbarIndex', - BUSBAR_SECTION_ID = 'busbarSectionId', BUS_OR_BUSBAR_SECTION = 'busOrBusbarSection', CASE_FILE = 'caseFile', CASE_FORMAT = 'caseFormat', @@ -66,7 +63,6 @@ export enum FieldConstants { G2 = 'g2', HVDC_LINE_LCC_DELETION_SPECIFIC_TYPE = 'HVDC_LINE_WITH_LCC', ID = 'id', - IS_AFTER_BUSBAR_SECTION_ID = 'isAfterBusBarSectionId', LOADFLOW_PARAMETERS = 'loadflowParameters', LOAD_TYPE = 'loadType', MARGINAL_COST = 'marginalCost', @@ -83,7 +79,6 @@ export enum FieldConstants { MODIFICATIONS = 'modifications', MINIMUM_ACTIVE_POWER = 'minimumActivePower', NAME = 'name', - NEW_SWITCH_STATES = 'newSwitchStates', NOMINAL_VOLTAGE_1 = 'nominalVoltage1', NOMINAL_VOLTAGE_2 = 'nominalVoltage2', NOMINAL_VOLTAGE_3 = 'nominalVoltage3', @@ -128,10 +123,6 @@ export enum FieldConstants { COUPLING_OMNIBUS = 'couplingOmnibus', IS_AFTER_BUSBAR_SECTION_ID = 'isAfterBusBarSectionId', NEW_SWITCH_STATES = 'newSwitchStates', - SWITCH_AFTER_NOT_REQUIRED = 'switchAfterNotRequired', - SWITCH_BEFORE_NOT_REQUIRED = 'switchBeforeNotRequired', - SWITCHES_AFTER_SECTIONS = 'switchesAfterSections', - SWITCHES_BEFORE_SECTIONS = 'switchesBeforeSections', ENABLE_OLG_MODIFICATION = 'enableOLGModification', HIDE_BUS_BAR_SECTION = 'hideBusBarSection', HIDE_NOMINAL_VOLTAGE = 'hideNominalVoltage', From 1f64ed93f705bb2103da2fd5812f8a75eb02a749 Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Thu, 13 Aug 2026 14:33:32 +0200 Subject: [PATCH 3/6] fix free input mode reference bus bar section validation Signed-off-by: benrejebmoh --- .../section/VoltageLevelSectionCreationForm.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx index 616e3598d..794ac6741 100644 --- a/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx +++ b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx @@ -193,8 +193,10 @@ export function VoltageLevelSectionCreationForm({ }; const handleChangeBusbarIndex = useCallback(() => { - setValue(FieldConstants.BUSBAR_SECTION_ID, null); - }, [setValue]); + if (!isFreeInputMode) { + setValue(FieldConstants.BUSBAR_SECTION_ID, null); + } + }, [isFreeInputMode, setValue]); const freeInputOutputTransform = useCallback( (value: Option | null) => (typeof value === 'string' ? { id: value, label: value } : value), From 2fd6d5fb5cb6620b3d5038feaff23ecfb6551b6f Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Mon, 17 Aug 2026 15:56:00 +0200 Subject: [PATCH 4/6] solving review comments Signed-off-by: benrejebmoh --- .../VoltageLevelSectionCreationForm.tsx | 7 +------ .../voltageLevelSectionCreation.utils.ts | 20 +++++++++---------- src/translations/en/networkModificationsEn.ts | 1 + src/translations/fr/networkModificationsFr.ts | 3 ++- src/utils/constants/fieldConstants.ts | 8 ++++---- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx index 794ac6741..191190f7e 100644 --- a/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx +++ b/src/features/network-modifications/voltageLevel/section/VoltageLevelSectionCreationForm.tsx @@ -13,6 +13,7 @@ import { AutocompleteInput, SelectInput, SwitchInput, useCustomFormContext } fro import { areIdsEqual, FieldConstants, getObjectId, Option } from '../../../../utils'; import { GridSection } from '../../../../components/composite/grid/grid-section'; import { filledTextField } from '../../common'; +import { PositionDiagramPaneType } from '../../common/connectivity/connectivity.type'; import { SWITCH_TYPE } from '../creation'; import { BusBarSections } from './voltageLevelSectionCreation.types'; import { POSITION_NEW_SECTION_SIDE } from './voltageLevelSectionCreation.utils'; @@ -33,12 +34,6 @@ const getArrayPosition = (data: BusBarSections, selectedOptionId: string) => { type OptionWithDisabled = Option & { disabled?: boolean }; -type PositionDiagramPaneType = React.ComponentType<{ - open: boolean; - onClose: () => void; - voltageLevelId: string; -}>; - export interface VoltageLevelSectionCreationFormProps { busBarSectionInfos?: BusBarSections; allBusbarSectionsList?: string[]; diff --git a/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts index 5b67b1937..401c7466d 100644 --- a/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts +++ b/src/features/network-modifications/voltageLevel/section/voltageLevelSectionCreation.utils.ts @@ -56,16 +56,16 @@ export const voltageLevelSectionCreationFormSchema = object() export type VoltageLevelSectionCreationFormData = InferType; export const voltageLevelSectionCreationEmptyFormData: DeepNullable = { - equipmentID: '', - busbarIndex: null, - busbarSectionId: null, - isAfterBusBarSectionId: null, - switchesBeforeSections: null, - switchesAfterSections: null, - allBusbarSections: false, - newSwitchStates: true, - switchBeforeNotRequired: false, - switchAfterNotRequired: false, + [FieldConstants.EQUIPMENT_ID]: '', + [FieldConstants.BUS_BAR_INDEX]: null, + [FieldConstants.BUSBAR_SECTION_ID]: null, + [FieldConstants.IS_AFTER_BUSBAR_SECTION_ID]: null, + [FieldConstants.SWITCHES_BEFORE_SECTIONS]: null, + [FieldConstants.SWITCHES_AFTER_SECTIONS]: null, + [FieldConstants.ALL_BUS_BAR_SECTIONS]: false, + [FieldConstants.NEW_SWITCH_STATES]: true, + [FieldConstants.SWITCH_BEFORE_NOT_REQUIRED]: false, + [FieldConstants.SWITCH_AFTER_NOT_REQUIRED]: false, }; const getBusBarIndexValue = ({ diff --git a/src/translations/en/networkModificationsEn.ts b/src/translations/en/networkModificationsEn.ts index b30ea31e8..8f3814da7 100644 --- a/src/translations/en/networkModificationsEn.ts +++ b/src/translations/en/networkModificationsEn.ts @@ -355,6 +355,7 @@ export const networkModificationsEn = { CouplingDeviceText: 'Bus bar sections', CouplingDeviceBusBarSectionToolTipText: 'If both bus bar sections have a different section number it creates an omnibus otherwise a coupling device', + // Voltage level section creation CreateVoltageLevelSection: 'Add busbar section', VoltageLevelSectionCreationError: 'Error while creating a section', BusBarSectionsReference: 'Busbar reference section', diff --git a/src/translations/fr/networkModificationsFr.ts b/src/translations/fr/networkModificationsFr.ts index fa674ec2f..97e49c46c 100644 --- a/src/translations/fr/networkModificationsFr.ts +++ b/src/translations/fr/networkModificationsFr.ts @@ -361,6 +361,7 @@ export const networkModificationsFr = { CouplingDeviceText: 'Sections de jeu de barre', CouplingDeviceBusBarSectionToolTipText: 'Si les deux sections de barre sélectionnées ont des numéros de tronçon/section différents la modification crée un omnibus, autrement elle crée un couplage', + // Voltage level section creation CreateVoltageLevelSection: 'Ajouter un tronçon ou une section', VoltageLevelSectionCreationError: "Erreur lors de la création d'une section", BusBarSectionsReference: 'Section de jeu de barres de référence', @@ -375,7 +376,7 @@ export const networkModificationsFr = { Before: 'Avant', After: 'Après', allBusbarSections: 'Tous', - allOptionHelperText: "Tous les jeux de barres n'ont pas les memes sections (index et nombre)", + allOptionHelperText: "Tous les jeux de barres n'ont pas les mêmes sections (index et nombre)", areSwitchesOpen: 'Ouverts', areSwitchesClosed: 'Fermés', }; \ No newline at end of file diff --git a/src/utils/constants/fieldConstants.ts b/src/utils/constants/fieldConstants.ts index f34e6fac9..3c3fcd23e 100644 --- a/src/utils/constants/fieldConstants.ts +++ b/src/utils/constants/fieldConstants.ts @@ -125,6 +125,10 @@ export enum FieldConstants { COUPLING_OMNIBUS = 'couplingOmnibus', IS_AFTER_BUSBAR_SECTION_ID = 'isAfterBusBarSectionId', NEW_SWITCH_STATES = 'newSwitchStates', + SWITCH_AFTER_NOT_REQUIRED = 'switchAfterNotRequired', + SWITCH_BEFORE_NOT_REQUIRED = 'switchBeforeNotRequired', + SWITCHES_AFTER_SECTIONS = 'switchesAfterSections', + SWITCHES_BEFORE_SECTIONS = 'switchesBeforeSections', ENABLE_OLG_MODIFICATION = 'enableOLGModification', HIDE_BUS_BAR_SECTION = 'hideBusBarSection', HIDE_NOMINAL_VOLTAGE = 'hideNominalVoltage', @@ -180,10 +184,6 @@ export enum FieldConstants { SUBSTATION_CREATION_ID = 'substationCreationId', SUBSTATION_ID = 'substationId', SUBSTATION_NAME = 'substationName', - SWITCH_AFTER_NOT_REQUIRED = 'switchAfterNotRequired', - SWITCH_BEFORE_NOT_REQUIRED = 'switchBeforeNotRequired', - SWITCHES_AFTER_SECTIONS = 'switchesAfterSections', - SWITCHES_BEFORE_SECTIONS = 'switchesBeforeSections', SWITCHES_BETWEEN_SECTIONS = 'switchesBetweenSections', TEMPORARY_LIMITS = 'temporaryLimits', TEMPORARY_LIMIT_NAME = 'name', From 3244698eef1cf63b1b2a7f6f6e07a3b9b4ee6d00 Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Tue, 18 Aug 2026 11:08:17 +0200 Subject: [PATCH 5/6] prettier Signed-off-by: benrejebmoh --- src/translations/en/networkModificationsEn.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/translations/en/networkModificationsEn.ts b/src/translations/en/networkModificationsEn.ts index 8f3814da7..4c4ce0450 100644 --- a/src/translations/en/networkModificationsEn.ts +++ b/src/translations/en/networkModificationsEn.ts @@ -374,5 +374,3 @@ export const networkModificationsEn = { areSwitchesOpen: 'Open', areSwitchesClosed: 'Closed', }; - - From 211a353ce0ac379da57b393f8e5b634c46572b09 Mon Sep 17 00:00:00 2001 From: benrejebmoh Date: Tue, 18 Aug 2026 11:12:19 +0200 Subject: [PATCH 6/6] prettier Signed-off-by: benrejebmoh --- src/translations/fr/networkModificationsFr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/fr/networkModificationsFr.ts b/src/translations/fr/networkModificationsFr.ts index 97e49c46c..08d1232b0 100644 --- a/src/translations/fr/networkModificationsFr.ts +++ b/src/translations/fr/networkModificationsFr.ts @@ -379,4 +379,4 @@ export const networkModificationsFr = { allOptionHelperText: "Tous les jeux de barres n'ont pas les mêmes sections (index et nombre)", areSwitchesOpen: 'Ouverts', areSwitchesClosed: 'Fermés', -}; \ No newline at end of file +};