From 143fade1ee1c779d4c37cf0753af2ab1f795c10c Mon Sep 17 00:00:00 2001 From: basseche Date: Tue, 18 Feb 2025 11:01:18 +0100 Subject: [PATCH 1/4] Enable equipment selection combobox when voltage level field is filled but is absent from network --- .../regulating-terminal-form.jsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx index e6e17b2642..12a8bde094 100644 --- a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx +++ b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx @@ -10,7 +10,7 @@ import { createFilterOptions } from '@mui/material/useAutocomplete'; import { EQUIPMENT, ID, TYPE, VOLTAGE_LEVEL } from 'components/utils/field-constants'; import PropTypes from 'prop-types'; import { useCallback, useEffect, useState } from 'react'; -import { useFormContext, useWatch } from 'react-hook-form'; +import { useFormContext } from 'react-hook-form'; import { AutocompleteInput } from '@gridsuite/commons-ui'; import { fetchVoltageLevelEquipments } from '../../../services/study/network-map'; @@ -51,20 +51,17 @@ const RegulatingTerminalForm = ({ previousEquipmentSectionTypeValue, }) => { const [equipmentsOptions, setEquipmentsOptions] = useState([]); - const { setValue } = useFormContext(); - - const watchVoltageLevelId = useWatch({ - name: `${id}.${VOLTAGE_LEVEL}.${ID}`, - }); + const { setValue, getValues } = useFormContext(); + const [voltageLevelId, setVoltageLevelId] = useState(getValues(`${id}.${VOLTAGE_LEVEL}.${ID}`)); useEffect(() => { - if (watchVoltageLevelId) { + if (voltageLevelId) { fetchVoltageLevelEquipments( studyUuid, currentNodeUuid, currentRootNetworkUuid, undefined, - watchVoltageLevelId, + voltageLevelId, true ).then((values) => { setEquipmentsOptions(values); @@ -72,11 +69,12 @@ const RegulatingTerminalForm = ({ } else { setEquipmentsOptions([]); } - }, [watchVoltageLevelId, id, studyUuid, currentNodeUuid, currentRootNetworkUuid]); + }, [voltageLevelId, studyUuid, currentNodeUuid, currentRootNetworkUuid]); const resetEquipment = useCallback(() => { + setVoltageLevelId(getValues(`${id}.${VOLTAGE_LEVEL}.${ID}`)); setValue(`${id}.${EQUIPMENT}`, null); - }, [id, setValue]); + }, [id, setValue, getValues]); return ( <> @@ -118,6 +116,7 @@ const RegulatingTerminalForm = ({ return filtered; }} PopperComponent={FittingPopper} + onBlur={(event) => setVoltageLevelId(event.target.value)} /> } @@ -144,7 +143,7 @@ const RegulatingTerminalForm = ({ autoHighlight selectOnFocus id="equipment" - disabled={!watchVoltageLevelId || disabled} + disabled={!voltageLevelId || disabled} previousValue={previousEquipmentSectionTypeValue} options={equipmentsOptions} getOptionLabel={(equipment) => { From f30182abbb982c193b6c584aeb0da13d6600afe4 Mon Sep 17 00:00:00 2001 From: Thang PHAM Date: Tue, 25 Feb 2025 13:32:42 +0100 Subject: [PATCH 2/4] Remote regulating terminal with creating voltage level on the fly Signed-off-by: Thang PHAM --- .../regulating-terminal-form.jsx | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx index c1f42cb8fe..0107d15980 100644 --- a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx +++ b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx @@ -48,7 +48,11 @@ const RegulatingTerminalForm = ({ }); useEffect(() => { - if (watchVoltageLevelId) { + if ( + watchVoltageLevelId && + /* avoid fetch non existing vl id */ + voltageLevelOptions.find((vlOption) => vlOption.id === watchVoltageLevelId) + ) { fetchVoltageLevelEquipments( studyUuid, currentNodeUuid, @@ -57,12 +61,14 @@ const RegulatingTerminalForm = ({ watchVoltageLevelId, true ).then((values) => { + console.log('XXX equipment options', { watchVoltageLevelId, values }); setEquipmentsOptions(values); }); } else { + console.log('XXX reset empty equipment options', { watchVoltageLevelId }); setEquipmentsOptions([]); } - }, [watchVoltageLevelId, id, studyUuid, currentNodeUuid, currentRootNetworkUuid]); + }, [watchVoltageLevelId, voltageLevelOptions, id, studyUuid, currentNodeUuid, currentRootNetworkUuid]); const resetEquipment = useCallback(() => { setValue(`${id}.${EQUIPMENT}`, null); @@ -81,14 +87,18 @@ const RegulatingTerminalForm = ({ name={`${id}.${VOLTAGE_LEVEL}`} label="VOLTAGE_LEVEL" size="small" - freeSolo + // particular outputTransform case for string type when a user clicks outside after editing whatever input + outputTransform={(value) => { + console.log('XXX VL ID inputValue', { value }); + return typeof value === 'string' ? { id: value, label: value } : value; + }} forcePopupIcon autoHighlight selectOnFocus disabled={disabled} id="voltage-level" options={voltageLevelOptions} - getOptionLabel={(vl) => (vl?.[ID] ? vl?.[ID] : '')} + getOptionLabel={(vl) => (vl?.id ? vl?.id : '')} onChangeCallback={resetEquipment} previousValue={previousRegulatingTerminalValue} /* Modifies the filter option method so that when a value is directly entered in the text field, a new option @@ -96,13 +106,11 @@ const RegulatingTerminalForm = ({ */ filterOptions={(options, params) => { const filtered = filter(options, params); - if ( - params.inputValue !== '' && - !options.find((opt) => opt?.[ID] === params.inputValue) - ) { + console.log('XXX options', { options }); + if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { filtered.push({ - inputValue: params.inputValue, - [ID]: params.inputValue, + id: params.inputValue, + label: params.inputValue, }); } return filtered; @@ -157,6 +165,7 @@ const RegulatingTerminalForm = ({ } return filtered; }} + allowNewValue PopperComponent={FittingPopper} /> } From 20d186f305d77ce0eaea9390e72a18314251160f Mon Sep 17 00:00:00 2001 From: basseche Date: Wed, 26 Feb 2025 17:20:07 +0100 Subject: [PATCH 3/4] fix second combobox behavior --- .../regulating-terminal-form.jsx | 179 +++++++++--------- 1 file changed, 86 insertions(+), 93 deletions(-) diff --git a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx index 0107d15980..ba5ce44112 100644 --- a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx +++ b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { Grid, Popper } from '@mui/material'; +import { Box, Grid, Popper } from '@mui/material'; import { createFilterOptions } from '@mui/material/useAutocomplete'; import { EQUIPMENT, ID, TYPE, VOLTAGE_LEVEL } from 'components/utils/field-constants'; import PropTypes from 'prop-types'; @@ -75,103 +75,96 @@ const RegulatingTerminalForm = ({ }, [id, setValue]); return ( - <> - - - { - { - console.log('XXX VL ID inputValue', { value }); - return typeof value === 'string' ? { id: value, label: value } : value; - }} - forcePopupIcon - autoHighlight - selectOnFocus - disabled={disabled} - id="voltage-level" - options={voltageLevelOptions} - getOptionLabel={(vl) => (vl?.id ? vl?.id : '')} - onChangeCallback={resetEquipment} - previousValue={previousRegulatingTerminalValue} - /* Modifies the filter option method so that when a value is directly entered in the text field, a new option + + + { + { + console.log('XXX VL ID inputValue', { value }); + return typeof value === 'string' ? { id: value, label: value } : value; + }} + forcePopupIcon + autoHighlight + selectOnFocus + disabled={disabled} + id="voltage-level" + options={voltageLevelOptions} + getOptionLabel={(vl) => (vl?.id ? vl?.id : '')} + onChangeCallback={resetEquipment} + previousValue={previousRegulatingTerminalValue} + /* Modifies the filter option method so that when a value is directly entered in the text field, a new option is created in the options list with a value equal to the input value */ - filterOptions={(options, params) => { - const filtered = filter(options, params); - console.log('XXX options', { options }); - if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { - filtered.push({ - id: params.inputValue, - label: params.inputValue, - }); - } - return filtered; - }} - PopperComponent={FittingPopper} - /> - } - - - {/* TODO: autoComplete prop is not working properly with material-ui v4, - it clears the field when blur event is raised, which actually forces the user to validate free input - with enter key for it to be validated. - check if autoComplete prop is fixed in v5 */} - { - (value === null ? '' : value)} - outputTransform={(value) => (value === '' ? null : value)} - label="Equipment" - size="small" - freeSolo - forcePopupIcon - autoHighlight - selectOnFocus - id="equipment" - disabled={!watchVoltageLevelId || disabled} - previousValue={previousEquipmentSectionTypeValue} - options={equipmentsOptions} - getOptionLabel={(equipment) => { - return equipment === '' - ? '' // to clear field - : (equipment?.[TYPE] ?? equipmentSectionTypeDefaultValue) + - ' : ' + - equipment?.[ID] || ''; - }} - /* Modifies the filter option method so that when a value is directly entered in the text field, a new option + filterOptions={(options, params) => { + const filtered = filter(options, params); + console.log('XXX options', { options }); + if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { + filtered.push({ + id: params.inputValue, + label: params.inputValue, + }); + } + return filtered; + }} + PopperComponent={FittingPopper} + allowNewValue + /> + } + + + { + { + return typeof value === 'string' ? { id: value, label: value } : value; + }} + label="Equipment" + size="small" + freeSolo + forcePopupIcon + autoHighlight + selectOnFocus + id="equipment" + disabled={!watchVoltageLevelId || disabled} + previousValue={previousEquipmentSectionTypeValue} + options={equipmentsOptions} + getOptionLabel={(equipment) => { + return equipment === '' ? '' : equipment?.[ID] || ''; + }} + renderOption={(props, option) => { + return {`${option?.[TYPE]} : ${option?.[ID]}`}; + }} + /* Modifies the filter option method so that when a value is directly entered in the text field, a new option is created in the options list with a value equal to the input value */ - filterOptions={(options, params) => { - const filtered = filter(options, params); - if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { - filtered.push({ - [TYPE]: equipmentSectionTypeDefaultValue, - [ID]: params.inputValue, - }); - } - return filtered; - }} - allowNewValue - PopperComponent={FittingPopper} - /> - } - + filterOptions={(options, params) => { + const filtered = filter(options, params); + if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { + filtered.push({ + [TYPE]: equipmentSectionTypeDefaultValue, + [ID]: params.inputValue, + }); + } + return filtered; + }} + allowNewValue + PopperComponent={FittingPopper} + /> + } - + ); }; From bcbe9fbe1e0f7c1b4262ba58af163d7104636716 Mon Sep 17 00:00:00 2001 From: Thang PHAM Date: Thu, 27 Feb 2025 11:01:32 +0100 Subject: [PATCH 4/4] rectification Signed-off-by: Thang PHAM --- .../regulating-terminal-form.jsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx index ba5ce44112..18ce041a23 100644 --- a/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx +++ b/src/components/dialogs/regulating-terminal/regulating-terminal-form.jsx @@ -61,11 +61,9 @@ const RegulatingTerminalForm = ({ watchVoltageLevelId, true ).then((values) => { - console.log('XXX equipment options', { watchVoltageLevelId, values }); setEquipmentsOptions(values); }); } else { - console.log('XXX reset empty equipment options', { watchVoltageLevelId }); setEquipmentsOptions([]); } }, [watchVoltageLevelId, voltageLevelOptions, id, studyUuid, currentNodeUuid, currentRootNetworkUuid]); @@ -86,9 +84,9 @@ const RegulatingTerminalForm = ({ name={`${id}.${VOLTAGE_LEVEL}`} label="VOLTAGE_LEVEL" size="small" - // particular outputTransform case for string type when a user clicks outside after editing whatever input + // particular outputTransform case for string type when a user typing whatever in the input (onInputChange) + // but not click on an option (onChange) outputTransform={(value) => { - console.log('XXX VL ID inputValue', { value }); return typeof value === 'string' ? { id: value, label: value } : value; }} forcePopupIcon @@ -105,7 +103,6 @@ const RegulatingTerminalForm = ({ */ filterOptions={(options, params) => { const filtered = filter(options, params); - console.log('XXX options', { options }); if (params.inputValue !== '' && !options.find((opt) => opt?.id === params.inputValue)) { filtered.push({ id: params.inputValue, @@ -128,11 +125,15 @@ const RegulatingTerminalForm = ({ { - return typeof value === 'string' ? { id: value, label: value } : value; + return typeof value === 'string' + ? value === '' + ? null + : { id: value, type: equipmentSectionTypeDefaultValue } + : value; }} + inputTransform={(value) => (value === null ? '' : value)} label="Equipment" size="small" - freeSolo forcePopupIcon autoHighlight selectOnFocus @@ -144,7 +145,12 @@ const RegulatingTerminalForm = ({ return equipment === '' ? '' : equipment?.[ID] || ''; }} renderOption={(props, option) => { - return {`${option?.[TYPE]} : ${option?.[ID]}`}; + const { key, ...optionProps } = props; + return ( + + {option?.[TYPE] ? `${option?.[TYPE]} : ${option?.[ID]}` : option?.[ID]} + + ); }} /* Modifies the filter option method so that when a value is directly entered in the text field, a new option is created in the options list with a value equal to the input value