From 930b4db7fae241351c64f5ca438882a4ca2feb71 Mon Sep 17 00:00:00 2001 From: souissimai Date: Tue, 17 Dec 2024 14:11:31 +0100 Subject: [PATCH 01/51] new IHM : root network Signed-off-by: souissimai --- src/components/dialogs/case-list-selector.jsx | 231 ++++ src/components/dialogs/create-case-dialog.tsx | 97 ++ .../dialogs/element-creation-dialog.tsx | 112 +- src/components/dialogs/import-case-dialog.tsx | 40 + src/components/graph/menus/editable-title.tsx | 17 +- src/components/graph/menus/node-editor.tsx | 7 +- .../graph/menus/root-network-editor.tsx | 73 ++ .../graph/menus/root-network-node-editor.tsx | 1011 +++++++++++++++++ src/components/left-drawer.jsx | 77 ++ .../network-modification-tree-pane.jsx | 3 + src/components/study-container.jsx | 15 +- src/components/utils/field-constants.ts | 2 + src/redux/actions.ts | 5 +- src/redux/reducer.ts | 5 + src/services/root-network.ts | 68 ++ src/translations/en.json | 5 + src/translations/fr.json | 5 + 17 files changed, 1743 insertions(+), 30 deletions(-) create mode 100644 src/components/dialogs/case-list-selector.jsx create mode 100644 src/components/dialogs/create-case-dialog.tsx create mode 100644 src/components/dialogs/import-case-dialog.tsx create mode 100644 src/components/graph/menus/root-network-editor.tsx create mode 100644 src/components/graph/menus/root-network-node-editor.tsx create mode 100644 src/components/left-drawer.jsx create mode 100644 src/services/root-network.ts diff --git a/src/components/dialogs/case-list-selector.jsx b/src/components/dialogs/case-list-selector.jsx new file mode 100644 index 0000000000..70469ab812 --- /dev/null +++ b/src/components/dialogs/case-list-selector.jsx @@ -0,0 +1,231 @@ +/** + * Copyright (c) 2020, 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, useState } from 'react'; +import PropTypes from 'prop-types'; + +import { FormattedMessage, useIntl } from 'react-intl'; +import { PARAM_FAVORITE_CONTINGENCY_LISTS } from '../../utils/config-params'; +import { useSelector } from 'react-redux'; +import { ElementType } from '@gridsuite/commons-ui'; +import { useSnackMessage, CheckBoxList } from '@gridsuite/commons-ui'; +import { updateConfigParameter } from '../../services/config'; +import { fetchContingencyAndFiltersLists } from '../../services/directory'; +import { fetchContingencyCount } from '../../services/study'; +import { DirectoryItemSelector } from '@gridsuite/commons-ui'; +import { isNodeBuilt } from 'components/graph/util/model-functions'; +import DeleteIcon from '@mui/icons-material/Delete'; +import IconButton from '@mui/material/IconButton'; +import { toggleElementFromList } from 'components/utils/utils'; +import { Grid, DialogActions, Button, DialogTitle, Typography, Dialog, DialogContent, Alert } from '@mui/material'; + +function makeButton(onClick, message, disabled) { + return ( + + + + ); +} + +const CaseListSelector = (props) => { + const favoriteContingencyListUuids = useSelector((state) => state[PARAM_FAVORITE_CONTINGENCY_LISTS]); + + const currentNode = useSelector((state) => state.currentTreeNode); + + const [contingencyList, setContingencyList] = useState([]); + + const [simulatedContingencyCount, setSimulatedContingencyCount] = useState(0); + + const [checkedContingencyList, setCheckedContingencyList] = useState([]); + + const [favoriteSelectorOpen, setFavoriteSelectorOpen] = useState(false); + + const { snackError } = useSnackMessage(); + + const intl = useIntl(); + + const handleClose = () => { + props.onClose(); + }; + + const handleStart = () => { + props.onStart(checkedContingencyList.map((c) => c.id)); + }; + + const saveFavorites = useCallback( + (newList) => { + updateConfigParameter(PARAM_FAVORITE_CONTINGENCY_LISTS, newList) + .then() + .catch((error) => { + snackError({ + messageTxt: error.message, + headerId: 'paramsChangingError', + }); + }); + }, + [snackError] + ); + + useEffect(() => { + setSimulatedContingencyCount(null); + var discardResult = false; + if (isNodeBuilt(currentNode) && props.open) { + fetchContingencyCount( + props.studyUuid, + currentNode.id, + checkedContingencyList.map((c) => c.id) + ).then((contingencyCount) => { + if (!discardResult) { + setSimulatedContingencyCount(contingencyCount); + } + }); + } + return () => { + discardResult = true; + }; + }, [props.open, props.studyUuid, currentNode, checkedContingencyList]); + + useEffect(() => { + if (favoriteContingencyListUuids && favoriteContingencyListUuids.length > 0 && props.open) { + fetchContingencyAndFiltersLists(favoriteContingencyListUuids) + .then((res) => { + const mapCont = res.reduce((map, obj) => { + map[obj.elementUuid] = { + id: obj.elementUuid, + type: obj.type, + name: obj.elementName, + }; + return map; + }, {}); + setContingencyList( + favoriteContingencyListUuids + .map((id) => mapCont[id]) + .filter((item) => item !== undefined) + .sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())) + ); + }) + .catch(() => { + snackError({ + headerId: 'getContingencyListError', + }); + }); + } else { + setContingencyList([]); + } + }, [favoriteContingencyListUuids, snackError, props.open]); + + function getSimulatedContingencyCountLabel() { + return simulatedContingencyCount != null ? simulatedContingencyCount : '...'; + } + + const handleAddFavorite = () => { + setFavoriteSelectorOpen(true); + }; + + const removeFromFavorites = useCallback( + (toRemove) => { + const toRemoveIdsSet = new Set(toRemove.map((e) => e.id)); + saveFavorites(contingencyList.map((e) => e.id).filter((id) => !toRemoveIdsSet.has(id))); + + setCheckedContingencyList((oldChecked) => oldChecked.filter((item) => !toRemoveIdsSet.has(item.id))); + }, + [contingencyList, saveFavorites] + ); + + const addFavorites = (favorites) => { + if (favorites && favorites.length > 0) { + // avoid duplicates here + const newFavoriteIdsSet = new Set([...favoriteContingencyListUuids, ...favorites.map((item) => item.id)]); + saveFavorites(Array.from([...newFavoriteIdsSet])); + } + setFavoriteSelectorOpen(false); + }; + + const handleSecondaryAction = useCallback( + (item, isItemHovered) => + isItemHovered && ( + { + e.stopPropagation(); + removeFromFavorites([item]); + }} + size={'small'} + > + + + ), + [removeFromFavorites] + ); + + return ( + <> + + + + + + + + v.id} + getItemLabel={(v) => v.name} + selectedItems={checkedContingencyList} + onSelectionChange={setCheckedContingencyList} + secondaryAction={handleSecondaryAction} + onItemClick={(contingencyList) => + setCheckedContingencyList((oldCheckedElements) => [ + ...toggleElementFromList(contingencyList, oldCheckedElements, (element) => element.id), + ]) + } + /> + + + + + + {makeButton(handleClose, 'close', false)} + {makeButton(handleAddFavorite, 'AddContingencyList', false)} + {makeButton( + () => removeFromFavorites(checkedContingencyList), + 'DeleteContingencyList', + checkedContingencyList.length === 0 + )} + {makeButton(handleStart, 'Execute', simulatedContingencyCount === 0)} + + + + + ); +}; + +CaseListSelector.propTypes = { + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + onStart: PropTypes.func.isRequired, + studyUuid: PropTypes.string, + currentNodeUuid: PropTypes.string, +}; + +export default CaseListSelector; diff --git a/src/components/dialogs/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog.tsx new file mode 100644 index 0000000000..ae3da15715 --- /dev/null +++ b/src/components/dialogs/create-case-dialog.tsx @@ -0,0 +1,97 @@ +/** + * 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 { useSelector } from 'react-redux'; +import { Grid } from '@mui/material'; +import { useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup/dist/yup'; +import { + CustomMuiDialog, + DescriptionField, + FieldConstants, + isObjectEmpty, + useConfidentialityWarning, + useSnackMessage, +} from '@gridsuite/commons-ui'; + +import yup from '../utils/yup-config'; +import { AppState } from 'redux/reducer'; + +interface IFormData { + [FieldConstants.CASE_NAME]: string; + [FieldConstants.CASE_FILE]: File | null; +} + +export interface CreateCaseDialogProps { + onClose: (e?: unknown, nextSelectedDirectoryId?: string | null) => void; + open: boolean; +} + +const getCreateCaseDialogFormValidationDefaultValues = () => ({ + [FieldConstants.CASE_NAME]: '', + [FieldConstants.CASE_FILE]: null, +}); + +const createCaseDialogFormValidationSchema = yup.object().shape({ + [FieldConstants.CASE_NAME]: yup.string().trim().required('nameEmpty'), + [FieldConstants.CASE_FILE]: yup.mixed().nullable().required(), +}); +export default function CreateCaseDialog({ onClose, open }: Readonly) { + const { snackError } = useSnackMessage(); + const confidentialityWarningKey = useConfidentialityWarning(); + + const createCaseFormMethods = useForm({ + defaultValues: getCreateCaseDialogFormValidationDefaultValues(), + resolver: yupResolver(createCaseDialogFormValidationSchema), + }); + + const { + formState: { errors, isValid }, + } = createCaseFormMethods; + + const isFormValid = isObjectEmpty(errors) && isValid; + + const userId = useSelector((state: AppState) => state.user?.profile.sub); + + const handleCreateNewCase = ({ caseName, caseFile }: IFormData): void => { + // @ts-expect-error TODO: manage null cases here + createCase(caseName, description ?? '', caseFile, activeDirectory) + .then(onClose) + .catch((err: any) => { + console.log('$$$$$'); + }); + }; + + return ( + + + + {/* */} + + + + + + {/* */} + {/* */} + + ); +} diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx index e800a0ea45..4396ac7608 100644 --- a/src/components/dialogs/element-creation-dialog.tsx +++ b/src/components/dialogs/element-creation-dialog.tsx @@ -19,26 +19,33 @@ import { UUID } from 'crypto'; import { useCallback, useEffect, useState } from 'react'; import { Grid, Box, Button, CircularProgress, Typography } from '@mui/material'; import { UniqueNameInput } from './commons/unique-name-input'; -import { DESCRIPTION, FOLDER_ID, FOLDER_NAME, NAME } from '../utils/field-constants'; +import { CASE_NAME, CASE_ID, DESCRIPTION, FOLDER_ID, FOLDER_NAME, NAME } from '../utils/field-constants'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import yup from '../utils/yup-config'; import { useSelector } from 'react-redux'; import ModificationDialog from './commons/modificationDialog'; import { AppState } from '../../redux/reducer'; +import ImportCaseDialog from './import-case-dialog'; interface FormData { [NAME]: string; [DESCRIPTION]: string; } + export interface IElementCreationDialog extends FormData { - [FOLDER_NAME]: string; - [FOLDER_ID]: UUID; + [FOLDER_NAME]?: string; + [FOLDER_ID]?: UUID; +} + +export interface IElementCreationDialog1 extends FormData { + [CASE_NAME]?: string; + [CASE_ID]?: UUID; } interface ElementCreationDialogProps { open: boolean; - onSave: (data: IElementCreationDialog) => void; + onSave: (data: IElementCreationDialog | IElementCreationDialog1) => void; onClose: () => void; type: ElementType; titleId: string; @@ -68,25 +75,41 @@ const ElementCreationDialog: React.FC = ({ }) => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); const { snackError } = useSnackMessage(); const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); const [destinationFolder, setDestinationFolder] = useState(); + const [selectedCase, setSelectedCase] = useState(null); + const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); const formMethods = useForm({ defaultValues: emptyFormData, resolver: yupResolver(formSchema), }); + // Check if the selection is valid based on element type + const isValidSelection = () => { + // add type on commons + if (type === ElementType.ROOT_NETWORK) { + return !!selectedCase; // ROOT_NETWORK requires selected case + } + return !!destinationFolder; // Other types require selected folder + }; + const { reset, + setValue, formState: { errors }, } = formMethods; - const disableSave = Object.keys(errors).length > 0; + const disableSave = Object.keys(errors).length > 0 || !isValidSelection(); + // Clear form and reset selected case const clear = useCallback(() => { reset(emptyFormData); + setSelectedCase(null); // Reset the selected case on clear }, [reset]); + // Fetch default directory based on study UUID const fetchDefaultDirectoryForStudy = useCallback(() => { // @ts-expect-error TODO: manage null case fetchDirectoryElementPath(studyUuid).then((res) => { @@ -106,6 +129,7 @@ const ElementCreationDialog: React.FC = ({ }); }, [studyUuid, snackError]); + // Auto-generate a name with prefix and current date useEffect(() => { if (prefixIdForGeneratedName) { const getCurrentDateTime = () => new Date().toISOString(); @@ -129,10 +153,18 @@ const ElementCreationDialog: React.FC = ({ } }, [fetchDefaultDirectoryForStudy, studyUuid, open]); + // Open directory selector const handleChangeFolder = () => { setDirectorySelectorOpen(true); }; + // Open case selector + const handleCaseSelection = () => { + console.log("?????????",rootNetworkUuid); + setCaseSelectorOpen(true); + }; + + // Set selected folder when a directory is selected const setSelectedFolder = (folder: TreeViewFinderNodeProps[]) => { if (folder?.length > 0 && folder[0].id !== destinationFolder?.id) { const { id, name } = folder[0]; @@ -143,18 +175,37 @@ const ElementCreationDialog: React.FC = ({ const handleSave = useCallback( (values: FormData) => { - if (destinationFolder) { - const creationData: IElementCreationDialog = { - ...values, - [FOLDER_NAME]: destinationFolder.name, - [FOLDER_ID]: destinationFolder.id as UUID, - }; - onSave(creationData); + if (type === ElementType.ROOT_NETWORK) { + if (selectedCase) { + // Save data for ROOT_NETWORK, including CASE_NAME and CASE_ID + const creationData1: IElementCreationDialog1 = { + ...values, + [CASE_NAME]: selectedCase.name, + [CASE_ID]: selectedCase.id as UUID, + }; + onSave(creationData1); + } else { + snackError({ + messageTxt: 'Please select a case before saving.', + headerId: 'caseNotSelectedError', + }); + } + } else { + if (destinationFolder) { + // Save data for other types, including FOLDER info + const creationData: IElementCreationDialog = { + ...values, + [FOLDER_NAME]: destinationFolder.name, + [FOLDER_ID]: destinationFolder.id as UUID, + }; + onSave(creationData); + } } }, - [onSave, destinationFolder] + [onSave, destinationFolder, selectedCase, snackError, type,rootNetworkUuid] ); + // Folder chooser component const folderChooser = ( @@ -170,6 +221,24 @@ const ElementCreationDialog: React.FC = ({ ); + // Case selection component + const caseSelection = ( + + + + + + ); + + // Handle case selection + const onSelectCase = (selectedCase: TreeViewFinderNodeProps) => { + setSelectedCase(selectedCase); + setValue(NAME, selectedCase.name); // Set the name from the selected case + setCaseSelectorOpen(false); + }; + return ( = ({ autoFocus /> - - - - {folderChooser} + {type !== ElementType.ROOT_NETWORK && ( + + + + )} + {type === ElementType.ROOT_NETWORK ? caseSelection : folderChooser} + + setCaseSelectorOpen(false)} + onSelectCase={onSelectCase} + /> + void; + onSelectCase: (selectedElement: TreeViewFinderNodeProps) => void; +} + +const ImportCaseDialog: FunctionComponent = ({ open, onClose, onSelectCase }) => { + const intl = useIntl(); + const studyUuid = useSelector((state: AppState) => state.studyUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); + const currentNode = useSelector((state: AppState) => state.currentTreeNode); + + const processSelectedElements = (selectedElements: TreeViewFinderNodeProps[]) => { + if (selectedElements && selectedElements.length > 0) { + const selectedCase = selectedElements[0]; // Assuming single selection + onSelectCase(selectedCase); + } + onClose(); + }; + + return ( + + ); +}; + +export default ImportCaseDialog; diff --git a/src/components/graph/menus/editable-title.tsx b/src/components/graph/menus/editable-title.tsx index 3a1a4d44a7..7941bba33a 100644 --- a/src/components/graph/menus/editable-title.tsx +++ b/src/components/graph/menus/editable-title.tsx @@ -40,19 +40,30 @@ interface EditableTitleProps { name: string; onClose: () => void; onChange?: (value: string) => void; + isCloseIconVisible: boolean; } -export const EditableTitle: FunctionComponent = ({ name, onClose, onChange }) => { +export const EditableTitle: FunctionComponent = ({ + name, + isCloseIconVisible, + onClose, + onChange, +}) => { const [openEditTitle, setOpenEditTitle] = useState(false); const intl = useIntl(); return ( - setOpenEditTitle(true)} disabled={onChange === undefined}> + setOpenEditTitle(true)} + disabled={onChange === undefined} + > - + { name={currentTreeNode?.data?.label ?? ''} onClose={closeModificationsDrawer} onChange={changeNodeName} + isCloseIconVisible={true} /> diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx new file mode 100644 index 0000000000..daa91e5d40 --- /dev/null +++ b/src/components/graph/menus/root-network-editor.tsx @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2021, 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 PropTypes from 'prop-types'; +import { lighten, darken } from '@mui/material/styles'; +import NetworkModificationNodeEditor from './network-modification-node-editor'; +import { useSnackMessage } from '@gridsuite/commons-ui'; +import { EditableTitle } from './editable-title'; +import { useDispatch, useSelector } from 'react-redux'; +import { setModificationsDrawerOpen } from '../../../redux/actions'; +import { updateTreeNode } from '../../../services/study/tree-subtree'; +import { Box } from '@mui/material'; +import { AppState } from '../../../redux/reducer'; +import { Theme } from '@mui/material/styles'; +import RootNetworkNodeEditor from './root-network-node-editor'; + +const styles = { + paper: (theme: Theme) => ({ + height: '100%', + display: 'flex', + flexDirection: 'column', + elevation: 3, + // background: "red", + + }), +}; + +const RootNetworkEditor = () => { + const dispatch = useDispatch(); + const { snackError } = useSnackMessage(); + const currentTreeNode = useSelector((state: AppState) => state.currentTreeNode); + const studyUuid = useSelector((state: AppState) => state.studyUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); + + const closeModificationsDrawer = () => { + dispatch(setModificationsDrawerOpen(false)); + }; + + const changeNodeName = (newName: string) => { + updateTreeNode(studyUuid, { + id: currentTreeNode?.id, + type: currentTreeNode?.type, + name: newName, + }).catch((error) => { + snackError({ + messageTxt: error.message, + headerId: 'NodeUpdateError', + }); + }); + }; + + return ( + + + + + ); +}; + +RootNetworkEditor.propTypes = { + className: PropTypes.string, +}; + +export default RootNetworkEditor; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx new file mode 100644 index 0000000000..db3e8e3da9 --- /dev/null +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -0,0 +1,1011 @@ +/** + * Copyright (c) 2024, 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 { + CheckBoxList, + ElementType, + MODIFICATION_TYPES, + useModificationLabelComputer, + useSnackMessage, +} from '@gridsuite/commons-ui'; + +import CreateNewFolderIcon from '@mui/icons-material/CreateNewFolder'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography } from '@mui/material'; +import IconButton from '@mui/material/IconButton'; + +import BatteryCreationDialog from 'components/dialogs/network-modifications/battery/creation/battery-creation-dialog'; +import BatteryModificationDialog from 'components/dialogs/network-modifications/battery/modification/battery-modification-dialog'; +import DeleteAttachingLineDialog from 'components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-dialog'; +import DeleteVoltageLevelOnLineDialog from 'components/dialogs/network-modifications/delete-voltage-level-on-line/delete-voltage-level-on-line-dialog'; +import EquipmentDeletionDialog from 'components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog'; +import GenerationDispatchDialog from 'components/dialogs/network-modifications/generation-dispatch/generation-dispatch-dialog'; +import GeneratorScalingDialog from 'components/dialogs/network-modifications/generator-scaling/generator-scaling-dialog'; +import GeneratorCreationDialog from 'components/dialogs/network-modifications/generator/creation/generator-creation-dialog'; +import GeneratorModificationDialog from 'components/dialogs/network-modifications/generator/modification/generator-modification-dialog'; +import LineAttachToVoltageLevelDialog from 'components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-dialog'; +import LineSplitWithVoltageLevelDialog from 'components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-dialog'; +import LineCreationDialog from 'components/dialogs/network-modifications/line/creation/line-creation-dialog'; +import LineModificationDialog from 'components/dialogs/network-modifications/line/modification/line-modification-dialog'; +import LinesAttachToSplitLinesDialog from 'components/dialogs/network-modifications/lines-attach-to-split-lines/lines-attach-to-split-lines-dialog'; +import LoadScalingDialog from 'components/dialogs/network-modifications/load-scaling/load-scaling-dialog'; +import { LoadCreationDialog } from '../../dialogs/network-modifications/load/creation/load-creation-dialog'; +import LoadModificationDialog from 'components/dialogs/network-modifications/load/modification/load-modification-dialog'; +import ShuntCompensatorCreationDialog from 'components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog'; +import ShuntCompensatorModificationDialog from 'components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog'; +import SubstationCreationDialog from 'components/dialogs/network-modifications/substation/creation/substation-creation-dialog'; +import SubstationModificationDialog from 'components/dialogs/network-modifications/substation/modification/substation-modification-dialog'; +import TabularCreationDialog from 'components/dialogs/network-modifications/tabular-creation/tabular-creation-dialog'; +import TabularModificationDialog from 'components/dialogs/network-modifications/tabular-modification/tabular-modification-dialog'; +import TwoWindingsTransformerCreationDialog from 'components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog'; +import VoltageInitModificationDialog from 'components/dialogs/network-modifications/voltage-init-modification/voltage-init-modification-dialog'; +import VoltageLevelCreationDialog from 'components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog'; +import VoltageLevelModificationDialog from 'components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog'; +import VscCreationDialog from 'components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog'; +import VscModificationDialog from 'components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog'; +import NetworkModificationsMenu from 'components/graph/menus/network-modifications-menu'; +import { UPDATE_TYPE } from 'components/network/constants'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { useDispatch, useSelector } from 'react-redux'; +import { + addNotification, + removeNotificationByNode, + resetLogsFilter, + setModificationsInProgress, +} from '../../../redux/actions'; +import TwoWindingsTransformerModificationDialog from '../../dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog'; +import { useIsAnyNodeBuilding } from '../../utils/is-any-node-building-hook'; + +import RestoreModificationDialog from 'components/dialogs/restore-modification-dialog'; +import { UUID } from 'crypto'; +import { DropResult } from 'react-beautiful-dnd'; +import { AppState, StudyUpdated } from 'redux/reducer'; +import { createCompositeModifications } from '../../../services/explore'; +import { fetchNetworkModification } from '../../../services/network-modification'; +import { + changeNetworkModificationOrder, + fetchNetworkModifications, + stashModifications, +} from '../../../services/study/network-modifications'; +import { FetchStatus } from '../../../services/utils'; +import ElementCreationDialog, { IElementCreationDialog, IElementCreationDialog1 } from '../../dialogs/element-creation-dialog'; +import { + MenuDefinition, + MenuDefinitionSubItem, + MenuDefinitionWithoutSubItem, + NetworkModificationCopyInfo, + NetworkModificationCopyType, + NetworkModificationData, + NetworkModificationMetadata, +} from './network-modification-menu.type'; +import { SwitchNetworkModificationActive } from './switch-network-modification-active'; +import StaticVarCompensatorCreationDialog from '../../dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog'; +import ModificationByAssignmentDialog from '../../dialogs/network-modifications/by-filter/by-assignment/modification-by-assignment-dialog'; +import ByFormulaDialog from '../../dialogs/network-modifications/by-filter/by-formula/by-formula-dialog'; +import ByFilterDeletionDialog from '../../dialogs/network-modifications/by-filter/by-filter-deletion/by-filter-deletion-dialog'; +import { LccCreationDialog } from '../../dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog'; +import ImportCaseDialog from 'components/dialogs/import-case-dialog'; +import CreateCaseDialog from 'components/dialogs/create-case-dialog'; +import { createRootNetwork } from 'services/root-network'; + +export const styles = { + listContainer: (theme: Theme) => ({ + overflowY: 'auto', + display: 'flex', + flexDirection: 'column', + flexGrow: 1, + paddingBottom: theme.spacing(8), + }), + listItem: { paddingLeft: 0, paddingTop: 0, paddingBottom: 0 }, + checkBoxLabel: { flexGrow: '1' }, + disabledModification: { opacity: 0.4 }, + checkBoxIcon: { minWidth: 0, padding: 0 }, + checkboxButton: { + padding: 0, + margin: 0, + display: 'flex', + alignItems: 'center', + }, + modificationsTitle: (theme: Theme) => ({ + display: 'flex', + alignItems: 'center', + margin: theme.spacing(0), + padding: theme.spacing(1), + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + overflow: 'hidden', + }), + toolbar: (theme: Theme) => ({ + '&': { + // Necessary to overrides some @media specific styles that are defined elsewhere + padding: 0, + minHeight: 0, + }, + border: theme.spacing(1), + margin: 0, + flexShrink: 0, + }), + toolbarIcon: (theme: Theme) => ({ + marginRight: theme.spacing(1), + }), + toolbarCheckbox: (theme: Theme) => ({ + marginLeft: theme.spacing(1.5), + }), + filler: { + flexGrow: 1, + }, + circularProgress: (theme: Theme) => ({ + marginRight: theme.spacing(2), + color: theme.palette.primary.contrastText, + }), + toolbarCircularProgress: (theme: Theme) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + marginLeft: theme.spacing(1.25), + marginRight: theme.spacing(2), + color: theme.palette.secondary.main, + }), + notification: (theme: Theme) => ({ + flex: 1, + alignContent: 'center', + justifyContent: 'center', + marginTop: theme.spacing(4), + textAlign: 'center', + color: theme.palette.primary.main, + }), + icon: (theme: Theme) => ({ + width: theme.spacing(3), + }), + iconEdit: (theme: Theme) => ({ + marginRight: theme.spacing(1), + }), +}; + +const nonEditableModificationTypes = new Set([ + 'EQUIPMENT_ATTRIBUTE_MODIFICATION', + 'GROOVY_SCRIPT', + 'OPERATING_STATUS_MODIFICATION', +]); + +const isEditableModification = (modif: NetworkModificationMetadata) => { + if (!modif) { + return false; + } + return !nonEditableModificationTypes.has(modif.type); +}; + +export function isChecked(s1: number) { + return s1 !== 0; +} + +export function isPartial(s1: number, s2: number) { + if (s1 === 0) { + return false; + } + return s1 !== s2; +} + +const RootNetworkNodeEditor = () => { + const notificationIdList = useSelector((state: AppState) => state.notificationIdList); + const studyUuid = useSelector((state: AppState) => state.studyUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); + const { snackInfo, snackError } = useSnackMessage(); + const [modifications, setModifications] = useState([]); + const [saveInProgress, setSaveInProgress] = useState(false); + const [deleteInProgress, setDeleteInProgress] = useState(false); + const [modificationsToRestore, setModificationsToRestore] = useState([]); + const currentNode = useSelector((state: AppState) => state.currentTreeNode); + + const currentNodeIdRef = useRef(); // initial empty to get first update + const [pendingState, setPendingState] = useState(false); + + const [selectedItems, setSelectedItems] = useState([]); + const [copiedModifications, setCopiedModifications] = useState([]); + const [copyInfos, setCopyInfos] = useState(null); + const copyInfosRef = useRef(); + copyInfosRef.current = copyInfos; + + const [isDragging, setIsDragging] = useState(false); + + const [editDialogOpen, setEditDialogOpen] = useState(undefined); + const [editData, setEditData] = useState(undefined); + const [editDataFetchStatus, setEditDataFetchStatus] = useState(FetchStatus.IDLE); + const [caseSelectionDialogOpen, setCaseSelectionDialogOpen] = useState(false); + const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); + const [createCompositeModificationDialogOpen, setCreateCompositeModificationDialogOpen] = useState(false); + const dispatch = useDispatch(); + const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); + const [messageId, setMessageId] = useState(''); + const [launchLoader, setLaunchLoader] = useState(false); + const [isUpdate, setIsUpdate] = useState(false); + const buttonAddRef = useRef(null); + + const cleanClipboard = useCallback(() => { + setCopyInfos(null); + setCopiedModifications((oldCopiedModifications) => { + if (oldCopiedModifications.length) { + snackInfo({ + messageId: 'CopiedModificationInvalidationMessage', + }); + } + return []; + }); + }, [snackInfo]); + + // TODO this is not complete. + // We should clean Clipboard on notifications when another user edit + // a modification on a public study which is in the clipboard. + // We don't have precision on notifications to do this for now. + const handleValidatedDialog = () => { + if (editData?.uuid && copiedModifications.includes(editData?.uuid)) { + cleanClipboard(); + } + }; + + const handleCloseDialog = () => { + setEditDialogOpen(undefined); + setEditData(undefined); + }; + + function withDefaultParams(Dialog: React.FC) { + return ( + + ); + } + + const menuDefinition: MenuDefinition[] = [ + { + id: 'CREATE', + label: 'menu.create', + subItems: [ + { + id: MODIFICATION_TYPES.SUBSTATION_CREATION.type, + label: 'SUBSTATION', + action: () => withDefaultParams(SubstationCreationDialog), + }, + { + id: MODIFICATION_TYPES.VOLTAGE_LEVEL_CREATION.type, + label: 'VOLTAGE_LEVEL', + action: () => withDefaultParams(VoltageLevelCreationDialog), + }, + { + id: MODIFICATION_TYPES.LINE_CREATION.type, + label: 'LINE', + action: () => withDefaultParams(LineCreationDialog), + }, + { + id: MODIFICATION_TYPES.TWO_WINDINGS_TRANSFORMER_CREATION.type, + label: 'TWO_WINDINGS_TRANSFORMER', + action: () => withDefaultParams(TwoWindingsTransformerCreationDialog), + }, + { + id: 'GENERATOR_CREATION', + label: 'GENERATOR', + action: () => withDefaultParams(GeneratorCreationDialog), + }, + { + id: MODIFICATION_TYPES.LOAD_CREATION.type, + label: 'LOAD', + action: () => withDefaultParams(LoadCreationDialog), + }, + { + id: MODIFICATION_TYPES.BATTERY_CREATION.type, + label: 'BATTERY', + action: () => withDefaultParams(BatteryCreationDialog), + }, + { + id: MODIFICATION_TYPES.SHUNT_COMPENSATOR_CREATION.type, + label: 'ShuntCompensator', + action: () => withDefaultParams(ShuntCompensatorCreationDialog), + }, + { + id: MODIFICATION_TYPES.STATIC_VAR_COMPENSATOR_CREATION.type, + label: 'StaticVarCompensator', + action: () => withDefaultParams(StaticVarCompensatorCreationDialog), + }, + { + id: MODIFICATION_TYPES.VSC_CREATION.type, + label: 'VSC', + action: () => withDefaultParams(VscCreationDialog), + }, + { + id: MODIFICATION_TYPES.LCC_CREATION.type, + label: 'LCC', + action: () => withDefaultParams(LccCreationDialog), + }, + ], + }, + { + id: 'CREATE_MULTIPLE', + label: 'menu.createMultiple', + action: () => withDefaultParams(TabularCreationDialog), + }, + { + id: 'EDIT', + label: 'ModifyFromMenu', + subItems: [ + { + id: MODIFICATION_TYPES.SUBSTATION_MODIFICATION.type, + label: 'SUBSTATION', + action: () => withDefaultParams(SubstationModificationDialog), + }, + { + id: MODIFICATION_TYPES.VOLTAGE_LEVEL_MODIFICATION.type, + label: 'VOLTAGE_LEVEL', + action: () => withDefaultParams(VoltageLevelModificationDialog), + }, + { + id: MODIFICATION_TYPES.LINE_MODIFICATION.type, + label: 'LINE', + action: () => withDefaultParams(LineModificationDialog), + }, + { + id: MODIFICATION_TYPES.TWO_WINDINGS_TRANSFORMER_MODIFICATION.type, + label: 'TWO_WINDINGS_TRANSFORMER', + action: () => withDefaultParams(TwoWindingsTransformerModificationDialog), + }, + { + id: MODIFICATION_TYPES.GENERATOR_MODIFICATION.type, + label: 'GENERATOR', + action: () => withDefaultParams(GeneratorModificationDialog), + }, + { + id: MODIFICATION_TYPES.LOAD_MODIFICATION.type, + label: 'LOAD', + action: () => withDefaultParams(LoadModificationDialog), + }, + { + id: MODIFICATION_TYPES.BATTERY_MODIFICATION.type, + label: 'BATTERY', + action: () => withDefaultParams(BatteryModificationDialog), + }, + { + id: MODIFICATION_TYPES.SHUNT_COMPENSATOR_MODIFICATION.type, + label: 'ShuntCompensator', + action: () => withDefaultParams(ShuntCompensatorModificationDialog), + }, + { + id: MODIFICATION_TYPES.VSC_MODIFICATION.type, + label: 'VSC', + action: () => withDefaultParams(VscModificationDialog), + }, + ], + }, + { + id: 'EDIT_MULTIPLE', + label: 'menu.modifyMultiple', + subItems: [ + { + id: MODIFICATION_TYPES.TABULAR_MODIFICATION.type, + label: 'BY_TABLE', + action: () => withDefaultParams(TabularModificationDialog), + }, + { + id: MODIFICATION_TYPES.BY_FORMULA_MODIFICATION.type, + label: 'BY_FORMULA', + action: () => withDefaultParams(ByFormulaDialog), + }, + { + id: MODIFICATION_TYPES.MODIFICATION_BY_ASSIGNMENT.type, + label: 'BY_FILTER', + action: () => withDefaultParams(ModificationByAssignmentDialog), + }, + ], + }, + { + id: 'EQUIPMENT_DELETION', + label: 'DeleteContingencyList', + subItems: [ + { + id: MODIFICATION_TYPES.EQUIPMENT_DELETION.type, + label: 'SingleEquipment', + action: () => withDefaultParams(EquipmentDeletionDialog), + }, + { + id: MODIFICATION_TYPES.BY_FILTER_DELETION.type, + label: 'MultipleEquipment', + action: () => withDefaultParams(ByFilterDeletionDialog), + }, + ], + }, + { + id: 'ATTACHING_SPLITTING_LINES', + label: 'AttachingAndSplittingLines', + subItems: [ + { + id: MODIFICATION_TYPES.LINE_SPLIT_WITH_VOLTAGE_LEVEL.type, + label: 'LineSplitWithVoltageLevel', + action: () => withDefaultParams(LineSplitWithVoltageLevelDialog), + }, + { + id: MODIFICATION_TYPES.LINE_ATTACH_TO_VOLTAGE_LEVEL.type, + label: 'LineAttachToVoltageLevel', + action: () => withDefaultParams(LineAttachToVoltageLevelDialog), + }, + { + id: MODIFICATION_TYPES.LINES_ATTACH_TO_SPLIT_LINES.type, + label: 'LinesAttachToSplitLines', + action: () => withDefaultParams(LinesAttachToSplitLinesDialog), + }, + { + id: MODIFICATION_TYPES.DELETE_VOLTAGE_LEVEL_ON_LINE.type, + label: 'DeleteVoltageLevelOnLine', + action: () => withDefaultParams(DeleteVoltageLevelOnLineDialog), + }, + { + id: MODIFICATION_TYPES.DELETE_ATTACHING_LINE.type, + label: 'DeleteAttachingLine', + action: () => withDefaultParams(DeleteAttachingLineDialog), + }, + ], + }, + { + id: 'GENERATION_AND_LOAD', + label: 'GenerationAndLoad', + subItems: [ + { + id: MODIFICATION_TYPES.GENERATOR_SCALING.type, + label: 'GeneratorScaling', + action: () => withDefaultParams(GeneratorScalingDialog), + }, + { + id: MODIFICATION_TYPES.LOAD_SCALING.type, + label: 'LoadScaling', + action: () => withDefaultParams(LoadScalingDialog), + }, + { + id: MODIFICATION_TYPES.GENERATION_DISPATCH.type, + label: 'GenerationDispatch', + action: () => withDefaultParams(GenerationDispatchDialog), + }, + ], + }, + { + id: 'VOLTAGE_INIT_MODIFICATION', + label: 'VoltageInitModification', + hide: true, + action: () => withDefaultParams(VoltageInitModificationDialog), + }, + ]; + + const subMenuItemsList = menuDefinition.reduce<(MenuDefinitionWithoutSubItem | MenuDefinitionSubItem)[]>( + (actions, currentMenuItem) => + !('subItems' in currentMenuItem) + ? [...actions, currentMenuItem] + : [...actions, ...currentMenuItem.subItems], + [] + ); + + const fillNotification = useCallback( + (study: StudyUpdated, messageId: string) => { + // (work for all users) + // specific message id for each action type + setMessageId(messageId); + dispatch(addNotification([study.eventData.headers.parentNode ?? []])); + }, + [dispatch] + ); + + const manageNotification = useCallback( + (study: StudyUpdated) => { + let messageId; + switch (study.eventData.headers['updateType']) { + case 'creatingInProgress': + messageId = 'network_modifications.creatingModification'; + break; + case 'updatingInProgress': + messageId = 'network_modifications.updatingModification'; + break; + case 'stashingInProgress': + messageId = 'network_modifications.stashingModification'; + break; + case 'restoringInProgress': + messageId = 'network_modifications.restoringModification'; + break; + default: + messageId = ''; + } + fillNotification(study, messageId); + }, + [fillNotification] + ); + + const updateSelectedItems = useCallback((modifications: NetworkModificationMetadata[]) => { + const toKeepIdsSet = new Set(modifications.map((e) => e.uuid)); + setSelectedItems((oldselectedItems) => oldselectedItems.filter((s) => toKeepIdsSet.has(s.uuid))); + }, []); + + const dofetchNetworkModifications = useCallback(() => { + console.log('fetchiiiiiiiiiiing ?????'); + + // Do not fetch modifications on the root node + if (currentNode?.type !== 'NETWORK_MODIFICATION') { + return; + } + setLaunchLoader(true); + console.log('fetchiiiiiiiiiiing ?????'); + fetchNetworkModifications(studyUuid, currentNode.id, false) + .then((res: NetworkModificationMetadata[]) => { + // Check if during asynchronous request currentNode has already changed + // otherwise accept fetch results + if (currentNode.id === currentNodeIdRef.current) { + const liveModifications = res.filter( + (networkModification) => networkModification.stashed === false + ); + updateSelectedItems(liveModifications); + setModifications(liveModifications); + setModificationsToRestore( + res.filter((networkModification) => networkModification.stashed === true) + ); + } + }) + .catch((error) => { + snackError({ + messageTxt: error.message, + }); + }) + .finally(() => { + setPendingState(false); + setLaunchLoader(false); + dispatch(setModificationsInProgress(false)); + }); + }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); + + useEffect(() => { + setEditDialogOpen(editData?.type); + }, [editData]); + + useEffect(() => { + // first time with currentNode initialized then fetch modifications + // (because if currentNode is not initialized, dofetchNetworkModifications silently does nothing) + // OR next time if currentNodeId changed then fetch modifications + if (currentNode && (!currentNodeIdRef.current || currentNodeIdRef.current !== currentNode.id)) { + currentNodeIdRef.current = currentNode.id; + // Current node has changed then clear the modifications list + setModifications([]); + setModificationsToRestore([]); + dofetchNetworkModifications(); + // reset the network modification and computing logs filter when the user changes the current node + dispatch(resetLogsFilter()); + } + }, [currentNode, dispatch, dofetchNetworkModifications]); + + useEffect(() => { + if (studyUpdatedForce.eventData.headers) { + if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { + if ( + copyInfosRef.current && + studyUpdatedForce.eventData.headers['nodes']?.some( + (nodeId) => nodeId === copyInfosRef.current?.originNodeUuid + ) + ) { + // Must clean modifications clipboard if the origin Node is removed + cleanClipboard(); + } + } + if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { + return; + } + + if ( + studyUpdatedForce.eventData.headers['updateType'] && + // @ts-expect-error TS2345: Argument of type string is not assignable to parameter of type UPDATE_TYPE (a restrained array of strings) + UPDATE_TYPE.includes(studyUpdatedForce.eventData.headers['updateType']) + ) { + if (studyUpdatedForce.eventData.headers['updateType'] === 'deletingInProgress') { + // deleting means removing from trashcan (stashed elements) so there is no network modification + setDeleteInProgress(true); + } else { + dispatch(setModificationsInProgress(true)); + setPendingState(true); + manageNotification(studyUpdatedForce); + } + } + // notify finished action (success or error => we remove the loader) + // error handling in dialog for each equipment (snackbar with specific error showed only for current user) + if (studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED') { + // fetch modifications because it must have changed + // Do not clear the modifications list, because currentNode is the concerned one + // this allows to append new modifications to the existing list. + dofetchNetworkModifications(); + dispatch( + removeNotificationByNode([ + studyUpdatedForce.eventData.headers['parentNode'], + ...(studyUpdatedForce.eventData.headers.nodes ?? []), + ]) + ); + } + if (studyUpdatedForce.eventData.headers['updateType'] === 'DELETE_FINISHED') { + setDeleteInProgress(false); + dofetchNetworkModifications(); + } + } + }, [dispatch, dofetchNetworkModifications, manageNotification, studyUpdatedForce, cleanClipboard]); + + const [openNetworkModificationsMenu, setOpenNetworkModificationsMenu] = useState(false); + + const isAnyNodeBuilding = useIsAnyNodeBuilding(); + + const mapDataLoading = useSelector((state: AppState) => state.mapDataLoading); + + const closeNetworkModificationConfiguration = () => { + setOpenNetworkModificationsMenu(false); + setEditData(undefined); + setEditDataFetchStatus(FetchStatus.IDLE); + }; + + const openRootNetworkCreationDialog = useCallback(() => { + setRootNetworkCreationDialogOpen(true); + }, []); + + const doDeleteModification = useCallback(() => { + const selectedModificationsUuid = selectedItems.map((item) => item.uuid); + stashModifications(studyUuid, currentNode?.id, selectedModificationsUuid) + .then(() => { + //if one of the deleted element was in the clipboard we invalidate the clipboard + if ( + copiedModifications.some((aCopiedModification) => + selectedModificationsUuid.includes(aCopiedModification) + ) + ) { + cleanClipboard(); + } + }) + .catch((errmsg) => { + snackError({ + messageTxt: errmsg, + headerId: 'errDeleteModificationMsg', + }); + }); + }, [currentNode?.id, selectedItems, snackError, studyUuid, cleanClipboard, copiedModifications]); + + const removeNullFields = useCallback((data: NetworkModificationData) => { + let dataTemp = data; + if (dataTemp) { + Object.keys(dataTemp).forEach((key) => { + if (dataTemp[key] && dataTemp[key] !== null && typeof dataTemp[key] === 'object') { + dataTemp[key] = removeNullFields(dataTemp[key]); + } + + if (dataTemp[key] === null) { + delete dataTemp[key]; + } + }); + } + return dataTemp; + }, []); + + const doEditModification = useCallback( + (modificationUuid: UUID, type: string) => { + setIsUpdate(true); + setEditDialogOpen(type); + setEditDataFetchStatus(FetchStatus.RUNNING); + const modification = fetchNetworkModification(modificationUuid); + modification + .then((res) => { + return res.json().then((data: NetworkModificationData) => { + //remove all null values to avoid showing a "null" in the forms + setEditData(removeNullFields(data)); + setEditDataFetchStatus(FetchStatus.SUCCEED); + }); + }) + .catch((error) => { + snackError({ + messageTxt: error.message, + }); + setEditDataFetchStatus(FetchStatus.FAILED); + }); + }, + [removeNullFields, snackError] + ); + + const onItemClick = (id: string) => { + setOpenNetworkModificationsMenu(false); + setEditDialogOpen(id); + setIsUpdate(false); + }; + + const toggleSelectAllModifications = useCallback(() => { + setSelectedItems((oldVal) => (oldVal.length === 0 ? modifications : [])); + }, [modifications]); + + const renderDialog = () => { + return subMenuItemsList.find((menuItem) => menuItem.id === editDialogOpen)?.action?.(); + }; + + const commit = useCallback( + ({ source, destination }: DropResult) => { + setIsDragging(false); + if (!currentNode?.id || !destination || source.index === destination.index) { + return; + } + const res = [...modifications]; + const [item] = res.splice(source.index, 1); + const before = res[destination.index]?.uuid; + res.splice(destination ? destination.index : modifications.length, 0, item); + + /* doing the local change before update to server */ + setModifications(res); + changeNetworkModificationOrder(studyUuid, currentNode.id, item.uuid, before).catch((error) => { + snackError({ + messageTxt: error.message, + headerId: 'errReorderModificationMsg', + }); + setModifications(modifications); // rollback + }); + }, + [modifications, studyUuid, currentNode?.id, snackError] + ); + + const isLoading = useCallback(() => { + return notificationIdList.filter((notification) => notification === currentNode?.id).length > 0; + }, [notificationIdList, currentNode?.id]); + + const intl = useIntl(); + const { computeLabel } = useModificationLabelComputer(); + const getModificationLabel = (modif: NetworkModificationMetadata): string => { + if (!modif) { + return ''; + } + return intl.formatMessage( + { id: 'network_modifications.' + modif.messageType }, + { + ...modif, + ...computeLabel(modif), + } + ); + }; + + const handleSecondaryAction = useCallback( + (modification: NetworkModificationMetadata, isItemHovered?: boolean) => { + return isItemHovered && !isDragging ? ( + + ) : null; + }, + [isAnyNodeBuilding, isDragging, mapDataLoading, isLoading] + ); + + const isModificationClickable = useCallback( + (modification: NetworkModificationMetadata) => + !isAnyNodeBuilding && !mapDataLoading && !isDragging && isEditableModification(modification), + [isAnyNodeBuilding, mapDataLoading, isDragging] + ); + + const renderNetworkModificationsList = () => { + return ( + ({ + label: { + ...(!modification.activated && { ...styles.disabledModification }), + ...styles.checkBoxLabel, + }, + checkBoxIcon: styles.checkBoxIcon, + checkboxButton: styles.checkboxButton, + }), + dragAndDropContainer: styles.listContainer, + }} + onItemClick={(modification) => { + isModificationClickable(modification) && doEditModification(modification.uuid, modification.type); + }} + isItemClickable={isModificationClickable} + selectedItems={selectedItems} + onSelectionChange={setSelectedItems} + items={modifications} + getItemId={(val) => val.uuid} + getItemLabel={getModificationLabel} + isDndDragAndDropActive + isDragDisable={isLoading() || isAnyNodeBuilding || mapDataLoading || deleteInProgress} + secondaryAction={handleSecondaryAction} + onDragEnd={commit} + onDragStart={() => setIsDragging(true)} + divider + /> + ); + }; + + const renderNetworkModificationsListTitleLoading = () => { + return ( + + + + + + + + + ); + }; + + const renderNetworkModificationsListTitleUpdating = () => { + return ( + + + + + + + + + ); + }; + + const renderNetworkModificationsListTitle = () => { + return ( + + + {pendingState && } + + + + + + ); + }; + + + + // const renderCaseSelectionDialog = () => { + // // return ( + // // setCaseSelectionDialogOpen(false)} + // // type={ElementType.ROOT_NETWORK} + // // titleId={'CreateRootNetwork'} + // // prefixIdForGeneratedName={'GeneratedModification'} + // // /> + // // ); + // return setCaseSelectionDialogOpen(false)} />; + // }; + + const renderRootNetworkCreationDialog = () => { + return ( + setRootNetworkCreationDialogOpen(false)} + onSave={doCreateRootNetwork} + type={ElementType.ROOT_NETWORK} + titleId={'CreateRootNetwork'} + /> + ); + + //return setRootNetworkCreationDialogOpen(false)} />; + }; + + const doCreateRootNetwork = ({ + name, + caseName, + caseId, + }: IElementCreationDialog1) => { +console.log("fetcccccccccch ???? " , name, +caseName, +caseId) + setSaveInProgress(true); + // createRootNetwork( caseId , + // "XIIDM", + // studyUuid, + // importParameters) + // createCompositeModifications(name, description, folderId, selectedModificationsUuid) + // .then(() => { + // snackInfo({ + // headerId: 'infoCreateModificationsMsg', + // headerValues: { + // nbModifications: String(selectedItems.length), + // studyDirectory: '/' + folderName, + // }, + // }); + // }) + // .catch((errmsg) => { + // snackError({ + // messageTxt: errmsg, + // headerId: 'errCreateModificationsMsg', + // }); + // }) + // .finally(() => { + // setSaveInProgress(false); + // }); + }; + + const renderPaneSubtitle = () => { + if (isLoading() && messageId) { + return renderNetworkModificationsListTitleLoading(); + } + if (launchLoader) { + return renderNetworkModificationsListTitleUpdating(); + } + return renderNetworkModificationsListTitle(); + }; + + return ( + <> + + + + + }> + + + + + + + + + + + {deleteInProgress ?? ( + }> + + + + + )} + + {rootNetworkCreationDialogOpen && renderRootNetworkCreationDialog()} + {renderPaneSubtitle()} + + {renderNetworkModificationsList()} + + + {editDialogOpen && renderDialog()} + + ); +}; + +export default RootNetworkNodeEditor; diff --git a/src/components/left-drawer.jsx b/src/components/left-drawer.jsx new file mode 100644 index 0000000000..0a23db1ce4 --- /dev/null +++ b/src/components/left-drawer.jsx @@ -0,0 +1,77 @@ +import Drawer from '@mui/material/Drawer'; +import PropTypes from 'prop-types'; +import { mergeSx } from './utils/functions'; +import { DRAWER_NODE_EDITOR_WIDTH } from '../utils/UIconstants'; +import RootNetworkEditor from './graph/menus/root-network-editor'; + +const styles = { + drawerPaper: { + position: 'static', + overflow: 'hidden', + flex: '1', + flexGrow: '1', + transition: 'none !important', + // backgroundColor: 'green !important', + }, + nodeEditor: (theme) => ({ + width: DRAWER_NODE_EDITOR_WIDTH + 'px', + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + zIndex: 51, + position: 'relative', + flexShrink: 1, + overflowY: 'none', + overflowX: 'none', + }), + nodeEditorShift: (theme) => ({ + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + pointerEvents: 'none', + marginRight: -DRAWER_NODE_EDITOR_WIDTH + 'px', // Shift out of view when closed + }), + leftDrawer: (theme) => ({ + width: DRAWER_NODE_EDITOR_WIDTH + 'px', + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + zIndex: 51, + position: 'relative', + flexShrink: 1, + overflowY: 'none', + overflowX: 'none', + }), + leftDrawerShift: (theme) => ({ + transition: theme.transitions.create('margin', { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + pointerEvents: 'none', + marginLeft: DRAWER_NODE_EDITOR_WIDTH + 'px', // Shift right when open + }), +}; + +// LeftDrawer Component +export const LeftDrawer = ({ open }) => { + return ( + + + + ); +}; + +LeftDrawer.propTypes = { + open: PropTypes.bool.isRequired, +}; diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index bad37f17a7..e6a6256866 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -43,6 +43,7 @@ import { buildNode, getUniqueNodeName, unbuildNode } from '../services/study'; import RestoreNodesDialog from './dialogs/restore-node-dialog'; import ScenarioEditor from './graph/menus/dynamic-simulation/scenario-editor'; import { StudyDisplayMode, CopyType, UpdateType } from './network-modification.type'; +import { LeftDrawer } from './left-drawer'; const styles = { container: { @@ -50,6 +51,7 @@ const styles = { height: '100%', display: 'flex', flexDirection: 'row', + // backgroundColor: 'yellow', }, }; @@ -511,6 +513,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) return ( <> + { setStudyUuid(studyUuidRequest); + + setRootNetworkUuid('40347c68-15d1-45f4-b878-ecfd0739171a'); + //get root network }) .catch((error) => { if (error.status === HttpStatusCode.NOT_FOUND) { @@ -148,7 +152,7 @@ function useStudy(studyUuidRequest) { .finally(() => setPending(false)); }, [studyUuidRequest, intlRef]); - return [studyUuid, pending, errMessage]; + return [studyUuid, rootNetworkUuid, pending, errMessage]; } export const UPDATE_TYPE_HEADER = 'updateType'; @@ -165,7 +169,9 @@ export function StudyContainer({ view, onChangeTab }) { const websocketExpectedCloseRef = useRef(); const intlRef = useIntlRef(); - const [studyUuid, studyPending, studyErrorMessage] = useStudy(decodeURIComponent(useParams().studyUuid)); + const [studyUuid, rootNetworkUuid, studyPending, studyErrorMessage] = useStudy( + decodeURIComponent(useParams().studyUuid) + ); const [studyName, setStudyName] = useState(); const prevStudyName = usePrevious(studyName); @@ -693,7 +699,8 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUuid) { websocketExpectedCloseRef.current = false; - dispatch(openStudy(studyUuid)); + //dispatch root network uuid + dispatch(openStudy(studyUuid, rootNetworkUuid)); const ws = connectNotifications(studyUuid); const wsDirectory = connectDeletedStudyNotifications(studyUuid); @@ -708,7 +715,7 @@ export function StudyContainer({ view, onChangeTab }) { } // Note: dispach, loadGeoData // connectNotifications don't change - }, [dispatch, studyUuid, connectNotifications, connectDeletedStudyNotifications]); + }, [dispatch, studyUuid, rootNetworkUuid, connectNotifications, connectDeletedStudyNotifications]); useEffect(() => { if (studyUuid) { diff --git a/src/components/utils/field-constants.ts b/src/components/utils/field-constants.ts index 8bf2123b68..067a72f02f 100644 --- a/src/components/utils/field-constants.ts +++ b/src/components/utils/field-constants.ts @@ -19,6 +19,8 @@ export const DESTINATION_FOLDER = 'destinationFolder'; export const FOLDER_NAME = 'folderName'; export const FOLDER_ID = 'folderId'; export const DESCRIPTION = 'description'; +export const CASE_NAME = 'caseName'; +export const CASE_ID = 'caseId'; export const SUBSTATION_ID = 'substationId'; export const NOMINAL_VOLTAGE = 'nominalVoltage'; export const NOMINAL_V = 'nominalV'; diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 787d9cf1ca..4aa70ce7e4 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -422,9 +422,10 @@ export function setParamsLoaded(): SetParamsLoadedAction { export const OPEN_STUDY = 'OPEN_STUDY'; export type OpenStudyAction = Readonly> & { studyRef: [UUID]; + rootNetworkRef: [UUID]; }; -export function openStudy(studyUuid: UUID): OpenStudyAction { - return { type: OPEN_STUDY, studyRef: [studyUuid] }; +export function openStudy(studyUuid: UUID, rootNetworkUuid: UUID): OpenStudyAction { + return { type: OPEN_STUDY, studyRef: [studyUuid], rootNetworkRef: [rootNetworkUuid] }; } export const CLOSE_STUDY = 'CLOSE_STUDY'; diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 60514f3641..5b5ce18c45 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -459,6 +459,7 @@ export interface AppState extends CommonStoreState { studyUpdated: StudyUpdated; studyUuid: UUID | null; + rootNetworkUuid: UUID | null; currentTreeNode: CurrentTreeNode | null; computingStatus: ComputingStatus; lastCompletedComputation: ComputingType | null; @@ -621,6 +622,7 @@ const initialTablesState: TablesState = { const initialState: AppState = { studyUuid: null, + rootNetworkUuid: null, currentTreeNode: null, selectionForCopy: { sourceStudyUuid: null, @@ -823,6 +825,8 @@ const initialState: AppState = { export const reducer = createReducer(initialState, (builder) => { builder.addCase(OPEN_STUDY, (state, action: OpenStudyAction) => { state.studyUuid = action.studyRef[0]; + state.rootNetworkUuid = action.rootNetworkRef[0]; + console.log("=================== ",action.studyRef) if (action.studyRef[0] != null) { state.diagramStates = loadDiagramStateFromSessionStorage(action.studyRef[0]); @@ -831,6 +835,7 @@ export const reducer = createReducer(initialState, (builder) => { builder.addCase(CLOSE_STUDY, (state, action: CloseStudyAction) => { state.studyUuid = null; + state.rootNetworkUuid = null; state.geoData = null; state.networkModificationTreeModel = null; }); diff --git a/src/services/root-network.ts b/src/services/root-network.ts new file mode 100644 index 0000000000..4ebd5f1003 --- /dev/null +++ b/src/services/root-network.ts @@ -0,0 +1,68 @@ +/** + * 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 { backendFetch } from './utils'; +import { UUID } from 'crypto'; +import { ElementType } from '@gridsuite/commons-ui'; + +export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; + +export function createRootNetworka( + newParameter: any, + name: string, + parameterType: ElementType, + description: string, + studyUuid: UUID +) { + let urlSearchParams = new URLSearchParams(); + urlSearchParams.append('name', name); + urlSearchParams.append('type', parameterType); + urlSearchParams.append('description', description); + urlSearchParams.append('studyUuid', studyUuid); + + urlSearchParams.toString(); + const createRootNetworkUrl = + PREFIX_STUDY_QUERIES + + '/v1/studies/' + + encodeURIComponent(studyUuid) + + '/root-networks?' + + urlSearchParams.toString(); + + console.debug(createRootNetworkUrl); + + return backendFetch(createRootNetworkUrl, { + method: 'post', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(newParameter), + }); +} + +export const createRootNetwork = ( + caseUuid: UUID, + caseFormat: string, + studyUuid: UUID, + importParameters: Record +) => { + const urlSearchParams = new URLSearchParams(); + urlSearchParams.append('caseUuid', caseUuid); + urlSearchParams.append('caseFormat', caseFormat); + + const recreateStudyNetworkUrl = + PREFIX_STUDY_QUERIES + + '/v1/studies/' + + encodeURIComponent(studyUuid) + + '/network?' + + urlSearchParams.toString(); + + console.debug(recreateStudyNetworkUrl); + + return backendFetch(recreateStudyNetworkUrl, { + method: 'post', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(importParameters), + }); +}; diff --git a/src/translations/en.json b/src/translations/en.json index 74eeda4331..aca8f550e2 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -367,6 +367,9 @@ "TwoSides.ONE": "Origin side", "TwoSides.TWO": "Extremity side", + "selectCase": "Select case", + "ChooseSituation": "Select a case", + "ContingencyListsSelection": "Contingency lists selection", "Execute": "Execute", "AddContingencyList": "Add", @@ -562,6 +565,8 @@ "HideMinimap": "Hide minimap", "DisplayTheWholeTree": "Display the whole tree", + "CreateRootNetwork": "Configure root network", + "Logs": "Logs", "logsTitle": "Logs : {title}", "showReport": "Show logs", diff --git a/src/translations/fr.json b/src/translations/fr.json index 4528ea4c1f..839f871dd4 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -368,6 +368,9 @@ "TwoSides.ONE": "Côté 1", "TwoSides.TWO": "Côté 2", + "selectCase": "Sélectionner une situation", + "ChooseSituation": "Choisir une situation", + "ContingencyListsSelection": "Sélection des listes d'aléas", "Execute": "Exécuter", "AddContingencyList": "Ajouter", @@ -563,6 +566,8 @@ "HideMinimap": "Masquer la mini-carte", "DisplayTheWholeTree": "Visualiser l'arbre en entier", + "CreateRootNetwork": "Configurer un réseau racine", + "Logs": "Logs", "logsTitle": "Logs : {title}", "showReport": "Afficher logs", From 914900da51d351abab4a2185866c1da3c39aabfa Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Tue, 17 Dec 2024 15:14:20 +0100 Subject: [PATCH 02/51] feat: add root network uuid to redux + fix fetch computation status endpoints Signed-off-by: LE SAULNIER Kevin --- .../use-all-computing-status.ts | 11 ++++- .../computing-status/use-computing-status.ts | 8 ++-- .../network-modification-node-editor.tsx | 5 --- .../graph/menus/root-network-node-editor.tsx | 24 ++++------- src/components/study-container.jsx | 33 ++++++++------- src/redux/actions.ts | 11 +++++ src/redux/reducer.ts | 11 ++++- src/services/dynamic-simulation.ts | 20 +++++---- src/services/study/dynamic-simulation.js | 24 +++++++---- src/services/study/filter.ts | 5 ++- src/services/study/geo-data.js | 7 ++-- src/services/study/index.ts | 27 ++++++------ src/services/study/loadflow.js | 24 ++++++----- src/services/study/network-map.ts | 17 ++++---- src/services/study/network-modifications.js | 6 +-- src/services/study/network.js | 31 ++++++++------ src/services/study/non-evacuated-energy.js | 20 +++++---- src/services/study/security-analysis.js | 24 +++++++---- src/services/study/sensitivity-analysis.js | 33 ++++++++++----- src/services/study/short-circuit-analysis.js | 41 ++++++++++++++----- src/services/study/state-estimation.js | 20 +++++---- src/services/study/study.ts | 23 +++++++++-- src/services/study/voltage-init.js | 24 +++++++---- 23 files changed, 282 insertions(+), 167 deletions(-) diff --git a/src/components/computing-status/use-all-computing-status.ts b/src/components/computing-status/use-all-computing-status.ts index ceff069737..ca5387e013 100644 --- a/src/components/computing-status/use-all-computing-status.ts +++ b/src/components/computing-status/use-all-computing-status.ts @@ -60,7 +60,7 @@ const dynamicSimulationStatusCompletions = ['dynamicSimulationResult', 'dynamicS const voltageInitStatusCompletions = ['voltageInitResult', 'voltageInit_failed']; const stateEstimationStatusCompletions = ['stateEstimationResult', 'stateEstimation_failed']; // this hook loads all current computation status into redux then keeps them up to date according to notifications -export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): void => { +export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID): void => { const securityAnalysisAvailability = useOptionalServiceStatus(OptionalServicesNames.SecurityAnalysis); const sensitivityAnalysisAvailability = useOptionalServiceStatus(OptionalServicesNames.SensitivityAnalysis); const nonEvacuatedEnergyAvailability = useOptionalServiceStatus(OptionalServicesNames.SensitivityAnalysis); @@ -72,6 +72,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchLoadFlowStatus, loadFlowStatusInvalidations, loadFlowStatusCompletions, @@ -82,6 +83,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchSecurityAnalysisStatus, securityAnalysisStatusInvalidations, securityAnalysisStatusCompletions, @@ -93,6 +95,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchSensitivityAnalysisStatus, sensitivityAnalysisStatusInvalidations, sensitivityAnalysisStatusCompletions, @@ -104,6 +107,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchNonEvacuatedEnergyStatus, nonEvacuatedEnergyStatusInvalidations, nonEvacuatedEnergyStatusCompletions, @@ -115,6 +119,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchShortCircuitAnalysisStatus, shortCircuitAnalysisStatusInvalidations, shortCircuitAnalysisStatusCompletions, @@ -126,6 +131,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchOneBusShortCircuitAnalysisStatus, oneBusShortCircuitAnalysisStatusInvalidations, oneBusShortCircuitAnalysisStatusCompletions, @@ -137,6 +143,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchDynamicSimulationStatus, dynamicSimulationStatusInvalidations, dynamicSimulationStatusCompletions, @@ -148,6 +155,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchVoltageInitStatus, voltageInitStatusInvalidations, voltageInitStatusCompletions, @@ -159,6 +167,7 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID): v useComputingStatus( studyUuid, currentNodeUuid, + currentRootNetworkUuid, fetchStateEstimationStatus, stateEstimationStatusInvalidations, stateEstimationStatusCompletions, diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index 0c23d97e34..68a7db6ea0 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -20,7 +20,8 @@ interface UseComputingStatusProps { ( studyUuid: UUID, nodeUuid: UUID, - fetcher: (studyUuid: UUID, nodeUuid: UUID) => Promise, + rootNetworkUuid: UUID, + fetcher: (studyUuid: UUID, nodeUuid: UUID, rootNetworkUuid: UUID) => Promise, invalidations: string[], completions: string[], resultConversion: (x: string) => RunningStatus, @@ -31,7 +32,7 @@ interface UseComputingStatusProps { interface LastUpdateProps { studyUpdatedForce: StudyUpdated; - fetcher: (studyUuid: UUID, nodeUuid: UUID) => Promise; + fetcher: (studyUuid: UUID, nodeUuid: UUID, rootNetworkUuid: UUID) => Promise; } function isWorthUpdate( @@ -84,6 +85,7 @@ function isWorthUpdate( export const useComputingStatus: UseComputingStatusProps = ( studyUuid, nodeUuid, + rootNetworkUuid, fetcher, invalidations, completions, @@ -114,7 +116,7 @@ export const useComputingStatus: UseComputingStatusProps = ( dispatch(setLastCompletedComputation()); nodeUuidRef.current = nodeUuid; - fetcher(studyUuid, nodeUuid) + fetcher(studyUuid, nodeUuid, rootNetworkUuid) .then((res: string) => { if (!canceledRequest && nodeUuidRef.current === nodeUuid) { const status = resultConversion(res); diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index 580df331d3..b644561bb8 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -325,11 +325,6 @@ const NetworkModificationNodeEditor = () => { label: 'VSC', action: () => withDefaultParams(VscCreationDialog), }, - { - id: MODIFICATION_TYPES.LCC_CREATION.type, - label: 'LCC', - action: () => withDefaultParams(LccCreationDialog), - }, ], }, { diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index db3e8e3da9..98a9fb227e 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -73,7 +73,10 @@ import { stashModifications, } from '../../../services/study/network-modifications'; import { FetchStatus } from '../../../services/utils'; -import ElementCreationDialog, { IElementCreationDialog, IElementCreationDialog1 } from '../../dialogs/element-creation-dialog'; +import ElementCreationDialog, { + IElementCreationDialog, + IElementCreationDialog1, +} from '../../dialogs/element-creation-dialog'; import { MenuDefinition, MenuDefinitionSubItem, @@ -322,11 +325,6 @@ const RootNetworkNodeEditor = () => { label: 'VSC', action: () => withDefaultParams(VscCreationDialog), }, - { - id: MODIFICATION_TYPES.LCC_CREATION.type, - label: 'LCC', - action: () => withDefaultParams(LccCreationDialog), - }, ], }, { @@ -868,8 +866,6 @@ const RootNetworkNodeEditor = () => { ); }; - - // const renderCaseSelectionDialog = () => { // // return ( // // { //return setRootNetworkCreationDialogOpen(false)} />; }; - const doCreateRootNetwork = ({ - name, - caseName, - caseId, - }: IElementCreationDialog1) => { -console.log("fetcccccccccch ???? " , name, -caseName, -caseId) + const doCreateRootNetwork = ({ name, caseName, caseId }: IElementCreationDialog1) => { + console.log('fetcccccccccch ???? ', name, caseName, caseId); setSaveInProgress(true); - // createRootNetwork( caseId , + // createRootNetwork( caseId , // "XIIDM", // studyUuid, // importParameters) diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 344fe5ee1f..ffe528d385 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -21,6 +21,7 @@ import { resetEquipmentsPostLoadflow, setStudyIndexationStatus, limitReductionModified, + setCurrentRootNetwork, } from '../redux/actions'; import WaitingLoader from './utils/waiting-loader'; import { useIntlRef, useSnackMessage } from '@gridsuite/commons-ui'; @@ -126,8 +127,8 @@ export function useNodeData(studyUuid, nodeUuid, fetcher, invalidations, default } function useStudy(studyUuidRequest) { + const dispatch = useDispatch(); const [studyUuid, setStudyUuid] = useState(undefined); - const [rootNetworkUuid, setRootNetworkUuid] = useState(undefined); const [pending, setPending] = useState(true); const [errMessage, setErrMessage] = useState(undefined); const intlRef = useIntlRef(); @@ -136,8 +137,7 @@ function useStudy(studyUuidRequest) { fetchStudyExists(studyUuidRequest) .then(() => { setStudyUuid(studyUuidRequest); - - setRootNetworkUuid('40347c68-15d1-45f4-b878-ecfd0739171a'); + dispatch(setCurrentRootNetwork('18be57cd-a4a4-4844-b285-98ac2e66f095')); //get root network }) .catch((error) => { @@ -152,7 +152,7 @@ function useStudy(studyUuidRequest) { .finally(() => setPending(false)); }, [studyUuidRequest, intlRef]); - return [studyUuid, rootNetworkUuid, pending, errMessage]; + return [studyUuid, pending, errMessage]; } export const UPDATE_TYPE_HEADER = 'updateType'; @@ -169,9 +169,7 @@ export function StudyContainer({ view, onChangeTab }) { const websocketExpectedCloseRef = useRef(); const intlRef = useIntlRef(); - const [studyUuid, rootNetworkUuid, studyPending, studyErrorMessage] = useStudy( - decodeURIComponent(useParams().studyUuid) - ); + const [studyUuid, studyPending, studyErrorMessage] = useStudy(decodeURIComponent(useParams().studyUuid)); const [studyName, setStudyName] = useState(); const prevStudyName = usePrevious(studyName); @@ -197,10 +195,11 @@ export function StudyContainer({ view, onChangeTab }) { const dispatch = useDispatch(); const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetwork = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); - useAllComputingStatus(studyUuid, currentNode?.id); + useAllComputingStatus(studyUuid, currentNode?.id, currentRootNetwork); const studyUpdatedForce = useSelector((state) => state.studyUpdated); @@ -450,7 +449,7 @@ export function StudyContainer({ view, onChangeTab }) { const networkModificationTreeModel = new NetworkModificationTreeModel(); networkModificationTreeModel.setTreeElements(tree); - fetchCaseName(studyUuid) + fetchCaseName(studyUuid, currentRootNetwork) .then((res) => { if (res) { networkModificationTreeModel.setCaseName(res); @@ -492,12 +491,12 @@ export function StudyContainer({ view, onChangeTab }) { .finally(() => console.debug('Network modification tree loading finished')); // Note: studyUuid and dispatch don't change }, - [studyUuid, dispatch, snackError, snackWarning] + [studyUuid, currentRootNetwork, dispatch, snackError, snackWarning] ); const checkStudyIndexation = useCallback(() => { setIsStudyIndexationPending(true); - return fetchStudyIndexationStatus(studyUuid) + return fetchStudyIndexationStatus(studyUuid, currentRootNetwork) .then((status) => { switch (status) { case StudyIndexationStatus.INDEXED: { @@ -511,7 +510,7 @@ export function StudyContainer({ view, onChangeTab }) { } case StudyIndexationStatus.NOT_INDEXED: { dispatch(setStudyIndexationStatus(status)); - reindexAllStudy(studyUuid) + reindexAllStudy(studyUuid, currentRootNetwork) .catch((error) => { // unknown error when trying to reindex study snackError({ @@ -542,11 +541,11 @@ export function StudyContainer({ view, onChangeTab }) { headerId: 'checkstudyIndexationError', }); }); - }, [studyUuid, dispatch, snackError]); + }, [studyUuid, currentRootNetwork, dispatch, snackError]); const checkNetworkExistenceAndRecreateIfNotFound = useCallback( (successCallback) => { - fetchNetworkExistence(studyUuid) + fetchNetworkExistence(studyUuid, currentRootNetwork) .then((response) => { if (response.status === HttpStatusCode.OK) { successCallback && successCallback(); @@ -556,7 +555,7 @@ export function StudyContainer({ view, onChangeTab }) { // response.state === NO_CONTENT // if network is not found, we try to recreate study network from existing case setIsStudyNetworkFound(false); - recreateStudyNetwork(studyUuid) + recreateStudyNetwork(studyUuid, currentRootNetwork) .then(() => { snackWarning({ headerId: 'recreatingNetworkStudy', @@ -700,7 +699,7 @@ export function StudyContainer({ view, onChangeTab }) { if (studyUuid) { websocketExpectedCloseRef.current = false; //dispatch root network uuid - dispatch(openStudy(studyUuid, rootNetworkUuid)); + dispatch(openStudy(studyUuid, currentRootNetwork)); const ws = connectNotifications(studyUuid); const wsDirectory = connectDeletedStudyNotifications(studyUuid); @@ -715,7 +714,7 @@ export function StudyContainer({ view, onChangeTab }) { } // Note: dispach, loadGeoData // connectNotifications don't change - }, [dispatch, studyUuid, rootNetworkUuid, connectNotifications, connectDeletedStudyNotifications]); + }, [dispatch, studyUuid, currentRootNetwork, connectNotifications, connectDeletedStudyNotifications]); useEffect(() => { if (studyUuid) { diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 4aa70ce7e4..221e944ceb 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -742,6 +742,17 @@ export function setCurrentTreeNode(currentTreeNode: CurrentTreeNode): CurrentTre }; } +export const CURRENT_ROOT_NETWORK = 'CURRENT_ROOT_NETWORK'; +export type CurrentRootNetworkAction = Readonly> & { + currentRootNetwork: UUID; +}; +export function setCurrentRootNetwork(currentRootNetwork: UUID): CurrentRootNetworkAction { + return { + type: CURRENT_ROOT_NETWORK, + currentRootNetwork: currentRootNetwork, + }; +} + export const SELECTION_FOR_COPY = 'SELECTION_FOR_COPY'; export type SelectionForCopyAction = Readonly> & { selectionForCopy: NonNullable; diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 5b5ce18c45..a824400d87 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -208,6 +208,8 @@ import { UseNameAction, STATEESTIMATION_RESULT_FILTER, StateEstimationResultFilterAction, + CURRENT_ROOT_NETWORK, + CurrentRootNetworkAction, } from './actions'; import { getLocalStorageComputedLanguage, @@ -461,6 +463,7 @@ export interface AppState extends CommonStoreState { studyUuid: UUID | null; rootNetworkUuid: UUID | null; currentTreeNode: CurrentTreeNode | null; + currentRootNetwork: UUID | null; computingStatus: ComputingStatus; lastCompletedComputation: ComputingType | null; computationStarting: boolean; @@ -624,6 +627,7 @@ const initialState: AppState = { studyUuid: null, rootNetworkUuid: null, currentTreeNode: null, + currentRootNetwork: null, selectionForCopy: { sourceStudyUuid: null, nodeId: null, @@ -826,7 +830,7 @@ export const reducer = createReducer(initialState, (builder) => { builder.addCase(OPEN_STUDY, (state, action: OpenStudyAction) => { state.studyUuid = action.studyRef[0]; state.rootNetworkUuid = action.rootNetworkRef[0]; - console.log("=================== ",action.studyRef) + console.log('=================== ', action.studyRef); if (action.studyRef[0] != null) { state.diagramStates = loadDiagramStateFromSessionStorage(action.studyRef[0]); @@ -1212,6 +1216,11 @@ export const reducer = createReducer(initialState, (builder) => { state.reloadMap = true; }); + builder.addCase(CURRENT_ROOT_NETWORK, (state, action: CurrentRootNetworkAction) => { + state.currentRootNetwork = action.currentRootNetwork; + state.reloadMap = true; + }); + builder.addCase(SELECTION_FOR_COPY, (state, action: SelectionForCopyAction) => { const selectionForCopy = action.selectionForCopy; if ( diff --git a/src/services/dynamic-simulation.ts b/src/services/dynamic-simulation.ts index 7998bd9fb7..d49354a181 100644 --- a/src/services/dynamic-simulation.ts +++ b/src/services/dynamic-simulation.ts @@ -7,7 +7,7 @@ import { Event } from '../components/dialogs/dynamicsimulation/event/types/event.type'; import { backendFetch, backendFetchJson, getRequestParamFromList } from './utils'; -import { getStudyUrlWithNodeUuid } from './study'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './study'; import { UUID } from 'crypto'; import { TimelineEvent, @@ -36,7 +36,9 @@ export function fetchDynamicSimulationTimeSeriesMetadata( `Fetching dynamic simulation time series's metadata on '${studyUuid}' and node '${currentNodeUuid}' ...` ); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/result/timeseries/metadata'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/dynamic-simulation/result/timeseries/metadata'; console.debug(url); return backendFetchJson(url); } @@ -46,7 +48,8 @@ export function fetchDynamicSimulationResultTimeline( currentNodeUuid: UUID ): Promise { console.info(`Fetching dynamic simulation timeline result on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/result/timeline'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/result/timeline'; console.debug(url); return backendFetchJson(url); } @@ -56,7 +59,7 @@ export function fetchDynamicSimulationResultTimeline( export function fetchDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID): Promise { console.info(`Fetching dynamic simulation events on '${studyUuid}' and node '${nodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/dynamic-simulation/events'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/dynamic-simulation/events'; console.debug(url); @@ -68,7 +71,9 @@ export function fetchDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, equ `Fetching dynamic simulation event with '${equipmentId}' on '${studyUuid}' and node '${nodeUuid}' ...` ); - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events?equipmentId=${equipmentId}`; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + `/dynamic-simulation/events?equipmentId=${equipmentId}`; console.debug(url); @@ -78,7 +83,7 @@ export function fetchDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, equ export function saveDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, event: Event) { console.info(`Saving dynamic simulation event on '${studyUuid}' and node '${nodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events`; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events`; console.debug(url); return backendFetch(url, { @@ -99,7 +104,8 @@ export function deleteDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID, e 'eventUuids' ); - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events?${eventIdsParams}`; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events?${eventIdsParams}`; console.debug(url); diff --git a/src/services/study/dynamic-simulation.js b/src/services/study/dynamic-simulation.js index 80bb7e7b21..0eab42da6e 100644 --- a/src/services/study/dynamic-simulation.js +++ b/src/services/study/dynamic-simulation.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid, PREFIX_STUDY_QUERIES } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchJson, backendFetchText, getRequestParamFromList } from '../utils'; @@ -19,7 +19,10 @@ export function getDynamicMappings(studyUuid) { export function startDynamicSimulation(studyUuid, currentNodeUuid, dynamicSimulationConfiguration) { console.info(`Running dynamic simulation on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const startDynamicSimulationUrl = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/dynamic-simulation/run`; + const startDynamicSimulationUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid + )}/dynamic-simulation/run`; // add body const body = JSON.stringify(dynamicSimulationConfiguration ?? {}); @@ -38,14 +41,19 @@ export function startDynamicSimulation(studyUuid, currentNodeUuid, dynamicSimula export function stopDynamicSimulation(studyUuid, currentNodeUuid) { console.info(`Stopping dynamic simulation on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const stopDynamicSimulationUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/stop'; + const stopDynamicSimulationUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/stop'; console.debug(stopDynamicSimulationUrl); return backendFetch(stopDynamicSimulationUrl, { method: 'put' }); } -export function fetchDynamicSimulationStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching dynamic simulation status on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/status'; +export function fetchDynamicSimulationStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching dynamic simulation status on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/dynamic-simulation/status'; console.debug(url); return backendFetchJson(url); } @@ -57,7 +65,7 @@ export function fetchDynamicSimulationResultTimeSeries(studyUuid, currentNodeUui const timeSeriesParams = getRequestParamFromList(timeSeriesNames, 'timeSeriesNames'); const urlSearchParams = new URLSearchParams(timeSeriesParams); - const url = `${getStudyUrlWithNodeUuid( + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, currentNodeUuid )}/dynamic-simulation/result/timeseries?${urlSearchParams}`; @@ -69,7 +77,7 @@ export function fetchDynamicSimulationResultTimeSeries(studyUuid, currentNodeUui export function fetchDynamicSimulationModels(studyUuid, nodeUuid) { console.info(`Fetching dynamic simulation models on '${studyUuid}' and node '${nodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/dynamic-simulation/models'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/dynamic-simulation/models'; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/filter.ts b/src/services/study/filter.ts index 9718e4be24..819e601ea3 100644 --- a/src/services/study/filter.ts +++ b/src/services/study/filter.ts @@ -7,7 +7,7 @@ import { backendFetchJson } from '../utils'; import { UUID } from 'crypto'; -import { getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { RuleGroupTypeExport } from '../../components/dialogs/filter/expert/expert-filter.type'; import { EQUIPMENT_TYPES } from 'components/utils/equipment-types'; @@ -33,7 +33,8 @@ export function evaluateJsonFilter( console.info(`Get matched elements of study '${studyUuid}' and node '${currentNodeUuid}' ...`); const evaluateFilterUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/filters/evaluate?inUpstreamBuiltParentNode=true'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/filters/evaluate?inUpstreamBuiltParentNode=true'; console.debug(evaluateFilterUrl); return backendFetchJson(evaluateFilterUrl, { method: 'post', diff --git a/src/services/study/geo-data.js b/src/services/study/geo-data.js index a960fae9e3..b8e5c96510 100644 --- a/src/services/study/geo-data.js +++ b/src/services/study/geo-data.js @@ -6,7 +6,7 @@ */ import { backendFetchJson, getQueryParamsList } from '../utils'; -import { getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; export function fetchSubstationPositions(studyUuid, currentNodeUuid, substationsIds) { console.info( @@ -17,7 +17,7 @@ export function fetchSubstationPositions(studyUuid, currentNodeUuid, substations substationsIds && substationsIds.length > 0 ? '?' + getQueryParamsList(substationsIds, 'substationId') : ''; const fetchSubstationPositionsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/geo-data/substations' + paramsList; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/geo-data/substations' + paramsList; console.debug(fetchSubstationPositionsUrl); return backendFetchJson(fetchSubstationPositionsUrl); } @@ -29,7 +29,8 @@ export function fetchLinePositions(studyUuid, currentNodeUuid, linesIds) { const paramsList = linesIds && linesIds.length > 0 ? '?' + getQueryParamsList(linesIds, 'lineId') : ''; - const fetchLinePositionsUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/geo-data/lines' + paramsList; + const fetchLinePositionsUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/geo-data/lines' + paramsList; console.debug(fetchLinePositionsUrl); return backendFetchJson(fetchLinePositionsUrl); diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 0bd46eecbf..c49e3afc3d 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -22,8 +22,10 @@ export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; export const getStudyUrl = (studyUuid: UUID) => `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}`; -export const getStudyUrlWithNodeUuid = (studyUuid: UUID, nodeUuid: UUID) => - `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/nodes/${encodeURIComponent(nodeUuid)}`; +export const getStudyUrlWithNodeUuidAndRootNetworkUuid = (studyUuid: UUID, nodeUuid: UUID, rootNetworkUuid: UUID) => + `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks/${encodeURIComponent( + rootNetworkUuid + )}/nodes/${encodeURIComponent(nodeUuid)}`; export const fetchStudy = (studyUuid: UUID) => { console.info(`Fetching study '${studyUuid}' ...`); @@ -48,7 +50,7 @@ export function getNetworkAreaDiagramUrl( ) { console.info(`Getting url of network area diagram of study '${studyUuid}' and node '${currentNodeUuid}'...`); return ( - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-area-diagram?' + new URLSearchParams({ depth: depth.toString(), @@ -78,7 +80,7 @@ export function fetchParentNodesReport( ); let url = - getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/parent-nodes-report?nodeOnlyReport=' + (nodeOnlyReport ? 'true' : 'false') + '&reportType=' + @@ -100,9 +102,9 @@ export function fetchNodeReportLogs( ) { let url; if (isGlobalLogs) { - url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/report/logs?'; + url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/report/logs?'; } else { - url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/report/' + reportId + '/logs?'; + url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/report/' + reportId + '/logs?'; } if (severityFilterList?.length) { url += '&' + getRequestParamFromList(severityFilterList, 'severityLevels'); @@ -150,7 +152,8 @@ export function fetchContingencyCount(studyUuid: UUID, currentNodeUuid: UUID, co const contingencyListNamesParams = getRequestParamFromList(contingencyListNames, 'contingencyListName'); const urlSearchParams = new URLSearchParams(contingencyListNamesParams); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/contingency-count?' + urlSearchParams; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/contingency-count?' + urlSearchParams; console.debug(url); return backendFetchJson(url); @@ -201,21 +204,21 @@ export function getAvailableComponentLibraries(): Promise { export function unbuildNode(studyUuid: UUID, currentNodeUuid: UUID) { console.info('Unbuild node ' + currentNodeUuid + ' of study ' + studyUuid + ' ...'); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/unbuild'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/unbuild'; console.debug(url); return backendFetchText(url, { method: 'post' }); } export function buildNode(studyUuid: UUID, currentNodeUuid: UUID) { console.info('Build node ' + currentNodeUuid + ' of study ' + studyUuid + ' ...'); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/build'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/build'; console.debug(url); return backendFetchText(url, { method: 'post' }); } -export function fetchCaseName(studyUuid: UUID) { +export function fetchCaseName(studyUuid: UUID, rootNetworkUuid: UUID) { console.info('Fetching case name'); - const url = getStudyUrl(studyUuid) + '/case/name'; + const url = getStudyUrl(studyUuid) + '/root-networks/' + encodeURIComponent(rootNetworkUuid) + '/case/name'; console.debug(url); return backendFetchText(url); @@ -260,7 +263,7 @@ export function fetchAvailableFilterEnumValues( filterEnum: string ) { console.info('fetch available filter values'); - const url = `${getStudyUrlWithNodeUuid( + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, nodeUuid )}/computation/result/enum-values?computingType=${encodeURIComponent(computingType)}&enumName=${encodeURIComponent( diff --git a/src/services/study/loadflow.js b/src/services/study/loadflow.js index a86c1c092f..4326fb385e 100644 --- a/src/services/study/loadflow.js +++ b/src/services/study/loadflow.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid, PREFIX_STUDY_QUERIES } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; export function getDefaultLoadFlowProvider() { @@ -50,33 +50,35 @@ export function setLoadFlowProvider(studyUuid, newProvider) { }); } -export function startLoadFlow(studyUuid, currentNodeUuid, limitReduction) { +export function startLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid, limitReduction) { console.info( 'Running loadflow on ' + studyUuid + ' and node ' + currentNodeUuid + ' with limit reduction ' + limitReduction ); const startLoadFlowUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/loadflow/run?limitReduction=' + limitReduction.toString(); console.debug(startLoadFlowUrl); return backendFetch(startLoadFlowUrl, { method: 'put' }); } -export function stopLoadFlow(studyUuid, currentNodeUuid) { +export function stopLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Stopping loadFlow on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const stopLoadFlowUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/loadflow/stop'; + const stopLoadFlowUrl = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/loadflow/stop'; console.debug(stopLoadFlowUrl); return backendFetch(stopLoadFlowUrl, { method: 'put' }); } -export function fetchLoadFlowStatus(studyUuid, currentNodeUuid) { +export function fetchLoadFlowStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Fetching loadFlow status on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/loadflow/status'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/loadflow/status'; console.debug(url); return backendFetchText(url); } -export function fetchLoadFlowResult(studyUuid, currentNodeUuid, queryParams) { +export function fetchLoadFlowResult(studyUuid, currentNodeUuid, currentRootNetworkUuid, queryParams) { console.info(`Fetching loadflow result on '${studyUuid}' and node '${currentNodeUuid}' ...`); const { sort, filters } = queryParams || {}; const params = new URLSearchParams({}); @@ -86,13 +88,13 @@ export function fetchLoadFlowResult(studyUuid, currentNodeUuid, queryParams) { if (filters?.length) { params.append('filters', JSON.stringify(filters)); } - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/loadflow/result'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/loadflow/result'; const urlWithParams = `${url}?${params.toString()}`; console.debug(urlWithParams); return backendFetchJson(urlWithParams); } -export function fetchLimitViolations(studyUuid, currentNodeUuid, queryParams) { +export function fetchLimitViolations(studyUuid, currentNodeUuid, currentRootNetworkUuid, queryParams) { console.info(`Fetching limit violations ...`); const { sort, filters, globalFilters } = queryParams || {}; const params = new URLSearchParams({}); @@ -107,7 +109,7 @@ export function fetchLimitViolations(studyUuid, currentNodeUuid, queryParams) { params.append('globalFilters', JSON.stringify(globalFilters)); } - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/limit-violations'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/limit-violations'; const urlWithParams = `${url}?${params.toString()}`; console.debug(urlWithParams); return backendFetchJson(urlWithParams); diff --git a/src/services/study/network-map.ts b/src/services/study/network-map.ts index acc7467796..72f372fcd4 100644 --- a/src/services/study/network-map.ts +++ b/src/services/study/network-map.ts @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetchJson, backendFetchText, getQueryParamsList } from '../utils'; import { EQUIPMENT_INFOS_TYPES } from '../../components/utils/equipment-types'; import { EquipmentInfos, EquipmentType, createFilter } from '@gridsuite/commons-ui'; @@ -21,7 +21,7 @@ export function fetchHvdcLineWithShuntCompensators(studyUuid: UUID, currentNodeU const urlSearchParams = new URLSearchParams(); urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchEquipmentsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-map' + '/hvdc-lines/' + hvdcLineId + @@ -37,7 +37,7 @@ export function fetchAllEquipments(studyUuid: UUID, currentNodeUuid: UUID, subst ); const fetchEquipmentsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-map/all' + '?' + getQueryParamsList(substationsIds, 'substationId'); @@ -61,7 +61,7 @@ export function fetchVoltageLevelEquipments( } const fetchEquipmentsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-map' + '/voltage-levels/' + encodeURIComponent(voltageLevelId) + @@ -93,7 +93,7 @@ export function fetchEquipmentsIds( const nominalVoltagesParamsList = nominalVoltages && nominalVoltages.length > 0 ? '&' + nominalVoltagesParams : ''; let fetchEquipmentsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-map/' + 'equipments-ids' + '?' + @@ -126,7 +126,7 @@ export function fetchVoltageLevelIdForLineOrTransformerBySide( urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); urlSearchParams.append('side', side); - const fetchEquipmentInfosUrl = `${getStudyUrlWithNodeUuid( + const fetchEquipmentInfosUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, currentNodeUuid )}/network-map/branch-or-3wt/${encodeURIComponent(equipmentId)}/voltage-level-id?${urlSearchParams.toString()}`; @@ -139,7 +139,8 @@ export function fetchAllCountries(studyUuid: UUID, currentNodeUuid: UUID) { console.info(`Fetching all countries of study '${studyUuid}' and node '${currentNodeUuid}' ...`); const fetchCountriesUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/network-map/countries?inUpstreamBuiltParentNode=true'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/network-map/countries?inUpstreamBuiltParentNode=true'; console.debug(fetchCountriesUrl); return backendFetchJson(fetchCountriesUrl); } @@ -267,7 +268,7 @@ export function fetchAllNominalVoltages(studyUuid: UUID, currentNodeUuid: UUID) console.info(`Fetching all nominal voltages of study '${studyUuid}' and node '${currentNodeUuid}' ...`); const fetchNominalVoltagesUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network-map/nominal-voltages?inUpstreamBuiltParentNode=true'; console.debug(fetchNominalVoltagesUrl); return backendFetchJson(fetchNominalVoltagesUrl); diff --git a/src/services/study/network-modifications.js b/src/services/study/network-modifications.js index 70d016c481..b5a42cd855 100644 --- a/src/services/study/network-modifications.js +++ b/src/services/study/network-modifications.js @@ -8,18 +8,18 @@ import { MODIFICATION_TYPES } from '@gridsuite/commons-ui'; import { toModificationOperation, toModificationUnsetOperation } from '../../components/utils/utils'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -import { getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { BRANCH_SIDE, OPERATING_STATUS_ACTION } from '../../components/network/constants'; function getNetworkModificationUrl(studyUuid, nodeUuid) { - return getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/network-modifications'; + return getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/network-modifications'; } export function changeNetworkModificationOrder(studyUuid, nodeUuid, itemUuid, beforeUuid) { console.info('reorder node ' + nodeUuid + ' of study ' + studyUuid + ' ...'); const url = - getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/network-modification/' + itemUuid + '?' + diff --git a/src/services/study/network.js b/src/services/study/network.js index ae4d1ca5ee..481f0fd3a8 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrlWithNodeUuid, PREFIX_STUDY_QUERIES } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { EQUIPMENT_INFOS_TYPES, EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { backendFetch, backendFetchJson, backendFetchText, getQueryParamsList, getUrlWithToken } from '../utils'; @@ -25,7 +25,7 @@ export function getVoltageLevelSingleLineDiagram( `Getting url of voltage level diagram '${voltageLevelId}' of study '${studyUuid}' and node '${currentNodeUuid}'...` ); return ( - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/svg-and-metadata?' + @@ -52,7 +52,7 @@ export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid, vol urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchSubstationIdUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/substation-id' + @@ -72,7 +72,7 @@ export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNode urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchBusbarSectionsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/buses-or-busbar-sections' + @@ -99,7 +99,7 @@ export function getSubstationSingleLineDiagram( `Getting url of substation diagram '${substationId}' of study '${studyUuid}' and node '${currentNodeUuid}'...` ); return ( - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/substations/' + encodeURIComponent(substationId) + '/svg-and-metadata?' + @@ -146,7 +146,7 @@ export function fetchNetworkElementsInfos( urlSearchParams.append('elementType', elementType); const fetchElementsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/elements' + '?' + urlSearchParams + @@ -180,7 +180,7 @@ export function fetchNetworkElementInfos( const optionalParams = new Map(); optionalParams.forEach((value, key) => urlSearchParams.append(`optionalParameters[${key}]`, value)); const fetchElementsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/network/elements/' + encodeURIComponent(elementId) + '?' + @@ -423,15 +423,15 @@ export function fetchBusbarSections(studyUuid, currentNodeUuid, substationsIds) ); } -export const fetchNetworkExistence = (studyUuid) => { - const fetchNetworkExistenceUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/network`; +export const fetchNetworkExistence = (studyUuid, rootNetworkUuid) => { + const fetchNetworkExistenceUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/root-networks/${rootNetworkUuid}/network`; return backendFetch(fetchNetworkExistenceUrl, { method: 'HEAD' }); }; -export const fetchStudyIndexationStatus = (studyUuid) => { +export const fetchStudyIndexationStatus = (studyUuid, rootNetworkUuid) => { console.info(`Fetching study indexation status of study '${studyUuid}' ...`); - const fetchStudyIndexationUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/indexation/status`; + const fetchStudyIndexationUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/root-networks/${rootNetworkUuid}/indexation/status`; console.debug(fetchStudyIndexationUrl); @@ -439,8 +439,13 @@ export const fetchStudyIndexationStatus = (studyUuid) => { }; /* export-network */ -export function getExportUrl(studyUuid, nodeUuid, exportFormat) { - const url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/export-network/' + exportFormat; +export function getExportUrl(studyUuid, nodeUuid, rootNetworkUuid, exportFormat) { + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + '/root-networks/' + + rootNetworkUuid + + '/export-network/' + + exportFormat; return getUrlWithToken(url); } diff --git a/src/services/study/non-evacuated-energy.js b/src/services/study/non-evacuated-energy.js index 93d396c3fd..19d980db40 100644 --- a/src/services/study/non-evacuated-energy.js +++ b/src/services/study/non-evacuated-energy.js @@ -5,12 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid, PREFIX_STUDY_QUERIES } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; export function startNonEvacuatedEnergy(studyUuid, currentNodeUuid) { console.info(`Running non evacuated energy analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/non-evacuated-energy/run'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/non-evacuated-energy/run'; console.debug(url); return backendFetch(url, { method: 'post' }); @@ -18,14 +18,20 @@ export function startNonEvacuatedEnergy(studyUuid, currentNodeUuid) { export function stopNonEvacuatedEnergy(studyUuid, currentNodeUuid) { console.info(`Stopping non evacuated energy analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/stop`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/stop`; console.debug(url); return backendFetch(url, { method: 'put' }); } -export function fetchNonEvacuatedEnergyStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching non evacuated energy analysis status on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/status`; +export function fetchNonEvacuatedEnergyStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching non evacuated energy analysis status on ${studyUuid} on root network '${currentRootNetworkUuid}' on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/non-evacuated-energy/status`; console.debug(url); return backendFetchText(url); } @@ -33,7 +39,7 @@ export function fetchNonEvacuatedEnergyStatus(studyUuid, currentNodeUuid) { export function fetchNonEvacuatedEnergyResult(studyUuid, currentNodeUuid) { console.info(`Fetching non evacuated energy analysis result on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/security-analysis.js b/src/services/study/security-analysis.js index b368a2fc98..2ba9af1ba1 100644 --- a/src/services/study/security-analysis.js +++ b/src/services/study/security-analysis.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid, PREFIX_STUDY_QUERIES } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchFile, backendFetchJson, backendFetchText, getRequestParamFromList } from '../utils'; export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyListNames) { @@ -15,7 +15,10 @@ export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyLis const contingencyListsQueryParams = getRequestParamFromList(contingencyListNames, 'contingencyListName'); const urlSearchParams = new URLSearchParams(contingencyListsQueryParams); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/security-analysis/run?${urlSearchParams}`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid + )}/security-analysis/run?${urlSearchParams}`; console.debug(url); return backendFetch(url, { method: 'post' }); @@ -23,14 +26,15 @@ export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyLis export function stopSecurityAnalysis(studyUuid, currentNodeUuid) { console.info('Stopping security analysis on ' + studyUuid + ' and node ' + currentNodeUuid + ' ...'); - const stopSecurityAnalysisUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/security-analysis/stop'; + const stopSecurityAnalysisUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/security-analysis/stop'; console.debug(stopSecurityAnalysisUrl); return backendFetch(stopSecurityAnalysisUrl, { method: 'put' }); } export function fetchSecurityAnalysisResult(studyUuid, currentNodeUuid, queryParams) { console.info(`Fetching security analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/security-analysis/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/security-analysis/result`; const { resultType, page, size, sort, filters } = queryParams || {}; @@ -60,7 +64,7 @@ export function downloadSecurityAnalysisResultZippedCsv( enumValueTranslations ) { console.info(`Fetching security analysis zipped csv on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/security-analysis/result/csv`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/security-analysis/result/csv`; const { resultType } = queryParams || {}; @@ -81,10 +85,14 @@ export function downloadSecurityAnalysisResultZippedCsv( }); } -export function fetchSecurityAnalysisStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching security analysis status on ${studyUuid} and node ${currentNodeUuid} ...`); +export function fetchSecurityAnalysisStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching security analysis status on ${studyUuid} on root network '${currentRootNetworkUuid}' and node ${currentNodeUuid} ...` + ); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/security-analysis/status'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/security-analysis/status'; console.debug(url); return backendFetchText(url); } diff --git a/src/services/study/sensitivity-analysis.js b/src/services/study/sensitivity-analysis.js index c31d5132c3..022b6d583f 100644 --- a/src/services/study/sensitivity-analysis.js +++ b/src/services/study/sensitivity-analysis.js @@ -5,14 +5,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { PREFIX_STUDY_QUERIES, getStudyUrl, getStudyUrlWithNodeUuid } from './index'; +import { PREFIX_STUDY_QUERIES, getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; const GET_PARAMETERS_PREFIX = import.meta.env.VITE_API_GATEWAY + '/sensitivity-analysis/v1/parameters'; export function startSensitivityAnalysis(studyUuid, currentNodeUuid) { console.info(`Running sensi on ${studyUuid} and node ${currentNodeUuid} ...`); - const startSensiAnalysisUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/sensitivity-analysis/run'; + const startSensiAnalysisUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/sensitivity-analysis/run'; console.debug(startSensiAnalysisUrl); return backendFetch(startSensiAnalysisUrl, { method: 'post' }); @@ -20,7 +21,7 @@ export function startSensitivityAnalysis(studyUuid, currentNodeUuid) { export function stopSensitivityAnalysis(studyUuid, currentNodeUuid) { console.info(`Stopping sensitivity analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const stopSensitivityAnalysisUrl = `${getStudyUrlWithNodeUuid( + const stopSensitivityAnalysisUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, currentNodeUuid )}/sensitivity-analysis/stop`; @@ -28,9 +29,15 @@ export function stopSensitivityAnalysis(studyUuid, currentNodeUuid) { return backendFetch(stopSensitivityAnalysisUrl, { method: 'put' }); } -export function fetchSensitivityAnalysisStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching sensitivity analysis status on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/sensitivity-analysis/status`; +export function fetchSensitivityAnalysisStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching sensitivity analysis status on ${studyUuid} on root network '${currentRootNetworkUuid}' and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/sensitivity-analysis/status`; console.debug(url); return backendFetchText(url); } @@ -43,7 +50,10 @@ export function fetchSensitivityAnalysisResult(studyUuid, currentNodeUuid, selec const jsoned = JSON.stringify(selector); urlSearchParams.append('selector', jsoned); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/sensitivity-analysis/result?${urlSearchParams}`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid + )}/sensitivity-analysis/result?${urlSearchParams}`; console.debug(url); return backendFetchJson(url); } @@ -56,7 +66,7 @@ export function fetchSensitivityAnalysisFilterOptions(studyUuid, currentNodeUuid const jsoned = JSON.stringify(selector); urlSearchParams.append('selector', jsoned); - const url = `${getStudyUrlWithNodeUuid( + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, currentNodeUuid )}/sensitivity-analysis/result/filter-options?${urlSearchParams}`; @@ -108,7 +118,7 @@ export function getSensitivityAnalysisFactorsCount(studyUuid, currentNodeUuid, i .filter((key) => newParams[key]) .forEach((key) => urlSearchParams.append(`ids[${key}]`, newParams[key])); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)} + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)} /sensitivity-analysis/factors-count?${urlSearchParams}`; console.debug(url); return backendFetch(url, { @@ -119,7 +129,10 @@ export function getSensitivityAnalysisFactorsCount(studyUuid, currentNodeUuid, i export function exportSensitivityResultsAsCsv(studyUuid, currentNodeUuid, csvConfig) { console.info(`Exporting sensitivity analysis on ${studyUuid} and node ${currentNodeUuid} as CSV ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/sensitivity-analysis/result/csv`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid + )}/sensitivity-analysis/result/csv`; console.debug(url); return backendFetch(url, { method: 'POST', diff --git a/src/services/study/short-circuit-analysis.js b/src/services/study/short-circuit-analysis.js index 11447b146d..b25cd9f6a3 100644 --- a/src/services/study/short-circuit-analysis.js +++ b/src/services/study/short-circuit-analysis.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { getShortCircuitAnalysisTypeFromEnum, ShortCircuitAnalysisType, @@ -25,33 +25,48 @@ export function startShortCircuitAnalysis(studyUuid, currentNodeUuid, busId) { busId && urlSearchParams.append('busId', busId); const startShortCircuitAnalysisUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/shortcircuit/run?' + urlSearchParams.toString(); + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/shortcircuit/run?' + + urlSearchParams.toString(); console.debug(startShortCircuitAnalysisUrl); return backendFetch(startShortCircuitAnalysisUrl, { method: 'put' }); } export function stopShortCircuitAnalysis(studyUuid, currentNodeUuid) { console.info(`Stopping short circuit analysis on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const stopShortCircuitAnalysisUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/shortcircuit/stop'; + const stopShortCircuitAnalysisUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/shortcircuit/stop'; console.debug(stopShortCircuitAnalysisUrl); return backendFetch(stopShortCircuitAnalysisUrl, { method: 'put' }); } -export function fetchShortCircuitAnalysisStatus(studyUuid, currentNodeUuid, type = ShortCircuitAnalysisType.ALL_BUSES) { +export function fetchShortCircuitAnalysisStatus( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + type = ShortCircuitAnalysisType.ALL_BUSES +) { const analysisType = getShortCircuitAnalysisTypeFromEnum(type); console.info( - `Fetching ${analysisType} short circuit analysis status on '${studyUuid}' and node '${currentNodeUuid}' ...` + `Fetching ${analysisType} short circuit analysis status on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` ); const urlSearchParams = new URLSearchParams(); urlSearchParams.append('type', analysisType); const url = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/shortcircuit/status?' + urlSearchParams.toString(); + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/shortcircuit/status?' + + urlSearchParams.toString(); console.debug(url); return backendFetchText(url); } -export function fetchOneBusShortCircuitAnalysisStatus(studyUuid, currentNodeUuid) { - return fetchShortCircuitAnalysisStatus(studyUuid, currentNodeUuid, ShortCircuitAnalysisType.ONE_BUS); +export function fetchOneBusShortCircuitAnalysisStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + return fetchShortCircuitAnalysisStatus( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + ShortCircuitAnalysisType.ONE_BUS + ); } export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, type }) { @@ -66,7 +81,9 @@ export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, ty } const url = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/shortcircuit/result?' + urlSearchParams.toString(); + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/shortcircuit/result?' + + urlSearchParams.toString(); console.debug(url); return backendFetchJson(url); } @@ -106,7 +123,9 @@ export function fetchShortCircuitAnalysisPagedResults({ } const url = - getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/shortcircuit/result?' + urlSearchParams.toString(); + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + '/shortcircuit/result?' + + urlSearchParams.toString(); console.debug(url); return backendFetchJson(url); } @@ -156,7 +175,7 @@ export function downloadShortCircuitResultZippedCsv( enumValueTranslations ) { console.info(`Fetching short-circuit analysis export csv on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/shortcircuit/result/csv`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/shortcircuit/result/csv`; const type = getShortCircuitAnalysisTypeFromEnum(analysisType); const param = new URLSearchParams({ type }); const urlWithParam = `${url}?${param.toString()}`; diff --git a/src/services/study/state-estimation.js b/src/services/study/state-estimation.js index 0171253b52..3445fae7e1 100644 --- a/src/services/study/state-estimation.js +++ b/src/services/study/state-estimation.js @@ -5,12 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; export function startStateEstimation(studyUuid, currentNodeUuid) { console.info(`Running state estimation on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/state-estimation/run'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/state-estimation/run'; console.debug(url); return backendFetch(url, { method: 'post' }); @@ -18,14 +18,20 @@ export function startStateEstimation(studyUuid, currentNodeUuid) { export function stopStateEstimation(studyUuid, currentNodeUuid) { console.info(`Stopping state estimation on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/state-estimation/stop`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/state-estimation/stop`; console.debug(url); return backendFetch(url, { method: 'put' }); } -export function fetchStateEstimationStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching state estimation status on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/state-estimation/status`; +export function fetchStateEstimationStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching state estimation status on ${studyUuid} on root network '${currentRootNetworkUuid}' and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/state-estimation/status`; console.debug(url); return backendFetchText(url); } @@ -33,7 +39,7 @@ export function fetchStateEstimationStatus(studyUuid, currentNodeUuid) { export function fetchStateEstimationResult(studyUuid, currentNodeUuid) { console.info(`Fetching state estimation result on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid)}/state-estimation/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/state-estimation/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/study.ts b/src/services/study/study.ts index 9824a94af3..1e41d9b70e 100644 --- a/src/services/study/study.ts +++ b/src/services/study/study.ts @@ -18,6 +18,7 @@ interface BasicStudyInfos { export const recreateStudyNetworkFromExistingCase = ( caseUuid: UUID, studyUuid: UUID, + rootNetworkUuid: UUID, importParameters: Record ): Promise => { const urlSearchParams = new URLSearchParams(); @@ -27,6 +28,8 @@ export const recreateStudyNetworkFromExistingCase = ( PREFIX_STUDY_QUERIES + '/v1/studies/' + encodeURIComponent(studyUuid) + + '/root-networks/' + + encodeURIComponent(rootNetworkUuid) + '/network?' + urlSearchParams.toString(); @@ -39,8 +42,14 @@ export const recreateStudyNetworkFromExistingCase = ( }); }; -export const recreateStudyNetwork = (studyUuid: UUID): Promise => { - const recreateStudyNetworkUrl = PREFIX_STUDY_QUERIES + '/v1/studies/' + encodeURIComponent(studyUuid) + '/network'; +export const recreateStudyNetwork = (studyUuid: UUID, rootNetworkUuid: UUID): Promise => { + const recreateStudyNetworkUrl = + PREFIX_STUDY_QUERIES + + '/v1/studies/' + + encodeURIComponent(studyUuid) + + '/root-networks/' + + encodeURIComponent(rootNetworkUuid) + + '/network'; console.debug(recreateStudyNetworkUrl); @@ -50,8 +59,14 @@ export const recreateStudyNetwork = (studyUuid: UUID): Promise }); }; -export const reindexAllStudy = (studyUuid: UUID): Promise => { - const reindexAllStudyUrl = PREFIX_STUDY_QUERIES + '/v1/studies/' + encodeURIComponent(studyUuid) + '/reindex-all'; +export const reindexAllStudy = (studyUuid: UUID, rootNetworkUuid: UUID): Promise => { + const reindexAllStudyUrl = + PREFIX_STUDY_QUERIES + + '/v1/studies/' + + encodeURIComponent(studyUuid) + + '/root-networks/' + + encodeURIComponent(rootNetworkUuid) + + '/reindex-all'; console.debug(reindexAllStudyUrl); diff --git a/src/services/study/voltage-init.js b/src/services/study/voltage-init.js index e077ce1bbe..df5c1113af 100644 --- a/src/services/study/voltage-init.js +++ b/src/services/study/voltage-init.js @@ -5,34 +5,40 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl, getStudyUrlWithNodeUuid } from './index'; +import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; export function startVoltageInit(studyUuid, currentNodeUuid) { console.info(`Running voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const startVoltageInitUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/voltage-init/run'; + const startVoltageInitUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/run'; console.debug(startVoltageInitUrl); return backendFetch(startVoltageInitUrl, { method: 'put' }); } export function stopVoltageInit(studyUuid, currentNodeUuid) { console.info(`Stopping voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const stopVoltageInitUrl = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/voltage-init/stop'; + const stopVoltageInitUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/stop'; console.debug(stopVoltageInitUrl); return backendFetch(stopVoltageInitUrl, { method: 'put' }); } -export function fetchVoltageInitStatus(studyUuid, currentNodeUuid) { - console.info(`Fetching voltage init status on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/voltage-init/status'; +export function fetchVoltageInitStatus(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Fetching voltage init status on '${studyUuid}' root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/voltage-init/status'; console.debug(url); return backendFetchText(url); } export function fetchVoltageInitResult(studyUuid, currentNodeUuid) { console.info(`Fetching voltage init result on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuid(studyUuid, currentNodeUuid) + '/voltage-init/result'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/result'; console.debug(url); return backendFetchJson(url); } @@ -64,7 +70,7 @@ export function getVoltageInitStudyParameters(studyUuid) { export function getVoltageInitModifications(studyUuid, currentNodeId) { console.info('get voltage init modifications'); const getVoltageInitModifications = - getStudyUrlWithNodeUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; console.debug(getVoltageInitModifications); return backendFetchJson(getVoltageInitModifications); } @@ -72,7 +78,7 @@ export function getVoltageInitModifications(studyUuid, currentNodeId) { export function cloneVoltageInitModifications(studyUuid, currentNodeId) { console.info('cloning voltage init modifications'); const cloneVoltageInitModificationsUrl = - getStudyUrlWithNodeUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; return backendFetch(cloneVoltageInitModificationsUrl, { method: 'PUT', From 3e026816ee9a734dd5f5fbdfc04a64e3cc530e4e Mon Sep 17 00:00:00 2001 From: souissimai Date: Tue, 17 Dec 2024 15:18:43 +0100 Subject: [PATCH 03/51] add Signed-off-by: souissimai --- .../graph/menus/root-network-node-editor.tsx | 276 +++--------------- 1 file changed, 41 insertions(+), 235 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index db3e8e3da9..980128ad95 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -9,6 +9,7 @@ import { CheckBoxList, ElementType, MODIFICATION_TYPES, + Parameter, useModificationLabelComputer, useSnackMessage, } from '@gridsuite/commons-ui'; @@ -92,6 +93,7 @@ import { LccCreationDialog } from '../../dialogs/network-modifications/hvdc-line import ImportCaseDialog from 'components/dialogs/import-case-dialog'; import CreateCaseDialog from 'components/dialogs/create-case-dialog'; import { createRootNetwork } from 'services/root-network'; +import { CaseImportParameters, GetCaseImportParametersReturn, getCaseImportParameters } from 'services/network-conversion'; export const styles = { listContainer: (theme: Theme) => ({ @@ -266,229 +268,7 @@ const RootNetworkNodeEditor = () => { /> ); } - - const menuDefinition: MenuDefinition[] = [ - { - id: 'CREATE', - label: 'menu.create', - subItems: [ - { - id: MODIFICATION_TYPES.SUBSTATION_CREATION.type, - label: 'SUBSTATION', - action: () => withDefaultParams(SubstationCreationDialog), - }, - { - id: MODIFICATION_TYPES.VOLTAGE_LEVEL_CREATION.type, - label: 'VOLTAGE_LEVEL', - action: () => withDefaultParams(VoltageLevelCreationDialog), - }, - { - id: MODIFICATION_TYPES.LINE_CREATION.type, - label: 'LINE', - action: () => withDefaultParams(LineCreationDialog), - }, - { - id: MODIFICATION_TYPES.TWO_WINDINGS_TRANSFORMER_CREATION.type, - label: 'TWO_WINDINGS_TRANSFORMER', - action: () => withDefaultParams(TwoWindingsTransformerCreationDialog), - }, - { - id: 'GENERATOR_CREATION', - label: 'GENERATOR', - action: () => withDefaultParams(GeneratorCreationDialog), - }, - { - id: MODIFICATION_TYPES.LOAD_CREATION.type, - label: 'LOAD', - action: () => withDefaultParams(LoadCreationDialog), - }, - { - id: MODIFICATION_TYPES.BATTERY_CREATION.type, - label: 'BATTERY', - action: () => withDefaultParams(BatteryCreationDialog), - }, - { - id: MODIFICATION_TYPES.SHUNT_COMPENSATOR_CREATION.type, - label: 'ShuntCompensator', - action: () => withDefaultParams(ShuntCompensatorCreationDialog), - }, - { - id: MODIFICATION_TYPES.STATIC_VAR_COMPENSATOR_CREATION.type, - label: 'StaticVarCompensator', - action: () => withDefaultParams(StaticVarCompensatorCreationDialog), - }, - { - id: MODIFICATION_TYPES.VSC_CREATION.type, - label: 'VSC', - action: () => withDefaultParams(VscCreationDialog), - }, - { - id: MODIFICATION_TYPES.LCC_CREATION.type, - label: 'LCC', - action: () => withDefaultParams(LccCreationDialog), - }, - ], - }, - { - id: 'CREATE_MULTIPLE', - label: 'menu.createMultiple', - action: () => withDefaultParams(TabularCreationDialog), - }, - { - id: 'EDIT', - label: 'ModifyFromMenu', - subItems: [ - { - id: MODIFICATION_TYPES.SUBSTATION_MODIFICATION.type, - label: 'SUBSTATION', - action: () => withDefaultParams(SubstationModificationDialog), - }, - { - id: MODIFICATION_TYPES.VOLTAGE_LEVEL_MODIFICATION.type, - label: 'VOLTAGE_LEVEL', - action: () => withDefaultParams(VoltageLevelModificationDialog), - }, - { - id: MODIFICATION_TYPES.LINE_MODIFICATION.type, - label: 'LINE', - action: () => withDefaultParams(LineModificationDialog), - }, - { - id: MODIFICATION_TYPES.TWO_WINDINGS_TRANSFORMER_MODIFICATION.type, - label: 'TWO_WINDINGS_TRANSFORMER', - action: () => withDefaultParams(TwoWindingsTransformerModificationDialog), - }, - { - id: MODIFICATION_TYPES.GENERATOR_MODIFICATION.type, - label: 'GENERATOR', - action: () => withDefaultParams(GeneratorModificationDialog), - }, - { - id: MODIFICATION_TYPES.LOAD_MODIFICATION.type, - label: 'LOAD', - action: () => withDefaultParams(LoadModificationDialog), - }, - { - id: MODIFICATION_TYPES.BATTERY_MODIFICATION.type, - label: 'BATTERY', - action: () => withDefaultParams(BatteryModificationDialog), - }, - { - id: MODIFICATION_TYPES.SHUNT_COMPENSATOR_MODIFICATION.type, - label: 'ShuntCompensator', - action: () => withDefaultParams(ShuntCompensatorModificationDialog), - }, - { - id: MODIFICATION_TYPES.VSC_MODIFICATION.type, - label: 'VSC', - action: () => withDefaultParams(VscModificationDialog), - }, - ], - }, - { - id: 'EDIT_MULTIPLE', - label: 'menu.modifyMultiple', - subItems: [ - { - id: MODIFICATION_TYPES.TABULAR_MODIFICATION.type, - label: 'BY_TABLE', - action: () => withDefaultParams(TabularModificationDialog), - }, - { - id: MODIFICATION_TYPES.BY_FORMULA_MODIFICATION.type, - label: 'BY_FORMULA', - action: () => withDefaultParams(ByFormulaDialog), - }, - { - id: MODIFICATION_TYPES.MODIFICATION_BY_ASSIGNMENT.type, - label: 'BY_FILTER', - action: () => withDefaultParams(ModificationByAssignmentDialog), - }, - ], - }, - { - id: 'EQUIPMENT_DELETION', - label: 'DeleteContingencyList', - subItems: [ - { - id: MODIFICATION_TYPES.EQUIPMENT_DELETION.type, - label: 'SingleEquipment', - action: () => withDefaultParams(EquipmentDeletionDialog), - }, - { - id: MODIFICATION_TYPES.BY_FILTER_DELETION.type, - label: 'MultipleEquipment', - action: () => withDefaultParams(ByFilterDeletionDialog), - }, - ], - }, - { - id: 'ATTACHING_SPLITTING_LINES', - label: 'AttachingAndSplittingLines', - subItems: [ - { - id: MODIFICATION_TYPES.LINE_SPLIT_WITH_VOLTAGE_LEVEL.type, - label: 'LineSplitWithVoltageLevel', - action: () => withDefaultParams(LineSplitWithVoltageLevelDialog), - }, - { - id: MODIFICATION_TYPES.LINE_ATTACH_TO_VOLTAGE_LEVEL.type, - label: 'LineAttachToVoltageLevel', - action: () => withDefaultParams(LineAttachToVoltageLevelDialog), - }, - { - id: MODIFICATION_TYPES.LINES_ATTACH_TO_SPLIT_LINES.type, - label: 'LinesAttachToSplitLines', - action: () => withDefaultParams(LinesAttachToSplitLinesDialog), - }, - { - id: MODIFICATION_TYPES.DELETE_VOLTAGE_LEVEL_ON_LINE.type, - label: 'DeleteVoltageLevelOnLine', - action: () => withDefaultParams(DeleteVoltageLevelOnLineDialog), - }, - { - id: MODIFICATION_TYPES.DELETE_ATTACHING_LINE.type, - label: 'DeleteAttachingLine', - action: () => withDefaultParams(DeleteAttachingLineDialog), - }, - ], - }, - { - id: 'GENERATION_AND_LOAD', - label: 'GenerationAndLoad', - subItems: [ - { - id: MODIFICATION_TYPES.GENERATOR_SCALING.type, - label: 'GeneratorScaling', - action: () => withDefaultParams(GeneratorScalingDialog), - }, - { - id: MODIFICATION_TYPES.LOAD_SCALING.type, - label: 'LoadScaling', - action: () => withDefaultParams(LoadScalingDialog), - }, - { - id: MODIFICATION_TYPES.GENERATION_DISPATCH.type, - label: 'GenerationDispatch', - action: () => withDefaultParams(GenerationDispatchDialog), - }, - ], - }, - { - id: 'VOLTAGE_INIT_MODIFICATION', - label: 'VoltageInitModification', - hide: true, - action: () => withDefaultParams(VoltageInitModificationDialog), - }, - ]; - - const subMenuItemsList = menuDefinition.reduce<(MenuDefinitionWithoutSubItem | MenuDefinitionSubItem)[]>( - (actions, currentMenuItem) => - !('subItems' in currentMenuItem) - ? [...actions, currentMenuItem] - : [...actions, ...currentMenuItem.subItems], - [] - ); + const fillNotification = useCallback( (study: StudyUpdated, messageId: string) => { @@ -723,10 +503,7 @@ const RootNetworkNodeEditor = () => { setSelectedItems((oldVal) => (oldVal.length === 0 ? modifications : [])); }, [modifications]); - const renderDialog = () => { - return subMenuItemsList.find((menuItem) => menuItem.id === editDialogOpen)?.action?.(); - }; - + const commit = useCallback( ({ source, destination }: DropResult) => { setIsDragging(false); @@ -898,6 +675,39 @@ const RootNetworkNodeEditor = () => { //return setRootNetworkCreationDialogOpen(false)} />; }; + /* Effects */ + // handle create r from existing case + useEffect(() => { + // getCurrentCaseImportParams(providedExistingCase.elementUuid); + + }, []); + function formatCaseImportParameters(params: CaseImportParameters[]): CaseImportParameters[] { + // sort possible values alphabetically to display select options sorted + return params?.map((parameter) => ({ + ...parameter, + possibleValues: parameter.possibleValues?.sort((a: any, b: any) => a.localeCompare(b)), + })); + } + const getCurrentCaseImportParams = useCallback( + (caseUuid: UUID) => { + getCaseImportParameters(caseUuid) + .then((result: GetCaseImportParametersReturn) => { + console.log(result) + const formattedParams = formatCaseImportParameters(result.parameters); + const caseFormat = result.formatName ; + }) + .catch(() => { + + // setError(`root.${FieldConstants.API_CALL}`, { + // type: 'parameterLoadingProblem', + // message: intl.formatMessage({ + // id: 'parameterLoadingProblem', + // }), + // }); + }); + }, + [intl ] + ); const doCreateRootNetwork = ({ name, caseName, @@ -906,6 +716,9 @@ const RootNetworkNodeEditor = () => { console.log("fetcccccccccch ???? " , name, caseName, caseId) +if(caseId){ + getCurrentCaseImportParams +} setSaveInProgress(true); // createRootNetwork( caseId , // "XIIDM", @@ -996,14 +809,7 @@ caseId) {renderNetworkModificationsList()} - - {editDialogOpen && renderDialog()} + ); }; From c99f16ca7f3f7a3ad4916fa26c26f3309f1998b1 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Tue, 17 Dec 2024 16:12:03 +0100 Subject: [PATCH 04/51] fix: migrating several other endpoints Signed-off-by: LE SAULNIER Kevin --- .../curve/dialog/equipment-filter.tsx | 3 +- src/components/map-viewer.jsx | 2 + .../network-modification-tree-pane.jsx | 7 +- src/components/network/gs-map-equipments.ts | 37 +++++-- src/components/network/network-map-tab.tsx | 29 ++++-- src/components/study-container.jsx | 1 + src/components/study-pane.jsx | 3 +- src/services/dynamic-simulation.ts | 19 ++-- src/services/study/geo-data.js | 16 +-- src/services/study/index.ts | 18 +++- src/services/study/network-map.ts | 27 +++-- src/services/study/network-modifications.js | 6 +- src/services/study/network.js | 99 ++++++++++++++----- 13 files changed, 195 insertions(+), 72 deletions(-) diff --git a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx index 03954c6bc7..20379e141a 100644 --- a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx +++ b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx @@ -56,6 +56,7 @@ const EquipmentFilter = forwardRef state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); const intl = useIntl(); const equipmentsRef = useRef>(null); @@ -91,7 +92,7 @@ const EquipmentFilter = forwardRef { const vlMap = new Map(); const nvSet = new Set(); diff --git a/src/components/map-viewer.jsx b/src/components/map-viewer.jsx index c54b65fc93..ee659ccc3b 100644 --- a/src/components/map-viewer.jsx +++ b/src/components/map-viewer.jsx @@ -137,6 +137,7 @@ export const Content = () => ( const MapViewer = ({ studyUuid, currentNode, + currentRootNetwork, view, openDiagramView, tableEquipment, @@ -321,6 +322,7 @@ const MapViewer = ({ lineFlowAlertThreshold={lineFlowAlertThreshold} openVoltageLevel={openVoltageLevel} currentNode={currentNode} + currentRootNetwork={currentRootNetwork} onChangeTab={onChangeTab} showInSpreadsheet={showInSpreadsheet} setErrorMessage={setErrorMessage} diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index e6a6256866..b88d9bd80f 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -51,7 +51,7 @@ const styles = { height: '100%', display: 'flex', flexDirection: 'row', - // backgroundColor: 'yellow', + // backgroundColor: 'yellow', }, }; @@ -132,6 +132,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const [activeNode, setActiveNode] = useState(null); const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetwork = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); currentNodeRef.current = currentNode; @@ -398,7 +399,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const handleBuildNode = useCallback( (element) => { - buildNode(studyUuid, element.id).catch((error) => { + buildNode(studyUuid, element.id, currentRootNetwork).catch((error) => { if (error.status === 403 && error.message.includes(HTTP_MAX_NODE_BUILDS_EXCEEDED_MESSAGE)) { // retrieve last word of the message (ex: "MAX_NODE_BUILDS_EXCEEDED max allowed built nodes : 2" -> 2) let limit = error.message.split(/[: ]+/).pop(); @@ -414,7 +415,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) } }); }, - [studyUuid, snackError] + [studyUuid, currentRootNetwork, snackError] ); const [openExportDialog, setOpenExportDialog] = useState(false); diff --git a/src/components/network/gs-map-equipments.ts b/src/components/network/gs-map-equipments.ts index 942436232f..ab5ee06f15 100644 --- a/src/components/network/gs-map-equipments.ts +++ b/src/components/network/gs-map-equipments.ts @@ -24,11 +24,35 @@ export default class GSMapEquipments extends MapEquipments { errHandler?: UseSnackMessageReturn['snackError']; intlRef: RefObject; - initEquipments(studyUuid: UUID, currentNodeUuid: UUID) { - const fetchSubstationsMapInfosPromise = fetchSubstationsMapInfos(studyUuid, currentNodeUuid, undefined, false); - const fetchLinesMapInfosPromise = fetchLinesMapInfos(studyUuid, currentNodeUuid, undefined, false); - const fetchTieLinesMapInfosPromise = fetchTieLinesMapInfos(studyUuid, currentNodeUuid, undefined, false); - const fetchHvdcLinesMapInfosPromise = fetchHvdcLinesMapInfos(studyUuid, currentNodeUuid, undefined, false); + initEquipments(studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID) { + const fetchSubstationsMapInfosPromise = fetchSubstationsMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + undefined, + false + ); + const fetchLinesMapInfosPromise = fetchLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + undefined, + false + ); + const fetchTieLinesMapInfosPromise = fetchTieLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + undefined, + false + ); + const fetchHvdcLinesMapInfosPromise = fetchHvdcLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + undefined, + false + ); this.dispatch(setMapEquipementsInitialized(false)); @@ -101,6 +125,7 @@ export default class GSMapEquipments extends MapEquipments { constructor( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, errHandler: UseSnackMessageReturn['snackError'], dispatch: Dispatch, intlRef: RefObject @@ -109,7 +134,7 @@ export default class GSMapEquipments extends MapEquipments { this.dispatch = dispatch; this.errHandler = errHandler; this.intlRef = intlRef; - this.initEquipments(studyUuid, currentNodeUuid); + this.initEquipments(studyUuid, currentNodeUuid, currentRootNetworkUuid); } reloadImpactedSubstationsEquipments(studyUuid: UUID, currentNode: any, substationsIds: string[] | null) { diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 0229705bec..43beee9b68 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -84,6 +84,7 @@ type NetworkMapTabProps = { networkMapRef: React.RefObject; studyUuid: UUID; currentNode: CurrentTreeNode; + currentRootNetwork: UUID; visible: boolean; lineFullPath: boolean; lineParallelPath: boolean; @@ -105,6 +106,7 @@ export const NetworkMapTab = ({ /* redux can be use as redux*/ studyUuid, currentNode, + currentRootNetwork, /* visual*/ visible, lineFullPath, @@ -581,17 +583,19 @@ export const NetworkMapTab = ({ console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); - const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId).then((data) => { - console.info(`Received substations of study '${studyUuid}'...`); - const newGeoData = new GeoData(new Map(), geoDataRef.current?.linePositionsById || new Map()); - newGeoData.setSubstationPositions(data); - setGeoData(newGeoData); - geoDataRef.current = newGeoData; - }); + const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetwork).then( + (data) => { + console.info(`Received substations of study '${studyUuid}'...`); + const newGeoData = new GeoData(new Map(), geoDataRef.current?.linePositionsById || new Map()); + newGeoData.setSubstationPositions(data); + setGeoData(newGeoData); + geoDataRef.current = newGeoData; + } + ); const linePositionsDone = !lineFullPath ? Promise.resolve() - : fetchLinePositions(studyUuid, rootNodeId).then((data) => { + : fetchLinePositions(studyUuid, rootNodeId, currentRootNetwork).then((data) => { console.info(`Received lines of study '${studyUuid}'...`); const newGeoData = new GeoData(geoDataRef.current?.substationPositionsById || new Map(), new Map()); newGeoData.setLinePositions(data); @@ -649,7 +653,14 @@ export const NetworkMapTab = ({ if (!isNodeBuilt(currentNode) || !studyUuid) { return; } - const gSMapEquipments = new GSMapEquipments(studyUuid, currentNode?.id, snackError, dispatch, intlRef); + const gSMapEquipments = new GSMapEquipments( + studyUuid, + currentNode?.id, + currentRootNetwork, + snackError, + dispatch, + intlRef + ); if (gSMapEquipments) { dispatch(resetMapReloaded()); } diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index ffe528d385..8f993f04f9 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -746,6 +746,7 @@ export function StudyContainer({ view, onChangeTab }) { { +const StudyPane = ({ studyUuid, currentNode, currentRootNetwork, setErrorMessage, ...props }) => { const [tableEquipment, setTableEquipment] = useState({ id: null, type: null, @@ -82,6 +82,7 @@ const StudyPane = ({ studyUuid, currentNode, setErrorMessage, ...props }) => { { console.info( - `Fetching dynamic simulation time series's metadata on '${studyUuid}' and node '${currentNodeUuid}' ...` + `Fetching dynamic simulation time series's metadata on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` ); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/dynamic-simulation/result/timeseries/metadata'; console.debug(url); return backendFetchJson(url); @@ -45,17 +46,21 @@ export function fetchDynamicSimulationTimeSeriesMetadata( export function fetchDynamicSimulationResultTimeline( studyUuid: UUID, - currentNodeUuid: UUID + currentNodeUuid: UUID, + currentRootNetworkUuid: UUID ): Promise { - console.info(`Fetching dynamic simulation timeline result on '${studyUuid}' and node '${currentNodeUuid}' ...`); + console.info( + `Fetching dynamic simulation timeline result on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/result/timeline'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/dynamic-simulation/result/timeline'; console.debug(url); return backendFetchJson(url); } // --- Event API - BEGIN - +//TODO: should not be linked to rootnetworkUUID export function fetchDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID): Promise { console.info(`Fetching dynamic simulation events on '${studyUuid}' and node '${nodeUuid}' ...`); diff --git a/src/services/study/geo-data.js b/src/services/study/geo-data.js index b8e5c96510..9a9ed6b473 100644 --- a/src/services/study/geo-data.js +++ b/src/services/study/geo-data.js @@ -8,29 +8,33 @@ import { backendFetchJson, getQueryParamsList } from '../utils'; import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; -export function fetchSubstationPositions(studyUuid, currentNodeUuid, substationsIds) { +export function fetchSubstationPositions(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { console.info( - `Fetching substation positions of study '${studyUuid}' and node '${currentNodeUuid}' with ids '${substationsIds}'...` + `Fetching substation positions of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' with ids '${substationsIds}'...` ); const paramsList = substationsIds && substationsIds.length > 0 ? '?' + getQueryParamsList(substationsIds, 'substationId') : ''; const fetchSubstationPositionsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/geo-data/substations' + paramsList; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/geo-data/substations' + + paramsList; console.debug(fetchSubstationPositionsUrl); return backendFetchJson(fetchSubstationPositionsUrl); } -export function fetchLinePositions(studyUuid, currentNodeUuid, linesIds) { +export function fetchLinePositions(studyUuid, currentNodeUuid, currentRootNetworkUuid, linesIds) { console.info( - `Fetching line positions of study '${studyUuid}' and node '${currentNodeUuid}' with ids '${linesIds}'...` + `Fetching line positions of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' with ids '${linesIds}'...` ); const paramsList = linesIds && linesIds.length > 0 ? '?' + getQueryParamsList(linesIds, 'lineId') : ''; const fetchLinePositionsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/geo-data/lines' + paramsList; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/geo-data/lines' + + paramsList; console.debug(fetchLinePositionsUrl); return backendFetchJson(fetchLinePositionsUrl); diff --git a/src/services/study/index.ts b/src/services/study/index.ts index c49e3afc3d..1da593b2b1 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -27,6 +27,9 @@ export const getStudyUrlWithNodeUuidAndRootNetworkUuid = (studyUuid: UUID, nodeU rootNetworkUuid )}/nodes/${encodeURIComponent(nodeUuid)}`; +export const getStudyUrlWithNodeUuid = (studyUuid: UUID, nodeUuid: UUID) => + `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/nodes/${encodeURIComponent(nodeUuid)}`; + export const fetchStudy = (studyUuid: UUID) => { console.info(`Fetching study '${studyUuid}' ...`); const fetchStudiesUrl = getStudyUrl(studyUuid); @@ -209,9 +212,18 @@ export function unbuildNode(studyUuid: UUID, currentNodeUuid: UUID) { return backendFetchText(url, { method: 'post' }); } -export function buildNode(studyUuid: UUID, currentNodeUuid: UUID) { - console.info('Build node ' + currentNodeUuid + ' of study ' + studyUuid + ' ...'); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/build'; +export function buildNode(studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID) { + console.info( + 'Build node ' + + currentNodeUuid + + ' on root network ' + + currentRootNetworkUuid + + ' of study ' + + studyUuid + + ' ...' + ); + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/build'; console.debug(url); return backendFetchText(url, { method: 'post' }); } diff --git a/src/services/study/network-map.ts b/src/services/study/network-map.ts index 72f372fcd4..20b110d9cf 100644 --- a/src/services/study/network-map.ts +++ b/src/services/study/network-map.ts @@ -14,14 +14,19 @@ import { createContingencyList } from 'services/explore'; import { ContingencyList, createIdentifierContingencyList } from './contingency-list'; import { UUID } from 'crypto'; -export function fetchHvdcLineWithShuntCompensators(studyUuid: UUID, currentNodeUuid: UUID, hvdcLineId: string) { +export function fetchHvdcLineWithShuntCompensators( + studyUuid: UUID, + currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, + hvdcLineId: string +) { console.info( - `Fetching HVDC Line '${hvdcLineId}' with Shunt Compensators of study '${studyUuid}' and node '${currentNodeUuid}'...` + `Fetching HVDC Line '${hvdcLineId}' with Shunt Compensators of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}'...` ); const urlSearchParams = new URLSearchParams(); urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchEquipmentsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map' + '/hvdc-lines/' + hvdcLineId + @@ -31,13 +36,18 @@ export function fetchHvdcLineWithShuntCompensators(studyUuid: UUID, currentNodeU return backendFetchJson(fetchEquipmentsUrl); } -export function fetchAllEquipments(studyUuid: UUID, currentNodeUuid: UUID, substationsIds: string[]) { +export function fetchAllEquipments( + studyUuid: UUID, + currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, + substationsIds: string[] +) { console.info( - `Fetching all equipments of study '${studyUuid}' and node '${currentNodeUuid}' with substations ids '${substationsIds}'...` + `Fetching all equipments of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' with substations ids '${substationsIds}'...` ); const fetchEquipmentsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map/all' + '?' + getQueryParamsList(substationsIds, 'substationId'); @@ -48,12 +58,13 @@ export function fetchAllEquipments(studyUuid: UUID, currentNodeUuid: UUID, subst export function fetchVoltageLevelEquipments( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, substationsIds: string[], voltageLevelId: string, inUpstreamBuiltParentNode: boolean ) { console.info( - `Fetching equipments of study '${studyUuid}' and node '${currentNodeUuid}' and voltage level '${voltageLevelId}' with substations ids '${substationsIds}'...` + `Fetching equipments of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' and voltage level '${voltageLevelId}' with substations ids '${substationsIds}'...` ); const urlSearchParams = new URLSearchParams(); if (inUpstreamBuiltParentNode !== undefined) { @@ -61,7 +72,7 @@ export function fetchVoltageLevelEquipments( } const fetchEquipmentsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map' + '/voltage-levels/' + encodeURIComponent(voltageLevelId) + diff --git a/src/services/study/network-modifications.js b/src/services/study/network-modifications.js index b5a42cd855..70d016c481 100644 --- a/src/services/study/network-modifications.js +++ b/src/services/study/network-modifications.js @@ -8,18 +8,18 @@ import { MODIFICATION_TYPES } from '@gridsuite/commons-ui'; import { toModificationOperation, toModificationUnsetOperation } from '../../components/utils/utils'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; +import { getStudyUrlWithNodeUuid } from './index'; import { EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { BRANCH_SIDE, OPERATING_STATUS_ACTION } from '../../components/network/constants'; function getNetworkModificationUrl(studyUuid, nodeUuid) { - return getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/network-modifications'; + return getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/network-modifications'; } export function changeNetworkModificationOrder(studyUuid, nodeUuid, itemUuid, beforeUuid) { console.info('reorder node ' + nodeUuid + ' of study ' + studyUuid + ' ...'); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/network-modification/' + itemUuid + '?' + diff --git a/src/services/study/network.js b/src/services/study/network.js index 481f0fd3a8..fa9269dc19 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -121,6 +121,7 @@ export function getSubstationSingleLineDiagram( export function fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, elementType, infoType, @@ -131,7 +132,7 @@ export function fetchNetworkElementsInfos( const nominalVoltagesStr = nominalVoltages ? `[${nominalVoltages}]` : '[]'; console.info( - `Fetching network '${elementType}' elements '${infoType}' infos of study '${studyUuid}' and node '${currentNodeUuid}' with ${substationsCount} substations ids and ${nominalVoltagesStr} nominal voltages.` + `Fetching network '${elementType}' elements '${infoType}' infos of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' with ${substationsCount} substations ids and ${nominalVoltagesStr} nominal voltages.` ); const nominalVoltagesParams = getQueryParamsList(nominalVoltages, 'nominalVoltages'); @@ -146,7 +147,7 @@ export function fetchNetworkElementsInfos( urlSearchParams.append('elementType', elementType); const fetchElementsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/elements' + '?' + urlSearchParams + @@ -163,6 +164,7 @@ export function fetchNetworkElementsInfos( export function fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, elementType, infoType, elementId, @@ -190,10 +192,17 @@ export function fetchNetworkElementInfos( return backendFetchJson(fetchElementsUrl); } -export function fetchSubstationsMapInfos(studyUuid, currentNodeUuid, substationsIds, inUpstreamBuiltParentNode) { +export function fetchSubstationsMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + substationsIds, + inUpstreamBuiltParentNode +) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.SUBSTATION, EQUIPMENT_INFOS_TYPES.MAP.type, @@ -201,10 +210,17 @@ export function fetchSubstationsMapInfos(studyUuid, currentNodeUuid, substations ); } -export function fetchLinesMapInfos(studyUuid, currentNodeUuid, substationsIds, inUpstreamBuiltParentNode) { +export function fetchLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + substationsIds, + inUpstreamBuiltParentNode +) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.LINE, EQUIPMENT_INFOS_TYPES.MAP.type, @@ -212,10 +228,17 @@ export function fetchLinesMapInfos(studyUuid, currentNodeUuid, substationsIds, i ); } -export function fetchTieLinesMapInfos(studyUuid, currentNodeUuid, substationsIds, inUpstreamBuiltParentNode) { +export function fetchTieLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + substationsIds, + inUpstreamBuiltParentNode +) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.TIE_LINE, EQUIPMENT_INFOS_TYPES.MAP.type, @@ -223,10 +246,17 @@ export function fetchTieLinesMapInfos(studyUuid, currentNodeUuid, substationsIds ); } -export function fetchHvdcLinesMapInfos(studyUuid, currentNodeUuid, substationsIds, inUpstreamBuiltParentNode) { +export function fetchHvdcLinesMapInfos( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + substationsIds, + inUpstreamBuiltParentNode +) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.HVDC_LINE, EQUIPMENT_INFOS_TYPES.MAP.type, @@ -234,10 +264,11 @@ export function fetchHvdcLinesMapInfos(studyUuid, currentNodeUuid, substationsId ); } -export function fetchSubstations(studyUuid, currentNodeUuid, substationsIds) { +export function fetchSubstations(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.SUBSTATION, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -245,10 +276,11 @@ export function fetchSubstations(studyUuid, currentNodeUuid, substationsIds) { ); } -export function fetchLines(studyUuid, currentNodeUuid, substationsIds) { +export function fetchLines(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.LINE, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -256,10 +288,11 @@ export function fetchLines(studyUuid, currentNodeUuid, substationsIds) { ); } -export function fetchVoltageLevels(studyUuid, currentNodeUuid, substationsIds) { +export function fetchVoltageLevels(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.VOLTAGE_LEVEL, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -267,10 +300,11 @@ export function fetchVoltageLevels(studyUuid, currentNodeUuid, substationsIds) { ); } -export function fetchVoltageLevelsListInfos(studyUuid, currentNodeUuid, substationsIds) { +export function fetchVoltageLevelsListInfos(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.VOLTAGE_LEVEL, EQUIPMENT_INFOS_TYPES.LIST.type, @@ -278,10 +312,11 @@ export function fetchVoltageLevelsListInfos(studyUuid, currentNodeUuid, substati ); } -export function fetchVoltageLevelsMapInfos(studyUuid, currentNodeUuid, substationsIds) { +export function fetchVoltageLevelsMapInfos(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.VOLTAGE_LEVEL, EQUIPMENT_INFOS_TYPES.MAP.type, @@ -289,10 +324,11 @@ export function fetchVoltageLevelsMapInfos(studyUuid, currentNodeUuid, substatio ); } -export function fetchTwoWindingsTransformers(studyUuid, currentNodeUuid, substationsIds) { +export function fetchTwoWindingsTransformers(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -300,10 +336,11 @@ export function fetchTwoWindingsTransformers(studyUuid, currentNodeUuid, substat ); } -export function fetchThreeWindingsTransformers(studyUuid, currentNodeUuid, substationsIds) { +export function fetchThreeWindingsTransformers(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.THREE_WINDINGS_TRANSFORMER, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -311,20 +348,22 @@ export function fetchThreeWindingsTransformers(studyUuid, currentNodeUuid, subst ); } -export function fetchGenerators(studyUuid, currentNodeUuid, substationsIds) { +export function fetchGenerators(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.GENERATOR, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchLoads(studyUuid, currentNodeUuid, substationsIds) { +export function fetchLoads(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.LOAD, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -332,30 +371,33 @@ export function fetchLoads(studyUuid, currentNodeUuid, substationsIds) { ); } -export function fetchDanglingLines(studyUuid, currentNodeUuid, substationsIds) { +export function fetchDanglingLines(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.DANGLING_LINE, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchBatteries(studyUuid, currentNodeUuid, substationsIds) { +export function fetchBatteries(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.BATTERY, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchHvdcLines(studyUuid, currentNodeUuid, substationsIds) { +export function fetchHvdcLines(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.HVDC_LINE, EQUIPMENT_INFOS_TYPES.TAB.type, @@ -363,60 +405,66 @@ export function fetchHvdcLines(studyUuid, currentNodeUuid, substationsIds) { ); } -export function fetchLccConverterStations(studyUuid, currentNodeUuid, substationsIds) { +export function fetchLccConverterStations(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.LCC_CONVERTER_STATION, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchVscConverterStations(studyUuid, currentNodeUuid, substationsIds) { +export function fetchVscConverterStations(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.VSC_CONVERTER_STATION, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchShuntCompensators(studyUuid, currentNodeUuid, substationsIds) { +export function fetchShuntCompensators(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.SHUNT_COMPENSATOR, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchStaticVarCompensators(studyUuid, currentNodeUuid, substationsIds) { +export function fetchStaticVarCompensators(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchBuses(studyUuid, currentNodeUuid, substationsIds) { +export function fetchBuses(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.BUS, EQUIPMENT_INFOS_TYPES.TAB.type ); } -export function fetchBusbarSections(studyUuid, currentNodeUuid, substationsIds) { +export function fetchBusbarSections(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.BUSBAR_SECTION, EQUIPMENT_INFOS_TYPES.TAB.type @@ -449,10 +497,11 @@ export function getExportUrl(studyUuid, nodeUuid, rootNetworkUuid, exportFormat) return getUrlWithToken(url); } -export function fetchTieLines(studyUuid, currentNodeUuid, substationsIds) { +export function fetchTieLines(studyUuid, currentNodeUuid, currentRootNetworkUuid, substationsIds) { return fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationsIds, EQUIPMENT_TYPES.TIE_LINE, EQUIPMENT_INFOS_TYPES.TAB.type From 7653e64b20d3a89163ffe2a63363548e97604798 Mon Sep 17 00:00:00 2001 From: souissimai Date: Wed, 18 Dec 2024 10:33:18 +0100 Subject: [PATCH 05/51] create root network Signed-off-by: souissimai --- .../dialogs/element-creation-dialog.tsx | 2 +- src/components/dialogs/import-case-dialog.tsx | 5 +- .../curve/dialog/equipment-filter.tsx | 2 +- .../menus/network-modification-menu.type.ts | 5 +- .../graph/menus/root-network-node-editor.tsx | 573 ++++++------------ src/components/network/network-map-tab.tsx | 4 +- src/components/study-container.jsx | 7 +- src/redux/actions.ts | 5 +- src/redux/reducer.ts | 5 - src/services/network-conversion.ts | 2 +- src/services/root-network.ts | 67 +- src/translations/en.json | 1 + src/translations/fr.json | 2 + 13 files changed, 229 insertions(+), 451 deletions(-) diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx index 4396ac7608..435b408514 100644 --- a/src/components/dialogs/element-creation-dialog.tsx +++ b/src/components/dialogs/element-creation-dialog.tsx @@ -75,7 +75,7 @@ const ElementCreationDialog: React.FC = ({ }) => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const { snackError } = useSnackMessage(); const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); diff --git a/src/components/dialogs/import-case-dialog.tsx b/src/components/dialogs/import-case-dialog.tsx index 158250c444..0de13e1e08 100644 --- a/src/components/dialogs/import-case-dialog.tsx +++ b/src/components/dialogs/import-case-dialog.tsx @@ -12,14 +12,11 @@ interface ImportCaseDialogProps { const ImportCaseDialog: FunctionComponent = ({ open, onClose, onSelectCase }) => { const intl = useIntl(); - const studyUuid = useSelector((state: AppState) => state.studyUuid); - const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); - const currentNode = useSelector((state: AppState) => state.currentTreeNode); const processSelectedElements = (selectedElements: TreeViewFinderNodeProps[]) => { if (selectedElements && selectedElements.length > 0) { const selectedCase = selectedElements[0]; // Assuming single selection - onSelectCase(selectedCase); + onSelectCase(selectedCase); } onClose(); }; diff --git a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx index 20379e141a..d296c07475 100644 --- a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx +++ b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx @@ -120,7 +120,7 @@ const EquipmentFilter = forwardRef { diff --git a/src/components/graph/menus/network-modification-menu.type.ts b/src/components/graph/menus/network-modification-menu.type.ts index 48ca673560..42214c7dcc 100644 --- a/src/components/graph/menus/network-modification-menu.type.ts +++ b/src/components/graph/menus/network-modification-menu.type.ts @@ -6,7 +6,10 @@ */ import { UUID } from 'crypto'; - +export interface RootNetworkMetadata { + rootNetworkUuid: UUID; + isCreating: boolean; +} export interface NetworkModificationMetadata { uuid: UUID; type: string; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index adb7a30f37..4a932a81d2 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -5,60 +5,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { - CheckBoxList, - ElementType, - MODIFICATION_TYPES, - Parameter, - useModificationLabelComputer, - useSnackMessage, -} from '@gridsuite/commons-ui'; +import { CheckBoxList, ElementType, Parameter, useSnackMessage } from '@gridsuite/commons-ui'; import CreateNewFolderIcon from '@mui/icons-material/CreateNewFolder'; import DeleteIcon from '@mui/icons-material/Delete'; import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography } from '@mui/material'; import IconButton from '@mui/material/IconButton'; -import BatteryCreationDialog from 'components/dialogs/network-modifications/battery/creation/battery-creation-dialog'; -import BatteryModificationDialog from 'components/dialogs/network-modifications/battery/modification/battery-modification-dialog'; -import DeleteAttachingLineDialog from 'components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-dialog'; -import DeleteVoltageLevelOnLineDialog from 'components/dialogs/network-modifications/delete-voltage-level-on-line/delete-voltage-level-on-line-dialog'; -import EquipmentDeletionDialog from 'components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog'; -import GenerationDispatchDialog from 'components/dialogs/network-modifications/generation-dispatch/generation-dispatch-dialog'; -import GeneratorScalingDialog from 'components/dialogs/network-modifications/generator-scaling/generator-scaling-dialog'; -import GeneratorCreationDialog from 'components/dialogs/network-modifications/generator/creation/generator-creation-dialog'; -import GeneratorModificationDialog from 'components/dialogs/network-modifications/generator/modification/generator-modification-dialog'; -import LineAttachToVoltageLevelDialog from 'components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-dialog'; -import LineSplitWithVoltageLevelDialog from 'components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-dialog'; -import LineCreationDialog from 'components/dialogs/network-modifications/line/creation/line-creation-dialog'; -import LineModificationDialog from 'components/dialogs/network-modifications/line/modification/line-modification-dialog'; -import LinesAttachToSplitLinesDialog from 'components/dialogs/network-modifications/lines-attach-to-split-lines/lines-attach-to-split-lines-dialog'; -import LoadScalingDialog from 'components/dialogs/network-modifications/load-scaling/load-scaling-dialog'; -import { LoadCreationDialog } from '../../dialogs/network-modifications/load/creation/load-creation-dialog'; -import LoadModificationDialog from 'components/dialogs/network-modifications/load/modification/load-modification-dialog'; -import ShuntCompensatorCreationDialog from 'components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog'; -import ShuntCompensatorModificationDialog from 'components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog'; -import SubstationCreationDialog from 'components/dialogs/network-modifications/substation/creation/substation-creation-dialog'; -import SubstationModificationDialog from 'components/dialogs/network-modifications/substation/modification/substation-modification-dialog'; -import TabularCreationDialog from 'components/dialogs/network-modifications/tabular-creation/tabular-creation-dialog'; -import TabularModificationDialog from 'components/dialogs/network-modifications/tabular-modification/tabular-modification-dialog'; -import TwoWindingsTransformerCreationDialog from 'components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog'; -import VoltageInitModificationDialog from 'components/dialogs/network-modifications/voltage-init-modification/voltage-init-modification-dialog'; -import VoltageLevelCreationDialog from 'components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog'; -import VoltageLevelModificationDialog from 'components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog'; -import VscCreationDialog from 'components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog'; -import VscModificationDialog from 'components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog'; -import NetworkModificationsMenu from 'components/graph/menus/network-modifications-menu'; import { UPDATE_TYPE } from 'components/network/constants'; import { useCallback, useEffect, useRef, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; -import { - addNotification, - removeNotificationByNode, - resetLogsFilter, - setModificationsInProgress, -} from '../../../redux/actions'; +import { removeNotificationByNode, setModificationsInProgress } from '../../../redux/actions'; import TwoWindingsTransformerModificationDialog from '../../dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog'; import { useIsAnyNodeBuilding } from '../../utils/is-any-node-building-hook'; @@ -66,37 +24,26 @@ import RestoreModificationDialog from 'components/dialogs/restore-modification-d import { UUID } from 'crypto'; import { DropResult } from 'react-beautiful-dnd'; import { AppState, StudyUpdated } from 'redux/reducer'; -import { createCompositeModifications } from '../../../services/explore'; import { fetchNetworkModification } from '../../../services/network-modification'; -import { - changeNetworkModificationOrder, - fetchNetworkModifications, - stashModifications, -} from '../../../services/study/network-modifications'; +import { changeNetworkModificationOrder, stashModifications } from '../../../services/study/network-modifications'; import { FetchStatus } from '../../../services/utils'; import ElementCreationDialog, { IElementCreationDialog, IElementCreationDialog1, } from '../../dialogs/element-creation-dialog'; import { - MenuDefinition, - MenuDefinitionSubItem, - MenuDefinitionWithoutSubItem, NetworkModificationCopyInfo, - NetworkModificationCopyType, NetworkModificationData, NetworkModificationMetadata, + RootNetworkMetadata, } from './network-modification-menu.type'; -import { SwitchNetworkModificationActive } from './switch-network-modification-active'; -import StaticVarCompensatorCreationDialog from '../../dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog'; -import ModificationByAssignmentDialog from '../../dialogs/network-modifications/by-filter/by-assignment/modification-by-assignment-dialog'; -import ByFormulaDialog from '../../dialogs/network-modifications/by-filter/by-formula/by-formula-dialog'; -import ByFilterDeletionDialog from '../../dialogs/network-modifications/by-filter/by-filter-deletion/by-filter-deletion-dialog'; -import { LccCreationDialog } from '../../dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog'; -import ImportCaseDialog from 'components/dialogs/import-case-dialog'; -import CreateCaseDialog from 'components/dialogs/create-case-dialog'; -import { createRootNetwork } from 'services/root-network'; -import { CaseImportParameters, GetCaseImportParametersReturn, getCaseImportParameters } from 'services/network-conversion'; + +import { + CaseImportParameters, + GetCaseImportParametersReturn, + getCaseImportParameters, +} from 'services/network-conversion'; +import { createRootNetwork, fetchRootNetworks } from 'services/root-network'; export const styles = { listContainer: (theme: Theme) => ({ @@ -199,18 +146,18 @@ export function isPartial(s1: number, s2: number) { const RootNetworkNodeEditor = () => { const notificationIdList = useSelector((state: AppState) => state.notificationIdList); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); + const rootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const { snackInfo, snackError } = useSnackMessage(); - const [modifications, setModifications] = useState([]); + const [rootNetworks, setRootNetworks] = useState([]); const [saveInProgress, setSaveInProgress] = useState(false); const [deleteInProgress, setDeleteInProgress] = useState(false); - const [modificationsToRestore, setModificationsToRestore] = useState([]); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); const currentNodeIdRef = useRef(); // initial empty to get first update const [pendingState, setPendingState] = useState(false); - const [selectedItems, setSelectedItems] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [copiedModifications, setCopiedModifications] = useState([]); const [copyInfos, setCopyInfos] = useState(null); const copyInfosRef = useRef(); @@ -258,94 +205,36 @@ const RootNetworkNodeEditor = () => { setEditData(undefined); }; - function withDefaultParams(Dialog: React.FC) { - return ( - - ); - } - - - const fillNotification = useCallback( - (study: StudyUpdated, messageId: string) => { - // (work for all users) - // specific message id for each action type - setMessageId(messageId); - dispatch(addNotification([study.eventData.headers.parentNode ?? []])); - }, - [dispatch] - ); - - const manageNotification = useCallback( - (study: StudyUpdated) => { - let messageId; - switch (study.eventData.headers['updateType']) { - case 'creatingInProgress': - messageId = 'network_modifications.creatingModification'; - break; - case 'updatingInProgress': - messageId = 'network_modifications.updatingModification'; - break; - case 'stashingInProgress': - messageId = 'network_modifications.stashingModification'; - break; - case 'restoringInProgress': - messageId = 'network_modifications.restoringModification'; - break; - default: - messageId = ''; - } - fillNotification(study, messageId); - }, - [fillNotification] - ); - - const updateSelectedItems = useCallback((modifications: NetworkModificationMetadata[]) => { - const toKeepIdsSet = new Set(modifications.map((e) => e.uuid)); - setSelectedItems((oldselectedItems) => oldselectedItems.filter((s) => toKeepIdsSet.has(s.uuid))); + const updateSelectedItems = useCallback((rootNetworks: RootNetworkMetadata[]) => { + const toKeepIdsSet = new Set(rootNetworks.map((e) => e.rootNetworkUuid)); + setSelectedItems((oldselectedItems) => oldselectedItems.filter((s) => toKeepIdsSet.has(s.rootNetworkUuid))); }, []); - const dofetchNetworkModifications = useCallback(() => { - console.log('fetchiiiiiiiiiiing ?????'); - - // Do not fetch modifications on the root node - if (currentNode?.type !== 'NETWORK_MODIFICATION') { - return; - } + const dofetchRootNetworks = useCallback(() => { setLaunchLoader(true); - console.log('fetchiiiiiiiiiiing ?????'); - fetchNetworkModifications(studyUuid, currentNode.id, false) - .then((res: NetworkModificationMetadata[]) => { - // Check if during asynchronous request currentNode has already changed - // otherwise accept fetch results - if (currentNode.id === currentNodeIdRef.current) { - const liveModifications = res.filter( - (networkModification) => networkModification.stashed === false - ); - updateSelectedItems(liveModifications); - setModifications(liveModifications); - setModificationsToRestore( - res.filter((networkModification) => networkModification.stashed === true) - ); - } - }) - .catch((error) => { - snackError({ - messageTxt: error.message, + + if (studyUuid) { + fetchRootNetworks(studyUuid) + .then((res: RootNetworkMetadata[]) => { + // Check if during asynchronous request currentNode has already changed + // otherwise accept fetch results + // if (currentNode.id === currentNodeIdRef.current) { + + updateSelectedItems(res); + setRootNetworks(res); + // } + }) + .catch((error) => { + snackError({ + messageTxt: error.message, + }); + }) + .finally(() => { + setPendingState(false); + setLaunchLoader(false); + // dispatch(setModificationsInProgress(false)); }); - }) - .finally(() => { - setPendingState(false); - setLaunchLoader(false); - dispatch(setModificationsInProgress(false)); - }); + } }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); useEffect(() => { @@ -356,87 +245,80 @@ const RootNetworkNodeEditor = () => { // first time with currentNode initialized then fetch modifications // (because if currentNode is not initialized, dofetchNetworkModifications silently does nothing) // OR next time if currentNodeId changed then fetch modifications - if (currentNode && (!currentNodeIdRef.current || currentNodeIdRef.current !== currentNode.id)) { - currentNodeIdRef.current = currentNode.id; + // if (currentNode && currentRootNetwork) { + if ( currentRootNetwork) { + // currentNodeIdRef.current = currentNode.id; // Current node has changed then clear the modifications list - setModifications([]); - setModificationsToRestore([]); - dofetchNetworkModifications(); + setRootNetworks([]); + dofetchRootNetworks(); // reset the network modification and computing logs filter when the user changes the current node - dispatch(resetLogsFilter()); + // dispatch(resetLogsFilter()); } - }, [currentNode, dispatch, dofetchNetworkModifications]); - - useEffect(() => { - if (studyUpdatedForce.eventData.headers) { - if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { - if ( - copyInfosRef.current && - studyUpdatedForce.eventData.headers['nodes']?.some( - (nodeId) => nodeId === copyInfosRef.current?.originNodeUuid - ) - ) { - // Must clean modifications clipboard if the origin Node is removed - cleanClipboard(); - } - } - if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { - return; - } - - if ( - studyUpdatedForce.eventData.headers['updateType'] && - // @ts-expect-error TS2345: Argument of type string is not assignable to parameter of type UPDATE_TYPE (a restrained array of strings) - UPDATE_TYPE.includes(studyUpdatedForce.eventData.headers['updateType']) - ) { - if (studyUpdatedForce.eventData.headers['updateType'] === 'deletingInProgress') { - // deleting means removing from trashcan (stashed elements) so there is no network modification - setDeleteInProgress(true); - } else { - dispatch(setModificationsInProgress(true)); - setPendingState(true); - manageNotification(studyUpdatedForce); - } - } - // notify finished action (success or error => we remove the loader) - // error handling in dialog for each equipment (snackbar with specific error showed only for current user) - if (studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED') { - // fetch modifications because it must have changed - // Do not clear the modifications list, because currentNode is the concerned one - // this allows to append new modifications to the existing list. - dofetchNetworkModifications(); - dispatch( - removeNotificationByNode([ - studyUpdatedForce.eventData.headers['parentNode'], - ...(studyUpdatedForce.eventData.headers.nodes ?? []), - ]) - ); - } - if (studyUpdatedForce.eventData.headers['updateType'] === 'DELETE_FINISHED') { - setDeleteInProgress(false); - dofetchNetworkModifications(); - } - } - }, [dispatch, dofetchNetworkModifications, manageNotification, studyUpdatedForce, cleanClipboard]); - - const [openNetworkModificationsMenu, setOpenNetworkModificationsMenu] = useState(false); + }, [currentRootNetwork, dofetchRootNetworks]); + + +// TODO MANAGE NOTIFICATION + // useEffect(() => { + // if (studyUpdatedForce.eventData.headers) { + // if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { + // if ( + // copyInfosRef.current && + // studyUpdatedForce.eventData.headers['nodes']?.some( + // (nodeId) => nodeId === copyInfosRef.current?.originNodeUuid + // ) + // ) { + // // Must clean modifications clipboard if the origin Node is removed + // cleanClipboard(); + // } + // } + // if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { + // return; + // } + + // if ( + // studyUpdatedForce.eventData.headers['updateType'] && + // // @ts-expect-error TS2345: Argument of type string is not assignable to parameter of type UPDATE_TYPE (a restrained array of strings) + // UPDATE_TYPE.includes(studyUpdatedForce.eventData.headers['updateType']) + // ) { + // if (studyUpdatedForce.eventData.headers['updateType'] === 'deletingInProgress') { + // // deleting means removing from trashcan (stashed elements) so there is no network modification + // setDeleteInProgress(true); + // } else { + // dispatch(setModificationsInProgress(true)); + // setPendingState(true); + // } + // } + // // notify finished action (success or error => we remove the loader) + // // error handling in dialog for each equipment (snackbar with specific error showed only for current user) + // if (studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED') { + // // fetch modifications because it must have changed + // // Do not clear the modifications list, because currentNode is the concerned one + // // this allows to append new modifications to the existing list. + // dofetchRootNetworks(); + // dispatch( + // removeNotificationByNode([ + // studyUpdatedForce.eventData.headers['parentNode'], + // ...(studyUpdatedForce.eventData.headers.nodes ?? []), + // ]) + // ); + // } + // if (studyUpdatedForce.eventData.headers['updateType'] === 'DELETE_FINISHED') { + // setDeleteInProgress(false); + // dofetchRootNetworks(); + // } + // } + // }, [dispatch, dofetchRootNetworks, studyUpdatedForce, cleanClipboard]); const isAnyNodeBuilding = useIsAnyNodeBuilding(); const mapDataLoading = useSelector((state: AppState) => state.mapDataLoading); - const closeNetworkModificationConfiguration = () => { - setOpenNetworkModificationsMenu(false); - setEditData(undefined); - setEditDataFetchStatus(FetchStatus.IDLE); - }; - const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); }, []); const doDeleteModification = useCallback(() => { - const selectedModificationsUuid = selectedItems.map((item) => item.uuid); + const selectedModificationsUuid = selectedItems.map((item) => item.rootNetworkUuid); stashModifications(studyUuid, currentNode?.id, selectedModificationsUuid) .then(() => { //if one of the deleted element was in the clipboard we invalidate the clipboard @@ -472,111 +354,39 @@ const RootNetworkNodeEditor = () => { return dataTemp; }, []); - const doEditModification = useCallback( - (modificationUuid: UUID, type: string) => { - setIsUpdate(true); - setEditDialogOpen(type); - setEditDataFetchStatus(FetchStatus.RUNNING); - const modification = fetchNetworkModification(modificationUuid); - modification - .then((res) => { - return res.json().then((data: NetworkModificationData) => { - //remove all null values to avoid showing a "null" in the forms - setEditData(removeNullFields(data)); - setEditDataFetchStatus(FetchStatus.SUCCEED); - }); - }) - .catch((error) => { - snackError({ - messageTxt: error.message, - }); - setEditDataFetchStatus(FetchStatus.FAILED); - }); - }, - [removeNullFields, snackError] - ); - - const onItemClick = (id: string) => { - setOpenNetworkModificationsMenu(false); - setEditDialogOpen(id); - setIsUpdate(false); - }; + - const toggleSelectAllModifications = useCallback(() => { - setSelectedItems((oldVal) => (oldVal.length === 0 ? modifications : [])); - }, [modifications]); - - - const commit = useCallback( - ({ source, destination }: DropResult) => { - setIsDragging(false); - if (!currentNode?.id || !destination || source.index === destination.index) { - return; - } - const res = [...modifications]; - const [item] = res.splice(source.index, 1); - const before = res[destination.index]?.uuid; - res.splice(destination ? destination.index : modifications.length, 0, item); - - /* doing the local change before update to server */ - setModifications(res); - changeNetworkModificationOrder(studyUuid, currentNode.id, item.uuid, before).catch((error) => { - snackError({ - messageTxt: error.message, - headerId: 'errReorderModificationMsg', - }); - setModifications(modifications); // rollback - }); - }, - [modifications, studyUuid, currentNode?.id, snackError] - ); + const toggleSelectAllRootNetworks = useCallback(() => { + setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); + }, [rootNetworks]); + const isLoading = useCallback(() => { return notificationIdList.filter((notification) => notification === currentNode?.id).length > 0; }, [notificationIdList, currentNode?.id]); const intl = useIntl(); - const { computeLabel } = useModificationLabelComputer(); - const getModificationLabel = (modif: NetworkModificationMetadata): string => { - if (!modif) { + const getRootNetworkLabel = (rootNetwork: RootNetworkMetadata): string => { + if (!rootNetwork) { return ''; } - return intl.formatMessage( - { id: 'network_modifications.' + modif.messageType }, - { - ...modif, - ...computeLabel(modif), - } - ); + // return intl.formatMessage( + // { id: 'network_modifications.' + modif.messageType }, + // { + // ...modif, + // ...computeLabel(modif), + // } + // ); + return intl.formatMessage({ id: 'root_network' }) + rootNetwork.rootNetworkUuid; }; - const handleSecondaryAction = useCallback( - (modification: NetworkModificationMetadata, isItemHovered?: boolean) => { - return isItemHovered && !isDragging ? ( - - ) : null; - }, - [isAnyNodeBuilding, isDragging, mapDataLoading, isLoading] - ); - - const isModificationClickable = useCallback( - (modification: NetworkModificationMetadata) => - !isAnyNodeBuilding && !mapDataLoading && !isDragging && isEditableModification(modification), - [isAnyNodeBuilding, mapDataLoading, isDragging] - ); - - const renderNetworkModificationsList = () => { + const renderRootNetworksList = () => { return ( ({ + items: (rootNetwork) => ({ label: { - ...(!modification.activated && { ...styles.disabledModification }), + ...(!rootNetwork.isCreating && { ...styles.disabledModification }), ...styles.checkBoxLabel, }, checkBoxIcon: styles.checkBoxIcon, @@ -585,25 +395,24 @@ const RootNetworkNodeEditor = () => { dragAndDropContainer: styles.listContainer, }} onItemClick={(modification) => { - isModificationClickable(modification) && doEditModification(modification.uuid, modification.type); + console.log(modification.rootNetworkUuid, 'on click'); }} - isItemClickable={isModificationClickable} selectedItems={selectedItems} onSelectionChange={setSelectedItems} - items={modifications} - getItemId={(val) => val.uuid} - getItemLabel={getModificationLabel} - isDndDragAndDropActive - isDragDisable={isLoading() || isAnyNodeBuilding || mapDataLoading || deleteInProgress} - secondaryAction={handleSecondaryAction} - onDragEnd={commit} - onDragStart={() => setIsDragging(true)} + items={rootNetworks} + getItemId={(val) => val.rootNetworkUuid} + getItemLabel={getRootNetworkLabel} + // isDndDragAndDropActive + // isDragDisable={isLoading() || isAnyNodeBuilding || mapDataLoading || deleteInProgress} + // secondaryAction={handleSecondaryAction} + // onDragEnd={commit} + // onDragStart={() => setIsDragging(true)} divider /> ); }; - const renderNetworkModificationsListTitleLoading = () => { + const renderRootNetworksListTitleLoading = () => { return ( @@ -616,7 +425,7 @@ const RootNetworkNodeEditor = () => { ); }; - const renderNetworkModificationsListTitleUpdating = () => { + const renderRootNetworksListTitleUpdating = () => { return ( @@ -629,7 +438,7 @@ const RootNetworkNodeEditor = () => { ); }; - const renderNetworkModificationsListTitle = () => { + const renderRootNetworksListTitle = () => { return ( @@ -639,7 +448,7 @@ const RootNetworkNodeEditor = () => { @@ -648,20 +457,6 @@ const RootNetworkNodeEditor = () => { ); }; - // const renderCaseSelectionDialog = () => { - // // return ( - // // setCaseSelectionDialogOpen(false)} - // // type={ElementType.ROOT_NETWORK} - // // titleId={'CreateRootNetwork'} - // // prefixIdForGeneratedName={'GeneratedModification'} - // // /> - // // ); - // return setCaseSelectionDialogOpen(false)} />; - // }; - const renderRootNetworkCreationDialog = () => { return ( { titleId={'CreateRootNetwork'} /> ); - - //return setRootNetworkCreationDialogOpen(false)} />; }; - /* Effects */ - // handle create r from existing case - useEffect(() => { - // getCurrentCaseImportParams(providedExistingCase.elementUuid); - - }, []); function formatCaseImportParameters(params: CaseImportParameters[]): CaseImportParameters[] { // sort possible values alphabetically to display select options sorted return params?.map((parameter) => ({ @@ -693,12 +480,11 @@ const RootNetworkNodeEditor = () => { (caseUuid: UUID) => { getCaseImportParameters(caseUuid) .then((result: GetCaseImportParametersReturn) => { - console.log(result) - const formattedParams = formatCaseImportParameters(result.parameters); - const caseFormat = result.formatName ; - }) + console.log(result); + const formattedParams = formatCaseImportParameters(result.parameters); + const caseFormat = result.formatName; + }) .catch(() => { - // setError(`root.${FieldConstants.API_CALL}`, { // type: 'parameterLoadingProblem', // message: intl.formatMessage({ @@ -707,45 +493,62 @@ const RootNetworkNodeEditor = () => { // }); }); }, - [intl ] + [intl] ); - const doCreateRootNetwork = ({ name, caseName, caseId }: IElementCreationDialog1) => { - console.log('fetcccccccccch ???? ', name, caseName, caseId); + function customizeCurrentParameters(params: Parameter[]): Record { + return params.reduce((obj, parameter) => { + // we check if the parameter is for extensions. If so, we select all possible values by default. + // the only way for the moment to check if the parameter is for extension, is by checking his name. + // TODO: implement a cleaner way to determine the extensions field + if (parameter.type === 'STRING_LIST' && parameter.name?.endsWith('extensions')) { + return { ...obj, [parameter.name]: parameter.possibleValues.toString() }; + } + return obj; + }, {} as Record); + } + + const doCreateRootNetwork = ({ name, caseName, caseId }: IElementCreationDialog1) => { setSaveInProgress(true); - // createRootNetwork( caseId , - // "XIIDM", - // studyUuid, - // importParameters) - // createCompositeModifications(name, description, folderId, selectedModificationsUuid) - // .then(() => { - // snackInfo({ - // headerId: 'infoCreateModificationsMsg', - // headerValues: { - // nbModifications: String(selectedItems.length), - // studyDirectory: '/' + folderName, - // }, - // }); - // }) - // .catch((errmsg) => { - // snackError({ - // messageTxt: errmsg, - // headerId: 'errCreateModificationsMsg', - // }); - // }) - // .finally(() => { - // setSaveInProgress(false); - // }); + + getCaseImportParameters(caseId) + .then((params: GetCaseImportParametersReturn) => { + // Format the parameters + const formattedParams = formatCaseImportParameters(params.parameters); + const customizedCurrentParameters = customizeCurrentParameters(formattedParams as Parameter[]); + // Call createRootNetwork with formatted parameters + + return createRootNetwork(caseId, params.formatName, studyUuid, customizedCurrentParameters); + }) + .then(() => { + // Success handler + snackInfo({ + headerId: 'infoCreateRootNetworkMsg', + headerValues: { + rootNetworkName: name, + }, + }); + }) + .catch((error) => { + // Error handler + snackError({ + messageTxt: error.message, + headerId: 'errCreateRootNetworksMsg', + }); + }) + .finally(() => { + setSaveInProgress(false); + }); }; const renderPaneSubtitle = () => { if (isLoading() && messageId) { - return renderNetworkModificationsListTitleLoading(); + return renderRootNetworksListTitleLoading(); } if (launchLoader) { - return renderNetworkModificationsListTitleUpdating(); + return renderRootNetworksListTitleUpdating(); } - return renderNetworkModificationsListTitle(); + return renderRootNetworksListTitle(); }; return ( @@ -756,13 +559,13 @@ const RootNetworkNodeEditor = () => { color={'primary'} edge="start" checked={isChecked(selectedItems.length)} - indeterminate={isPartial(selectedItems.length, modifications?.length)} + indeterminate={isPartial(selectedItems.length, rootNetworks?.length)} disableRipple - onClick={toggleSelectAllModifications} + onClick={toggleSelectAllRootNetworks} /> - }> + }> { {rootNetworkCreationDialogOpen && renderRootNetworkCreationDialog()} {renderPaneSubtitle()} - {renderNetworkModificationsList()} - - + {renderRootNetworksList()} ); }; diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 43beee9b68..361be29a72 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -618,7 +618,7 @@ export const NetworkMapTab = ({ .finally(() => { dispatch(setMapDataLoading(false)); }); - }, [rootNodeId, lineFullPath, studyUuid, dispatch, snackError]); + }, [rootNodeId, currentRootNetwork, lineFullPath, studyUuid, dispatch, snackError]); const loadGeoData = useCallback(() => { if (studyUuid && currentNodeRef.current) { @@ -664,7 +664,7 @@ export const NetworkMapTab = ({ if (gSMapEquipments) { dispatch(resetMapReloaded()); } - }, [currentNode, dispatch, intlRef, snackError, studyUuid]); + }, [currentNode, currentRootNetwork, dispatch, intlRef, snackError, studyUuid]); const reloadMapEquipments = useCallback( (currentNodeAtReloadCalling: CurrentTreeNode | null, substationsIds: UUID[] | undefined) => { diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 8f993f04f9..d6f2412862 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -137,8 +137,7 @@ function useStudy(studyUuidRequest) { fetchStudyExists(studyUuidRequest) .then(() => { setStudyUuid(studyUuidRequest); - dispatch(setCurrentRootNetwork('18be57cd-a4a4-4844-b285-98ac2e66f095')); - //get root network + dispatch(setCurrentRootNetwork('c7b1672a-8eba-45da-b761-675a8c5ec9b5')); }) .catch((error) => { if (error.status === HttpStatusCode.NOT_FOUND) { @@ -150,7 +149,7 @@ function useStudy(studyUuidRequest) { } }) .finally(() => setPending(false)); - }, [studyUuidRequest, intlRef]); + }, [studyUuidRequest, dispatch, intlRef]); return [studyUuid, pending, errMessage]; } @@ -589,7 +588,7 @@ export function StudyContainer({ view, onChangeTab }) { ); }); }, - [studyUuid, checkStudyIndexation, loadTree, snackWarning, intlRef] + [studyUuid, currentRootNetwork, dispatch, checkStudyIndexation, loadTree, snackWarning, intlRef] ); useEffect(() => { diff --git a/src/redux/actions.ts b/src/redux/actions.ts index 221e944ceb..f73851f949 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -422,10 +422,9 @@ export function setParamsLoaded(): SetParamsLoadedAction { export const OPEN_STUDY = 'OPEN_STUDY'; export type OpenStudyAction = Readonly> & { studyRef: [UUID]; - rootNetworkRef: [UUID]; }; -export function openStudy(studyUuid: UUID, rootNetworkUuid: UUID): OpenStudyAction { - return { type: OPEN_STUDY, studyRef: [studyUuid], rootNetworkRef: [rootNetworkUuid] }; +export function openStudy(studyUuid: UUID): OpenStudyAction { + return { type: OPEN_STUDY, studyRef: [studyUuid] }; } export const CLOSE_STUDY = 'CLOSE_STUDY'; diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index a824400d87..6119df4345 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -461,7 +461,6 @@ export interface AppState extends CommonStoreState { studyUpdated: StudyUpdated; studyUuid: UUID | null; - rootNetworkUuid: UUID | null; currentTreeNode: CurrentTreeNode | null; currentRootNetwork: UUID | null; computingStatus: ComputingStatus; @@ -625,7 +624,6 @@ const initialTablesState: TablesState = { const initialState: AppState = { studyUuid: null, - rootNetworkUuid: null, currentTreeNode: null, currentRootNetwork: null, selectionForCopy: { @@ -829,8 +827,6 @@ const initialState: AppState = { export const reducer = createReducer(initialState, (builder) => { builder.addCase(OPEN_STUDY, (state, action: OpenStudyAction) => { state.studyUuid = action.studyRef[0]; - state.rootNetworkUuid = action.rootNetworkRef[0]; - console.log('=================== ', action.studyRef); if (action.studyRef[0] != null) { state.diagramStates = loadDiagramStateFromSessionStorage(action.studyRef[0]); @@ -839,7 +835,6 @@ export const reducer = createReducer(initialState, (builder) => { builder.addCase(CLOSE_STUDY, (state, action: CloseStudyAction) => { state.studyUuid = null; - state.rootNetworkUuid = null; state.geoData = null; state.networkModificationTreeModel = null; }); diff --git a/src/services/network-conversion.ts b/src/services/network-conversion.ts index ffa815c369..4f497df213 100644 --- a/src/services/network-conversion.ts +++ b/src/services/network-conversion.ts @@ -23,7 +23,7 @@ export interface GetCaseImportParametersReturn { parameters: CaseImportParameters[]; } -export function getCaseImportParameters(caseUuid: UUID): Promise { +export function getCaseImportParameters(caseUuid: UUID | undefined): Promise { console.info(`get import parameters for case '${caseUuid}' ...`); const getExportFormatsUrl = PREFIX_NETWORK_CONVERSION_SERVER_QUERIES + '/v1/cases/' + caseUuid + '/import-parameters'; diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 4ebd5f1003..b2e1666743 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -5,64 +5,45 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { backendFetch } from './utils'; +import { backendFetch, backendFetchJson } from './utils'; import { UUID } from 'crypto'; import { ElementType } from '@gridsuite/commons-ui'; export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; -export function createRootNetworka( - newParameter: any, - name: string, - parameterType: ElementType, - description: string, - studyUuid: UUID -) { - let urlSearchParams = new URLSearchParams(); - urlSearchParams.append('name', name); - urlSearchParams.append('type', parameterType); - urlSearchParams.append('description', description); - urlSearchParams.append('studyUuid', studyUuid); - - urlSearchParams.toString(); - const createRootNetworkUrl = - PREFIX_STUDY_QUERIES + - '/v1/studies/' + - encodeURIComponent(studyUuid) + - '/root-networks?' + +export function fetchRootNetworks(studyUuid: UUID) { + console.info('Fetching root network for studyUuid : ', studyUuid); + const urlSearchParams = new URLSearchParams(); + const rootNetworkssGetUrl = + `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks` + urlSearchParams.toString(); - console.debug(createRootNetworkUrl); - - return backendFetch(createRootNetworkUrl, { - method: 'post', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(newParameter), - }); + console.debug(rootNetworkssGetUrl); + return backendFetchJson(rootNetworkssGetUrl); } export const createRootNetwork = ( - caseUuid: UUID, + caseUuid: UUID | undefined, caseFormat: string, - studyUuid: UUID, + studyUuid: UUID | null, importParameters: Record ) => { - const urlSearchParams = new URLSearchParams(); - urlSearchParams.append('caseUuid', caseUuid); - urlSearchParams.append('caseFormat', caseFormat); + if (!studyUuid || !caseUuid) { + throw new Error('studyUuid and caseUuid are required parameters.'); + } - const recreateStudyNetworkUrl = + const createRootNetworkUrl = PREFIX_STUDY_QUERIES + - '/v1/studies/' + - encodeURIComponent(studyUuid) + - '/network?' + - urlSearchParams.toString(); + `/v1/studies/${encodeURIComponent(studyUuid)}/root-networks?` + + `caseUuid=${encodeURIComponent(caseUuid)}&` + + `caseFormat=${encodeURIComponent(caseFormat)}`; - console.debug(recreateStudyNetworkUrl); - - return backendFetch(recreateStudyNetworkUrl, { - method: 'post', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(importParameters), + console.debug(createRootNetworkUrl); + return backendFetch(createRootNetworkUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: importParameters ? JSON.stringify(importParameters) : '', }); }; diff --git a/src/translations/en.json b/src/translations/en.json index d19817585b..448ddd23f7 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1229,6 +1229,7 @@ "SaveModificationTo": "Save to GridExplore", "ModificationsSelection": "Modification selection", "errCreateModificationsMsg": "Network modifications creation error", + "errCreateRootNetworksMsg": "Root Networks creation error", "infoCreateModificationsMsg": "Composite modification of {nbModifications} unitary network modifications created in {studyDirectory}", "idSelector.idNeeded": "Please select an ID", "SpreadsheetFetchError": "An error occurred while fetching equipments in the spreadsheet", diff --git a/src/translations/fr.json b/src/translations/fr.json index ddf403c8ff..adc8b7b3d9 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1228,6 +1228,8 @@ "SaveModificationTo": "Enregistrer dans GridExplore", "ModificationsSelection": "Sélection des modifications", "errCreateModificationsMsg": "Une erreur est survenue lors de la création des modifications", + "errCreateRootNetworksMsg": "Une erreur est survenue lors de la création du réseau racine", + "infoCreateModificationsMsg": "Création d'une modification composite de {nbModifications} modifications unitaires dans {studyDirectory}", "idSelector.idNeeded": "Veuillez sélectionner un ID", "SpreadsheetFetchError": "Une erreur est survenue lors du chargement des ouvrages dans le tableur", From 9abc7b4a398b4ae7c542a712ae86b744693edbb1 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Wed, 18 Dec 2024 10:45:04 +0100 Subject: [PATCH 06/51] fix: node can now be built Signed-off-by: LE SAULNIER Kevin --- src/components/app-top-bar.jsx | 2 + src/components/diagrams/diagram-pane.tsx | 1 + src/components/network/gs-map-equipments.ts | 33 +++++++++++++--- src/components/network/network-map-tab.tsx | 9 ++++- src/components/run-button-container.jsx | 43 +++++++++++++-------- src/services/study/loadflow.js | 11 +++++- src/services/study/network.js | 4 +- src/services/study/security-analysis.js | 9 +++-- 8 files changed, 81 insertions(+), 31 deletions(-) diff --git a/src/components/app-top-bar.jsx b/src/components/app-top-bar.jsx index 245a024b3f..46cdfd5395 100644 --- a/src/components/app-top-bar.jsx +++ b/src/components/app-top-bar.jsx @@ -70,6 +70,7 @@ const AppTopBar = ({ user, tabIndex, onChangeTab, userManager }) => { const theme = useSelector((state) => state[PARAM_THEME]); const studyUuid = useSelector((state) => state.studyUuid); const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetwork = useSelector((state) => state.currentRootNetwork); const [isDialogSearchOpen, setIsDialogSearchOpen] = useState(false); const [appsAndUrls, setAppsAndUrls] = useState([]); @@ -175,6 +176,7 @@ const AppTopBar = ({ user, tabIndex, onChangeTab, userManager }) => { diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index f1a65a5a89..4e858df1a4 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -767,6 +767,7 @@ export function DiagramPane({ studyUuid, currentNode, showInSpreadsheet, visible // This effect will trigger the diagrams' forced update useEffect(() => { + console.log('TEST', studyUpdatedForce); if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === 'loadflowResult') { //TODO reload data more intelligently diff --git a/src/components/network/gs-map-equipments.ts b/src/components/network/gs-map-equipments.ts index ab5ee06f15..71f7512bef 100644 --- a/src/components/network/gs-map-equipments.ts +++ b/src/components/network/gs-map-equipments.ts @@ -137,11 +137,34 @@ export default class GSMapEquipments extends MapEquipments { this.initEquipments(studyUuid, currentNodeUuid, currentRootNetworkUuid); } - reloadImpactedSubstationsEquipments(studyUuid: UUID, currentNode: any, substationsIds: string[] | null) { - const updatedSubstations = fetchSubstationsMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedTieLines = fetchTieLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedHvdcLines = fetchHvdcLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); + reloadImpactedSubstationsEquipments( + studyUuid: UUID, + currentNode: any, + rootNetworkUuid: UUID, + substationsIds: string[] | null + ) { + const updatedSubstations = fetchSubstationsMapInfos( + studyUuid, + currentNode?.id, + rootNetworkUuid, + substationsIds, + true + ); + const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, rootNetworkUuid, substationsIds, true); + const updatedTieLines = fetchTieLinesMapInfos( + studyUuid, + currentNode?.id, + rootNetworkUuid, + substationsIds, + true + ); + const updatedHvdcLines = fetchHvdcLinesMapInfos( + studyUuid, + currentNode?.id, + rootNetworkUuid, + substationsIds, + true + ); updatedSubstations.catch((error) => { console.error(error.message); if (this.errHandler) { diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 361be29a72..2eee9118a8 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -673,7 +673,12 @@ export const NetworkMapTab = ({ } const { updatedSubstations, updatedLines, updatedTieLines, updatedHvdcLines } = mapEquipments - ? mapEquipments.reloadImpactedSubstationsEquipments(studyUuid, currentNode, substationsIds ?? null) + ? mapEquipments.reloadImpactedSubstationsEquipments( + studyUuid, + currentNode, + currentRootNetwork, + substationsIds ?? null + ) : { updatedSubstations: Promise.resolve([]), updatedLines: Promise.resolve([]), @@ -710,7 +715,7 @@ export const NetworkMapTab = ({ dispatch(setMapDataLoading(false)); }); }, - [currentNode, dispatch, mapEquipments, studyUuid] + [currentNode, currentRootNetwork, dispatch, mapEquipments, studyUuid] ); const updateMapEquipments = useCallback( diff --git a/src/components/run-button-container.jsx b/src/components/run-button-container.jsx index 58a2610ede..d5321a6f75 100644 --- a/src/components/run-button-container.jsx +++ b/src/components/run-button-container.jsx @@ -35,7 +35,7 @@ import { startStateEstimation, stopStateEstimation } from '../services/study/sta import { OptionalServicesNames, OptionalServicesStatus } from './utils/optional-services'; import { useOptionalServiceStatus } from '../hooks/use-optional-service-status'; -export function RunButtonContainer({ studyUuid, currentNode, disabled }) { +export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, disabled }) { const loadFlowStatus = useSelector((state) => state.computingStatus[ComputingType.LOAD_FLOW]); const securityAnalysisStatus = useSelector((state) => state.computingStatus[ComputingType.SECURITY_ANALYSIS]); @@ -116,7 +116,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { // close the contingency list selection window setShowContingencyListSelector(false); }, - () => startSecurityAnalysis(studyUuid, currentNode?.id, contingencyListNames), + () => startSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetwork, contingencyListNames), () => {}, null, null @@ -152,7 +152,8 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { startComputationAsync( ComputingType.LOAD_FLOW, null, - () => startLoadFlow(studyUuid, currentNode?.id, limitReductionParam / 100.0), + () => + startLoadFlow(studyUuid, currentNode?.id, currentRootNetwork, limitReductionParam / 100.0), () => {}, null, 'startLoadFlowError' @@ -169,7 +170,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.SECURITY_ANALYSIS, () => - stopSecurityAnalysis(studyUuid, currentNode?.id) + stopSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -179,7 +180,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { startComputationAsync( ComputingType.SENSITIVITY_ANALYSIS, null, - () => startSensitivityAnalysis(studyUuid, currentNode?.id), + () => startSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetwork), () => {}, null, 'startSensitivityAnalysisError' @@ -187,7 +188,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.SENSITIVITY_ANALYSIS, () => - stopSensitivityAnalysis(studyUuid, currentNode?.id) + stopSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -198,7 +199,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { ComputingType.NON_EVACUATED_ENERGY_ANALYSIS, null, () => { - return startNonEvacuatedEnergy(studyUuid, currentNode?.id); + return startNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetwork); }, () => {}, null, @@ -207,7 +208,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.NON_EVACUATED_ENERGY_ANALYSIS, () => - stopNonEvacuatedEnergy(studyUuid, currentNode?.id) + stopNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -217,7 +218,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { startComputationAsync( ComputingType.SHORT_CIRCUIT, null, - () => startShortCircuitAnalysis(studyUuid, currentNode?.id), + () => startShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetwork), () => {}, null, 'startShortCircuitError' @@ -225,7 +226,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.SHORT_CIRCUIT, () => - stopShortCircuitAnalysis(studyUuid, currentNode?.id) + stopShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -239,7 +240,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { setShowDynamicSimulationParametersSelector(true); } else { // start server side dynamic simulation directly - return startDynamicSimulation(studyUuid, currentNode?.id); + return startDynamicSimulation(studyUuid, currentNode?.id, currentRootNetwork); } }) .catch((error) => { @@ -251,7 +252,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.DYNAMIC_SIMULATION, () => - stopDynamicSimulation(studyUuid, currentNode?.id) + stopDynamicSimulation(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -261,7 +262,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { startComputationAsync( ComputingType.VOLTAGE_INITIALIZATION, null, - () => startVoltageInit(studyUuid, currentNode?.id), + () => startVoltageInit(studyUuid, currentNode?.id, currentRootNetwork), () => {}, null, 'startVoltageInitError' @@ -269,7 +270,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.VOLTAGE_INITIALIZATION, () => - stopVoltageInit(studyUuid, currentNode?.id) + stopVoltageInit(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, @@ -280,7 +281,7 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { ComputingType.STATE_ESTIMATION, null, () => { - return startStateEstimation(studyUuid, currentNode?.id); + return startStateEstimation(studyUuid, currentNode?.id, currentRootNetwork); }, () => {}, null, @@ -289,12 +290,20 @@ export function RunButtonContainer({ studyUuid, currentNode, disabled }) { }, actionOnRunnable() { actionOnRunnables(ComputingType.STATE_ESTIMATION, () => - stopStateEstimation(studyUuid, currentNode?.id) + stopStateEstimation(studyUuid, currentNode?.id, currentRootNetwork) ); }, }, }; - }, [dispatch, snackError, startComputationAsync, studyUuid, limitReductionParam, currentNode?.id]); + }, [ + dispatch, + snackError, + startComputationAsync, + studyUuid, + limitReductionParam, + currentNode?.id, + currentRootNetwork, + ]); // running status is refreshed more often, so we memoize it apart const getRunningStatus = useCallback( diff --git a/src/services/study/loadflow.js b/src/services/study/loadflow.js index 4326fb385e..b1bb846cb9 100644 --- a/src/services/study/loadflow.js +++ b/src/services/study/loadflow.js @@ -52,10 +52,17 @@ export function setLoadFlowProvider(studyUuid, newProvider) { export function startLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid, limitReduction) { console.info( - 'Running loadflow on ' + studyUuid + ' and node ' + currentNodeUuid + ' with limit reduction ' + limitReduction + 'Running loadflow on ' + + studyUuid + + ' on root network ' + + currentRootNetworkUuid + + ' and node ' + + currentNodeUuid + + ' with limit reduction ' + + limitReduction ); const startLoadFlowUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/loadflow/run?limitReduction=' + limitReduction.toString(); console.debug(startLoadFlowUrl); diff --git a/src/services/study/network.js b/src/services/study/network.js index fa9269dc19..1fbed82083 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -171,7 +171,7 @@ export function fetchNetworkElementInfos( inUpstreamBuiltParentNode ) { console.info( - `Fetching specific network element '${elementId}' of type '${elementType}' of study '${studyUuid}' and node '${currentNodeUuid}' ...` + `Fetching specific network element '${elementId}' of type '${elementType}' of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` ); const urlSearchParams = new URLSearchParams(); if (inUpstreamBuiltParentNode !== undefined) { @@ -182,7 +182,7 @@ export function fetchNetworkElementInfos( const optionalParams = new Map(); optionalParams.forEach((value, key) => urlSearchParams.append(`optionalParameters[${key}]`, value)); const fetchElementsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/elements/' + encodeURIComponent(elementId) + '?' + diff --git a/src/services/study/security-analysis.js b/src/services/study/security-analysis.js index 2ba9af1ba1..f3e4adc065 100644 --- a/src/services/study/security-analysis.js +++ b/src/services/study/security-analysis.js @@ -8,8 +8,10 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchFile, backendFetchJson, backendFetchText, getRequestParamFromList } from '../utils'; -export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyListNames) { - console.info(`Running security analysis on ${studyUuid} and node ${currentNodeUuid} ...`); +export function startSecurityAnalysis(studyUuid, currentNodeUuid, currentRootNetwork, contingencyListNames) { + console.info( + `Running security analysis on ${studyUuid} on root network ${currentRootNetwork} and node ${currentNodeUuid} ...` + ); // Add params to Url const contingencyListsQueryParams = getRequestParamFromList(contingencyListNames, 'contingencyListName'); @@ -17,7 +19,8 @@ export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyLis const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetwork )}/security-analysis/run?${urlSearchParams}`; console.debug(url); From 11d0b82941983fbd6f781e7f98a6242d6245b3d6 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 19 Dec 2024 11:45:12 +0100 Subject: [PATCH 07/51] changing endpoints Signed-off-by: souissimai --- .../computing-status/use-computing-status.ts | 11 +- .../dialogs/element-creation-dialog.tsx | 3 +- src/components/dialogs/import-case-dialog.tsx | 2 - .../curve/dialog/equipment-filter.tsx | 9 +- .../network-modification-node-editor.tsx | 5 + .../graph/menus/root-network-editor.tsx | 22 +-- .../graph/menus/root-network-node-editor.tsx | 153 +++++------------- src/components/left-drawer.jsx | 2 +- src/components/network/gs-map-equipments.ts | 39 ++++- .../selection-creation-panel/use-save-map.ts | 5 +- src/components/report-viewer-tab.jsx | 1 + src/components/result-view-tab.tsx | 64 ++++++-- .../dynamic-simulation-result-synthesis.tsx | 1 + .../dynamic-simulation-result-tab.jsx | 20 ++- .../dynamic-simulation-result-time-series.jsx | 3 +- .../dynamic-simulation-result-timeline.tsx | 1 + .../results/loadflow/load-flow-result-tab.tsx | 27 +++- .../results/loadflow/load-flow-result.type.ts | 1 + .../security-analysis-result-tab.tsx | 3 +- .../security-analysis.type.ts | 1 + .../non-evacuated-energy-result-tab.tsx | 6 +- .../non-evacuated-energy-result.type.ts | 1 + .../sensitivity-analysis-result-tab.jsx | 2 +- .../shortcircuit-analysis-export-button.tsx | 12 +- .../shortcircuit-analysis-result-tab.tsx | 3 + .../state-estimation-result-tab.tsx | 10 +- .../state-estimation-result.type.ts | 1 + .../spreadsheet/use-spreadsheet-equipments.ts | 30 +++- src/components/study-container.jsx | 39 ++++- src/components/study-pane.jsx | 5 +- src/components/voltage-init-result-tab.jsx | 2 +- src/hooks/use-report-fetcher.tsx | 10 +- src/services/dynamic-simulation.ts | 40 ++++- src/services/root-network.ts | 16 +- src/services/study/filter.ts | 7 +- src/services/study/index.ts | 35 ++-- src/services/study/loadflow.js | 14 +- src/services/study/network-map.ts | 19 ++- src/services/study/non-evacuated-energy.js | 6 +- src/services/study/security-analysis.js | 18 ++- src/services/study/short-circuit-analysis.js | 10 +- src/services/study/state-estimation.js | 4 +- src/services/study/voltage-init.js | 21 +-- src/translations/en.json | 3 + src/translations/fr.json | 4 + 45 files changed, 429 insertions(+), 262 deletions(-) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index 68a7db6ea0..75787e3afa 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -135,7 +135,16 @@ export const useComputingStatus: UseComputingStatusProps = ( return () => { canceledRequest = true; }; - }, [nodeUuid, fetcher, studyUuid, resultConversion, dispatch, computingType, isComputationCompleted]); + }, [ + nodeUuid, + rootNetworkUuid, + fetcher, + studyUuid, + resultConversion, + dispatch, + computingType, + isComputationCompleted, + ]); /* initial fetch and update */ useEffect(() => { diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx index 435b408514..ac086e73ca 100644 --- a/src/components/dialogs/element-creation-dialog.tsx +++ b/src/components/dialogs/element-creation-dialog.tsx @@ -160,7 +160,6 @@ const ElementCreationDialog: React.FC = ({ // Open case selector const handleCaseSelection = () => { - console.log("?????????",rootNetworkUuid); setCaseSelectorOpen(true); }; @@ -202,7 +201,7 @@ const ElementCreationDialog: React.FC = ({ } } }, - [onSave, destinationFolder, selectedCase, snackError, type,rootNetworkUuid] + [onSave, destinationFolder, selectedCase, snackError, type] ); // Folder chooser component diff --git a/src/components/dialogs/import-case-dialog.tsx b/src/components/dialogs/import-case-dialog.tsx index 0de13e1e08..e39a6ab2a2 100644 --- a/src/components/dialogs/import-case-dialog.tsx +++ b/src/components/dialogs/import-case-dialog.tsx @@ -1,8 +1,6 @@ import { useIntl } from 'react-intl'; import { ElementType, DirectoryItemSelector, TreeViewFinderNodeProps } from '@gridsuite/commons-ui'; import { FunctionComponent } from 'react'; -import { useSelector } from 'react-redux'; -import { AppState } from 'redux/reducer'; interface ImportCaseDialogProps { open: boolean; diff --git a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx index d296c07475..1c9ade4575 100644 --- a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx +++ b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/equipment-filter.tsx @@ -88,7 +88,7 @@ const EquipmentFilter = forwardRef { - if (!studyUuid || !currentNode?.id) { + if (!currentRootNetwork || !studyUuid || !currentNode?.id) { return; } // Load voltage level IDs @@ -112,7 +112,7 @@ const EquipmentFilter = forwardRef setCountries(countryCodes)) .catch((error) => { snackError({ @@ -124,7 +124,7 @@ const EquipmentFilter = forwardRef { - if (!studyUuid || !currentNode?.id) { + if (!studyUuid || !currentRootNetwork || !currentNode?.id) { return; } const expertFilter = buildExpertFilter( @@ -135,10 +135,11 @@ const EquipmentFilter = forwardRef { label: 'VSC', action: () => withDefaultParams(VscCreationDialog), }, + { + id: MODIFICATION_TYPES.LCC_CREATION.type, + label: 'LCC', + action: () => withDefaultParams(LccCreationDialog), + }, ], }, { diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index daa91e5d40..eaa131a8bb 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -24,41 +24,23 @@ const styles = { display: 'flex', flexDirection: 'column', elevation: 3, - // background: "red", - + // background: "red", }), -}; +}; const RootNetworkEditor = () => { const dispatch = useDispatch(); - const { snackError } = useSnackMessage(); const currentTreeNode = useSelector((state: AppState) => state.currentTreeNode); - const studyUuid = useSelector((state: AppState) => state.studyUuid); - const rootNetworkUuid = useSelector((state: AppState) => state.rootNetworkUuid); const closeModificationsDrawer = () => { dispatch(setModificationsDrawerOpen(false)); }; - const changeNodeName = (newName: string) => { - updateTreeNode(studyUuid, { - id: currentTreeNode?.id, - type: currentTreeNode?.type, - name: newName, - }).catch((error) => { - snackError({ - messageTxt: error.message, - headerId: 'NodeUpdateError', - }); - }); - }; - return ( diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 4a932a81d2..3e4e1549d5 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -12,29 +12,18 @@ import DeleteIcon from '@mui/icons-material/Delete'; import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography } from '@mui/material'; import IconButton from '@mui/material/IconButton'; -import { UPDATE_TYPE } from 'components/network/constants'; import { useCallback, useEffect, useRef, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; -import { removeNotificationByNode, setModificationsInProgress } from '../../../redux/actions'; -import TwoWindingsTransformerModificationDialog from '../../dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog'; import { useIsAnyNodeBuilding } from '../../utils/is-any-node-building-hook'; -import RestoreModificationDialog from 'components/dialogs/restore-modification-dialog'; import { UUID } from 'crypto'; -import { DropResult } from 'react-beautiful-dnd'; -import { AppState, StudyUpdated } from 'redux/reducer'; -import { fetchNetworkModification } from '../../../services/network-modification'; -import { changeNetworkModificationOrder, stashModifications } from '../../../services/study/network-modifications'; +import { AppState } from 'redux/reducer'; import { FetchStatus } from '../../../services/utils'; -import ElementCreationDialog, { - IElementCreationDialog, - IElementCreationDialog1, -} from '../../dialogs/element-creation-dialog'; +import ElementCreationDialog, { IElementCreationDialog1 } from '../../dialogs/element-creation-dialog'; import { NetworkModificationCopyInfo, NetworkModificationData, - NetworkModificationMetadata, RootNetworkMetadata, } from './network-modification-menu.type'; @@ -43,7 +32,8 @@ import { GetCaseImportParametersReturn, getCaseImportParameters, } from 'services/network-conversion'; -import { createRootNetwork, fetchRootNetworks } from 'services/root-network'; +import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; +import { i } from 'mathjs'; export const styles = { listContainer: (theme: Theme) => ({ @@ -119,19 +109,6 @@ export const styles = { }), }; -const nonEditableModificationTypes = new Set([ - 'EQUIPMENT_ATTRIBUTE_MODIFICATION', - 'GROOVY_SCRIPT', - 'OPERATING_STATUS_MODIFICATION', -]); - -const isEditableModification = (modif: NetworkModificationMetadata) => { - if (!modif) { - return false; - } - return !nonEditableModificationTypes.has(modif.type); -}; - export function isChecked(s1: number) { return s1 !== 0; } @@ -163,8 +140,6 @@ const RootNetworkNodeEditor = () => { const copyInfosRef = useRef(); copyInfosRef.current = copyInfos; - const [isDragging, setIsDragging] = useState(false); - const [editDialogOpen, setEditDialogOpen] = useState(undefined); const [editData, setEditData] = useState(undefined); const [editDataFetchStatus, setEditDataFetchStatus] = useState(FetchStatus.IDLE); @@ -178,33 +153,6 @@ const RootNetworkNodeEditor = () => { const [isUpdate, setIsUpdate] = useState(false); const buttonAddRef = useRef(null); - const cleanClipboard = useCallback(() => { - setCopyInfos(null); - setCopiedModifications((oldCopiedModifications) => { - if (oldCopiedModifications.length) { - snackInfo({ - messageId: 'CopiedModificationInvalidationMessage', - }); - } - return []; - }); - }, [snackInfo]); - - // TODO this is not complete. - // We should clean Clipboard on notifications when another user edit - // a modification on a public study which is in the clipboard. - // We don't have precision on notifications to do this for now. - const handleValidatedDialog = () => { - if (editData?.uuid && copiedModifications.includes(editData?.uuid)) { - cleanClipboard(); - } - }; - - const handleCloseDialog = () => { - setEditDialogOpen(undefined); - setEditData(undefined); - }; - const updateSelectedItems = useCallback((rootNetworks: RootNetworkMetadata[]) => { const toKeepIdsSet = new Set(rootNetworks.map((e) => e.rootNetworkUuid)); setSelectedItems((oldselectedItems) => oldselectedItems.filter((s) => toKeepIdsSet.has(s.rootNetworkUuid))); @@ -212,7 +160,6 @@ const RootNetworkNodeEditor = () => { const dofetchRootNetworks = useCallback(() => { setLaunchLoader(true); - if (studyUuid) { fetchRootNetworks(studyUuid) .then((res: RootNetworkMetadata[]) => { @@ -232,11 +179,19 @@ const RootNetworkNodeEditor = () => { .finally(() => { setPendingState(false); setLaunchLoader(false); - // dispatch(setModificationsInProgress(false)); + // dispatch(setModificationsInProgress(false)); }); } }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); + useEffect(() => { + if (studyUpdatedForce.eventData.headers) { + if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { + dofetchRootNetworks(); + } + } + }, [studyUpdatedForce, dofetchRootNetworks]); + useEffect(() => { setEditDialogOpen(editData?.type); }, [editData]); @@ -245,19 +200,20 @@ const RootNetworkNodeEditor = () => { // first time with currentNode initialized then fetch modifications // (because if currentNode is not initialized, dofetchNetworkModifications silently does nothing) // OR next time if currentNodeId changed then fetch modifications - // if (currentNode && currentRootNetwork) { - if ( currentRootNetwork) { + // if (currentNode && currentRootNetwork) { + + if (!currentRootNetwork) { // currentNodeIdRef.current = currentNode.id; // Current node has changed then clear the modifications list setRootNetworks([]); - dofetchRootNetworks(); + // reset the network modification and computing logs filter when the user changes the current node // dispatch(resetLogsFilter()); } + dofetchRootNetworks(); }, [currentRootNetwork, dofetchRootNetworks]); - -// TODO MANAGE NOTIFICATION + // TODO MANAGE NOTIFICATION // useEffect(() => { // if (studyUpdatedForce.eventData.headers) { // if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { @@ -317,26 +273,21 @@ const RootNetworkNodeEditor = () => { setRootNetworkCreationDialogOpen(true); }, []); - const doDeleteModification = useCallback(() => { - const selectedModificationsUuid = selectedItems.map((item) => item.rootNetworkUuid); - stashModifications(studyUuid, currentNode?.id, selectedModificationsUuid) - .then(() => { - //if one of the deleted element was in the clipboard we invalidate the clipboard - if ( - copiedModifications.some((aCopiedModification) => - selectedModificationsUuid.includes(aCopiedModification) - ) - ) { - cleanClipboard(); - } - }) - .catch((errmsg) => { - snackError({ - messageTxt: errmsg, - headerId: 'errDeleteModificationMsg', + const doDeleteRootNetwork = useCallback(() => { + const selectedRootNetworksUuid = selectedItems.map((item) => item.rootNetworkUuid); + if (studyUuid) { + deleteRootNetworks(studyUuid, selectedRootNetworksUuid) + .then(() => { + //if one of the deleted element was in the clipboard we invalidate the clipboard + }) + .catch((errmsg) => { + snackError({ + messageTxt: errmsg, + headerId: 'errDeleteModificationMsg', + }); }); - }); - }, [currentNode?.id, selectedItems, snackError, studyUuid, cleanClipboard, copiedModifications]); + } + }, [currentNode?.id, selectedItems, snackError, studyUuid, copiedModifications]); const removeNullFields = useCallback((data: NetworkModificationData) => { let dataTemp = data; @@ -354,13 +305,10 @@ const RootNetworkNodeEditor = () => { return dataTemp; }, []); - - const toggleSelectAllRootNetworks = useCallback(() => { setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); }, [rootNetworks]); - const isLoading = useCallback(() => { return notificationIdList.filter((notification) => notification === currentNode?.id).length > 0; }, [notificationIdList, currentNode?.id]); @@ -370,14 +318,7 @@ const RootNetworkNodeEditor = () => { if (!rootNetwork) { return ''; } - // return intl.formatMessage( - // { id: 'network_modifications.' + modif.messageType }, - // { - // ...modif, - // ...computeLabel(modif), - // } - // ); - return intl.formatMessage({ id: 'root_network' }) + rootNetwork.rootNetworkUuid; + return intl.formatMessage({ id: 'RootNetwork' }) + ' ' + rootNetwork.rootNetworkUuid; }; const renderRootNetworksList = () => { @@ -386,13 +327,13 @@ const RootNetworkNodeEditor = () => { sx={{ items: (rootNetwork) => ({ label: { - ...(!rootNetwork.isCreating && { ...styles.disabledModification }), + ...(rootNetwork.isCreating && { ...styles.disabledModification }), ...styles.checkBoxLabel, }, checkBoxIcon: styles.checkBoxIcon, checkboxButton: styles.checkboxButton, }), - dragAndDropContainer: styles.listContainer, + // dragAndDropContainer: styles.listContainer, }} onItemClick={(modification) => { console.log(modification.rootNetworkUuid, 'on click'); @@ -476,25 +417,6 @@ const RootNetworkNodeEditor = () => { possibleValues: parameter.possibleValues?.sort((a: any, b: any) => a.localeCompare(b)), })); } - const getCurrentCaseImportParams = useCallback( - (caseUuid: UUID) => { - getCaseImportParameters(caseUuid) - .then((result: GetCaseImportParametersReturn) => { - console.log(result); - const formattedParams = formatCaseImportParameters(result.parameters); - const caseFormat = result.formatName; - }) - .catch(() => { - // setError(`root.${FieldConstants.API_CALL}`, { - // type: 'parameterLoadingProblem', - // message: intl.formatMessage({ - // id: 'parameterLoadingProblem', - // }), - // }); - }); - }, - [intl] - ); function customizeCurrentParameters(params: Parameter[]): Record { return params.reduce((obj, parameter) => { @@ -540,7 +462,6 @@ const RootNetworkNodeEditor = () => { setSaveInProgress(false); }); }; - const renderPaneSubtitle = () => { if (isLoading() && messageId) { return renderRootNetworksListTitleLoading(); @@ -579,7 +500,7 @@ const RootNetworkNodeEditor = () => { ({ width: DRAWER_NODE_EDITOR_WIDTH + 'px', diff --git a/src/components/network/gs-map-equipments.ts b/src/components/network/gs-map-equipments.ts index ab5ee06f15..9d87b5b0eb 100644 --- a/src/components/network/gs-map-equipments.ts +++ b/src/components/network/gs-map-equipments.ts @@ -137,11 +137,40 @@ export default class GSMapEquipments extends MapEquipments { this.initEquipments(studyUuid, currentNodeUuid, currentRootNetworkUuid); } - reloadImpactedSubstationsEquipments(studyUuid: UUID, currentNode: any, substationsIds: string[] | null) { - const updatedSubstations = fetchSubstationsMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedTieLines = fetchTieLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); - const updatedHvdcLines = fetchHvdcLinesMapInfos(studyUuid, currentNode?.id, substationsIds, true); + reloadImpactedSubstationsEquipments( + studyUuid: UUID, + currentNode: any, + currentRootNetworkUuid: UUID, + substationsIds: string[] | null + ) { + const updatedSubstations = fetchSubstationsMapInfos( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + substationsIds, + true + ); + const updatedLines = fetchLinesMapInfos( + studyUuid, + currentNode?.id, + substationsIds, + currentRootNetworkUuid, + true + ); + const updatedTieLines = fetchTieLinesMapInfos( + studyUuid, + currentNode?.id, + substationsIds, + currentRootNetworkUuid, + true + ); + const updatedHvdcLines = fetchHvdcLinesMapInfos( + studyUuid, + currentNode?.id, + substationsIds, + currentRootNetworkUuid, + true + ); updatedSubstations.catch((error) => { console.error(error.message); if (this.errHandler) { diff --git a/src/components/network/selection-creation-panel/use-save-map.ts b/src/components/network/selection-creation-panel/use-save-map.ts index b87547dc28..021db245d2 100644 --- a/src/components/network/selection-creation-panel/use-save-map.ts +++ b/src/components/network/selection-creation-panel/use-save-map.ts @@ -27,6 +27,7 @@ export const useSaveMap = (): UseSaveMapOutput => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNodeUuid = useSelector((state: AppState) => state.currentTreeNode?.id); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const { snackInfo, snackError, snackWarning } = useSnackMessage(); const [pendingState, setPendingState] = useState(false); @@ -63,6 +64,7 @@ export const useSaveMap = (): UseSaveMapOutput => { // @ts-expect-error TODO: manage null case studyUuid, currentNodeUuid, + currentRootNetworkUuid, selectedEquipmentsIds, nominalVoltages ); @@ -79,6 +81,7 @@ export const useSaveMap = (): UseSaveMapOutput => { // @ts-expect-error TODO: manage null case studyUuid, currentNodeUuid, + currentRootNetworkUuid, equipments, nominalVoltages ); @@ -110,7 +113,7 @@ export const useSaveMap = (): UseSaveMapOutput => { } return true; // success }, - [currentNodeUuid, intl, snackError, snackInfo, snackWarning, studyUuid] + [currentNodeUuid, currentRootNetworkUuid, intl, snackError, snackInfo, snackWarning, studyUuid] ); return { pendingState, onSaveSelection }; diff --git a/src/components/report-viewer-tab.jsx b/src/components/report-viewer-tab.jsx index 4010d7284f..17d296bb8d 100644 --- a/src/components/report-viewer-tab.jsx +++ b/src/components/report-viewer-tab.jsx @@ -34,6 +34,7 @@ const styles = { * @param studyId : string study id * @param visible : boolean window visible * @param currentNode : object visualized node + * @param currentRootNetwork : current rootnetwork uuid * @param disabled : boolean disabled * @returns {*} node * @constructor diff --git a/src/components/result-view-tab.tsx b/src/components/result-view-tab.tsx index 5a6ba447d5..5d4d500fb8 100644 --- a/src/components/result-view-tab.tsx +++ b/src/components/result-view-tab.tsx @@ -46,6 +46,7 @@ const styles = { interface IResultViewTabProps { studyUuid: UUID; currentNode: CurrentTreeNode; + currentRootNetwork: UUID; openVoltageLevelDiagram: (voltageLevelId: string) => void; disabled: boolean; view: string; @@ -62,6 +63,7 @@ export interface IService { * control results views * @param studyUuid : string uuid of study * @param currentNode : object current node + * @param currentRootNetwork : uuid of current root network * @param openVoltageLevelDiagram : function * @param resultTabIndexRedirection : ResultTabIndexRedirection to specific tab [RootTab, LevelOneTab, ...] * @param disabled @@ -71,6 +73,7 @@ export interface IService { export const ResultViewTab: FunctionComponent = ({ studyUuid, currentNode, + currentRootNetwork, openVoltageLevelDiagram, disabled, view, @@ -92,10 +95,14 @@ export const ResultViewTab: FunctionComponent = ({ const renderLoadFlowResult = useMemo(() => { return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const renderSecurityAnalysisResult = useMemo(() => { return ( @@ -103,59 +110,86 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, openVoltageLevelDiagram]); + }, [studyUuid, currentNode, currentRootNetwork, openVoltageLevelDiagram]); const renderVoltageInitResult = useMemo(() => { return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const renderSensitivityAnalysisResult = useMemo(() => { return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const renderNonEvacuatedEnergyResult = useMemo(() => { + console.log('ùùùùùù renderNonEvacuatedEnergyResult ',currentRootNetwork); return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const renderShortCircuitAnalysisResult = useMemo(() => { return ( - + ); - }, [view, currentNode?.id, studyUuid]); + }, [view, currentNode?.id, studyUuid, currentRootNetwork]); const renderDynamicSimulationResult = useMemo(() => { return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const renderStateEstimationResult = useMemo(() => { return ( - + ); - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetwork]); const services: IService[] = useMemo(() => { return [ diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx index e50218199d..5d233c1000 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx @@ -42,6 +42,7 @@ const defaultColDef = { type DynamicSimulationResultSynthesisProps = { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; }; const DynamicSimulationResultSynthesis = memo(({ nodeUuid, studyUuid }: DynamicSimulationResultSynthesisProps) => { diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx index 11faf3c179..b149218c91 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx @@ -25,7 +25,7 @@ const TAB_INDEX_TIMELINE = 'DynamicSimulationTabTimeline'; const TAB_INDEX_STATUS = 'DynamicSimulationTabStatus'; const TAB_INDEX_LOGS = 'ComputationResultsLogs'; -const DynamicSimulationResultTab = ({ studyUuid, nodeUuid }) => { +const DynamicSimulationResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { const intl = useIntl(); const [tabIndex, setTabIndex] = useState(TAB_INDEX_TIME_SERIES); @@ -66,13 +66,25 @@ const DynamicSimulationResultTab = ({ studyUuid, nodeUuid }) => { - + - + - + diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx index 9ade8cc765..55bbdb2be8 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx @@ -36,7 +36,7 @@ const styles = { }, }; -const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid }) => { +const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid, rootNetworkUuid }) => { const [result, loadTimeSeries, isLoading] = useResultTimeSeries(nodeUuid, studyUuid); // tab id is automatically increased and reset to zero when there is no tab. @@ -182,6 +182,7 @@ const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid }) => { DynamicSimulationResultTimeSeries.propTypes = { nodeUuid: PropTypes.string, studyUuid: PropTypes.string, + rootNetworkUuid: PropTypes.string, }; export default DynamicSimulationResultTimeSeries; diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx index f50bbec247..c41b687c38 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx @@ -64,6 +64,7 @@ const defaultColDef = { type DynamicSimulationResultTimelineProps = { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; }; const DynamicSimulationResultTimeline = memo(({ studyUuid, nodeUuid }: DynamicSimulationResultTimelineProps) => { diff --git a/src/components/results/loadflow/load-flow-result-tab.tsx b/src/components/results/loadflow/load-flow-result-tab.tsx index 0661018f06..07cb8dfbc8 100644 --- a/src/components/results/loadflow/load-flow-result-tab.tsx +++ b/src/components/results/loadflow/load-flow-result-tab.tsx @@ -68,7 +68,7 @@ export interface GlobalFilter { limitViolationsTypes?: LimitTypes[]; } -export const LoadFlowResultTab: FunctionComponent = ({ studyUuid, nodeUuid }) => { +export const LoadFlowResultTab: FunctionComponent = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { const { snackError } = useSnackMessage(); const intl = useIntl(); const loadflowResultInvalidations = ['loadflowResult']; @@ -94,7 +94,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu // load countries useEffect(() => { - fetchAllCountries(studyUuid, nodeUuid) + fetchAllCountries(studyUuid, nodeUuid, rootNetworkUuid) .then((countryCodes) => { setCountriesFilter( countryCodes.map((countryCode: string) => ({ @@ -109,7 +109,8 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu headerId: 'FetchCountryError', }); }); - fetchAllNominalVoltages(studyUuid, nodeUuid) + + fetchAllNominalVoltages(studyUuid, nodeUuid, rootNetworkUuid) .then((nominalVoltages) => { setVoltageLevelsFilter( nominalVoltages.map((nominalV: number) => ({ @@ -124,7 +125,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu headerId: 'FetchNominalVoltagesError', }); }); - }, [nodeUuid, studyUuid, snackError, loadFlowStatus]); + }, [nodeUuid, studyUuid, rootNetworkUuid, snackError, loadFlowStatus]); const getGlobalFilterParameter = useCallback( (globalFilter: GlobalFilter | undefined) => { @@ -165,7 +166,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu value: limitTypeValues, }); } - return fetchLimitViolations(studyUuid, nodeUuid, { + return fetchLimitViolations(studyUuid, nodeUuid, rootNetworkUuid, { sort: sortConfig.map((sort) => ({ ...sort, colId: FROM_COLUMN_TO_FIELD_LIMIT_VIOLATION_RESULT[sort.colId], @@ -173,14 +174,24 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu filters: mapFieldsToColumnsFilter(updatedFilters, mappingFields(tabIndex)), globalFilters: getGlobalFilterParameter(globalFilter), }); - }, [studyUuid, nodeUuid, sortConfig, filterSelector, tabIndex, globalFilter, getGlobalFilterParameter, intl]); + }, [ + studyUuid, + nodeUuid, + rootNetworkUuid, + sortConfig, + filterSelector, + tabIndex, + globalFilter, + getGlobalFilterParameter, + intl, + ]); const fetchloadflowResultWithParameters = useCallback(() => { - return fetchLoadFlowResult(studyUuid, nodeUuid, { + return fetchLoadFlowResult(studyUuid, nodeUuid, rootNetworkUuid, { sort: sortConfig, filters: filterSelector, }); - }, [studyUuid, nodeUuid, sortConfig, filterSelector]); + }, [studyUuid, nodeUuid, rootNetworkUuid, sortConfig, filterSelector]); const fetchResult = useMemo(() => { if (tabIndex === 0 || tabIndex === 1) { diff --git a/src/components/results/loadflow/load-flow-result.type.ts b/src/components/results/loadflow/load-flow-result.type.ts index 8de76ba99c..f7ee26653c 100644 --- a/src/components/results/loadflow/load-flow-result.type.ts +++ b/src/components/results/loadflow/load-flow-result.type.ts @@ -41,6 +41,7 @@ export enum LimitTypes { export interface LoadFlowTabProps { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; } export interface LoadflowResultTap { diff --git a/src/components/results/securityanalysis/security-analysis-result-tab.tsx b/src/components/results/securityanalysis/security-analysis-result-tab.tsx index 18836a9bcb..3f875581ee 100644 --- a/src/components/results/securityanalysis/security-analysis-result-tab.tsx +++ b/src/components/results/securityanalysis/security-analysis-result-tab.tsx @@ -77,6 +77,7 @@ const styles = { export const SecurityAnalysisResultTab: FunctionComponent = ({ studyUuid, nodeUuid, + rootNetworkUuid, openVoltageLevelDiagram, }) => { const intl = useIntl(); @@ -164,7 +165,7 @@ export const SecurityAnalysisResultTab: FunctionComponent void; } diff --git a/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx b/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx index 5dd8f96aad..afc0c32c09 100644 --- a/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx +++ b/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx @@ -20,7 +20,7 @@ import { useSelector } from 'react-redux'; import { AppState } from '../../../../redux/reducer'; import { ComputingType } from '../../../computing-status/computing-type'; import { RESULTS_LOADING_DELAY } from '../../../network/constants'; - + const styles = { container: { display: 'flex', @@ -41,7 +41,8 @@ const styles = { export const NON_EVACUATED_ENERGY_RESULT_INVALIDATIONS = ['nonEvacuatedEnergyResult']; -export const NonEvacuatedEnergyResultTab: FunctionComponent = ({ studyUuid, nodeUuid }) => { +export const NonEvacuatedEnergyResultTab: FunctionComponent = ({ studyUuid, nodeUuid, rootNetworkUuid +}) => { const [tabIndex, setTabIndex] = useState(0); const RESULTS_TAB_INDEX = 0; @@ -54,6 +55,7 @@ export const NonEvacuatedEnergyResultTab: FunctionComponent c.headerComponentParams.displayName); } -const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid }) => { +const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { const { snackError } = useSnackMessage(); const intl = useIntl(); const [nOrNkIndex, setNOrNkIndex] = useState(0); diff --git a/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx b/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx index cb4af1de17..ef8db1dd0f 100644 --- a/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx +++ b/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx @@ -18,13 +18,14 @@ import { BranchSide } from 'components/utils/constants'; interface ShortCircuitExportButtonProps { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; csvHeaders?: string[]; analysisType: number; disabled?: boolean; } export const ShortCircuitExportButton: FunctionComponent = (props) => { - const { studyUuid, nodeUuid, csvHeaders, disabled = false, analysisType } = props; + const { studyUuid, nodeUuid, rootNetworkUuid, csvHeaders, disabled = false, analysisType } = props; const { snackError } = useSnackMessage(); const [isCsvExportLoading, setIsCsvExportLoading] = useState(false); @@ -62,7 +63,14 @@ export const ShortCircuitExportButton: FunctionComponent { setIsCsvExportLoading(true); setIsCsvExportSuccessful(false); - downloadShortCircuitResultZippedCsv(studyUuid, nodeUuid, analysisType, csvHeaders, enumValueTranslations) + downloadShortCircuitResultZippedCsv( + studyUuid, + nodeUuid, + rootNetworkUuid, + analysisType, + csvHeaders, + enumValueTranslations + ) .then((response) => { response.blob().then((fileBlob: Blob) => { downloadZipFile( diff --git a/src/components/results/shortcircuit/shortcircuit-analysis-result-tab.tsx b/src/components/results/shortcircuit/shortcircuit-analysis-result-tab.tsx index b63f66f65e..e4760d6787 100644 --- a/src/components/results/shortcircuit/shortcircuit-analysis-result-tab.tsx +++ b/src/components/results/shortcircuit/shortcircuit-analysis-result-tab.tsx @@ -31,6 +31,7 @@ import { GridReadyEvent } from 'ag-grid-community'; interface ShortCircuitAnalysisResultTabProps { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; view: string; } @@ -41,6 +42,7 @@ function getDisplayedColumns(params: any) { export const ShortCircuitAnalysisResultTab: FunctionComponent = ({ studyUuid, nodeUuid, + rootNetworkUuid, view, }) => { const lastCompletedComputation = useSelector((state: AppState) => state.lastCompletedComputation); @@ -144,6 +146,7 @@ export const ShortCircuitAnalysisResultTab: FunctionComponent = ({ studyUuid, nodeUuid }) => { +export const StateEstimationResultTab: FunctionComponent = ({ + studyUuid, + nodeUuid, + rootNetworkUuid, +}) => { const intl = useIntl(); const stateEstimationResultInvalidations = ['stateEstimationResult']; @@ -53,8 +57,8 @@ export const StateEstimationResultTab: FunctionComponent { - return fetchStateEstimationResult(studyUuid, nodeUuid); - }, [studyUuid, nodeUuid]); + return fetchStateEstimationResult(studyUuid, nodeUuid, rootNetworkUuid); + }, [studyUuid, nodeUuid, rootNetworkUuid]); const fetchResult = useMemo(() => { return fetchEstimResults; diff --git a/src/components/results/stateestimation/state-estimation-result.type.ts b/src/components/results/stateestimation/state-estimation-result.type.ts index f484d2ea4b..e2368a8cc2 100644 --- a/src/components/results/stateestimation/state-estimation-result.type.ts +++ b/src/components/results/stateestimation/state-estimation-result.type.ts @@ -32,6 +32,7 @@ export interface StateEstimationResult { export interface StateEstimationTabProps { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; } export interface StateEstimationResultTableProps { diff --git a/src/components/spreadsheet/use-spreadsheet-equipments.ts b/src/components/spreadsheet/use-spreadsheet-equipments.ts index 2dee4d89d6..9cccdca1cd 100644 --- a/src/components/spreadsheet/use-spreadsheet-equipments.ts +++ b/src/components/spreadsheet/use-spreadsheet-equipments.ts @@ -25,7 +25,7 @@ import { fetchAllEquipments } from 'services/study/network-map'; export type EquipmentProps = { type: SpreadsheetEquipmentType; - fetchers: Array<(studyUuid: UUID, currentNodeId: UUID) => Promise>; + fetchers: Array<(studyUuid: UUID, currentNodeId: UUID, currentRootNetworkUuid: UUID) => Promise>; }; type FormatFetchedEquipments = (equipments: Identifiable[]) => Identifiable[]; @@ -39,6 +39,7 @@ export const useSpreadsheetEquipments = ( const equipments = allEquipments[equipment.type]; const studyUuid = useSelector((state: AppState) => state.studyUuid); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const [errorMessage, setErrorMessage] = useState(); const [isFetching, setIsFetching] = useState(false); @@ -82,11 +83,13 @@ export const useSpreadsheetEquipments = ( } resetImpactedElementTypes(); } - if (impactedSubstationsIds.length > 0 && studyUuid && currentNode?.id) { + if (impactedSubstationsIds.length > 0 && studyUuid && currentRootNetworkUuid && currentNode?.id) { // The formatting of the fetched equipments is done in the reducer - fetchAllEquipments(studyUuid, currentNode.id, impactedSubstationsIds).then((values) => { - dispatch(updateEquipments(values)); - }); + fetchAllEquipments(studyUuid, currentRootNetworkUuid, currentNode.id, impactedSubstationsIds).then( + (values) => { + dispatch(updateEquipments(values)); + } + ); resetImpactedSubstationsIds(); } if (deletedEquipments.length > 0) { @@ -118,6 +121,7 @@ export const useSpreadsheetEquipments = ( deletedEquipments, impactedElementTypes, studyUuid, + currentRootNetworkUuid, currentNode?.id, dispatch, allEquipments, @@ -127,10 +131,12 @@ export const useSpreadsheetEquipments = ( ]); useEffect(() => { - if (shouldFetchEquipments && studyUuid && currentNode?.id) { + if (shouldFetchEquipments && studyUuid && currentRootNetworkUuid && currentNode?.id) { setErrorMessage(null); setIsFetching(true); - Promise.all(equipment.fetchers.map((fetcher) => fetcher(studyUuid, currentNode?.id))) + Promise.all( + equipment.fetchers.map((fetcher) => fetcher(studyUuid, currentNode?.id, currentRootNetworkUuid)) + ) .then((results) => { let fetchedEquipments = results.flat(); if (formatFetchedEquipments) { @@ -144,7 +150,15 @@ export const useSpreadsheetEquipments = ( setIsFetching(false); }); } - }, [equipment, shouldFetchEquipments, studyUuid, currentNode?.id, dispatch, formatFetchedEquipments]); + }, [ + equipment, + shouldFetchEquipments, + studyUuid, + currentRootNetworkUuid, + currentNode?.id, + dispatch, + formatFetchedEquipments, + ]); return { equipments, errorMessage, isFetching }; }; diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index d6f2412862..efd1760def 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -23,6 +23,8 @@ import { limitReductionModified, setCurrentRootNetwork, } from '../redux/actions'; +import { fetchRootNetworks } from 'services/root-network'; + import WaitingLoader from './utils/waiting-loader'; import { useIntlRef, useSnackMessage } from '@gridsuite/commons-ui'; import NetworkModificationTreeModel from './graph/network-modification-tree-model'; @@ -137,9 +139,34 @@ function useStudy(studyUuidRequest) { fetchStudyExists(studyUuidRequest) .then(() => { setStudyUuid(studyUuidRequest); - dispatch(setCurrentRootNetwork('c7b1672a-8eba-45da-b761-675a8c5ec9b5')); + + // Fetch root networks and set the first one as the current root network + fetchRootNetworks(studyUuidRequest) + .then((rootNetworks) => { + if (rootNetworks && rootNetworks.length > 0) { + console.log('======== rootNetworks[0].rootnetworkUuid', rootNetworks[0].rootNetworkUuid); + // Validate that currentRootNetwork is set + + dispatch(setCurrentRootNetwork(rootNetworks[0].rootNetworkUuid)); + } else { + // Handle case where no root networks are available + setErrMessage( + intlRef.current.formatMessage( + { id: 'noRootNetworksFound' }, + { studyUuid: studyUuidRequest } + ) + ); + } + }) + .catch((error) => { + // Handle errors when fetching root networks + setErrMessage( + intlRef.current.formatMessage({ id: 'fetchRootNetworksError' }, { error: error.message }) + ); + }); }) .catch((error) => { + // Handle errors when fetching study existence if (error.status === HttpStatusCode.NOT_FOUND) { setErrMessage( intlRef.current.formatMessage({ id: 'studyNotFound' }, { studyUuid: studyUuidRequest }) @@ -306,6 +333,7 @@ export function StudyContainer({ view, onChangeTab }) { }, [snackInfo, snackWarning, snackError, userName] ); + console.info(`%%%%%%%%% ????'${currentRootNetwork}'...`); const connectNotifications = useCallback( (studyUuid) => { @@ -588,14 +616,14 @@ export function StudyContainer({ view, onChangeTab }) { ); }); }, - [studyUuid, currentRootNetwork, dispatch, checkStudyIndexation, loadTree, snackWarning, intlRef] + [studyUuid, currentRootNetwork, checkStudyIndexation, loadTree, snackWarning, intlRef] ); useEffect(() => { - if (studyUuid && !isStudyNetworkFound) { + if (studyUuid && currentRootNetwork && !isStudyNetworkFound) { checkNetworkExistenceAndRecreateIfNotFound(); } - }, [isStudyNetworkFound, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); + }, [isStudyNetworkFound, currentRootNetwork, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); // study_network_recreation_done notification // checking another time if we can find network, if we do, we display a snackbar info @@ -695,7 +723,7 @@ export function StudyContainer({ view, onChangeTab }) { }, [studyUuid, studyUpdatedForce, fetchStudyPath, snackInfo]); useEffect(() => { - if (studyUuid) { + if (studyUuid && currentRootNetwork) { websocketExpectedCloseRef.current = false; //dispatch root network uuid dispatch(openStudy(studyUuid, currentRootNetwork)); @@ -744,6 +772,7 @@ export function StudyContainer({ view, onChangeTab }) { > { +const StudyPane = ({ studyUuid, currentRootNetwork, currentNode, setErrorMessage, ...props }) => { const [tableEquipment, setTableEquipment] = useState({ id: null, type: null, @@ -97,6 +97,7 @@ const StudyPane = ({ studyUuid, currentNode, currentRootNetwork, setErrorMessage - { +export const VoltageInitResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid}) => { const voltageInitStatus = useSelector((state) => state.computingStatus[ComputingType.VOLTAGE_INITIALIZATION]); const [voltageInitResult, isWaiting] = useNodeData( diff --git a/src/hooks/use-report-fetcher.tsx b/src/hooks/use-report-fetcher.tsx index f9ae4f30fa..d5c83df09a 100644 --- a/src/hooks/use-report-fetcher.tsx +++ b/src/hooks/use-report-fetcher.tsx @@ -65,6 +65,7 @@ export const useReportFetcher = ( const [isLoading, setIsLoading] = useState(false); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); const treeModel = useSelector((state: AppState) => state.networkModificationTreeModel); const { snackError } = useSnackMessage(); @@ -100,11 +101,12 @@ export const useReportFetcher = ( const fetchRawParentReport = useCallback( (nodeOnlyReport?: boolean) => { - if (currentNode !== null && studyUuid) { + if (currentNode !== null && studyUuid && currentRootNetwork) { return fetch(() => fetchParentNodesReport( studyUuid, currentNode.id, + currentRootNetwork, nodeOnlyReport ?? true, getContainerDefaultSeverityList(), computingAndNetworkModificationType @@ -118,16 +120,16 @@ export const useReportFetcher = ( const fetchReportLogs = useCallback( (reportId: string, severityList: string[], reportType: ReportType, messageFilter: string) => { - if (!studyUuid) { + if (!studyUuid || !currentRootNetwork) { return; } let fetchPromise: (severityList: string[], reportId: string) => Promise; if (reportType === ReportType.GLOBAL) { fetchPromise = (severityList: string[]) => - fetchNodeReportLogs(studyUuid, currentNode!.id, null, severityList, messageFilter, true); + fetchNodeReportLogs(studyUuid, currentNode!.id,currentRootNetwork, null, severityList, messageFilter, true); } else { fetchPromise = (severityList: string[], reportId: string) => - fetchNodeReportLogs(studyUuid, currentNode!.id, reportId, severityList, messageFilter, false); + fetchNodeReportLogs(studyUuid, currentNode!.id,currentRootNetwork, reportId, severityList, messageFilter, false); } return fetchPromise(severityList, reportId).then((r) => { return mapReportLogs(prettifyReportLogMessage(r, nodesNames)); diff --git a/src/services/dynamic-simulation.ts b/src/services/dynamic-simulation.ts index d406937698..e7a2a398a1 100644 --- a/src/services/dynamic-simulation.ts +++ b/src/services/dynamic-simulation.ts @@ -61,23 +61,34 @@ export function fetchDynamicSimulationResultTimeline( // --- Event API - BEGIN //TODO: should not be linked to rootnetworkUUID -export function fetchDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID): Promise { +export function fetchDynamicSimulationEvents( + studyUuid: UUID, + nodeUuid: UUID, + currentRootNetworkUuid: UUID +): Promise { console.info(`Fetching dynamic simulation events on '${studyUuid}' and node '${nodeUuid}' ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/dynamic-simulation/events'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + + '/dynamic-simulation/events'; console.debug(url); return backendFetchJson(url); } -export function fetchDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, equipmentId: string): Promise { +export function fetchDynamicSimulationEvent( + studyUuid: UUID, + nodeUuid: UUID, + currentRootNetworkUuid: UUID, + equipmentId: string +): Promise { console.info( `Fetching dynamic simulation event with '${equipmentId}' on '${studyUuid}' and node '${nodeUuid}' ...` ); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + `/dynamic-simulation/events?equipmentId=${equipmentId}`; console.debug(url); @@ -85,10 +96,17 @@ export function fetchDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, equ return backendFetchJson(url); } -export function saveDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, event: Event) { +export function saveDynamicSimulationEvent( + studyUuid: UUID, + nodeUuid: UUID, + currentRootNetworkUuid: UUID, + event: Event +) { console.info(`Saving dynamic simulation event on '${studyUuid}' and node '${nodeUuid}' ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events`; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + + `/dynamic-simulation/events`; console.debug(url); return backendFetch(url, { @@ -101,7 +119,12 @@ export function saveDynamicSimulationEvent(studyUuid: UUID, nodeUuid: UUID, even }); } -export function deleteDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID, events: Event[]) { +export function deleteDynamicSimulationEvents( + studyUuid: UUID, + nodeUuid: UUID, + currentRootNetworkUuid: UUID, + events: Event[] +) { console.info(`Delete dynamic simulation events on '${studyUuid}' and node '${nodeUuid}' ...`); const eventIdsParams = getRequestParamFromList( @@ -110,7 +133,8 @@ export function deleteDynamicSimulationEvents(studyUuid: UUID, nodeUuid: UUID, e ); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + `/dynamic-simulation/events?${eventIdsParams}`; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + + `/dynamic-simulation/events?${eventIdsParams}`; console.debug(url); diff --git a/src/services/root-network.ts b/src/services/root-network.ts index b2e1666743..d119e63e68 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -7,7 +7,6 @@ import { backendFetch, backendFetchJson } from './utils'; import { UUID } from 'crypto'; -import { ElementType } from '@gridsuite/commons-ui'; export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; @@ -47,3 +46,18 @@ export const createRootNetwork = ( body: importParameters ? JSON.stringify(importParameters) : '', }); }; + +export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { + // Assuming we want to delete each root network individually: + const rootNetworkUuid = rootNetworkUuids[0]; // Modify as needed if deleting multiple root networks + + const rootNetworkDeleteUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent( + studyUuid + )}/root-networks/${encodeURIComponent(rootNetworkUuid)}`; + + console.debug(rootNetworkDeleteUrl); // Debugging the URL + + return backendFetch(rootNetworkDeleteUrl, { + method: 'DELETE', + }); +} diff --git a/src/services/study/filter.ts b/src/services/study/filter.ts index 819e601ea3..4694948c34 100644 --- a/src/services/study/filter.ts +++ b/src/services/study/filter.ts @@ -28,12 +28,15 @@ export interface IdentifiableAttributes { export function evaluateJsonFilter( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, filter: ExpertFilter // at moment only ExpertFilter but in futur may add others filter types to compose a union type ): Promise { - console.info(`Get matched elements of study '${studyUuid}' and node '${currentNodeUuid}' ...`); + console.info( + `Get matched elements of study '${studyUuid}' with a root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const evaluateFilterUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/filters/evaluate?inUpstreamBuiltParentNode=true'; console.debug(evaluateFilterUrl); return backendFetchJson(evaluateFilterUrl, { diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 1da593b2b1..2ce25f4933 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -47,13 +47,14 @@ export const fetchStudyExists = (studyUuid: UUID) => { export function getNetworkAreaDiagramUrl( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, voltageLevelsIds: UUID[], depth: number, withGeoData: boolean ) { console.info(`Getting url of network area diagram of study '${studyUuid}' and node '${currentNodeUuid}'...`); return ( - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-area-diagram?' + new URLSearchParams({ depth: depth.toString(), @@ -67,6 +68,7 @@ export function getNetworkAreaDiagramUrl( export function fetchParentNodesReport( studyUuid: UUID, nodeUuid: UUID, + currentRootNetworkUuid: UUID, nodeOnlyReport: boolean, severityFilterList: string[], reportType: keyof typeof COMPUTING_AND_NETWORK_MODIFICATION_TYPE @@ -83,7 +85,7 @@ export function fetchParentNodesReport( ); let url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/parent-nodes-report?nodeOnlyReport=' + (nodeOnlyReport ? 'true' : 'false') + '&reportType=' + @@ -98,6 +100,7 @@ export function fetchParentNodesReport( export function fetchNodeReportLogs( studyUuid: UUID, nodeUuid: UUID, + currentRootNetworkUuid: UUID, reportId: string | null, severityFilterList: string[], messageFilter: string, @@ -105,9 +108,13 @@ export function fetchNodeReportLogs( ) { let url; if (isGlobalLogs) { - url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/report/logs?'; + url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/report/logs?'; } else { - url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/report/' + reportId + '/logs?'; + url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + + '/report/' + + reportId + + '/logs?'; } if (severityFilterList?.length) { url += '&' + getRequestParamFromList(severityFilterList, 'severityLevels'); @@ -147,7 +154,12 @@ export function searchEquipmentsInfos( ); } -export function fetchContingencyCount(studyUuid: UUID, currentNodeUuid: UUID, contingencyListNames: string[]) { +export function fetchContingencyCount( + studyUuid: UUID, + currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, + contingencyListNames: string[] +) { console.info( `Fetching contingency count for ${contingencyListNames} on '${studyUuid}' and node '${currentNodeUuid}'...` ); @@ -156,7 +168,9 @@ export function fetchContingencyCount(studyUuid: UUID, currentNodeUuid: UUID, co const urlSearchParams = new URLSearchParams(contingencyListNamesParams); const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/contingency-count?' + urlSearchParams; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/contingency-count?' + + urlSearchParams; console.debug(url); return backendFetchJson(url); @@ -205,9 +219,10 @@ export function getAvailableComponentLibraries(): Promise { return backendFetchJson(getAvailableComponentLibrariesUrl); } -export function unbuildNode(studyUuid: UUID, currentNodeUuid: UUID) { +export function unbuildNode(studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID) { console.info('Unbuild node ' + currentNodeUuid + ' of study ' + studyUuid + ' ...'); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/unbuild'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/unbuild'; console.debug(url); return backendFetchText(url, { method: 'post' }); } @@ -271,13 +286,15 @@ export function getServersInfos() { export function fetchAvailableFilterEnumValues( studyUuid: UUID, nodeUuid: UUID, + currentRootNetworkUuid: UUID, computingType: ComputingType, filterEnum: string ) { console.info('fetch available filter values'); const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - nodeUuid + nodeUuid, + currentRootNetworkUuid )}/computation/result/enum-values?computingType=${encodeURIComponent(computingType)}&enumName=${encodeURIComponent( filterEnum )}`; diff --git a/src/services/study/loadflow.js b/src/services/study/loadflow.js index 4326fb385e..0a531af7bc 100644 --- a/src/services/study/loadflow.js +++ b/src/services/study/loadflow.js @@ -55,7 +55,7 @@ export function startLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid 'Running loadflow on ' + studyUuid + ' and node ' + currentNodeUuid + ' with limit reduction ' + limitReduction ); const startLoadFlowUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/loadflow/run?limitReduction=' + limitReduction.toString(); console.debug(startLoadFlowUrl); @@ -64,7 +64,9 @@ export function startLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid export function stopLoadFlow(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Stopping loadFlow on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const stopLoadFlowUrl = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/loadflow/stop'; + const stopLoadFlowUrl = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/loadflow/stop'; console.debug(stopLoadFlowUrl); return backendFetch(stopLoadFlowUrl, { method: 'put' }); } @@ -88,7 +90,9 @@ export function fetchLoadFlowResult(studyUuid, currentNodeUuid, currentRootNetwo if (filters?.length) { params.append('filters', JSON.stringify(filters)); } - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/loadflow/result'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/loadflow/result'; const urlWithParams = `${url}?${params.toString()}`; console.debug(urlWithParams); return backendFetchJson(urlWithParams); @@ -109,7 +113,9 @@ export function fetchLimitViolations(studyUuid, currentNodeUuid, currentRootNetw params.append('globalFilters', JSON.stringify(globalFilters)); } - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/limit-violations'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/limit-violations'; const urlWithParams = `${url}?${params.toString()}`; console.debug(urlWithParams); return backendFetchJson(urlWithParams); diff --git a/src/services/study/network-map.ts b/src/services/study/network-map.ts index 20b110d9cf..1dd26113f9 100644 --- a/src/services/study/network-map.ts +++ b/src/services/study/network-map.ts @@ -87,6 +87,7 @@ export function fetchVoltageLevelEquipments( export function fetchEquipmentsIds( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, substationsIds: string[], equipmentType: EquipmentType, inUpstreamBuiltParentNode: boolean, @@ -104,7 +105,7 @@ export function fetchEquipmentsIds( const nominalVoltagesParamsList = nominalVoltages && nominalVoltages.length > 0 ? '&' + nominalVoltagesParams : ''; let fetchEquipmentsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map/' + 'equipments-ids' + '?' + @@ -126,6 +127,7 @@ export function fetchEquipmentsIds( export function fetchVoltageLevelIdForLineOrTransformerBySide( studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, equipmentId: string, side: string ) { @@ -139,18 +141,19 @@ export function fetchVoltageLevelIdForLineOrTransformerBySide( const fetchEquipmentInfosUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/network-map/branch-or-3wt/${encodeURIComponent(equipmentId)}/voltage-level-id?${urlSearchParams.toString()}`; console.debug(fetchEquipmentInfosUrl); return backendFetchText(fetchEquipmentInfosUrl); } -export function fetchAllCountries(studyUuid: UUID, currentNodeUuid: UUID) { +export function fetchAllCountries(studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID) { console.info(`Fetching all countries of study '${studyUuid}' and node '${currentNodeUuid}' ...`); const fetchCountriesUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map/countries?inUpstreamBuiltParentNode=true'; console.debug(fetchCountriesUrl); return backendFetchJson(fetchCountriesUrl); @@ -183,6 +186,7 @@ export async function createMapFilter( destinationDirectoryId: UUID, studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, selectedEquipmentsIds: string[], nominalVoltages: number[] ) { @@ -207,6 +211,7 @@ export async function createMapFilter( const elementsIds = await fetchEquipmentsIds( studyUuid, currentNodeUuid, + currentRootNetworkUuid, selectedEquipmentsIds, equipmentType, false, @@ -232,6 +237,7 @@ export async function createMapContingencyList( destinationDirectoryId: UUID, studyUuid: UUID, currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, selectedEquipments: EquipmentInfos[], nominalVoltages: number[] ) { @@ -252,6 +258,7 @@ export async function createMapContingencyList( const elementsIds = await fetchNetworkElementsInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, selectedEquipmentsIds, equipmentType, EQUIPMENT_INFOS_TYPES.LIST.type, @@ -275,11 +282,11 @@ export async function createMapContingencyList( return createContingencyList(equipmentContingencyList, elementName, '', destinationDirectoryId); } -export function fetchAllNominalVoltages(studyUuid: UUID, currentNodeUuid: UUID) { +export function fetchAllNominalVoltages(studyUuid: UUID, currentNodeUuid: UUID, currentRootNetworkUuid: UUID) { console.info(`Fetching all nominal voltages of study '${studyUuid}' and node '${currentNodeUuid}' ...`); const fetchNominalVoltagesUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-map/nominal-voltages?inUpstreamBuiltParentNode=true'; console.debug(fetchNominalVoltagesUrl); return backendFetchJson(fetchNominalVoltagesUrl); diff --git a/src/services/study/non-evacuated-energy.js b/src/services/study/non-evacuated-energy.js index 19d980db40..5bbb122d64 100644 --- a/src/services/study/non-evacuated-energy.js +++ b/src/services/study/non-evacuated-energy.js @@ -36,10 +36,10 @@ export function fetchNonEvacuatedEnergyStatus(studyUuid, currentNodeUuid, curren return backendFetchText(url); } -export function fetchNonEvacuatedEnergyResult(studyUuid, currentNodeUuid) { - console.info(`Fetching non evacuated energy analysis result on ${studyUuid} and node ${currentNodeUuid} ...`); +export function fetchNonEvacuatedEnergyResult(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.log(currentRootNetworkUuid,`*****Fetching non evacuated energy analysis result on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid)}/non-evacuated-energy/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/security-analysis.js b/src/services/study/security-analysis.js index 2ba9af1ba1..53108d81ac 100644 --- a/src/services/study/security-analysis.js +++ b/src/services/study/security-analysis.js @@ -8,7 +8,7 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchFile, backendFetchJson, backendFetchText, getRequestParamFromList } from '../utils'; -export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyListNames) { +export function startSecurityAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid, contingencyListNames) { console.info(`Running security analysis on ${studyUuid} and node ${currentNodeUuid} ...`); // Add params to Url @@ -17,24 +17,30 @@ export function startSecurityAnalysis(studyUuid, currentNodeUuid, contingencyLis const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/security-analysis/run?${urlSearchParams}`; console.debug(url); return backendFetch(url, { method: 'post' }); } -export function stopSecurityAnalysis(studyUuid, currentNodeUuid) { +export function stopSecurityAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info('Stopping security analysis on ' + studyUuid + ' and node ' + currentNodeUuid + ' ...'); const stopSecurityAnalysisUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/security-analysis/stop'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/security-analysis/stop'; console.debug(stopSecurityAnalysisUrl); return backendFetch(stopSecurityAnalysisUrl, { method: 'put' }); } -export function fetchSecurityAnalysisResult(studyUuid, currentNodeUuid, queryParams) { +export function fetchSecurityAnalysisResult(studyUuid, currentNodeUuid, currentRootNetworkUuid, queryParams) { console.info(`Fetching security analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/security-analysis/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/security-analysis/result`; const { resultType, page, size, sort, filters } = queryParams || {}; diff --git a/src/services/study/short-circuit-analysis.js b/src/services/study/short-circuit-analysis.js index b25cd9f6a3..ad580f7b0a 100644 --- a/src/services/study/short-circuit-analysis.js +++ b/src/services/study/short-circuit-analysis.js @@ -91,6 +91,7 @@ export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, ty export function fetchShortCircuitAnalysisPagedResults({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, selector = {}, type = ShortCircuitAnalysisType.ALL_BUSES, }) { @@ -123,7 +124,7 @@ export function fetchShortCircuitAnalysisPagedResults({ } const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/shortcircuit/result?' + urlSearchParams.toString(); console.debug(url); @@ -170,12 +171,17 @@ export function invalidateShortCircuitStatus(studyUuid) { export function downloadShortCircuitResultZippedCsv( studyUuid, currentNodeUuid, + currentRootNetworkUuid, analysisType, headersCsv, enumValueTranslations ) { console.info(`Fetching short-circuit analysis export csv on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/shortcircuit/result/csv`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/shortcircuit/result/csv`; const type = getShortCircuitAnalysisTypeFromEnum(analysisType); const param = new URLSearchParams({ type }); const urlWithParam = `${url}?${param.toString()}`; diff --git a/src/services/study/state-estimation.js b/src/services/study/state-estimation.js index 3445fae7e1..c677b8ccfe 100644 --- a/src/services/study/state-estimation.js +++ b/src/services/study/state-estimation.js @@ -36,10 +36,10 @@ export function fetchStateEstimationStatus(studyUuid, currentNodeUuid, currentRo return backendFetchText(url); } -export function fetchStateEstimationResult(studyUuid, currentNodeUuid) { +export function fetchStateEstimationResult(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Fetching state estimation result on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/state-estimation/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid)}/state-estimation/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/voltage-init.js b/src/services/study/voltage-init.js index df5c1113af..e21c2eec60 100644 --- a/src/services/study/voltage-init.js +++ b/src/services/study/voltage-init.js @@ -8,19 +8,19 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -export function startVoltageInit(studyUuid, currentNodeUuid) { +export function startVoltageInit(studyUuid, currentNodeUuid,currentRootNetworkUuid) { console.info(`Running voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); const startVoltageInitUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/run'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/run'; console.debug(startVoltageInitUrl); return backendFetch(startVoltageInitUrl, { method: 'put' }); } -export function stopVoltageInit(studyUuid, currentNodeUuid) { +export function stopVoltageInit(studyUuid, currentNodeUuid,currentRootNetworkUuid) { console.info(`Stopping voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); const stopVoltageInitUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/stop'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/stop'; console.debug(stopVoltageInitUrl); return backendFetch(stopVoltageInitUrl, { method: 'put' }); } @@ -36,9 +36,10 @@ export function fetchVoltageInitStatus(studyUuid, currentNodeUuid, currentRootNe return backendFetchText(url); } -export function fetchVoltageInitResult(studyUuid, currentNodeUuid) { +export function fetchVoltageInitResult(studyUuid, currentNodeUuid, currentRootNetworkUuid + ) { console.info(`Fetching voltage init result on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/voltage-init/result'; + const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/result'; console.debug(url); return backendFetchJson(url); } @@ -67,18 +68,18 @@ export function getVoltageInitStudyParameters(studyUuid) { return backendFetchJson(getVoltageInitParams); } -export function getVoltageInitModifications(studyUuid, currentNodeId) { +export function getVoltageInitModifications(studyUuid, currentNodeId,currentRootNetworkUuid) { console.info('get voltage init modifications'); const getVoltageInitModifications = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId,currentRootNetworkUuid) + '/voltage-init/modifications'; console.debug(getVoltageInitModifications); return backendFetchJson(getVoltageInitModifications); } -export function cloneVoltageInitModifications(studyUuid, currentNodeId) { +export function cloneVoltageInitModifications(studyUuid, currentNodeId,currentRootNetworkUuid) { console.info('cloning voltage init modifications'); const cloneVoltageInitModificationsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId,currentRootNetworkUuid) + '/voltage-init/modifications'; return backendFetch(cloneVoltageInitModificationsUrl, { method: 'PUT', diff --git a/src/translations/en.json b/src/translations/en.json index 448ddd23f7..f2be7d7487 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -53,6 +53,8 @@ "SingleLineDiagram": "Single line diagram", "NetworkAreaDiagram": "Network area diagram", "studyNotFound": "Study with id \"{studyUuid}\" has not been found", + "RootNetworkNotFound": "No root network was found for the study with ID \"{studyUuid}\"", + "svgNotFound": "Diagram has not been found: {error}; {svgUrl}", "svgLoadingFail": "The diagram couldn't be loaded", "networkLoadingFail": "Network of study with id \"{studyUuid}\" couldn't be loaded", @@ -603,6 +605,7 @@ "NodeBuildingError": "An error occurred while building node", "NodeUnbuildingError": "An error occurred while unbuilding node", "NetworkModifications": "Network modifications", + "RootNetwork": "Root Network", "CreateLoad": "Create load", "ModifyLoad": "Modify load", "NameOptional": "Name (optional)", diff --git a/src/translations/fr.json b/src/translations/fr.json index adc8b7b3d9..2f9f8590d5 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -54,6 +54,8 @@ "NetworkAreaDiagram": "Image nodale de zone", "studyNotFound": "L'étude avec l'identifiant \"{studyUuid}\" n'a pas été trouvée", + "RootNetworkNotFound": "Aucun réseau racine n'a été trouvé pour l'étude avec l'ID \"{studyUuid}\"", + "svgNotFound": "L'image poste n'a pas été trouvée : {error}; {svgUrl}", "svgLoadingFail": "L'image n'a pas pu être chargée", "networkLoadingFail": "Le réseau de l'étude avec l'identifiant \"{studyUuid}\" n'a pas pu être chargé", @@ -605,6 +607,8 @@ "NodeBuildingError": "Une erreur est survenue lors de la réalisation du nœud", "NodeUnbuildingError": "Une erreur est survenue lors de la déréalisation du nœud", "NetworkModifications": "Modifications de réseau", + "RootNetwork": "Réseau racine", + "CreateLoad": "Créer une consommation", "ModifyLoad": "Modifier une consommation", "NameOptional": "Nom (optionnel)", From 9af2d7bf184995eb89473d2ef88e0be7b3fe5dda Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 19 Dec 2024 13:26:02 +0100 Subject: [PATCH 08/51] switch between rootnetworks Signed-off-by: souissimai --- .../graph/menus/root-network-node-editor.tsx | 45 +++++++++++-------- src/components/network/network-map-tab.tsx | 11 +++-- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 3e4e1549d5..fbe2de9159 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -15,7 +15,6 @@ import IconButton from '@mui/material/IconButton'; import { useCallback, useEffect, useRef, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; -import { useIsAnyNodeBuilding } from '../../utils/is-any-node-building-hook'; import { UUID } from 'crypto'; import { AppState } from 'redux/reducer'; @@ -33,7 +32,10 @@ import { getCaseImportParameters, } from 'services/network-conversion'; import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; -import { i } from 'mathjs'; +import { SwitchNetworkModificationActive } from './switch-network-modification-active'; +import RemoveRedEyeIcon from '@mui/icons-material/RemoveRedEye'; +import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; +import { setCurrentRootNetwork } from 'redux/actions'; export const styles = { listContainer: (theme: Theme) => ({ @@ -131,7 +133,6 @@ const RootNetworkNodeEditor = () => { const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); - const currentNodeIdRef = useRef(); // initial empty to get first update const [pendingState, setPendingState] = useState(false); const [selectedItems, setSelectedItems] = useState([]); @@ -142,16 +143,11 @@ const RootNetworkNodeEditor = () => { const [editDialogOpen, setEditDialogOpen] = useState(undefined); const [editData, setEditData] = useState(undefined); - const [editDataFetchStatus, setEditDataFetchStatus] = useState(FetchStatus.IDLE); - const [caseSelectionDialogOpen, setCaseSelectionDialogOpen] = useState(false); const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); - const [createCompositeModificationDialogOpen, setCreateCompositeModificationDialogOpen] = useState(false); const dispatch = useDispatch(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const [messageId, setMessageId] = useState(''); const [launchLoader, setLaunchLoader] = useState(false); - const [isUpdate, setIsUpdate] = useState(false); - const buttonAddRef = useRef(null); const updateSelectedItems = useCallback((rootNetworks: RootNetworkMetadata[]) => { const toKeepIdsSet = new Set(rootNetworks.map((e) => e.rootNetworkUuid)); @@ -265,9 +261,6 @@ const RootNetworkNodeEditor = () => { // } // }, [dispatch, dofetchRootNetworks, studyUpdatedForce, cleanClipboard]); - const isAnyNodeBuilding = useIsAnyNodeBuilding(); - - const mapDataLoading = useSelector((state: AppState) => state.mapDataLoading); const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); @@ -349,6 +342,26 @@ const RootNetworkNodeEditor = () => { // onDragEnd={commit} // onDragStart={() => setIsDragging(true)} divider + secondaryAction={(rootNetwork) => { + const isCurrentRootNetwork = rootNetwork.rootNetworkUuid === currentRootNetwork; + + return ( + + { + if (rootNetwork.rootNetworkUuid !== currentRootNetwork) { + // Set this root network as the current root network + dispatch(setCurrentRootNetwork(rootNetwork.rootNetworkUuid)); + } + }} + > + {isCurrentRootNetwork ? : } + + + ); + }} /> ); }; @@ -492,7 +505,7 @@ const RootNetworkNodeEditor = () => { onClick={openRootNetworkCreationDialog} size={'small'} sx={styles.toolbarIcon} - disabled={isAnyNodeBuilding || mapDataLoading || deleteInProgress} + disabled={false} //TODO > @@ -503,13 +516,7 @@ const RootNetworkNodeEditor = () => { onClick={doDeleteRootNetwork} size={'small'} sx={styles.toolbarIcon} - disabled={ - selectedItems.length === 0 || - isAnyNodeBuilding || - mapDataLoading || - deleteInProgress || - !currentNode - } + disabled={selectedItems.length === 0 || !currentNode} > diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 2eee9118a8..8c96b5ab02 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -423,15 +423,20 @@ export const NetworkMapTab = ({ const getMissingEquipmentsPositions = useCallback( ( notFoundEquipmentsIds: string[], - fetchEquipmentCB: (studyUuid: UUID, nodeId: UUID, equipmentIds: string[]) => Promise + fetchEquipmentCB: ( + studyUuid: UUID, + nodeId: UUID, + currentRootNetwork: UUID, + equipmentIds: string[] + ) => Promise ) => { if (notFoundEquipmentsIds.length === 0 || !currentNodeRef.current) { return Promise.resolve([]); } - return fetchEquipmentCB(studyUuid, currentNodeRef.current!.id, notFoundEquipmentsIds); + return fetchEquipmentCB(studyUuid, currentNodeRef.current!.id, currentRootNetwork, notFoundEquipmentsIds); }, - [studyUuid] + [studyUuid, currentRootNetwork] ); const updateSubstationsTemporaryGeoData = useCallback( From 8b546d486923f35dea4391689023742bc4f40ece Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Fri, 20 Dec 2024 14:57:39 +0100 Subject: [PATCH 09/51] fix: reload tree + reset equipment on root network change Signed-off-by: LE SAULNIER Kevin --- src/components/study-container.jsx | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index efd1760def..943761473c 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -224,6 +224,7 @@ export function StudyContainer({ view, onChangeTab }) { const currentRootNetwork = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); + const currentRootNetworkRef = useRef(); useAllComputingStatus(studyUuid, currentNode?.id, currentRootNetwork); @@ -620,7 +621,11 @@ export function StudyContainer({ view, onChangeTab }) { ); useEffect(() => { - if (studyUuid && currentRootNetwork && !isStudyNetworkFound) { + if ( + (studyUuid && currentRootNetwork && !isStudyNetworkFound) || + (currentRootNetworkRef.current && currentRootNetworkRef.current != currentRootNetwork) + ) { + console.log('RELOADING CHECK NETWORK', currentRootNetwork); checkNetworkExistenceAndRecreateIfNotFound(); } }, [isStudyNetworkFound, currentRootNetwork, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); @@ -658,6 +663,9 @@ export function StudyContainer({ view, onChangeTab }) { } let previousCurrentNode = currentNodeRef.current; currentNodeRef.current = currentNode; + + let previousCurrentRootNetwork = currentRootNetworkRef.current; + currentRootNetworkRef.current = currentRootNetwork; // if only node renaming, do not reload network if (isNodeRenamed(previousCurrentNode, currentNode)) { return; @@ -667,11 +675,15 @@ export function StudyContainer({ view, onChangeTab }) { } // A modification has been added to the currentNode and this one has been built incrementally. // No need to load the network because reloadImpactedSubstationsEquipments will be executed in the notification useEffect. - if (isSameNode(previousCurrentNode, currentNode) && isNodeBuilt(previousCurrentNode)) { + if ( + previousCurrentRootNetwork == currentRootNetwork && + isSameNode(previousCurrentNode, currentNode) && + isNodeBuilt(previousCurrentNode) + ) { return; } dispatch(resetEquipments()); - }, [currentNode, wsConnected, dispatch]); + }, [currentNode, currentRootNetwork, wsConnected, dispatch]); useEffect(() => { if (studyUpdatedForce.eventData.headers) { @@ -723,10 +735,10 @@ export function StudyContainer({ view, onChangeTab }) { }, [studyUuid, studyUpdatedForce, fetchStudyPath, snackInfo]); useEffect(() => { - if (studyUuid && currentRootNetwork) { + if (studyUuid) { websocketExpectedCloseRef.current = false; //dispatch root network uuid - dispatch(openStudy(studyUuid, currentRootNetwork)); + dispatch(openStudy(studyUuid)); const ws = connectNotifications(studyUuid); const wsDirectory = connectDeletedStudyNotifications(studyUuid); @@ -741,7 +753,7 @@ export function StudyContainer({ view, onChangeTab }) { } // Note: dispach, loadGeoData // connectNotifications don't change - }, [dispatch, studyUuid, currentRootNetwork, connectNotifications, connectDeletedStudyNotifications]); + }, [dispatch, studyUuid, connectNotifications, connectDeletedStudyNotifications]); useEffect(() => { if (studyUuid) { From 7c74af06a394e1c95a4226d5e060c5aef415b74f Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 23 Dec 2024 10:01:12 +0100 Subject: [PATCH 10/51] refresh spreadsheet when switching root networ + endpoint with root network uuid Signed-off-by: souissimai --- src/components/app-top-bar.jsx | 4 +- src/components/diagrams/diagram-pane.tsx | 12 +++-- .../position-diagram-pane.tsx | 5 ++- .../single-line-diagram-content.tsx | 4 ++ .../connectivity/branch-connectivity-form.tsx | 6 ++- .../connectivity/connectivity-form.jsx | 6 ++- src/components/dialogs/create-case-dialog.tsx | 11 +++-- .../dialogs/equipment-search-dialog.tsx | 4 ++ .../creation/battery-creation-form.jsx | 5 ++- .../battery-modification-form.jsx | 2 + .../equipment-deletion-dialog.jsx | 5 ++- .../equipment-deletion-form.jsx | 11 ++--- .../hvdc-lcc-deletion-utils.js | 4 +- .../creation/generator-creation-form.jsx | 6 ++- .../generator-modification-form.jsx | 5 ++- ...egulating-terminal-modification-dialog.jsx | 6 ++- .../lcc/creation/lcc-converter-station.tsx | 5 ++- .../converter-station-pane.tsx | 5 ++- .../line-attach-to-voltage-level-form.jsx | 4 ++ .../line-split-with-voltage-level-form.jsx | 6 ++- .../line-to-attach-or-split-form.jsx | 9 ++-- .../line-characteristics-pane.jsx | 5 ++- .../line-modification-dialog-tabs.jsx | 4 +- .../lines-attach-to-split-lines-form.jsx | 9 ++-- .../load/creation/load-creation-form.tsx | 6 ++- .../modification/load-modification-form.jsx | 3 +- .../shunt-compensator-creation-form.jsx | 7 +-- .../shunt-compensator-modification-form.jsx | 3 +- .../creation/set-points-limits-form.tsx | 3 ++ ...static-var-compensator-creation-dialog.tsx | 4 +- .../static-var-compensator-creation-form.tsx | 6 ++- ...nsformer-creation-characteristics-pane.jsx | 8 +++- ...ndings-transformer-modification-dialog.jsx | 6 ++- .../phase-tap-changer-pane.jsx | 2 + .../ratio-tap-changer-pane.jsx | 2 + .../regulating-terminal-form.jsx | 5 ++- .../dialogs/set-points/voltage-regulation.jsx | 2 + src/components/map-viewer.jsx | 5 ++- .../menus/operating-status-menu.tsx | 4 ++ .../network-modification-tree-pane.jsx | 6 +-- src/components/network/gs-map-equipments.ts | 10 ++--- src/components/network/network-map-tab.tsx | 45 +++++++++++++------ src/components/result-view-tab.tsx | 40 ++++++++--------- .../loadflow/load-flow-result-utils.ts | 5 ++- .../spreadsheet/config/spreadsheet.type.ts | 2 +- src/components/spreadsheet/table-wrapper.tsx | 5 ++- src/components/study-container.jsx | 40 ++++++++--------- src/components/study-pane.jsx | 8 ++-- src/components/tooltips/equipment-popover.jsx | 2 + .../top-bar-equipment-search-dialog.tsx | 5 +++ .../use-search-matching-equipments.tsx | 4 +- ...use-top-bar-search-matching-equipments.tsx | 4 +- src/hooks/use-voltage-levels-list-infos.ts | 8 ++-- src/services/study/geo-data.js | 1 - src/services/study/index.ts | 3 +- src/services/study/network-modifications.js | 8 ++-- src/services/study/network.js | 14 +++--- 57 files changed, 274 insertions(+), 145 deletions(-) diff --git a/src/components/app-top-bar.jsx b/src/components/app-top-bar.jsx index 46cdfd5395..e77cfaf642 100644 --- a/src/components/app-top-bar.jsx +++ b/src/components/app-top-bar.jsx @@ -70,7 +70,7 @@ const AppTopBar = ({ user, tabIndex, onChangeTab, userManager }) => { const theme = useSelector((state) => state[PARAM_THEME]); const studyUuid = useSelector((state) => state.studyUuid); const currentNode = useSelector((state) => state.currentTreeNode); - const currentRootNetwork = useSelector((state) => state.currentRootNetwork); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const [isDialogSearchOpen, setIsDialogSearchOpen] = useState(false); const [appsAndUrls, setAppsAndUrls] = useState([]); @@ -176,7 +176,7 @@ const AppTopBar = ({ user, tabIndex, onChangeTab, userManager }) => { diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index 4e858df1a4..964b1f1885 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -56,7 +56,7 @@ import { AppState, CurrentTreeNode, DiagramState } from 'redux/reducer'; import { SLDMetadata, DiagramMetadata } from '@powsybl/network-viewer'; // Returns a callback that returns a promise -const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode) => { +const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode, currentRootNetworkUuid: UUID) => { const { snackError } = useSnackMessage(); const paramUseName = useSelector((state: AppState) => state[PARAM_USE_NAME]); const { getNameOrId } = useNameOrId(); @@ -72,6 +72,7 @@ const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode) => { ? getVoltageLevelSingleLineDiagram( studyUuid, currentNode?.id, + currentRootNetworkUuid, voltageLevelId, paramUseName, centerName, @@ -90,6 +91,7 @@ const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode) => { ? getSubstationSingleLineDiagram( studyUuid, currentNode?.id, + currentRootNetworkUuid, voltageLevelId, paramUseName, centerName, @@ -105,7 +107,7 @@ const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode) => { const checkAndGetNetworkAreaDiagramUrl = useCallback( (voltageLevelsIds: UUID[], depth: number) => isNodeBuilt(currentNode) - ? getNetworkAreaDiagramUrl(studyUuid, currentNode?.id, voltageLevelsIds, depth, initNadWithGeoData) + ? getNetworkAreaDiagramUrl(studyUuid, currentNode?.id,currentRootNetworkUuid, voltageLevelsIds, depth, initNadWithGeoData) : null, [studyUuid, currentNode, initNadWithGeoData] ); @@ -294,6 +296,7 @@ const styles = { interface DiagramPaneProps { studyUuid: UUID; currentNode: CurrentTreeNode; + currentRootNetworkUuid: UUID; showInSpreadsheet: (equipment: { equipmentId: string | null; equipmentType: EquipmentType | null }) => void; visible: boolean; } @@ -313,17 +316,18 @@ type DiagramView = { depth?: number; error?: string; nodeId?: UUID; + rootNetworkId?: UUID; additionalMetadata?: any; fetchSvg?: () => Promise>; }; -export function DiagramPane({ studyUuid, currentNode, showInSpreadsheet, visible }: DiagramPaneProps) { +export function DiagramPane({ studyUuid, currentNode, currentRootNetworkUuid, showInSpreadsheet, visible }: DiagramPaneProps) { const dispatch = useDispatch(); const intl = useIntl(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const [views, setViews] = useState([]); const fullScreenDiagram = useSelector((state: AppState) => state.fullScreenDiagram); - const createView = useDisplayView(studyUuid, currentNode); + const createView = useDisplayView(studyUuid, currentNode, currentRootNetworkUuid); const diagramStates = useSelector((state: AppState) => state.diagramStates); const networkAreaDiagramDepth = useSelector((state: AppState) => state.networkAreaDiagramDepth); const previousNetworkAreaDiagramDepth = useRef(networkAreaDiagramDepth); diff --git a/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx b/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx index f5202d284e..346756ca09 100644 --- a/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx +++ b/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx @@ -28,6 +28,7 @@ interface PositionDiagramPaneProps { onClose: () => void; voltageLevelId?: { id: UUID }; currentNodeUuid: UUID; + currentRootNetworkUuid: UUID; studyUuid: UUID; } @@ -36,6 +37,7 @@ const PositionDiagramPane: FC = ({ onClose, voltageLevelId, currentNodeUuid, + currentRootNetworkUuid, studyUuid, }) => { const useName = useSelector((state: AppState) => state[PARAM_USE_NAME]); @@ -55,6 +57,7 @@ const PositionDiagramPane: FC = ({ getVoltageLevelSingleLineDiagram( studyUuid, currentNodeUuid, + currentRootNetworkUuid, voltageLevelId?.id, useName, centerName, @@ -63,7 +66,7 @@ const PositionDiagramPane: FC = ({ SLD_DISPLAY_MODE.FEEDER_POSITION, language ), - [studyUuid, currentNodeUuid, voltageLevelId?.id, useName, centerName, diagonalName, componentLibrary, language] + [studyUuid, currentNodeUuid,currentRootNetworkUuid, voltageLevelId?.id, useName, centerName, diagonalName, componentLibrary, language] ); useEffect(() => { diff --git a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx index dd2a8b4d68..92675e01e2 100644 --- a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx +++ b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx @@ -127,6 +127,8 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { const diagramViewerRef = useRef(); const { snackError } = useSnackMessage(); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); + const [modificationInProgress, setModificationInProgress] = useState(false); const isAnyNodeBuilding = useIsAnyNodeBuilding(); const [locallySwitchedBreaker, setLocallySwitchedBreaker] = useState(); @@ -488,6 +490,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} defaultIdValue={equipmentToModify?.equipmentId} isUpdate={true} onClose={() => closeModificationDialog()} @@ -505,6 +508,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} defaultIdValue={equipmentToDelete?.equipmentId} isUpdate={true} onClose={() => closeDeletionDialog()} diff --git a/src/components/dialogs/connectivity/branch-connectivity-form.tsx b/src/components/dialogs/connectivity/branch-connectivity-form.tsx index 2bad50dd8b..f8f3122832 100644 --- a/src/components/dialogs/connectivity/branch-connectivity-form.tsx +++ b/src/components/dialogs/connectivity/branch-connectivity-form.tsx @@ -18,6 +18,7 @@ import GridItem from '../commons/grid-item'; interface BranchConnectivityFormProps { currentNode: CurrentTreeNode; studyUuid: UUID; + currentRootNetworkUuid: UUID; isModification?: boolean; previousValues?: any; } @@ -25,10 +26,11 @@ interface BranchConnectivityFormProps { const BranchConnectivityForm: FunctionComponent = ({ currentNode, studyUuid, + currentRootNetworkUuid, isModification = false, previousValues, }) => { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id,currentRootNetworkUuid); const id1 = `${CONNECTIVITY}.${CONNECTIVITY_1}`; const id2 = `${CONNECTIVITY}.${CONNECTIVITY_2}`; @@ -37,6 +39,7 @@ const BranchConnectivityForm: FunctionComponent = ( id={id1} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} voltageLevelOptions={voltageLevelOptions} withPosition={true} isEquipmentModification={isModification} @@ -52,6 +55,7 @@ const BranchConnectivityForm: FunctionComponent = ( id={id2} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} voltageLevelOptions={voltageLevelOptions} withPosition={true} isEquipmentModification={isModification} diff --git a/src/components/dialogs/connectivity/connectivity-form.jsx b/src/components/dialogs/connectivity/connectivity-form.jsx index ae8683e5ae..6593e8f237 100644 --- a/src/components/dialogs/connectivity/connectivity-form.jsx +++ b/src/components/dialogs/connectivity/connectivity-form.jsx @@ -57,6 +57,7 @@ export const ConnectivityForm = ({ newBusOrBusbarSectionOptions = [], studyUuid, currentNode, + currentRootNetworkUuid, onVoltageLevelChangeCallback = undefined, isEquipmentModification = false, previousValues, @@ -79,7 +80,7 @@ export const ConnectivityForm = ({ return; } if (watchVoltageLevelId) { - fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid, watchVoltageLevelId).then( + fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid,currentRootNetworkUuid, watchVoltageLevelId).then( (busesOrbusbarSections) => { setBusOrBusbarSectionOptions(busesOrbusbarSections); } @@ -88,7 +89,7 @@ export const ConnectivityForm = ({ setBusOrBusbarSectionOptions([]); setValue(`${id}.${BUS_OR_BUSBAR_SECTION}`, null); } - }, [watchVoltageLevelId, studyUuid, currentNodeUuid, voltageLevelOptions, setValue, id, isEquipmentModification]); + }, [watchVoltageLevelId, studyUuid, currentNodeUuid, currentRootNetworkUuid,voltageLevelOptions, setValue, id, isEquipmentModification]); useEffect(() => { if (isEquipmentModification) { @@ -295,6 +296,7 @@ export const ConnectivityForm = ({ onClose={handleCloseDiagramPane} voltageLevelId={{ id: watchVoltageLevelId }} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> ); diff --git a/src/components/dialogs/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog.tsx index ae3da15715..c187ddb183 100644 --- a/src/components/dialogs/create-case-dialog.tsx +++ b/src/components/dialogs/create-case-dialog.tsx @@ -49,11 +49,14 @@ export default function CreateCaseDialog({ onClose, open }: Readonly(createCaseDialogFormValidationSchema), }); - const { - formState: { errors, isValid }, - } = createCaseFormMethods; +const { + formState: { errors, isValid }, + getValues, // This should be destructured directly from formMethods +} = createCaseFormMethods; - const isFormValid = isObjectEmpty(errors) && isValid; + const isFormValid = isObjectEmpty(errors) && isValid && getValues(FieldConstants.CASE_FILE) !== null; + + const userId = useSelector((state: AppState) => state.user?.profile.sub); diff --git a/src/components/dialogs/equipment-search-dialog.tsx b/src/components/dialogs/equipment-search-dialog.tsx index e4b8785693..dc6ef1843d 100644 --- a/src/components/dialogs/equipment-search-dialog.tsx +++ b/src/components/dialogs/equipment-search-dialog.tsx @@ -27,6 +27,7 @@ interface EquipmentSearchDialogProps { onSelectionChange: (equipment: EquipmentInfos) => void; equipmentType: EquipmentType; currentNodeUuid: UUID; + currentRootNetworkUuid: UUID; } /** @@ -36,6 +37,7 @@ interface EquipmentSearchDialogProps { * @param {Function} onSelectionChange: callback when the selection changes * @param {String} equipmentType: the type of equipment we want to search * @param {String} currentNodeUuid: the node selected + * @param {String} currentRootNetworkUuid: the root network UUID */ const EquipmentSearchDialog: FC = ({ open, @@ -43,6 +45,7 @@ const EquipmentSearchDialog: FC = ({ onSelectionChange, equipmentType, currentNodeUuid, + currentRootNetworkUuid }) => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); @@ -50,6 +53,7 @@ const EquipmentSearchDialog: FC = ({ // @ts-expect-error TODO: manage null case studyUuid: studyUuid, nodeUuid: currentNodeUuid, + currentRootNetworkUuid: currentRootNetworkUuid, inUpstreamBuiltParentNode: true, equipmentType: equipmentType, }); diff --git a/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx b/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx index ea4b5456e9..978e61f30b 100644 --- a/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx +++ b/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx @@ -24,8 +24,8 @@ import useVoltageLevelsListInfos from '../../../../../hooks/use-voltage-levels-l import GridItem from '../../../commons/grid-item'; import GridSection from '../../../commons/grid-section'; -const BatteryCreationForm = ({ studyUuid, currentNode }) => { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id); +const BatteryCreationForm = ({ studyUuid, currentNode, rootNetworkUuid }) => { + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id,rootNetworkUuid); const batteryIdField = ( @@ -39,6 +39,7 @@ const BatteryCreationForm = ({ studyUuid, currentNode }) => { withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={rootNetworkUuid} /> ); diff --git a/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx b/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx index 802a5f1fcc..4ec22fc3c0 100644 --- a/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx +++ b/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx @@ -27,6 +27,7 @@ import GridSection from '../../../commons/grid-section'; const BatteryModificationForm = ({ studyUuid, currentNode, + rootNetworkUuid, batteryToModify, updatePreviousReactiveCapabilityCurveTable, equipmentId, @@ -100,6 +101,7 @@ const BatteryModificationForm = ({ withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={rootNetworkUuid} isEquipmentModification={true} previousValues={batteryToModify} /> diff --git a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx index 3f3798631c..60510010ae 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx +++ b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx @@ -47,6 +47,7 @@ const emptyFormData = { const EquipmentDeletionDialog = ({ studyUuid, currentNode, + currentRootNetworkUuid, editData, isUpdate, defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the SLD/map @@ -98,6 +99,7 @@ const EquipmentDeletionDialog = ({ deleteEquipment( studyUuid, currentNodeUuid, + currentRootNetworkUuid, formData[TYPE], formData[EQUIPMENT_ID], editData?.uuid, @@ -135,7 +137,7 @@ const EquipmentDeletionDialog = ({ isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - + ); @@ -144,6 +146,7 @@ const EquipmentDeletionDialog = ({ EquipmentDeletionDialog.propTypes = { studyUuid: PropTypes.string, currentNode: PropTypes.object, + currentRootNetworkUuid: PropTypes.string, editData: PropTypes.object, isUpdate: PropTypes.bool, defaultIdValue: PropTypes.string, diff --git a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx index 78dda4deaa..0d8879dadb 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx +++ b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx @@ -25,7 +25,7 @@ import { fetchEquipmentsIds } from '../../../../services/study/network-map'; import useGetLabelEquipmentTypes from '../../../../hooks/use-get-label-equipment-types'; import GridItem from '../../commons/grid-item'; -const DeleteEquipmentForm = ({ studyUuid, currentNode, editData }) => { +const DeleteEquipmentForm = ({ studyUuid, currentNode,currentRootNetworkUuid, editData }) => { const { snackError } = useSnackMessage(); const editedIdRef = useRef(null); const currentTypeRef = useRef(null); @@ -66,7 +66,7 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode, editData }) => { currentTypeRef.current = watchType; } let ignore = false; - fetchEquipmentsIds(studyUuid, currentNode?.id, undefined, watchType, true) + fetchEquipmentsIds(studyUuid, currentNode?.id,currentRootNetworkUuid, undefined, watchType, true) .then((vals) => { // check race condition here if (!ignore) { @@ -83,10 +83,10 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode, editData }) => { ignore = true; }; } - }, [studyUuid, currentNode?.id, watchType, snackError]); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid,watchType, snackError]); useEffect(() => { - if (studyUuid && currentNode?.id) { + if (studyUuid && currentNode?.id && currentRootNetworkUuid) { if (editData?.equipmentId) { if (editedIdRef.current === null) { // The first time we render an edition, we want to merge the @@ -104,6 +104,7 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode, editData }) => { hvdcLccSpecificUpdate( studyUuid, currentNode?.id, + currentRootNetworkUuid, watchEquipmentId, watchEquipmentId === editedIdRef.current ? editData : null ); @@ -111,7 +112,7 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode, editData }) => { setValue(DELETION_SPECIFIC_DATA, null); } } - }, [studyUuid, currentNode?.id, watchEquipmentId, snackError, setValue, hvdcLccSpecificUpdate, editData]); + }, [studyUuid, currentNode?.id,currentRootNetworkUuid, watchEquipmentId, snackError, setValue, hvdcLccSpecificUpdate, editData]); const handleChange = useCallback(() => { setValue(EQUIPMENT_ID, null); diff --git a/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js b/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js index 3837004c80..9e6e9056ec 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js +++ b/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js @@ -78,8 +78,8 @@ const useHvdcLccDeletion = () => { ); const specificUpdate = useCallback( - (studyUuid, nodeId, equipmentId, editData) => { - fetchHvdcLineWithShuntCompensators(studyUuid, nodeId, equipmentId) + (studyUuid, nodeId,rootNetworkUuid, equipmentId, editData) => { + fetchHvdcLineWithShuntCompensators(studyUuid, nodeId,rootNetworkUuid, equipmentId) .then((hvdcLineData) => { updateMcsLists(hvdcLineData, editData); }) diff --git a/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx b/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx index 2b85c99e1a..c6bb83eb0c 100644 --- a/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx +++ b/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx @@ -37,9 +37,9 @@ import useVoltageLevelsListInfos from '../../../../../hooks/use-voltage-levels-l import GridItem from '../../../commons/grid-item'; import GridSection from '../../../commons/grid-section'; -const GeneratorCreationForm = ({ studyUuid, currentNode }) => { +const GeneratorCreationForm = ({ studyUuid, currentNode, currentRootNetworkUuid }) => { const currentNodeUuid = currentNode?.id; - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid,currentRootNetworkUuid); const generatorIdField = ( @@ -65,6 +65,7 @@ const GeneratorCreationForm = ({ studyUuid, currentNode }) => { withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} /> ); @@ -132,6 +133,7 @@ const GeneratorCreationForm = ({ studyUuid, currentNode }) => { diff --git a/src/components/dialogs/network-modifications/generator/modification/generator-modification-form.jsx b/src/components/dialogs/network-modifications/generator/modification/generator-modification-form.jsx index 3454661ed8..338d55edc0 100644 --- a/src/components/dialogs/network-modifications/generator/modification/generator-modification-form.jsx +++ b/src/components/dialogs/network-modifications/generator/modification/generator-modification-form.jsx @@ -34,13 +34,14 @@ import GridSection from '../../../commons/grid-section'; const GeneratorModificationForm = ({ studyUuid, currentNode, + currentRootNetworkUuid, generatorToModify, updatePreviousReactiveCapabilityCurveTable, equipmentId, }) => { const currentNodeUuid = currentNode?.id; const intl = useIntl(); - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid, currentRootNetworkUuid); const energySourceLabelId = getEnergySourceLabel(generatorToModify?.energySource); const previousEnergySourceLabel = energySourceLabelId @@ -181,6 +182,7 @@ const GeneratorModificationForm = ({ withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} isEquipmentModification={true} previousValues={generatorToModify} /> @@ -232,6 +234,7 @@ const GeneratorModificationForm = ({ { - if (studyUuid && currentNode.id) { - fetchVoltageLevelsListInfos(studyUuid, currentNode.id) + if (studyUuid && currentNode.id && currentRootNetworkUuid) { + fetchVoltageLevelsListInfos(studyUuid, currentNode.id,currentRootNetworkUuid) .then((values) => { setVoltageLevelOptions(values.sort((a, b) => a.id.localeCompare(b.id))); }) @@ -125,6 +126,7 @@ const RegulatingTerminalModificationDialog = ({ voltageLevelOptions={voltageLevelOptions} equipmentSectionTypeDefaultValue={''} currentNodeUuid={currentNode.id} + currentRootNetworkUuid={currentRootNetworkUuid} studyUuid={studyUuid} previousRegulatingTerminalValue={previousData?.regulatingTerminalVlId} previousEquipmentSectionTypeValue={getTapChangerEquipmentSectionTypeValue(previousData)} diff --git a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx index 8776060cf9..7e3c5da11a 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx @@ -211,6 +211,7 @@ interface LccConverterStationProps { id: string; stationLabel: string; currentNode: CurrentTreeNode; + currentRootNetworkUuid: UUID; studyUuid: UUID; } @@ -219,8 +220,9 @@ export default function LccConverterStation({ stationLabel, currentNode, studyUuid, + currentRootNetworkUuid }: Readonly) { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id,currentRootNetworkUuid); const stationIdField = ; @@ -233,6 +235,7 @@ export default function LccConverterStation({ withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} previousValues={undefined} /> ); diff --git a/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx b/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx index 069b988c18..f955e806b8 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx @@ -40,6 +40,7 @@ interface VscConverterStationPaneProps { stationLabel: string; currentNode: CurrentTreeNode; studyUuid: UUID; + currentRootNetworkUuid:UUID; isModification?: boolean; previousValues?: ConverterStationElementModificationInfos | null; updatePreviousReactiveCapabilityCurveTableConverterStation?: UpdateReactiveCapabilityCurveTable; @@ -50,6 +51,7 @@ const ConverterStationPane: FunctionComponent = ({ stationLabel, currentNode, studyUuid, + currentRootNetworkUuid, isModification = false, previousValues, updatePreviousReactiveCapabilityCurveTableConverterStation, @@ -68,7 +70,7 @@ const ConverterStationPane: FunctionComponent = ({ } }); - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id,currentRootNetworkUuid); const generatorIdField = isModification ? ( = ({ withPosition={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} isEquipmentModification={isModification} previousValues={previousValues} /> diff --git a/src/components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-form.jsx b/src/components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-form.jsx index ac83244193..9668adfa8f 100644 --- a/src/components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-form.jsx +++ b/src/components/dialogs/network-modifications/line-attach-to-voltage-level/line-attach-to-voltage-level-form.jsx @@ -36,6 +36,7 @@ import GridItem from '../../commons/grid-item'; const LineAttachToVoltageLevelForm = ({ studyUuid, currentNode, + currentRootNetworkUuid, onLineCreationDo, lineToEdit, onVoltageLevelCreationDo, @@ -102,6 +103,7 @@ const LineAttachToVoltageLevelForm = ({ newBusOrBusbarSectionOptions={busbarSectionOptions} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} /> ); @@ -160,6 +162,7 @@ const LineAttachToVoltageLevelForm = ({ onClose={onVoltageLevelDialogClose} currentNode={currentNode} studyUuid={studyUuid} + currentRootNetworkUuid={currentRootNetworkUuid} onCreateVoltageLevel={onVoltageLevelCreationDo} editData={isVoltageLevelEdit ? voltageLevelToEdit : null} /> @@ -170,6 +173,7 @@ const LineAttachToVoltageLevelForm = ({ onClose={onLineDialogClose} currentNode={currentNode} studyUuid={studyUuid} + currentRootNetworkUuid={currentRootNetworkUuid} displayConnectivity={false} onCreateLine={onLineCreationDo} editData={lineToEdit} diff --git a/src/components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-form.jsx b/src/components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-form.jsx index 4058b750b4..b081c2b154 100644 --- a/src/components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-form.jsx +++ b/src/components/dialogs/network-modifications/line-split-with-voltage-level/line-split-with-voltage-level-form.jsx @@ -24,6 +24,7 @@ import GridItem from '../../commons/grid-item'; const LineSplitWithVoltageLevelForm = ({ studyUuid, currentNode, + currentRootNetworkUuid, onVoltageLevelCreationDo, voltageLevelToEdit, allVoltageLevelOptions, @@ -43,7 +44,8 @@ const LineSplitWithVoltageLevelForm = ({ }; const lineToSplitForm = ( - + ); const newLine1IdField = ; @@ -71,6 +73,7 @@ const LineSplitWithVoltageLevelForm = ({ newBusOrBusbarSectionOptions={busbarSectionOptions} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} /> ); @@ -110,6 +113,7 @@ const LineSplitWithVoltageLevelForm = ({ onClose={onVoltageLevelDialogClose} currentNode={currentNode} studyUuid={studyUuid} + currentRootNetworkUuid={currentRootNetworkUuid} onCreateVoltageLevel={onVoltageLevelCreationDo} editData={isVoltageLevelEdit ? voltageLevelToEdit : null} /> diff --git a/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx b/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx index e69c421f78..b9687f7099 100644 --- a/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx +++ b/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx @@ -17,7 +17,7 @@ import { EQUIPMENT_TYPES } from '../../../utils/equipment-types'; import { fetchEquipmentsIds } from '../../../../services/study/network-map'; import GridItem from '../../commons/grid-item'; -export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode }) => { +export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode,currentRootNetworkUuid }) => { const [line1Substation, setLine1Substation] = useState(''); const [line2Substation, setLine2Substation] = useState(''); const [linesOptions, setLinesOptions] = useState([]); @@ -27,8 +27,9 @@ export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode }) => { }); useEffect(() => { - if (studyUuid && currentNode?.id) { - fetchEquipmentsIds(studyUuid, currentNode?.id, undefined, EQUIPMENT_TYPES.LINE, true) + if (studyUuid && currentNode?.id && currentRootNetworkUuid) { + fetchEquipmentsIds(studyUuid, currentNode?.id, currentRootNetworkUuid +, undefined, EQUIPMENT_TYPES.LINE, true) .then((values) => { setLinesOptions(values.sort()); }) @@ -39,7 +40,7 @@ export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode }) => { }); }); } - }, [studyUuid, currentNode?.id, watchLineToAttachOrSplit, snackError]); + }, [studyUuid, currentNode?.id,currentRootNetworkUuid, watchLineToAttachOrSplit, snackError]); useEffect(() => { const lineToAttachOrSplit = linesOptions.find((l) => l?.id === watchLineToAttachOrSplit); diff --git a/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx b/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx index b4a8e3faf7..7a7b098cf5 100644 --- a/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx +++ b/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx @@ -37,13 +37,14 @@ const LineCharacteristicsPane = ({ id = CHARACTERISTICS, studyUuid, currentNode, + currentRootNetworkUuid, displayConnectivity, lineToModify, clearableFields = false, isModification = false, }) => { const currentNodeUuid = currentNode.id; - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid,currentRootNetworkUuid); const seriesResistanceField = ( @@ -120,6 +122,7 @@ const LineCharacteristicsPane = ({ id={`${id}.${CONNECTIVITY_2}`} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} voltageLevelOptions={voltageLevelOptions} withPosition={true} /> diff --git a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog-tabs.jsx b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog-tabs.jsx index 4de8ca5fb6..f1ae33b1c6 100644 --- a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog-tabs.jsx +++ b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog-tabs.jsx @@ -11,13 +11,14 @@ import LimitsPane from '../../../limits/limits-pane'; import LineCharacteristicsPane from '../characteristics-pane/line-characteristics-pane'; import BranchConnectivityForm from '../../../connectivity/branch-connectivity-form'; -const LineModificationDialogTabs = ({ studyUuid, currentNode, lineToModify, tabIndex }) => { +const LineModificationDialogTabs = ({ studyUuid, currentNode,currentRootNetworkUuid, lineToModify, tabIndex }) => { return ( <> diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/creation/characteristics-pane/two-windings-transformer-creation-characteristics-pane.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/creation/characteristics-pane/two-windings-transformer-creation-characteristics-pane.jsx index 8817a3d549..6d0a5a881a 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/creation/characteristics-pane/two-windings-transformer-creation-characteristics-pane.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/creation/characteristics-pane/two-windings-transformer-creation-characteristics-pane.jsx @@ -29,14 +29,17 @@ const TwoWindingsTransformerCreationCharacteristicsPane = ({ id = CHARACTERISTICS, studyUuid, currentNode, + currentRootNetworkUuid, tabIndex, }) => { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id, currentRootNetworkUuid + ); const connectivity1Field = ( @@ -47,6 +50,7 @@ const TwoWindingsTransformerCreationCharacteristicsPane = ({ id={`${id}.${CONNECTIVITY_2}`} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} voltageLevelOptions={voltageLevelOptions} withPosition={true} /> @@ -81,6 +85,7 @@ const TwoWindingsTransformerCreationCharacteristicsPane = ({ @@ -89,6 +94,7 @@ const TwoWindingsTransformerCreationCharacteristicsPane = ({ diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx index 50b554707d..9af529b2a4 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx @@ -171,6 +171,7 @@ const TwoWindingsTransformerModificationDialog = ({ studyUuid, defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the SLD currentNode, + currentRootNetworkUuid, isUpdate, editData, // contains data when we try to edit an existing hypothesis from the current node's list editDataFetchStatus, @@ -189,7 +190,7 @@ const TwoWindingsTransformerModificationDialog = ({ resolver: yupResolver(formSchema), }); const { reset, getValues, setValue } = formMethods; - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid,currentRootNetworkUuid); const computeRatioTapChangerRegulationMode = (ratioTapChangerFormValues) => { if (ratioTapChangerFormValues?.[REGULATING]?.value == null) { @@ -525,6 +526,7 @@ const TwoWindingsTransformerModificationDialog = ({ currentNode, studyUuid, currentNodeUuid, + currentRootNetworkUuid, selectedId, fillRatioTapChangerRegulationAttributes, fillPhaseTapChangerRegulationAttributes, @@ -691,6 +693,7 @@ const TwoWindingsTransformerModificationDialog = ({ { if (watchVoltageLevelId) { - fetchVoltageLevelEquipments(studyUuid, currentNodeUuid, undefined, watchVoltageLevelId, true).then( + fetchVoltageLevelEquipments(studyUuid, currentNodeUuid,currentRootNetworkUuid, undefined, watchVoltageLevelId, true).then( (values) => { setEquipmentsOptions(values); } @@ -66,7 +67,7 @@ const RegulatingTerminalForm = ({ } else { setEquipmentsOptions([]); } - }, [watchVoltageLevelId, id, studyUuid, currentNodeUuid]); + }, [watchVoltageLevelId, id, studyUuid, currentNodeUuid, currentRootNetworkUuid]); const resetEquipment = useCallback(() => { setValue(`${id}.${EQUIPMENT}`, null); diff --git a/src/components/dialogs/set-points/voltage-regulation.jsx b/src/components/dialogs/set-points/voltage-regulation.jsx index 6d239eaeae..4c04c58aea 100644 --- a/src/components/dialogs/set-points/voltage-regulation.jsx +++ b/src/components/dialogs/set-points/voltage-regulation.jsx @@ -19,6 +19,7 @@ import GridItem from '../commons/grid-item'; const VoltageRegulation = ({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, voltageLevelOptions, previousValues, isEquipmentModification, @@ -78,6 +79,7 @@ const VoltageRegulation = ({ voltageLevelOptions={voltageLevelOptions} equipmentSectionTypeDefaultValue={''} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} studyUuid={studyUuid} previousRegulatingTerminalValue={previousValues?.regulatingTerminalVlId} previousEquipmentSectionTypeValue={ diff --git a/src/components/map-viewer.jsx b/src/components/map-viewer.jsx index ee659ccc3b..15dd0c22f2 100644 --- a/src/components/map-viewer.jsx +++ b/src/components/map-viewer.jsx @@ -137,7 +137,7 @@ export const Content = () => ( const MapViewer = ({ studyUuid, currentNode, - currentRootNetwork, + currentRootNetworkUuid, view, openDiagramView, tableEquipment, @@ -322,7 +322,7 @@ const MapViewer = ({ lineFlowAlertThreshold={lineFlowAlertThreshold} openVoltageLevel={openVoltageLevel} currentNode={currentNode} - currentRootNetwork={currentRootNetwork} + currentRootNetworkUuid={currentRootNetworkUuid} onChangeTab={onChangeTab} showInSpreadsheet={showInSpreadsheet} setErrorMessage={setErrorMessage} @@ -350,6 +350,7 @@ const MapViewer = ({ studyUuid={studyUuid} showInSpreadsheet={showInSpreadsheet} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} visible={ !isInDrawingMode && view === StudyView.MAP && diff --git a/src/components/menus/operating-status-menu.tsx b/src/components/menus/operating-status-menu.tsx index d05f94001e..b216f12ea6 100644 --- a/src/components/menus/operating-status-menu.tsx +++ b/src/components/menus/operating-status-menu.tsx @@ -63,6 +63,7 @@ export type MenuBranchProps = { onOpenDynamicSimulationEventDialog?: (id: string, type: EquipmentType | null, dialogTitle: string) => void; currentNode?: CurrentTreeNode; studyUuid?: UUID; + currentRootNetworkUuid?: UUID; modificationInProgress?: boolean; setModificationInProgress?: (progress: boolean) => void; }; @@ -81,6 +82,7 @@ const withOperatingStatusMenu = onOpenDynamicSimulationEventDialog, currentNode, studyUuid, + currentRootNetworkUuid, modificationInProgress, setModificationInProgress, }: MenuBranchProps) => { @@ -103,6 +105,7 @@ const withOperatingStatusMenu = fetchNetworkElementInfos( studyUuid, currentNode?.id, + currentRootNetworkUuid, equipmentType, EQUIPMENT_INFOS_TYPES.OPERATING_STATUS.type, equipment.id, @@ -403,6 +406,7 @@ withOperatingStatusMenu.propTypes = { onOpenDynamicSimulationEventDialog: PropTypes.func.isRequired, currentNode: PropTypes.object, studyUuid: PropTypes.string.isRequired, + currentRootNetworkUuid: PropTypes.string.isRequired, modificationInProgress: PropTypes.func, setModificationInProgress: PropTypes.func, }; diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index b88d9bd80f..007e7e52a7 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -132,7 +132,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const [activeNode, setActiveNode] = useState(null); const currentNode = useSelector((state) => state.currentTreeNode); - const currentRootNetwork = useSelector((state) => state.currentRootNetwork); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); currentNodeRef.current = currentNode; @@ -399,7 +399,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const handleBuildNode = useCallback( (element) => { - buildNode(studyUuid, element.id, currentRootNetwork).catch((error) => { + buildNode(studyUuid, element.id, currentRootNetworkUuid).catch((error) => { if (error.status === 403 && error.message.includes(HTTP_MAX_NODE_BUILDS_EXCEEDED_MESSAGE)) { // retrieve last word of the message (ex: "MAX_NODE_BUILDS_EXCEEDED max allowed built nodes : 2" -> 2) let limit = error.message.split(/[: ]+/).pop(); @@ -415,7 +415,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) } }); }, - [studyUuid, currentRootNetwork, snackError] + [studyUuid, currentRootNetworkUuid, snackError] ); const [openExportDialog, setOpenExportDialog] = useState(false); diff --git a/src/components/network/gs-map-equipments.ts b/src/components/network/gs-map-equipments.ts index 71f7512bef..6e637ecf42 100644 --- a/src/components/network/gs-map-equipments.ts +++ b/src/components/network/gs-map-equipments.ts @@ -140,28 +140,28 @@ export default class GSMapEquipments extends MapEquipments { reloadImpactedSubstationsEquipments( studyUuid: UUID, currentNode: any, - rootNetworkUuid: UUID, + currentRootNetworkUuid: UUID, substationsIds: string[] | null ) { const updatedSubstations = fetchSubstationsMapInfos( studyUuid, currentNode?.id, - rootNetworkUuid, + currentRootNetworkUuid, substationsIds, true ); - const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, rootNetworkUuid, substationsIds, true); + const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, currentRootNetworkUuid, substationsIds, true); const updatedTieLines = fetchTieLinesMapInfos( studyUuid, currentNode?.id, - rootNetworkUuid, + currentRootNetworkUuid, substationsIds, true ); const updatedHvdcLines = fetchHvdcLinesMapInfos( studyUuid, currentNode?.id, - rootNetworkUuid, + currentRootNetworkUuid, substationsIds, true ); diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 8c96b5ab02..1ae536d5e3 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -84,7 +84,7 @@ type NetworkMapTabProps = { networkMapRef: React.RefObject; studyUuid: UUID; currentNode: CurrentTreeNode; - currentRootNetwork: UUID; + currentRootNetworkUuid: UUID; visible: boolean; lineFullPath: boolean; lineParallelPath: boolean; @@ -106,7 +106,7 @@ export const NetworkMapTab = ({ /* redux can be use as redux*/ studyUuid, currentNode, - currentRootNetwork, + currentRootNetworkUuid, /* visual*/ visible, lineFullPath, @@ -157,6 +157,7 @@ export const NetworkMapTab = ({ const basicDataReady = mapEquipments && geoData; const lineFullPathRef = useRef(); + const rootNetworkRef = useRef(); /* This Set stores the geo data that are collected from the server AFTER the initialization. @@ -426,7 +427,7 @@ export const NetworkMapTab = ({ fetchEquipmentCB: ( studyUuid: UUID, nodeId: UUID, - currentRootNetwork: UUID, + currentRootNetworkUuid: UUID, equipmentIds: string[] ) => Promise ) => { @@ -434,9 +435,9 @@ export const NetworkMapTab = ({ return Promise.resolve([]); } - return fetchEquipmentCB(studyUuid, currentNodeRef.current!.id, currentRootNetwork, notFoundEquipmentsIds); + return fetchEquipmentCB(studyUuid, currentNodeRef.current!.id, currentRootNetworkUuid, notFoundEquipmentsIds); }, - [studyUuid, currentRootNetwork] + [studyUuid, currentRootNetworkUuid] ); const updateSubstationsTemporaryGeoData = useCallback( @@ -588,7 +589,7 @@ export const NetworkMapTab = ({ console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); - const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetwork).then( + const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetworkUuid).then( (data) => { console.info(`Received substations of study '${studyUuid}'...`); const newGeoData = new GeoData(new Map(), geoDataRef.current?.linePositionsById || new Map()); @@ -600,7 +601,7 @@ export const NetworkMapTab = ({ const linePositionsDone = !lineFullPath ? Promise.resolve() - : fetchLinePositions(studyUuid, rootNodeId, currentRootNetwork).then((data) => { + : fetchLinePositions(studyUuid, rootNodeId, currentRootNetworkUuid).then((data) => { console.info(`Received lines of study '${studyUuid}'...`); const newGeoData = new GeoData(geoDataRef.current?.substationPositionsById || new Map(), new Map()); newGeoData.setLinePositions(data); @@ -623,7 +624,7 @@ export const NetworkMapTab = ({ .finally(() => { dispatch(setMapDataLoading(false)); }); - }, [rootNodeId, currentRootNetwork, lineFullPath, studyUuid, dispatch, snackError]); + }, [rootNodeId, currentRootNetworkUuid, lineFullPath, studyUuid, dispatch, snackError]); const loadGeoData = useCallback(() => { if (studyUuid && currentNodeRef.current) { @@ -661,7 +662,7 @@ export const NetworkMapTab = ({ const gSMapEquipments = new GSMapEquipments( studyUuid, currentNode?.id, - currentRootNetwork, + currentRootNetworkUuid, snackError, dispatch, intlRef @@ -669,7 +670,7 @@ export const NetworkMapTab = ({ if (gSMapEquipments) { dispatch(resetMapReloaded()); } - }, [currentNode, currentRootNetwork, dispatch, intlRef, snackError, studyUuid]); + }, [currentNode, currentRootNetworkUuid, dispatch, intlRef, snackError, studyUuid]); const reloadMapEquipments = useCallback( (currentNodeAtReloadCalling: CurrentTreeNode | null, substationsIds: UUID[] | undefined) => { @@ -681,7 +682,7 @@ export const NetworkMapTab = ({ ? mapEquipments.reloadImpactedSubstationsEquipments( studyUuid, currentNode, - currentRootNetwork, + currentRootNetworkUuid, substationsIds ?? null ) : { @@ -720,7 +721,7 @@ export const NetworkMapTab = ({ dispatch(setMapDataLoading(false)); }); }, - [currentNode, currentRootNetwork, dispatch, mapEquipments, studyUuid] + [currentNode, currentRootNetworkUuid, dispatch, mapEquipments, studyUuid] ); const updateMapEquipments = useCallback( @@ -877,7 +878,25 @@ export const NetworkMapTab = ({ if (isInitialized && lineFullPath && !prevLineFullPath) { loadGeoData(); } - }, [isInitialized, lineFullPath, loadGeoData]); + }, [isInitialized, lineFullPath, loadGeoData, currentRootNetworkUuid]); + + + // Effect to handle changes in currentRootNetworkUuid +useEffect(() => { + const prevRootNetworkPath = rootNetworkRef.current; + rootNetworkRef.current = currentRootNetworkUuid; + + if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath) { + console.log("yyyyyyyyyyyyyy"); + loadRootNodeGeoData(); + // set initialized to false to trigger "missing geo-data fetching" + setInitialized(false); + // set isRootNodeGeoDataLoaded to false so "missing geo-data fetching" waits for root node geo-data to be fully fetched before triggering + setIsRootNodeGeoDataLoaded(false); + } +}, [currentRootNetworkUuid, loadRootNodeGeoData]); + + let choiceVoltageLevelsSubstation: EquipmentMap | null = null; if (choiceVoltageLevelsSubstationId) { diff --git a/src/components/result-view-tab.tsx b/src/components/result-view-tab.tsx index 5d4d500fb8..e34628d0df 100644 --- a/src/components/result-view-tab.tsx +++ b/src/components/result-view-tab.tsx @@ -46,7 +46,7 @@ const styles = { interface IResultViewTabProps { studyUuid: UUID; currentNode: CurrentTreeNode; - currentRootNetwork: UUID; + currentRootNetworkUuid: UUID; openVoltageLevelDiagram: (voltageLevelId: string) => void; disabled: boolean; view: string; @@ -63,7 +63,7 @@ export interface IService { * control results views * @param studyUuid : string uuid of study * @param currentNode : object current node - * @param currentRootNetwork : uuid of current root network + * @param currentRootNetworkUuid : uuid of current root network * @param openVoltageLevelDiagram : function * @param resultTabIndexRedirection : ResultTabIndexRedirection to specific tab [RootTab, LevelOneTab, ...] * @param disabled @@ -73,7 +73,7 @@ export interface IService { export const ResultViewTab: FunctionComponent = ({ studyUuid, currentNode, - currentRootNetwork, + currentRootNetworkUuid, openVoltageLevelDiagram, disabled, view, @@ -98,11 +98,11 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderSecurityAnalysisResult = useMemo(() => { return ( @@ -110,12 +110,12 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork, openVoltageLevelDiagram]); + }, [studyUuid, currentNode, currentRootNetworkUuid, openVoltageLevelDiagram]); const renderVoltageInitResult = useMemo(() => { return ( @@ -123,11 +123,11 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderSensitivityAnalysisResult = useMemo(() => { return ( @@ -135,24 +135,24 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderNonEvacuatedEnergyResult = useMemo(() => { - console.log('ùùùùùù renderNonEvacuatedEnergyResult ',currentRootNetwork); + console.log('ùùùùùù renderNonEvacuatedEnergyResult ',currentRootNetworkUuid); return ( ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderShortCircuitAnalysisResult = useMemo(() => { return ( @@ -160,12 +160,12 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [view, currentNode?.id, studyUuid, currentRootNetwork]); + }, [view, currentNode?.id, studyUuid, currentRootNetworkUuid]); const renderDynamicSimulationResult = useMemo(() => { return ( @@ -173,11 +173,11 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderStateEstimationResult = useMemo(() => { return ( @@ -185,11 +185,11 @@ export const ResultViewTab: FunctionComponent = ({ ); - }, [studyUuid, currentNode, currentRootNetwork]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const services: IService[] = useMemo(() => { return [ diff --git a/src/components/results/loadflow/load-flow-result-utils.ts b/src/components/results/loadflow/load-flow-result-utils.ts index 077174b1bf..0c52bb3e7d 100644 --- a/src/components/results/loadflow/load-flow-result-utils.ts +++ b/src/components/results/loadflow/load-flow-result-utils.ts @@ -174,17 +174,18 @@ export const useFetchFiltersEnums = (): { }); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); const loadFlowStatus = useSelector((state: AppState) => state.computingStatus[ComputingType.LOAD_FLOW]); useEffect(() => { - if (loadFlowStatus !== RunningStatus.SUCCEED || !studyUuid || !currentNode?.id) { + if (loadFlowStatus !== RunningStatus.SUCCEED || !studyUuid || !currentNode?.id || !currentRootNetwork) { return; } const filterTypes = ['computation-status', 'limit-types', 'branch-sides']; const promises = filterTypes.map((filterType) => - fetchAvailableFilterEnumValues(studyUuid, currentNode.id, computingType.LOAD_FLOW, filterType) + fetchAvailableFilterEnumValues(studyUuid, currentNode.id, currentRootNetwork, computingType.LOAD_FLOW, filterType) ); setLoading(true); diff --git a/src/components/spreadsheet/config/spreadsheet.type.ts b/src/components/spreadsheet/config/spreadsheet.type.ts index 7424f7df75..aaa7c75b3c 100644 --- a/src/components/spreadsheet/config/spreadsheet.type.ts +++ b/src/components/spreadsheet/config/spreadsheet.type.ts @@ -9,7 +9,7 @@ import type { UUID } from 'crypto'; import type { EQUIPMENT_TYPES } from '../../utils/equipment-types'; import type { CustomColDef } from '../../custom-aggrid/custom-aggrid-header.type'; -export type EquipmentFetcher = (studyUuid: UUID, currentNodeUuid: UUID, substationsIds: string[]) => Promise; +export type EquipmentFetcher = (studyUuid: UUID, currentNodeUuid: UUID,currentRootNetworkUuid:UUID, substationsIds: string[]) => Promise; export type SpreadsheetEquipmentType = Exclude< EQUIPMENT_TYPES, diff --git a/src/components/spreadsheet/table-wrapper.tsx b/src/components/spreadsheet/table-wrapper.tsx index ceda8c2113..623140cddc 100644 --- a/src/components/spreadsheet/table-wrapper.tsx +++ b/src/components/spreadsheet/table-wrapper.tsx @@ -145,6 +145,7 @@ const styles = { interface TableWrapperProps { studyUuid: string; currentNode: CurrentTreeNode; + currentRootNetworkUuid: string; equipmentId: string; equipmentType: SpreadsheetEquipmentType; equipmentChanged: boolean; @@ -154,6 +155,7 @@ interface TableWrapperProps { const TableWrapper: FunctionComponent = ({ studyUuid, currentNode, + currentRootNetworkUuid, equipmentId, equipmentType, equipmentChanged, @@ -1106,6 +1108,7 @@ const TableWrapper: FunctionComponent = ({ fetchNetworkElementInfos( studyUuid, currentNode.id, + currentRootNetworkUuid, lastModifiedEquipment.metadata.equipmentType, EQUIPMENT_INFOS_TYPES.TAB.type, lastModifiedEquipment.id, @@ -1125,7 +1128,7 @@ const TableWrapper: FunctionComponent = ({ }); } } - }, [lastModifiedEquipment, currentNode.id, studyUuid, studyUpdatedForce, formatFetchedEquipmentHandler, dispatch]); + }, [lastModifiedEquipment, currentNode.id, studyUuid,currentRootNetworkUuid, studyUpdatedForce, formatFetchedEquipmentHandler, dispatch]); //this listener is called for each cell modified const handleCellEditingStopped = useCallback( diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 943761473c..980d98c0fe 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -221,12 +221,12 @@ export function StudyContainer({ view, onChangeTab }) { const dispatch = useDispatch(); const currentNode = useSelector((state) => state.currentTreeNode); - const currentRootNetwork = useSelector((state) => state.currentRootNetwork); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); const currentRootNetworkRef = useRef(); - useAllComputingStatus(studyUuid, currentNode?.id, currentRootNetwork); + useAllComputingStatus(studyUuid, currentNode?.id, currentRootNetworkUuid); const studyUpdatedForce = useSelector((state) => state.studyUpdated); @@ -334,8 +334,7 @@ export function StudyContainer({ view, onChangeTab }) { }, [snackInfo, snackWarning, snackError, userName] ); - console.info(`%%%%%%%%% ????'${currentRootNetwork}'...`); - + const connectNotifications = useCallback( (studyUuid) => { console.info(`Connecting to notifications '${studyUuid}'...`); @@ -477,7 +476,7 @@ export function StudyContainer({ view, onChangeTab }) { const networkModificationTreeModel = new NetworkModificationTreeModel(); networkModificationTreeModel.setTreeElements(tree); - fetchCaseName(studyUuid, currentRootNetwork) + fetchCaseName(studyUuid, currentRootNetworkUuid) .then((res) => { if (res) { networkModificationTreeModel.setCaseName(res); @@ -519,12 +518,12 @@ export function StudyContainer({ view, onChangeTab }) { .finally(() => console.debug('Network modification tree loading finished')); // Note: studyUuid and dispatch don't change }, - [studyUuid, currentRootNetwork, dispatch, snackError, snackWarning] + [studyUuid, currentRootNetworkUuid, dispatch, snackError, snackWarning] ); const checkStudyIndexation = useCallback(() => { setIsStudyIndexationPending(true); - return fetchStudyIndexationStatus(studyUuid, currentRootNetwork) + return fetchStudyIndexationStatus(studyUuid, currentRootNetworkUuid) .then((status) => { switch (status) { case StudyIndexationStatus.INDEXED: { @@ -538,7 +537,7 @@ export function StudyContainer({ view, onChangeTab }) { } case StudyIndexationStatus.NOT_INDEXED: { dispatch(setStudyIndexationStatus(status)); - reindexAllStudy(studyUuid, currentRootNetwork) + reindexAllStudy(studyUuid, currentRootNetworkUuid) .catch((error) => { // unknown error when trying to reindex study snackError({ @@ -569,11 +568,11 @@ export function StudyContainer({ view, onChangeTab }) { headerId: 'checkstudyIndexationError', }); }); - }, [studyUuid, currentRootNetwork, dispatch, snackError]); + }, [studyUuid, currentRootNetworkUuid, dispatch, snackError]); const checkNetworkExistenceAndRecreateIfNotFound = useCallback( (successCallback) => { - fetchNetworkExistence(studyUuid, currentRootNetwork) + fetchNetworkExistence(studyUuid, currentRootNetworkUuid) .then((response) => { if (response.status === HttpStatusCode.OK) { successCallback && successCallback(); @@ -583,7 +582,7 @@ export function StudyContainer({ view, onChangeTab }) { // response.state === NO_CONTENT // if network is not found, we try to recreate study network from existing case setIsStudyNetworkFound(false); - recreateStudyNetwork(studyUuid, currentRootNetwork) + recreateStudyNetwork(studyUuid, currentRootNetworkUuid) .then(() => { snackWarning({ headerId: 'recreatingNetworkStudy', @@ -617,18 +616,18 @@ export function StudyContainer({ view, onChangeTab }) { ); }); }, - [studyUuid, currentRootNetwork, checkStudyIndexation, loadTree, snackWarning, intlRef] + [studyUuid, currentRootNetworkUuid, checkStudyIndexation, loadTree, snackWarning, intlRef] ); useEffect(() => { if ( - (studyUuid && currentRootNetwork && !isStudyNetworkFound) || - (currentRootNetworkRef.current && currentRootNetworkRef.current != currentRootNetwork) + (studyUuid && currentRootNetworkUuid && !isStudyNetworkFound) || + (currentRootNetworkRef.current && currentRootNetworkRef.current != currentRootNetworkUuid) ) { - console.log('RELOADING CHECK NETWORK', currentRootNetwork); + console.log('RELOADING CHECK NETWORK', currentRootNetworkUuid); checkNetworkExistenceAndRecreateIfNotFound(); } - }, [isStudyNetworkFound, currentRootNetwork, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); + }, [isStudyNetworkFound, currentRootNetworkUuid, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); // study_network_recreation_done notification // checking another time if we can find network, if we do, we display a snackbar info @@ -665,7 +664,7 @@ export function StudyContainer({ view, onChangeTab }) { currentNodeRef.current = currentNode; let previousCurrentRootNetwork = currentRootNetworkRef.current; - currentRootNetworkRef.current = currentRootNetwork; + currentRootNetworkRef.current = currentRootNetworkUuid; // if only node renaming, do not reload network if (isNodeRenamed(previousCurrentNode, currentNode)) { return; @@ -676,14 +675,14 @@ export function StudyContainer({ view, onChangeTab }) { // A modification has been added to the currentNode and this one has been built incrementally. // No need to load the network because reloadImpactedSubstationsEquipments will be executed in the notification useEffect. if ( - previousCurrentRootNetwork == currentRootNetwork && + previousCurrentRootNetwork == currentRootNetworkUuid && isSameNode(previousCurrentNode, currentNode) && isNodeBuilt(previousCurrentNode) ) { return; } dispatch(resetEquipments()); - }, [currentNode, currentRootNetwork, wsConnected, dispatch]); + }, [currentNode, currentRootNetworkUuid, wsConnected, dispatch]); useEffect(() => { if (studyUpdatedForce.eventData.headers) { @@ -784,9 +783,8 @@ export function StudyContainer({ view, onChangeTab }) { > { +const StudyPane = ({ studyUuid, currentRootNetworkUuid, currentNode, setErrorMessage, ...props }) => { const [tableEquipment, setTableEquipment] = useState({ id: null, type: null, @@ -82,7 +82,7 @@ const StudyPane = ({ studyUuid, currentRootNetwork, currentNode, setErrorMessage { const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const [equipmentInfo, setEquipmentInfo] = useState(null); const intl = useIntl(); const [localAnchorEl, setLocalAnchorEl] = useState(null); @@ -39,6 +40,7 @@ const EquipmentPopover = ({ studyUuid, anchorEl, anchorPosition, equipmentId, eq fetchNetworkElementInfos( studyUuid, currentNodeId, + currentRootNetworkUuid, equipmentType, EQUIPMENT_INFOS_TYPES.TOOLTIP.type, equipmentId, diff --git a/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx b/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx index 77b163c459..eb331fdae7 100644 --- a/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx +++ b/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx @@ -42,6 +42,7 @@ export const TopBarEquipmentSearchDialog: FunctionComponent state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const [equipmentTypeFilter, setEquipmentTypeFilter] = useState(null); const { searchTerm, updateSearchTerm, equipmentsFound, isLoading } = useTopBarSearchMatchingEquipment({ @@ -49,6 +50,9 @@ export const TopBarEquipmentSearchDialog: FunctionComponent { - const { studyUuid, nodeUuid, inUpstreamBuiltParentNode, equipmentType } = props; + const { studyUuid, nodeUuid,currentRootNetworkUuid, inUpstreamBuiltParentNode, equipmentType } = props; const { getUseNameParameterKey, getNameOrId } = useNameOrId(); @@ -28,6 +29,7 @@ export const useSearchMatchingEquipments = (props: UseSearchMatchingEquipmentsPr searchEquipmentsInfos( studyUuid, nodeUuid, + currentRootNetworkUuid, newSearchTerm, getUseNameParameterKey, inUpstreamBuiltParentNode, diff --git a/src/components/top-bar-equipment-seach-dialog/use-top-bar-search-matching-equipments.tsx b/src/components/top-bar-equipment-seach-dialog/use-top-bar-search-matching-equipments.tsx index 3475adf117..1aec61fe8b 100644 --- a/src/components/top-bar-equipment-seach-dialog/use-top-bar-search-matching-equipments.tsx +++ b/src/components/top-bar-equipment-seach-dialog/use-top-bar-search-matching-equipments.tsx @@ -13,14 +13,16 @@ import { EquipmentType } from '@gridsuite/commons-ui'; interface UseTopBarSearchMatchingEquipmentProps { studyUuid: UUID; nodeUuid: UUID; + currentRootNetworkUuid: UUID; equipmentType?: EquipmentType; } export const useTopBarSearchMatchingEquipment = (props: UseTopBarSearchMatchingEquipmentProps) => { - const { nodeUuid, studyUuid, equipmentType } = props; + const { nodeUuid, studyUuid, currentRootNetworkUuid, equipmentType } = props; const { equipmentsFound, searchTerm, ...otherStates } = useSearchMatchingEquipments({ studyUuid: studyUuid, nodeUuid: nodeUuid, + currentRootNetworkUuid: currentRootNetworkUuid, equipmentType: equipmentType ?? undefined, }); diff --git a/src/hooks/use-voltage-levels-list-infos.ts b/src/hooks/use-voltage-levels-list-infos.ts index ee4d2f4362..ab128f80c9 100644 --- a/src/hooks/use-voltage-levels-list-infos.ts +++ b/src/hooks/use-voltage-levels-list-infos.ts @@ -9,16 +9,16 @@ import { UUID } from 'crypto'; import { useEffect, useState } from 'react'; import { fetchVoltageLevelsListInfos } from '../services/study/network'; -export default function useVoltageLevelsListInfos(studyUuid: UUID, nodeUuid: UUID) { +export default function useVoltageLevelsListInfos(studyUuid: UUID, nodeUuid: UUID, currentRootNetworkUuid: UUID) { const [voltageLevelsListInfos, setVoltageLevelsListInfos] = useState([]); useEffect(() => { - if (studyUuid && nodeUuid) { - fetchVoltageLevelsListInfos(studyUuid, nodeUuid).then((values) => { + if (studyUuid && nodeUuid && currentRootNetworkUuid) { + fetchVoltageLevelsListInfos(studyUuid, nodeUuid,currentRootNetworkUuid).then((values) => { setVoltageLevelsListInfos( values.sort((a: { id: string }, b: { id: string }) => a.id.localeCompare(b.id)) ); }); } - }, [studyUuid, nodeUuid]); + }, [studyUuid, nodeUuid,currentRootNetworkUuid ]); return voltageLevelsListInfos; } diff --git a/src/services/study/geo-data.js b/src/services/study/geo-data.js index 9a9ed6b473..b83b14cf52 100644 --- a/src/services/study/geo-data.js +++ b/src/services/study/geo-data.js @@ -12,7 +12,6 @@ export function fetchSubstationPositions(studyUuid, currentNodeUuid, currentRoot console.info( `Fetching substation positions of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' with ids '${substationsIds}'...` ); - const paramsList = substationsIds && substationsIds.length > 0 ? '?' + getQueryParamsList(substationsIds, 'substationId') : ''; diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 2ce25f4933..b69236cac0 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -134,6 +134,7 @@ export function fetchSvg(svgUrl: string) { export function searchEquipmentsInfos( studyUuid: UUID, nodeUuid: UUID, + currentRootNetworkUuid: UUID, searchTerm: string, getUseNameParameterKey: () => 'name' | 'id', inUpstreamBuiltParentNode?: boolean, @@ -150,7 +151,7 @@ export function searchEquipmentsInfos( urlSearchParams.append('equipmentType', equipmentType); } return backendFetchJson( - getStudyUrl(studyUuid) + '/nodes/' + encodeURIComponent(nodeUuid) + '/search?' + urlSearchParams.toString() + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/search?' + urlSearchParams.toString() ); } diff --git a/src/services/study/network-modifications.js b/src/services/study/network-modifications.js index 70d016c481..18d18287fa 100644 --- a/src/services/study/network-modifications.js +++ b/src/services/study/network-modifications.js @@ -12,8 +12,8 @@ import { getStudyUrlWithNodeUuid } from './index'; import { EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { BRANCH_SIDE, OPERATING_STATUS_ACTION } from '../../components/network/constants'; -function getNetworkModificationUrl(studyUuid, nodeUuid) { - return getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/network-modifications'; +function getNetworkModificationUrl(studyUuid, nodeUuid, currentRootNetworkUuid) { + return getStudyUrlWithNodeUuid(studyUuid, nodeUuid,currentRootNetworkUuid) + '/network-modifications'; } export function changeNetworkModificationOrder(studyUuid, nodeUuid, itemUuid, beforeUuid) { @@ -1623,8 +1623,8 @@ export function deleteAttachingLine( }); } -export function deleteEquipment(studyUuid, nodeUuid, equipmentType, equipmentId, modificationUuid, equipmentInfos) { - let deleteEquipmentUrl = getNetworkModificationUrl(studyUuid, nodeUuid); +export function deleteEquipment(studyUuid, nodeUuid,currentRootNetworkUuid, equipmentType, equipmentId, modificationUuid, equipmentInfos) { + let deleteEquipmentUrl = getNetworkModificationUrl(studyUuid, nodeUuid,currentRootNetworkUuid); if (modificationUuid) { deleteEquipmentUrl += '/' + encodeURIComponent(modificationUuid); diff --git a/src/services/study/network.js b/src/services/study/network.js index 1fbed82083..012a2f4772 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -13,6 +13,7 @@ import { backendFetch, backendFetchJson, backendFetchText, getQueryParamsList, g export function getVoltageLevelSingleLineDiagram( studyUuid, currentNodeUuid, + currentRootNetworkUuid, voltageLevelId, useName, centerLabel, @@ -25,7 +26,7 @@ export function getVoltageLevelSingleLineDiagram( `Getting url of voltage level diagram '${voltageLevelId}' of study '${studyUuid}' and node '${currentNodeUuid}'...` ); return ( - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/svg-and-metadata?' + @@ -44,7 +45,7 @@ export function getVoltageLevelSingleLineDiagram( ); } -export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid, voltageLevelId) { +export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid,currentRootNetworkUuid, voltageLevelId) { console.info( `Fetching substation ID for the voltage level '${voltageLevelId}' of study '${studyUuid}' and node '${currentNodeUuid}' + ' for voltage level '${voltageLevelId}'...` ); @@ -52,7 +53,7 @@ export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid, vol urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchSubstationIdUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/substation-id' + @@ -64,7 +65,7 @@ export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid, vol return backendFetchText(fetchSubstationIdUrl); } -export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid, voltageLevelId) { +export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid, currentRootNetworkUuid,voltageLevelId) { console.info( `Fetching buses or busbar sections of study '${studyUuid}' and node '${currentNodeUuid}' + ' for voltage level '${voltageLevelId}'...` ); @@ -72,7 +73,7 @@ export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNode urlSearchParams.append('inUpstreamBuiltParentNode', 'true'); const fetchBusbarSectionsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/voltage-levels/' + encodeURIComponent(voltageLevelId) + '/buses-or-busbar-sections' + @@ -87,6 +88,7 @@ export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNode export function getSubstationSingleLineDiagram( studyUuid, currentNodeUuid, + currentRootNetworkUuid, substationId, useName, centerLabel, @@ -99,7 +101,7 @@ export function getSubstationSingleLineDiagram( `Getting url of substation diagram '${substationId}' of study '${studyUuid}' and node '${currentNodeUuid}'...` ); return ( - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network/substations/' + encodeURIComponent(substationId) + '/svg-and-metadata?' + From f62c33cd99af6f36b5142148852d4f83a7ff9c44 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 23 Dec 2024 11:03:24 +0100 Subject: [PATCH 11/51] fix: reload tree when changing root network Signed-off-by: LE SAULNIER Kevin --- src/components/network/network-map-tab.tsx | 52 +++++++++++++++------- src/components/study-container.jsx | 4 +- src/services/study/tree-subtree.js | 6 ++- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 1ae536d5e3..f639f3ee8e 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -435,7 +435,12 @@ export const NetworkMapTab = ({ return Promise.resolve([]); } - return fetchEquipmentCB(studyUuid, currentNodeRef.current!.id, currentRootNetworkUuid, notFoundEquipmentsIds); + return fetchEquipmentCB( + studyUuid, + currentNodeRef.current!.id, + currentRootNetworkUuid, + notFoundEquipmentsIds + ); }, [studyUuid, currentRootNetworkUuid] ); @@ -588,6 +593,7 @@ export const NetworkMapTab = ({ const loadRootNodeGeoData = useCallback(() => { console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); + geoDataRef.current = null; const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetworkUuid).then( (data) => { @@ -810,25 +816,32 @@ export const NetworkMapTab = ({ isCurrentNodeBuiltRef.current = isNodeBuilt(currentNode); // if only renaming, do not reload geo data if (isNodeRenamed(previousCurrentNode, currentNode)) { + console.log('test 1'); return; } if (disabled) { + console.log('test 2'); return; } // as long as rootNodeId is not set, we don't fetch any geodata if (!rootNodeId) { + console.log('test 3'); return; } // Hack to avoid reload Geo Data when switching display mode to TREE then back to MAP or HYBRID // TODO REMOVE LATER if (!reloadMapNeeded) { + console.log('test 4'); return; } if (!isMapEquipmentsInitialized) { + console.log('test 5'); // load default node map equipments loadMapEquipments(); } if (!isRootNodeGeoDataLoaded) { + console.log('test 6'); + // load root node geodata loadRootNodeGeoData(); } @@ -880,23 +893,20 @@ export const NetworkMapTab = ({ } }, [isInitialized, lineFullPath, loadGeoData, currentRootNetworkUuid]); - // Effect to handle changes in currentRootNetworkUuid -useEffect(() => { - const prevRootNetworkPath = rootNetworkRef.current; - rootNetworkRef.current = currentRootNetworkUuid; - - if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath) { - console.log("yyyyyyyyyyyyyy"); - loadRootNodeGeoData(); - // set initialized to false to trigger "missing geo-data fetching" - setInitialized(false); - // set isRootNodeGeoDataLoaded to false so "missing geo-data fetching" waits for root node geo-data to be fully fetched before triggering - setIsRootNodeGeoDataLoaded(false); - } -}, [currentRootNetworkUuid, loadRootNodeGeoData]); - + useEffect(() => { + const prevRootNetworkPath = rootNetworkRef.current; + rootNetworkRef.current = currentRootNetworkUuid; + if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath) { + console.log('yyyyyyyyyyyyyy'); + loadRootNodeGeoData(); + // set initialized to false to trigger "missing geo-data fetching" + setInitialized(false); + // set isRootNodeGeoDataLoaded to false so "missing geo-data fetching" waits for root node geo-data to be fully fetched before triggering + setIsRootNodeGeoDataLoaded(false); + } + }, [currentRootNetworkUuid, loadRootNodeGeoData]); let choiceVoltageLevelsSubstation: EquipmentMap | null = null; if (choiceVoltageLevelsSubstationId) { @@ -955,12 +965,20 @@ useEffect(() => { /> ); + console.log('EQUIPMENT TO DISPLAY', mapEquipments); + console.log('GEODATA TO DISPLAY', geoData); + console.log( + 'COMPARE DISPLAY', + [...(updatedLines ?? []), ...(updatedTieLines ?? []), ...(updatedHvdcLines ?? [])], + visible, + disabled + ); const renderMap = () => ( { console.info(`Connecting to notifications '${studyUuid}'...`); @@ -469,7 +469,7 @@ export function StudyContainer({ view, onChangeTab }) { (initIndexationStatus) => { console.info(`Loading network modification tree of study '${studyUuid}'...`); - const networkModificationTree = fetchNetworkModificationTree(studyUuid); + const networkModificationTree = fetchNetworkModificationTree(studyUuid, currentRootNetworkUuid); networkModificationTree .then((tree) => { diff --git a/src/services/study/tree-subtree.js b/src/services/study/tree-subtree.js index 132f1fd282..742c963b1d 100644 --- a/src/services/study/tree-subtree.js +++ b/src/services/study/tree-subtree.js @@ -137,9 +137,11 @@ export function fetchNetworkModificationTreeNode(studyUuid, nodeUuid) { return backendFetchJson(url); } -export function fetchNetworkModificationTree(studyUuid) { +export function fetchNetworkModificationTree(studyUuid, rootNetworkUuid) { console.info('Fetching network modification tree'); - const url = getStudyUrl(studyUuid) + '/tree'; + const urlSearchParams = new URLSearchParams(); + urlSearchParams.set('rootNetworkUuid', rootNetworkUuid); + const url = getStudyUrl(studyUuid) + '/tree?' + urlSearchParams.toString(); console.debug(url); return backendFetchJson(url); } From d126d2df50ee08942651f7fefefdcfeb590bed86 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 23 Dec 2024 15:29:38 +0100 Subject: [PATCH 12/51] fix: fetch single node info Signed-off-by: LE SAULNIER Kevin --- src/components/network-modification-tree-pane.jsx | 14 ++++++++------ src/services/study/tree-subtree.js | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 007e7e52a7..6c1fcd4cbc 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -150,13 +150,15 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const updateNodes = useCallback( (updatedNodesIds) => { - Promise.all(updatedNodesIds.map((nodeId) => fetchNetworkModificationTreeNode(studyUuid, nodeId))).then( - (values) => { - dispatch(networkModificationTreeNodesUpdated(values)); - } - ); + Promise.all( + updatedNodesIds.map((nodeId) => + fetchNetworkModificationTreeNode(studyUuid, nodeId, currentRootNetworkUuid) + ) + ).then((values) => { + dispatch(networkModificationTreeNodesUpdated(values)); + }); }, - [studyUuid, dispatch] + [studyUuid, currentRootNetworkUuid, dispatch] ); const isSubtreeImpacted = useCallback( diff --git a/src/services/study/tree-subtree.js b/src/services/study/tree-subtree.js index 742c963b1d..cd7b714e69 100644 --- a/src/services/study/tree-subtree.js +++ b/src/services/study/tree-subtree.js @@ -130,9 +130,12 @@ export function updateTreeNode(studyUuid, node) { }); } -export function fetchNetworkModificationTreeNode(studyUuid, nodeUuid) { +export function fetchNetworkModificationTreeNode(studyUuid, nodeUuid, rootNetworkUuid) { console.info('Fetching network modification tree node : ', nodeUuid); - const url = getStudyUrl(studyUuid) + '/tree/nodes/' + encodeURIComponent(nodeUuid); + const urlSearchParams = new URLSearchParams(); + urlSearchParams.set('rootNetworkUuid', rootNetworkUuid); + const url = + getStudyUrl(studyUuid) + '/tree/nodes/' + encodeURIComponent(nodeUuid) + '?' + urlSearchParams.toString(); console.debug(url); return backendFetchJson(url); } From bdf757a82f3e8b379f60c75bab4272e98e054bb8 Mon Sep 17 00:00:00 2001 From: souissimai Date: Tue, 24 Dec 2024 14:47:27 +0100 Subject: [PATCH 13/51] migrating endpoints Signed-off-by: souissimai --- .../computing-status/use-computing-status.ts | 12 +- src/components/diagrams/diagram-pane.tsx | 42 +++- .../position-diagram-pane.tsx | 12 +- .../single-line-diagram-content.tsx | 5 +- .../connectivity/branch-connectivity-form.tsx | 2 +- .../connectivity/connectivity-form.jsx | 24 +- src/components/dialogs/create-case-dialog.tsx | 12 +- .../dialogs/element-creation-dialog.tsx | 1 - .../dialogs/equipment-search-dialog.tsx | 2 +- .../creation/battery-creation-form.jsx | 6 +- .../battery-modification-form.jsx | 4 +- .../equipment-deletion-dialog.jsx | 9 +- .../equipment-deletion-form.jsx | 17 +- .../hvdc-lcc-deletion-utils.js | 4 +- .../creation/generator-creation-form.jsx | 2 +- ...egulating-terminal-modification-dialog.jsx | 5 +- .../lcc/creation/lcc-converter-station.tsx | 4 +- .../converter-station-pane.tsx | 4 +- .../line-split-with-voltage-level-form.jsx | 6 +- .../line-to-attach-or-split-form.jsx | 14 +- .../line-characteristics-pane.jsx | 2 +- .../line-modification-dialog-tabs.jsx | 2 +- .../lines-attach-to-split-lines-form.jsx | 14 +- .../load/creation/load-creation-form.tsx | 8 +- .../modification/load-modification-form.jsx | 2 +- .../shunt-compensator-creation-form.jsx | 6 +- .../shunt-compensator-modification-form.jsx | 8 +- .../creation/set-points-limits-form.tsx | 2 +- ...static-var-compensator-creation-dialog.tsx | 7 +- .../static-var-compensator-creation-form.tsx | 2 +- ...nsformer-creation-characteristics-pane.jsx | 3 +- ...ndings-transformer-modification-dialog.jsx | 5 +- .../sensi/sensitivity-analysis-parameters.tsx | 4 +- .../regulating-terminal-form.jsx | 15 +- .../graph/menus/root-network-node-editor.tsx | 2 +- src/components/map-viewer.jsx | 7 +- .../menus/operating-status-menu.tsx | 2 +- .../network-modification-tree-pane.jsx | 7 +- src/components/network/gs-map-equipments.ts | 8 +- src/components/network/network-map-tab.tsx | 5 +- src/components/result-view-tab.tsx | 18 +- .../dynamic-simulation-result-synthesis.tsx | 113 +++++----- .../dynamic-simulation-result-tab.jsx | 8 +- .../dynamic-simulation-result-time-series.jsx | 6 +- .../dynamic-simulation-result-timeline.tsx | 209 +++++++++--------- .../hooks/useResultTimeSeries.ts | 3 +- .../results/loadflow/load-flow-result-tab.tsx | 21 +- .../loadflow/load-flow-result-utils.ts | 10 +- .../results/loadflow/load-flow-result.type.ts | 2 +- .../security-analysis-result-tab.tsx | 17 +- .../security-analysis.type.ts | 2 +- .../non-evacuated-energy-result-tab.tsx | 9 +- .../non-evacuated-energy-result.type.ts | 2 +- .../paged-sensitivity-analysis-result.jsx | 21 +- .../sensitivity-analysis-result-tab.jsx | 8 +- .../shortcircuit-analysis-export-button.tsx | 17 +- .../shortcircuit-analysis-result-tab.tsx | 6 +- .../state-estimation-result-tab.tsx | 7 +- .../state-estimation-result.type.ts | 2 +- src/components/run-button-container.jsx | 39 ++-- .../spreadsheet/config/spreadsheet.type.ts | 7 +- src/components/spreadsheet/table-wrapper.tsx | 10 +- src/components/study-container.jsx | 19 +- src/components/tooltips/equipment-popover.jsx | 4 +- .../top-bar-equipment-search-dialog.tsx | 12 +- .../use-search-matching-equipments.tsx | 4 +- src/components/voltage-init-result-tab.jsx | 3 +- src/hooks/use-report-fetcher.tsx | 24 +- src/hooks/use-voltage-levels-list-infos.ts | 4 +- src/services/study/index.ts | 4 +- src/services/study/network-modifications.js | 14 +- src/services/study/network.js | 9 +- src/services/study/non-evacuated-energy.js | 30 ++- src/services/study/security-analysis.js | 1 - src/services/study/sensitivity-analysis.js | 55 +++-- src/services/study/short-circuit-analysis.js | 23 +- src/services/study/state-estimation.js | 6 +- src/services/study/study.ts | 12 +- src/services/study/voltage-init.js | 27 ++- 79 files changed, 683 insertions(+), 403 deletions(-) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index 75787e3afa..7bcd2a7245 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -20,8 +20,8 @@ interface UseComputingStatusProps { ( studyUuid: UUID, nodeUuid: UUID, - rootNetworkUuid: UUID, - fetcher: (studyUuid: UUID, nodeUuid: UUID, rootNetworkUuid: UUID) => Promise, + currentRootNetworkUuid: UUID, + fetcher: (studyUuid: UUID, nodeUuid: UUID, currentRootNetworkUuid: UUID) => Promise, invalidations: string[], completions: string[], resultConversion: (x: string) => RunningStatus, @@ -32,7 +32,7 @@ interface UseComputingStatusProps { interface LastUpdateProps { studyUpdatedForce: StudyUpdated; - fetcher: (studyUuid: UUID, nodeUuid: UUID, rootNetworkUuid: UUID) => Promise; + fetcher: (studyUuid: UUID, nodeUuid: UUID, currentRootNetworkUuid: UUID) => Promise; } function isWorthUpdate( @@ -85,7 +85,7 @@ function isWorthUpdate( export const useComputingStatus: UseComputingStatusProps = ( studyUuid, nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, fetcher, invalidations, completions, @@ -116,7 +116,7 @@ export const useComputingStatus: UseComputingStatusProps = ( dispatch(setLastCompletedComputation()); nodeUuidRef.current = nodeUuid; - fetcher(studyUuid, nodeUuid, rootNetworkUuid) + fetcher(studyUuid, nodeUuid, currentRootNetworkUuid) .then((res: string) => { if (!canceledRequest && nodeUuidRef.current === nodeUuid) { const status = resultConversion(res); @@ -137,7 +137,7 @@ export const useComputingStatus: UseComputingStatusProps = ( }; }, [ nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, fetcher, studyUuid, resultConversion, diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index 964b1f1885..e4a6de673e 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -82,7 +82,16 @@ const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode, currentRo language ) : null, - [currentNode, studyUuid, paramUseName, centerName, diagonalName, componentLibrary, language] + [ + currentNode, + studyUuid, + currentRootNetworkUuid, + paramUseName, + centerName, + diagonalName, + componentLibrary, + language, + ] ); const checkAndGetSubstationSingleLineDiagramUrl = useCallback( @@ -101,15 +110,32 @@ const useDisplayView = (studyUuid: UUID, currentNode: CurrentTreeNode, currentRo language ) : null, - [centerName, componentLibrary, diagonalName, studyUuid, substationLayout, paramUseName, currentNode, language] + [ + centerName, + componentLibrary, + diagonalName, + studyUuid, + substationLayout, + paramUseName, + currentNode, + currentRootNetworkUuid, + language, + ] ); const initNadWithGeoData = useSelector((state: AppState) => state[PARAM_INIT_NAD_WITH_GEO_DATA]); const checkAndGetNetworkAreaDiagramUrl = useCallback( (voltageLevelsIds: UUID[], depth: number) => isNodeBuilt(currentNode) - ? getNetworkAreaDiagramUrl(studyUuid, currentNode?.id,currentRootNetworkUuid, voltageLevelsIds, depth, initNadWithGeoData) + ? getNetworkAreaDiagramUrl( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + voltageLevelsIds, + depth, + initNadWithGeoData + ) : null, - [studyUuid, currentNode, initNadWithGeoData] + [studyUuid, currentNode, currentRootNetworkUuid, initNadWithGeoData] ); // this callback returns a promise @@ -321,7 +347,13 @@ type DiagramView = { fetchSvg?: () => Promise>; }; -export function DiagramPane({ studyUuid, currentNode, currentRootNetworkUuid, showInSpreadsheet, visible }: DiagramPaneProps) { +export function DiagramPane({ + studyUuid, + currentNode, + currentRootNetworkUuid, + showInSpreadsheet, + visible, +}: DiagramPaneProps) { const dispatch = useDispatch(); const intl = useIntl(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); diff --git a/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx b/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx index 346756ca09..2b7c2fc1da 100644 --- a/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx +++ b/src/components/diagrams/singleLineDiagram/position-diagram-pane.tsx @@ -66,7 +66,17 @@ const PositionDiagramPane: FC = ({ SLD_DISPLAY_MODE.FEEDER_POSITION, language ), - [studyUuid, currentNodeUuid,currentRootNetworkUuid, voltageLevelId?.id, useName, centerName, diagonalName, componentLibrary, language] + [ + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + voltageLevelId?.id, + useName, + centerName, + diagonalName, + componentLibrary, + language, + ] ); useEffect(() => { diff --git a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx index 92675e01e2..1f249294fa 100644 --- a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx +++ b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx @@ -128,7 +128,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { const { snackError } = useSnackMessage(); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); - + const [modificationInProgress, setModificationInProgress] = useState(false); const isAnyNodeBuilding = useIsAnyNodeBuilding(); const [locallySwitchedBreaker, setLocallySwitchedBreaker] = useState(); @@ -301,7 +301,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { dispatch(setComputingStatus(ComputingType.SHORT_CIRCUIT_ONE_BUS, RunningStatus.RUNNING)); displayOneBusShortcircuitAnalysisLoader(); dispatch(setComputationStarting(true)); - startShortCircuitAnalysis(studyUuid, currentNode?.id, busId) + startShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid, busId) .catch((error) => { snackError({ messageTxt: error.message, @@ -321,6 +321,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { displayOneBusShortcircuitAnalysisLoader, studyUuid, currentNode?.id, + currentRootNetworkUuid, snackError, resetOneBusShortcircuitAnalysisLoader, ] diff --git a/src/components/dialogs/connectivity/branch-connectivity-form.tsx b/src/components/dialogs/connectivity/branch-connectivity-form.tsx index f8f3122832..15ea1de722 100644 --- a/src/components/dialogs/connectivity/branch-connectivity-form.tsx +++ b/src/components/dialogs/connectivity/branch-connectivity-form.tsx @@ -30,7 +30,7 @@ const BranchConnectivityForm: FunctionComponent = ( isModification = false, previousValues, }) => { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id,currentRootNetworkUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id, currentRootNetworkUuid); const id1 = `${CONNECTIVITY}.${CONNECTIVITY_1}`; const id2 = `${CONNECTIVITY}.${CONNECTIVITY_2}`; diff --git a/src/components/dialogs/connectivity/connectivity-form.jsx b/src/components/dialogs/connectivity/connectivity-form.jsx index 6593e8f237..0008c8f60c 100644 --- a/src/components/dialogs/connectivity/connectivity-form.jsx +++ b/src/components/dialogs/connectivity/connectivity-form.jsx @@ -80,16 +80,28 @@ export const ConnectivityForm = ({ return; } if (watchVoltageLevelId) { - fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid,currentRootNetworkUuid, watchVoltageLevelId).then( - (busesOrbusbarSections) => { - setBusOrBusbarSectionOptions(busesOrbusbarSections); - } - ); + fetchBusesOrBusbarSectionsForVoltageLevel( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + watchVoltageLevelId + ).then((busesOrbusbarSections) => { + setBusOrBusbarSectionOptions(busesOrbusbarSections); + }); } else { setBusOrBusbarSectionOptions([]); setValue(`${id}.${BUS_OR_BUSBAR_SECTION}`, null); } - }, [watchVoltageLevelId, studyUuid, currentNodeUuid, currentRootNetworkUuid,voltageLevelOptions, setValue, id, isEquipmentModification]); + }, [ + watchVoltageLevelId, + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + voltageLevelOptions, + setValue, + id, + isEquipmentModification, + ]); useEffect(() => { if (isEquipmentModification) { diff --git a/src/components/dialogs/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog.tsx index c187ddb183..dd999b4828 100644 --- a/src/components/dialogs/create-case-dialog.tsx +++ b/src/components/dialogs/create-case-dialog.tsx @@ -49,14 +49,12 @@ export default function CreateCaseDialog({ onClose, open }: Readonly(createCaseDialogFormValidationSchema), }); -const { - formState: { errors, isValid }, - getValues, // This should be destructured directly from formMethods -} = createCaseFormMethods; + const { + formState: { errors, isValid }, + getValues, // This should be destructured directly from formMethods + } = createCaseFormMethods; - const isFormValid = isObjectEmpty(errors) && isValid && getValues(FieldConstants.CASE_FILE) !== null; - - + const isFormValid = isObjectEmpty(errors) && isValid && getValues(FieldConstants.CASE_FILE) !== null; const userId = useSelector((state: AppState) => state.user?.profile.sub); diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx index ac086e73ca..daf23a2356 100644 --- a/src/components/dialogs/element-creation-dialog.tsx +++ b/src/components/dialogs/element-creation-dialog.tsx @@ -75,7 +75,6 @@ const ElementCreationDialog: React.FC = ({ }) => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const rootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const { snackError } = useSnackMessage(); const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); diff --git a/src/components/dialogs/equipment-search-dialog.tsx b/src/components/dialogs/equipment-search-dialog.tsx index dc6ef1843d..b2cd924ce1 100644 --- a/src/components/dialogs/equipment-search-dialog.tsx +++ b/src/components/dialogs/equipment-search-dialog.tsx @@ -45,7 +45,7 @@ const EquipmentSearchDialog: FC = ({ onSelectionChange, equipmentType, currentNodeUuid, - currentRootNetworkUuid + currentRootNetworkUuid, }) => { const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); diff --git a/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx b/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx index 978e61f30b..1095b1473b 100644 --- a/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx +++ b/src/components/dialogs/network-modifications/battery/creation/battery-creation-form.jsx @@ -24,8 +24,8 @@ import useVoltageLevelsListInfos from '../../../../../hooks/use-voltage-levels-l import GridItem from '../../../commons/grid-item'; import GridSection from '../../../commons/grid-section'; -const BatteryCreationForm = ({ studyUuid, currentNode, rootNetworkUuid }) => { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id,rootNetworkUuid); +const BatteryCreationForm = ({ studyUuid, currentNode, currentRootNetworkUuid }) => { + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode.id, currentRootNetworkUuid); const batteryIdField = ( @@ -39,7 +39,7 @@ const BatteryCreationForm = ({ studyUuid, currentNode, rootNetworkUuid }) => { withPosition={true} studyUuid={studyUuid} currentNode={currentNode} - currentRootNetworkUuid={rootNetworkUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> ); diff --git a/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx b/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx index 4ec22fc3c0..e67a2a675e 100644 --- a/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx +++ b/src/components/dialogs/network-modifications/battery/modification/battery-modification-form.jsx @@ -27,7 +27,7 @@ import GridSection from '../../../commons/grid-section'; const BatteryModificationForm = ({ studyUuid, currentNode, - rootNetworkUuid, + currentRootNetworkUuid, batteryToModify, updatePreviousReactiveCapabilityCurveTable, equipmentId, @@ -101,7 +101,7 @@ const BatteryModificationForm = ({ withPosition={true} studyUuid={studyUuid} currentNode={currentNode} - currentRootNetworkUuid={rootNetworkUuid} + currentRootNetworkUuid={currentRootNetworkUuid} isEquipmentModification={true} previousValues={batteryToModify} /> diff --git a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx index 60510010ae..289a030f1e 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx +++ b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx @@ -111,7 +111,7 @@ const EquipmentDeletionDialog = ({ }); }); }, - [currentNodeUuid, editData, snackError, studyUuid] + [currentNodeUuid, editData, currentRootNetworkUuid, snackError, studyUuid] ); const clear = useCallback(() => { @@ -137,7 +137,12 @@ const EquipmentDeletionDialog = ({ isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - + ); diff --git a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx index 0d8879dadb..162818b4e2 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx +++ b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-form.jsx @@ -25,7 +25,7 @@ import { fetchEquipmentsIds } from '../../../../services/study/network-map'; import useGetLabelEquipmentTypes from '../../../../hooks/use-get-label-equipment-types'; import GridItem from '../../commons/grid-item'; -const DeleteEquipmentForm = ({ studyUuid, currentNode,currentRootNetworkUuid, editData }) => { +const DeleteEquipmentForm = ({ studyUuid, currentNode, currentRootNetworkUuid, editData }) => { const { snackError } = useSnackMessage(); const editedIdRef = useRef(null); const currentTypeRef = useRef(null); @@ -66,7 +66,7 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode,currentRootNetworkUuid, ed currentTypeRef.current = watchType; } let ignore = false; - fetchEquipmentsIds(studyUuid, currentNode?.id,currentRootNetworkUuid, undefined, watchType, true) + fetchEquipmentsIds(studyUuid, currentNode?.id, currentRootNetworkUuid, undefined, watchType, true) .then((vals) => { // check race condition here if (!ignore) { @@ -83,7 +83,7 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode,currentRootNetworkUuid, ed ignore = true; }; } - }, [studyUuid, currentNode?.id, currentRootNetworkUuid,watchType, snackError]); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid, watchType, snackError]); useEffect(() => { if (studyUuid && currentNode?.id && currentRootNetworkUuid) { @@ -112,7 +112,16 @@ const DeleteEquipmentForm = ({ studyUuid, currentNode,currentRootNetworkUuid, ed setValue(DELETION_SPECIFIC_DATA, null); } } - }, [studyUuid, currentNode?.id,currentRootNetworkUuid, watchEquipmentId, snackError, setValue, hvdcLccSpecificUpdate, editData]); + }, [ + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + watchEquipmentId, + snackError, + setValue, + hvdcLccSpecificUpdate, + editData, + ]); const handleChange = useCallback(() => { setValue(EQUIPMENT_ID, null); diff --git a/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js b/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js index 9e6e9056ec..fdc1975186 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js +++ b/src/components/dialogs/network-modifications/equipment-deletion/hvdc-lcc-deletion/hvdc-lcc-deletion-utils.js @@ -78,8 +78,8 @@ const useHvdcLccDeletion = () => { ); const specificUpdate = useCallback( - (studyUuid, nodeId,rootNetworkUuid, equipmentId, editData) => { - fetchHvdcLineWithShuntCompensators(studyUuid, nodeId,rootNetworkUuid, equipmentId) + (studyUuid, nodeId, currentRootNetworkUuid, equipmentId, editData) => { + fetchHvdcLineWithShuntCompensators(studyUuid, nodeId, currentRootNetworkUuid, equipmentId) .then((hvdcLineData) => { updateMcsLists(hvdcLineData, editData); }) diff --git a/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx b/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx index c6bb83eb0c..d636544778 100644 --- a/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx +++ b/src/components/dialogs/network-modifications/generator/creation/generator-creation-form.jsx @@ -39,7 +39,7 @@ import GridSection from '../../../commons/grid-section'; const GeneratorCreationForm = ({ studyUuid, currentNode, currentRootNetworkUuid }) => { const currentNodeUuid = currentNode?.id; - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid,currentRootNetworkUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid, currentRootNetworkUuid); const generatorIdField = ( diff --git a/src/components/dialogs/network-modifications/generator/modification/regulating-terminal-modification-dialog.jsx b/src/components/dialogs/network-modifications/generator/modification/regulating-terminal-modification-dialog.jsx index b235ccb1a5..622c4f103c 100644 --- a/src/components/dialogs/network-modifications/generator/modification/regulating-terminal-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/generator/modification/regulating-terminal-modification-dialog.jsx @@ -82,7 +82,7 @@ const RegulatingTerminalModificationDialog = ({ useEffect(() => { if (studyUuid && currentNode.id && currentRootNetworkUuid) { - fetchVoltageLevelsListInfos(studyUuid, currentNode.id,currentRootNetworkUuid) + fetchVoltageLevelsListInfos(studyUuid, currentNode.id, currentRootNetworkUuid) .then((values) => { setVoltageLevelOptions(values.sort((a, b) => a.id.localeCompare(b.id))); }) @@ -90,7 +90,7 @@ const RegulatingTerminalModificationDialog = ({ console.error('Error fetching voltage levels: ', error); }); } - }, [studyUuid, currentNode]); + }, [studyUuid, currentNode, currentRootNetworkUuid]); const onSubmit = useCallback( (voltageRegulationGenerator) => { @@ -163,6 +163,7 @@ RegulatingTerminalModificationDialog.propTypes = { data: PropTypes.object, studyUuid: PropTypes.string, currentNode: PropTypes.object, + currentRootNetworkUuid: PropTypes.string, onModifyRegulatingTerminalGenerator: PropTypes.func, }; diff --git a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx index 7e3c5da11a..1d0c3fe1da 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-converter-station.tsx @@ -220,9 +220,9 @@ export default function LccConverterStation({ stationLabel, currentNode, studyUuid, - currentRootNetworkUuid + currentRootNetworkUuid, }: Readonly) { - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id,currentRootNetworkUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id, currentRootNetworkUuid); const stationIdField = ; diff --git a/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx b/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx index f955e806b8..a43e8b3e19 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/vsc/converter-station/converter-station-pane.tsx @@ -40,7 +40,7 @@ interface VscConverterStationPaneProps { stationLabel: string; currentNode: CurrentTreeNode; studyUuid: UUID; - currentRootNetworkUuid:UUID; + currentRootNetworkUuid: UUID; isModification?: boolean; previousValues?: ConverterStationElementModificationInfos | null; updatePreviousReactiveCapabilityCurveTableConverterStation?: UpdateReactiveCapabilityCurveTable; @@ -70,7 +70,7 @@ const ConverterStationPane: FunctionComponent = ({ } }); - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id,currentRootNetworkUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNode?.id, currentRootNetworkUuid); const generatorIdField = isModification ? ( ); diff --git a/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx b/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx index b9687f7099..6905fa43a4 100644 --- a/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx +++ b/src/components/dialogs/network-modifications/line-to-attach-or-split-form/line-to-attach-or-split-form.jsx @@ -17,7 +17,7 @@ import { EQUIPMENT_TYPES } from '../../../utils/equipment-types'; import { fetchEquipmentsIds } from '../../../../services/study/network-map'; import GridItem from '../../commons/grid-item'; -export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode,currentRootNetworkUuid }) => { +export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode, currentRootNetworkUuid }) => { const [line1Substation, setLine1Substation] = useState(''); const [line2Substation, setLine2Substation] = useState(''); const [linesOptions, setLinesOptions] = useState([]); @@ -28,8 +28,14 @@ export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode,currentR useEffect(() => { if (studyUuid && currentNode?.id && currentRootNetworkUuid) { - fetchEquipmentsIds(studyUuid, currentNode?.id, currentRootNetworkUuid -, undefined, EQUIPMENT_TYPES.LINE, true) + fetchEquipmentsIds( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + undefined, + EQUIPMENT_TYPES.LINE, + true + ) .then((values) => { setLinesOptions(values.sort()); }) @@ -40,7 +46,7 @@ export const LineToAttachOrSplitForm = ({ label, studyUuid, currentNode,currentR }); }); } - }, [studyUuid, currentNode?.id,currentRootNetworkUuid, watchLineToAttachOrSplit, snackError]); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid, watchLineToAttachOrSplit, snackError]); useEffect(() => { const lineToAttachOrSplit = linesOptions.find((l) => l?.id === watchLineToAttachOrSplit); diff --git a/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx b/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx index 7a7b098cf5..38309a5ab5 100644 --- a/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx +++ b/src/components/dialogs/network-modifications/line/characteristics-pane/line-characteristics-pane.jsx @@ -44,7 +44,7 @@ const LineCharacteristicsPane = ({ isModification = false, }) => { const currentNodeUuid = currentNode.id; - const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid,currentRootNetworkUuid); + const voltageLevelOptions = useVoltageLevelsListInfos(studyUuid, currentNodeUuid, currentRootNetworkUuid); const seriesResistanceField = ( { +const LineModificationDialogTabs = ({ studyUuid, currentNode, currentRootNetworkUuid, lineToModify, tabIndex }) => { return ( <> {/* Map */} diff --git a/src/components/menus/operating-status-menu.tsx b/src/components/menus/operating-status-menu.tsx index b216f12ea6..a164a96d58 100644 --- a/src/components/menus/operating-status-menu.tsx +++ b/src/components/menus/operating-status-menu.tsx @@ -116,7 +116,7 @@ const withOperatingStatusMenu = } }); } - }, [studyUuid, currentNode?.id, equipmentType, equipment?.id]); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid, equipmentType, equipment?.id]); const isNodeEditable = useMemo( function () { diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 6c1fcd4cbc..dc14953823 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -76,7 +76,7 @@ const noSelectionForCopy = { const HTTP_MAX_NODE_BUILDS_EXCEEDED_MESSAGE = 'MAX_NODE_BUILDS_EXCEEDED'; -export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) => { +export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, currentRootNetworkUuid }) => { const dispatch = useDispatch(); const intlRef = useIntlRef(); const { snackError, snackInfo } = useSnackMessage(); @@ -132,7 +132,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const [activeNode, setActiveNode] = useState(null); const currentNode = useSelector((state) => state.currentTreeNode); - const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const currentNodeRef = useRef(); currentNodeRef.current = currentNode; @@ -389,14 +388,14 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay }) const handleUnbuildNode = useCallback( (element) => { - unbuildNode(studyUuid, element.id).catch((error) => { + unbuildNode(studyUuid, element.id, currentRootNetworkUuid).catch((error) => { snackError({ messageTxt: error.message, headerId: 'NodeUnbuildingError', }); }); }, - [studyUuid, snackError] + [studyUuid, currentRootNetworkUuid, snackError] ); const handleBuildNode = useCallback( diff --git a/src/components/network/gs-map-equipments.ts b/src/components/network/gs-map-equipments.ts index 6e637ecf42..b1fd512072 100644 --- a/src/components/network/gs-map-equipments.ts +++ b/src/components/network/gs-map-equipments.ts @@ -150,7 +150,13 @@ export default class GSMapEquipments extends MapEquipments { substationsIds, true ); - const updatedLines = fetchLinesMapInfos(studyUuid, currentNode?.id, currentRootNetworkUuid, substationsIds, true); + const updatedLines = fetchLinesMapInfos( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + substationsIds, + true + ); const updatedTieLines = fetchTieLinesMapInfos( studyUuid, currentNode?.id, diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index f639f3ee8e..61b894e8a6 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -261,6 +261,7 @@ export const NetworkMapTab = ({ open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} defaultIdValue={equipmentToModify?.id} isUpdate={true} onClose={() => closeModificationDialog()} @@ -967,6 +968,8 @@ export const NetworkMapTab = ({ console.log('EQUIPMENT TO DISPLAY', mapEquipments); console.log('GEODATA TO DISPLAY', geoData); + console.log('lineFullPath TO DISPLAY', lineFullPath); + console.log('lineFullPath TO DISPLAY', lineFullPath); console.log( 'COMPARE DISPLAY', [...(updatedLines ?? []), ...(updatedTieLines ?? []), ...(updatedHvdcLines ?? [])], @@ -978,7 +981,7 @@ export const NetworkMapTab = ({ ref={networkMapRef} mapEquipments={mapEquipments} geoData={geoData} - updatedLines={[] /*[...(updatedLines ?? []), ...(updatedTieLines ?? []), ...(updatedHvdcLines ?? [])]*/} + updatedLines={[...(updatedLines ?? []), ...(updatedTieLines ?? []), ...(updatedHvdcLines ?? [])]} displayOverlayLoader={!basicDataReady && mapDataLoading} filteredNominalVoltages={filteredNominalVoltages} labelsZoomThreshold={LABELS_ZOOM_THRESHOLD} diff --git a/src/components/result-view-tab.tsx b/src/components/result-view-tab.tsx index e34628d0df..6061a10e39 100644 --- a/src/components/result-view-tab.tsx +++ b/src/components/result-view-tab.tsx @@ -98,7 +98,7 @@ export const ResultViewTab: FunctionComponent = ({ ); @@ -110,7 +110,7 @@ export const ResultViewTab: FunctionComponent = ({ @@ -123,7 +123,7 @@ export const ResultViewTab: FunctionComponent = ({ ); @@ -135,20 +135,20 @@ export const ResultViewTab: FunctionComponent = ({ ); }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderNonEvacuatedEnergyResult = useMemo(() => { - console.log('ùùùùùù renderNonEvacuatedEnergyResult ',currentRootNetworkUuid); + console.log('ùùùùùù renderNonEvacuatedEnergyResult ', currentRootNetworkUuid); return ( ); @@ -160,7 +160,7 @@ export const ResultViewTab: FunctionComponent = ({ @@ -173,7 +173,7 @@ export const ResultViewTab: FunctionComponent = ({ ); @@ -185,7 +185,7 @@ export const ResultViewTab: FunctionComponent = ({ ); diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx index 5d233c1000..cdb3d34192 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-synthesis.tsx @@ -42,69 +42,72 @@ const defaultColDef = { type DynamicSimulationResultSynthesisProps = { studyUuid: UUID; nodeUuid: UUID; - rootNetworkUuid: UUID; + currentRootNetworkUuid: UUID; }; -const DynamicSimulationResultSynthesis = memo(({ nodeUuid, studyUuid }: DynamicSimulationResultSynthesisProps) => { - const intl = useIntl(); +const DynamicSimulationResultSynthesis = memo( + ({ nodeUuid, studyUuid, currentRootNetworkUuid }: DynamicSimulationResultSynthesisProps) => { + const intl = useIntl(); - const [result, isLoading] = useNodeData( - studyUuid, - nodeUuid, - fetchDynamicSimulationStatus, - dynamicSimulationResultInvalidations, - null, - (status: RunningStatus) => - status && [ - { - status, - }, - ] - ); + const [result, isLoading] = useNodeData( + studyUuid, + nodeUuid, + currentRootNetworkUuid, + fetchDynamicSimulationStatus, + dynamicSimulationResultInvalidations, + null, + (status: RunningStatus) => + status && [ + { + status, + }, + ] + ); - const columnDefs = useMemo( - () => [ - makeAgGridCustomHeaderColumn({ - headerName: intl.formatMessage({ + const columnDefs = useMemo( + () => [ + makeAgGridCustomHeaderColumn({ + headerName: intl.formatMessage({ + id: 'status', + }), id: 'status', + field: 'status', + width: MEDIUM_COLUMN_WIDTH, + cellRenderer: StatusCellRender, }), - id: 'status', - field: 'status', - width: MEDIUM_COLUMN_WIDTH, - cellRenderer: StatusCellRender, - }), - ], - [intl] - ); + ], + [intl] + ); - // messages to show when no data - const dynamicSimulationStatus = useSelector( - (state: AppState) => state.computingStatus[ComputingType.DYNAMIC_SIMULATION] - ); - const messages = useIntlResultStatusMessages(intl, true); - const overlayMessage = useMemo( - () => getNoRowsMessage(messages, result, dynamicSimulationStatus, !isLoading), - [messages, result, dynamicSimulationStatus, isLoading] - ); + // messages to show when no data + const dynamicSimulationStatus = useSelector( + (state: AppState) => state.computingStatus[ComputingType.DYNAMIC_SIMULATION] + ); + const messages = useIntlResultStatusMessages(intl, true); + const overlayMessage = useMemo( + () => getNoRowsMessage(messages, result, dynamicSimulationStatus, !isLoading), + [messages, result, dynamicSimulationStatus, isLoading] + ); - const rowDataToShow = useMemo(() => (overlayMessage ? [] : result), [result, overlayMessage]); + const rowDataToShow = useMemo(() => (overlayMessage ? [] : result), [result, overlayMessage]); - return ( - <> - {isLoading && ( - - - - )} - - - ); -}); + return ( + <> + {isLoading && ( + + + + )} + + + ); + } +); export default DynamicSimulationResultSynthesis; diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx index b149218c91..1e9698ba0c 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-tab.jsx @@ -25,7 +25,7 @@ const TAB_INDEX_TIMELINE = 'DynamicSimulationTabTimeline'; const TAB_INDEX_STATUS = 'DynamicSimulationTabStatus'; const TAB_INDEX_LOGS = 'ComputationResultsLogs'; -const DynamicSimulationResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { +const DynamicSimulationResultTab = ({ studyUuid, nodeUuid, currentRootNetworkUuid }) => { const intl = useIntl(); const [tabIndex, setTabIndex] = useState(TAB_INDEX_TIME_SERIES); @@ -69,21 +69,21 @@ const DynamicSimulationResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) => diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx index 55bbdb2be8..4ca9633495 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-time-series.jsx @@ -36,8 +36,8 @@ const styles = { }, }; -const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid, rootNetworkUuid }) => { - const [result, loadTimeSeries, isLoading] = useResultTimeSeries(nodeUuid, studyUuid); +const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid, currentRootNetworkUuid }) => { + const [result, loadTimeSeries, isLoading] = useResultTimeSeries(nodeUuid, studyUuid, currentRootNetworkUuid); // tab id is automatically increased and reset to zero when there is no tab. const [tabIncId, setTabIncId] = useState(1); @@ -182,7 +182,7 @@ const DynamicSimulationResultTimeSeries = memo(({ nodeUuid, studyUuid, rootNetwo DynamicSimulationResultTimeSeries.propTypes = { nodeUuid: PropTypes.string, studyUuid: PropTypes.string, - rootNetworkUuid: PropTypes.string, + currentRootNetworkUuid: PropTypes.string, }; export default DynamicSimulationResultTimeSeries; diff --git a/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx b/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx index c41b687c38..2f3612b138 100644 --- a/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx +++ b/src/components/results/dynamicsimulation/dynamic-simulation-result-timeline.tsx @@ -64,121 +64,124 @@ const defaultColDef = { type DynamicSimulationResultTimelineProps = { studyUuid: UUID; nodeUuid: UUID; - rootNetworkUuid: UUID; + currentRootNetworkUuid: UUID; }; -const DynamicSimulationResultTimeline = memo(({ studyUuid, nodeUuid }: DynamicSimulationResultTimelineProps) => { - const intl = useIntl(); - const gridRef = useRef(null); +const DynamicSimulationResultTimeline = memo( + ({ studyUuid, nodeUuid, currentRootNetworkUuid }: DynamicSimulationResultTimelineProps) => { + const intl = useIntl(); + const gridRef = useRef(null); - const [timelines, isLoading] = useNodeData( - studyUuid, - nodeUuid, - fetchDynamicSimulationResultTimeline, - dynamicSimulationResultInvalidations - ); + const [timelines, isLoading] = useNodeData( + studyUuid, + nodeUuid, + currentRootNetworkUuid, + fetchDynamicSimulationResultTimeline, + dynamicSimulationResultInvalidations + ); - const { onSortChanged, sortConfig } = useAgGridSort(DYNAMIC_SIMULATION_RESULT_SORT_STORE, TIMELINE); + const { onSortChanged, sortConfig } = useAgGridSort(DYNAMIC_SIMULATION_RESULT_SORT_STORE, TIMELINE); - const { updateFilter, filterSelector } = useAggridLocalRowFilter(gridRef, { - filterType: DYNAMIC_SIMULATION_RESULT_STORE_FIELD, - filterTab: TIMELINE, - // @ts-expect-error TODO: found how to have Action type in props type - filterStoreAction: setDynamicSimulationResultFilter, - }); + const { updateFilter, filterSelector } = useAggridLocalRowFilter(gridRef, { + filterType: DYNAMIC_SIMULATION_RESULT_STORE_FIELD, + filterTab: TIMELINE, + // @ts-expect-error TODO: found how to have Action type in props type + filterStoreAction: setDynamicSimulationResultFilter, + }); - const sortAndFilterProps = useMemo( - () => ({ - sortProps: { - onSortChanged, - sortConfig, - }, - filterProps: { - updateFilter, - filterSelector, - }, - }), - [onSortChanged, sortConfig, updateFilter, filterSelector] - ); - - // columns are defined from fields in {@link TimelineEvent} types - const columnDefs = useMemo( - () => [ - makeAgGridCustomHeaderColumn({ - headerName: intl.formatMessage({ - id: 'DynamicSimulationTimelineEventTime', - }), - field: COL_TIME, - width: MIN_COLUMN_WIDTH, - numeric: true, - fractionDigits: 2, - id: 'agNumberColumnFilter', - filter: 'agNumberColumnFilter', - filterParams: { - filterDataType: FILTER_DATA_TYPES.NUMBER, - filterComparators: Object.values(FILTER_NUMBER_COMPARATORS), + const sortAndFilterProps = useMemo( + () => ({ + sortProps: { + onSortChanged, + sortConfig, }, - cellRenderer: NumberCellRenderer, - ...sortAndFilterProps, - }), - makeAgGridCustomHeaderColumn({ - headerName: intl.formatMessage({ - id: 'DynamicSimulationTimelineEventModelName', - }), - id: COL_MODEL_NAME, - field: COL_MODEL_NAME, - width: MEDIUM_COLUMN_WIDTH, - filterParams: { - filterDataType: FILTER_DATA_TYPES.TEXT, - filterComparators: [FILTER_TEXT_COMPARATORS.STARTS_WITH, FILTER_TEXT_COMPARATORS.CONTAINS], + filterProps: { + updateFilter, + filterSelector, }, - ...sortAndFilterProps, }), - makeAgGridCustomHeaderColumn({ - headerName: intl.formatMessage({ - id: 'DynamicSimulationTimelineEventModelMessage', + [onSortChanged, sortConfig, updateFilter, filterSelector] + ); + + // columns are defined from fields in {@link TimelineEvent} types + const columnDefs = useMemo( + () => [ + makeAgGridCustomHeaderColumn({ + headerName: intl.formatMessage({ + id: 'DynamicSimulationTimelineEventTime', + }), + field: COL_TIME, + width: MIN_COLUMN_WIDTH, + numeric: true, + fractionDigits: 2, + id: 'agNumberColumnFilter', + filter: 'agNumberColumnFilter', + filterParams: { + filterDataType: FILTER_DATA_TYPES.NUMBER, + filterComparators: Object.values(FILTER_NUMBER_COMPARATORS), + }, + cellRenderer: NumberCellRenderer, + ...sortAndFilterProps, }), - id: COL_MESSAGE, - field: COL_MESSAGE, - width: LARGE_COLUMN_WIDTH, - filterParams: { - filterDataType: FILTER_DATA_TYPES.TEXT, - filterComparators: [FILTER_TEXT_COMPARATORS.STARTS_WITH, FILTER_TEXT_COMPARATORS.CONTAINS], - }, - ...sortAndFilterProps, - }), - ], - [intl, sortAndFilterProps] - ); + makeAgGridCustomHeaderColumn({ + headerName: intl.formatMessage({ + id: 'DynamicSimulationTimelineEventModelName', + }), + id: COL_MODEL_NAME, + field: COL_MODEL_NAME, + width: MEDIUM_COLUMN_WIDTH, + filterParams: { + filterDataType: FILTER_DATA_TYPES.TEXT, + filterComparators: [FILTER_TEXT_COMPARATORS.STARTS_WITH, FILTER_TEXT_COMPARATORS.CONTAINS], + }, + ...sortAndFilterProps, + }), + makeAgGridCustomHeaderColumn({ + headerName: intl.formatMessage({ + id: 'DynamicSimulationTimelineEventModelMessage', + }), + id: COL_MESSAGE, + field: COL_MESSAGE, + width: LARGE_COLUMN_WIDTH, + filterParams: { + filterDataType: FILTER_DATA_TYPES.TEXT, + filterComparators: [FILTER_TEXT_COMPARATORS.STARTS_WITH, FILTER_TEXT_COMPARATORS.CONTAINS], + }, + ...sortAndFilterProps, + }), + ], + [intl, sortAndFilterProps] + ); - // messages to show when no data - const dynamicSimulationStatus = useSelector( - (state: AppState) => state.computingStatus[ComputingType.DYNAMIC_SIMULATION] - ); - const messages = useIntlResultStatusMessages(intl, true); - const overlayMessage = useMemo( - () => getNoRowsMessage(messages, timelines, dynamicSimulationStatus, !isLoading), - [messages, timelines, dynamicSimulationStatus, isLoading] - ); + // messages to show when no data + const dynamicSimulationStatus = useSelector( + (state: AppState) => state.computingStatus[ComputingType.DYNAMIC_SIMULATION] + ); + const messages = useIntlResultStatusMessages(intl, true); + const overlayMessage = useMemo( + () => getNoRowsMessage(messages, timelines, dynamicSimulationStatus, !isLoading), + [messages, timelines, dynamicSimulationStatus, isLoading] + ); - const rowDataToShow = useMemo(() => (overlayMessage ? [] : timelines), [timelines, overlayMessage]); + const rowDataToShow = useMemo(() => (overlayMessage ? [] : timelines), [timelines, overlayMessage]); - return ( - <> - {isLoading && ( - - - - )} - - - ); -}); + return ( + <> + {isLoading && ( + + + + )} + + + ); + } +); export default DynamicSimulationResultTimeline; diff --git a/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts b/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts index e02ee41fa3..9ecb381f76 100644 --- a/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts +++ b/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts @@ -14,10 +14,11 @@ import { TimeSeriesMetadata } from '../types/dynamic-simulation-result.type'; import { dynamicSimulationResultInvalidations } from '../utils/dynamic-simulation-result-utils'; import { fetchDynamicSimulationTimeSeriesMetadata } from '../../../../services/dynamic-simulation'; -const useResultTimeSeries = (nodeUuid: UUID, studyUuid: UUID) => { +const useResultTimeSeries = (nodeUuid: UUID, studyUuid: UUID, currentRootNetworkUuid: UUID) => { const [result, isLoading] = useNodeData( studyUuid, nodeUuid, + currentRootNetworkUuid, fetchDynamicSimulationTimeSeriesMetadata, dynamicSimulationResultInvalidations, null, diff --git a/src/components/results/loadflow/load-flow-result-tab.tsx b/src/components/results/loadflow/load-flow-result-tab.tsx index 07cb8dfbc8..8ffd026070 100644 --- a/src/components/results/loadflow/load-flow-result-tab.tsx +++ b/src/components/results/loadflow/load-flow-result-tab.tsx @@ -68,7 +68,11 @@ export interface GlobalFilter { limitViolationsTypes?: LimitTypes[]; } -export const LoadFlowResultTab: FunctionComponent = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { +export const LoadFlowResultTab: FunctionComponent = ({ + studyUuid, + nodeUuid, + currentRootNetworkUuid, +}) => { const { snackError } = useSnackMessage(); const intl = useIntl(); const loadflowResultInvalidations = ['loadflowResult']; @@ -94,7 +98,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu // load countries useEffect(() => { - fetchAllCountries(studyUuid, nodeUuid, rootNetworkUuid) + fetchAllCountries(studyUuid, nodeUuid, currentRootNetworkUuid) .then((countryCodes) => { setCountriesFilter( countryCodes.map((countryCode: string) => ({ @@ -110,7 +114,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu }); }); - fetchAllNominalVoltages(studyUuid, nodeUuid, rootNetworkUuid) + fetchAllNominalVoltages(studyUuid, nodeUuid, currentRootNetworkUuid) .then((nominalVoltages) => { setVoltageLevelsFilter( nominalVoltages.map((nominalV: number) => ({ @@ -125,7 +129,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu headerId: 'FetchNominalVoltagesError', }); }); - }, [nodeUuid, studyUuid, rootNetworkUuid, snackError, loadFlowStatus]); + }, [nodeUuid, studyUuid, currentRootNetworkUuid, snackError, loadFlowStatus]); const getGlobalFilterParameter = useCallback( (globalFilter: GlobalFilter | undefined) => { @@ -166,7 +170,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu value: limitTypeValues, }); } - return fetchLimitViolations(studyUuid, nodeUuid, rootNetworkUuid, { + return fetchLimitViolations(studyUuid, nodeUuid, currentRootNetworkUuid, { sort: sortConfig.map((sort) => ({ ...sort, colId: FROM_COLUMN_TO_FIELD_LIMIT_VIOLATION_RESULT[sort.colId], @@ -177,7 +181,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu }, [ studyUuid, nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, sortConfig, filterSelector, tabIndex, @@ -187,11 +191,11 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu ]); const fetchloadflowResultWithParameters = useCallback(() => { - return fetchLoadFlowResult(studyUuid, nodeUuid, rootNetworkUuid, { + return fetchLoadFlowResult(studyUuid, nodeUuid, currentRootNetworkUuid, { sort: sortConfig, filters: filterSelector, }); - }, [studyUuid, nodeUuid, rootNetworkUuid, sortConfig, filterSelector]); + }, [studyUuid, nodeUuid, currentRootNetworkUuid, sortConfig, filterSelector]); const fetchResult = useMemo(() => { if (tabIndex === 0 || tabIndex === 1) { @@ -204,6 +208,7 @@ export const LoadFlowResultTab: FunctionComponent = ({ studyUu const [loadflowResult, isLoadingResult, setResult] = useNodeData( studyUuid, nodeUuid, + currentRootNetworkUuid, fetchResult, loadflowResultInvalidations ); diff --git a/src/components/results/loadflow/load-flow-result-utils.ts b/src/components/results/loadflow/load-flow-result-utils.ts index 0c52bb3e7d..44cbe2d81b 100644 --- a/src/components/results/loadflow/load-flow-result-utils.ts +++ b/src/components/results/loadflow/load-flow-result-utils.ts @@ -185,7 +185,13 @@ export const useFetchFiltersEnums = (): { const filterTypes = ['computation-status', 'limit-types', 'branch-sides']; const promises = filterTypes.map((filterType) => - fetchAvailableFilterEnumValues(studyUuid, currentNode.id, currentRootNetwork, computingType.LOAD_FLOW, filterType) + fetchAvailableFilterEnumValues( + studyUuid, + currentNode.id, + currentRootNetwork, + computingType.LOAD_FLOW, + filterType + ) ); setLoading(true); @@ -203,7 +209,7 @@ export const useFetchFiltersEnums = (): { .finally(() => { setLoading(false); }); - }, [loadFlowStatus, studyUuid, currentNode?.id]); + }, [loadFlowStatus, studyUuid, currentNode?.id, currentRootNetwork]); return { loading, result, error }; }; diff --git a/src/components/results/loadflow/load-flow-result.type.ts b/src/components/results/loadflow/load-flow-result.type.ts index f7ee26653c..ca17d69506 100644 --- a/src/components/results/loadflow/load-flow-result.type.ts +++ b/src/components/results/loadflow/load-flow-result.type.ts @@ -41,7 +41,7 @@ export enum LimitTypes { export interface LoadFlowTabProps { studyUuid: UUID; nodeUuid: UUID; - rootNetworkUuid: UUID; + currentRootNetworkUuid: UUID; } export interface LoadflowResultTap { diff --git a/src/components/results/securityanalysis/security-analysis-result-tab.tsx b/src/components/results/securityanalysis/security-analysis-result-tab.tsx index 3f875581ee..67ed1c09b5 100644 --- a/src/components/results/securityanalysis/security-analysis-result-tab.tsx +++ b/src/components/results/securityanalysis/security-analysis-result-tab.tsx @@ -77,7 +77,7 @@ const styles = { export const SecurityAnalysisResultTab: FunctionComponent = ({ studyUuid, nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, openVoltageLevelDiagram, }) => { const intl = useIntl(); @@ -165,14 +165,25 @@ export const SecurityAnalysisResultTab: FunctionComponent void; } diff --git a/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx b/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx index afc0c32c09..b246242d49 100644 --- a/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx +++ b/src/components/results/sensitivity-analysis/non-evacuated-energy/non-evacuated-energy-result-tab.tsx @@ -20,7 +20,7 @@ import { useSelector } from 'react-redux'; import { AppState } from '../../../../redux/reducer'; import { ComputingType } from '../../../computing-status/computing-type'; import { RESULTS_LOADING_DELAY } from '../../../network/constants'; - + const styles = { container: { display: 'flex', @@ -41,7 +41,10 @@ const styles = { export const NON_EVACUATED_ENERGY_RESULT_INVALIDATIONS = ['nonEvacuatedEnergyResult']; -export const NonEvacuatedEnergyResultTab: FunctionComponent = ({ studyUuid, nodeUuid, rootNetworkUuid +export const NonEvacuatedEnergyResultTab: FunctionComponent = ({ + studyUuid, + nodeUuid, + currentRootNetworkUuid, }) => { const [tabIndex, setTabIndex] = useState(0); @@ -55,7 +58,7 @@ export const NonEvacuatedEnergyResultTab: FunctionComponent { setOptions(res); }) @@ -122,7 +123,7 @@ const PagedSensitivityAnalysisResult = ({ }), }); }); - }, [nOrNkIndex, sensiKind, studyUuid, nodeUuid, snackError, intl]); + }, [nOrNkIndex, sensiKind, studyUuid, currentRootNetworkUuid, nodeUuid, snackError, intl]); const fetchResult = useCallback(() => { const sortSelector = sortConfig?.length @@ -150,7 +151,7 @@ const PagedSensitivityAnalysisResult = ({ ...sortSelector, }; setIsLoading(true); - fetchSensitivityAnalysisResult(studyUuid, nodeUuid, selector) + fetchSensitivityAnalysisResult(studyUuid, nodeUuid, currentRootNetworkUuid, selector) .then((res) => { const { filteredSensitivitiesCount = 0 } = res || {}; @@ -168,7 +169,19 @@ const PagedSensitivityAnalysisResult = ({ .finally(() => { setIsLoading(false); }); - }, [nOrNkIndex, sensiKind, page, rowsPerPage, filterSelector, sortConfig, studyUuid, nodeUuid, snackError, intl]); + }, [ + nOrNkIndex, + sensiKind, + page, + rowsPerPage, + filterSelector, + sortConfig, + studyUuid, + nodeUuid, + currentRootNetworkUuid, + snackError, + intl, + ]); useEffect(() => { if (sensiStatus === RunningStatus.RUNNING) { diff --git a/src/components/results/sensitivity-analysis/sensitivity-analysis-result-tab.jsx b/src/components/results/sensitivity-analysis/sensitivity-analysis-result-tab.jsx index 5a954a847c..88b7181018 100644 --- a/src/components/results/sensitivity-analysis/sensitivity-analysis-result-tab.jsx +++ b/src/components/results/sensitivity-analysis/sensitivity-analysis-result-tab.jsx @@ -46,7 +46,7 @@ function getDisplayedColumns(params) { return params.api.columnModel.columnDefs.map((c) => c.headerComponentParams.displayName); } -const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) => { +const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, currentRootNetworkUuid }) => { const { snackError } = useSnackMessage(); const intl = useIntl(); const [nOrNkIndex, setNOrNkIndex] = useState(0); @@ -111,7 +111,7 @@ const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) const handleExportResultAsCsv = useCallback(() => { setIsCsvExportLoading(true); setIsCsvExportSuccessful(false); - exportSensitivityResultsAsCsv(studyUuid, nodeUuid, { + exportSensitivityResultsAsCsv(studyUuid, nodeUuid, currentRootNetworkUuid, { csvHeaders: csvHeaders, resultTab: SensitivityResultTabs[nOrNkIndex].id, sensitivityFunctionType: FUNCTION_TYPES[sensiKind], @@ -132,7 +132,7 @@ const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) setIsCsvExportSuccessful(false); }) .finally(() => setIsCsvExportLoading(false)); - }, [snackError, studyUuid, nodeUuid, intl, nOrNkIndex, sensiKind, csvHeaders]); + }, [snackError, studyUuid, nodeUuid, currentRootNetworkUuid, intl, nOrNkIndex, sensiKind, csvHeaders]); return ( <> @@ -163,6 +163,7 @@ const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) sensiKind={sensiKind} studyUuid={studyUuid} nodeUuid={nodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} page={page} setPage={setPage} sortProps={{ @@ -194,6 +195,7 @@ const SensitivityAnalysisResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid }) SensitivityAnalysisResultTab.propTypes = { studyUuid: PropTypes.string.isRequired, nodeUuid: PropTypes.string.isRequired, + currentRootNetworkUuid: PropTypes.string.isRequired, }; export default SensitivityAnalysisResultTab; diff --git a/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx b/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx index ef8db1dd0f..c88733ffe5 100644 --- a/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx +++ b/src/components/results/shortcircuit/shortcircuit-analysis-export-button.tsx @@ -18,14 +18,14 @@ import { BranchSide } from 'components/utils/constants'; interface ShortCircuitExportButtonProps { studyUuid: UUID; nodeUuid: UUID; - rootNetworkUuid: UUID; + currentRootNetworkUuid: UUID; csvHeaders?: string[]; analysisType: number; disabled?: boolean; } export const ShortCircuitExportButton: FunctionComponent = (props) => { - const { studyUuid, nodeUuid, rootNetworkUuid, csvHeaders, disabled = false, analysisType } = props; + const { studyUuid, nodeUuid, currentRootNetworkUuid, csvHeaders, disabled = false, analysisType } = props; const { snackError } = useSnackMessage(); const [isCsvExportLoading, setIsCsvExportLoading] = useState(false); @@ -66,7 +66,7 @@ export const ShortCircuitExportButton: FunctionComponent setIsCsvExportLoading(false)); - }, [studyUuid, nodeUuid, intl, snackError, csvHeaders, analysisType, enumValueTranslations]); + }, [ + studyUuid, + nodeUuid, + currentRootNetworkUuid, + intl, + snackError, + csvHeaders, + analysisType, + enumValueTranslations, + ]); return ( = ({ studyUuid, nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, view, }) => { const lastCompletedComputation = useSelector((state: AppState) => state.lastCompletedComputation); @@ -146,7 +146,7 @@ export const ShortCircuitAnalysisResultTab: FunctionComponent = ({ studyUuid, nodeUuid, - rootNetworkUuid, + currentRootNetworkUuid, }) => { const intl = useIntl(); const stateEstimationResultInvalidations = ['stateEstimationResult']; @@ -57,8 +57,8 @@ export const StateEstimationResultTab: FunctionComponent { - return fetchStateEstimationResult(studyUuid, nodeUuid, rootNetworkUuid); - }, [studyUuid, nodeUuid, rootNetworkUuid]); + return fetchStateEstimationResult(studyUuid, nodeUuid, currentRootNetworkUuid); + }, [studyUuid, nodeUuid, currentRootNetworkUuid]); const fetchResult = useMemo(() => { return fetchEstimResults; @@ -67,6 +67,7 @@ export const StateEstimationResultTab: FunctionComponent state.computingStatus[ComputingType.LOAD_FLOW]); const securityAnalysisStatus = useSelector((state) => state.computingStatus[ComputingType.SECURITY_ANALYSIS]); @@ -116,7 +116,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, // close the contingency list selection window setShowContingencyListSelector(false); }, - () => startSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetwork, contingencyListNames), + () => startSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid, contingencyListNames), () => {}, null, null @@ -153,7 +153,12 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, ComputingType.LOAD_FLOW, null, () => - startLoadFlow(studyUuid, currentNode?.id, currentRootNetwork, limitReductionParam / 100.0), + startLoadFlow( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + limitReductionParam / 100.0 + ), () => {}, null, 'startLoadFlowError' @@ -170,7 +175,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.SECURITY_ANALYSIS, () => - stopSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetwork) + stopSecurityAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -180,7 +185,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, startComputationAsync( ComputingType.SENSITIVITY_ANALYSIS, null, - () => startSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetwork), + () => startSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid), () => {}, null, 'startSensitivityAnalysisError' @@ -188,7 +193,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.SENSITIVITY_ANALYSIS, () => - stopSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetwork) + stopSensitivityAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -199,7 +204,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, ComputingType.NON_EVACUATED_ENERGY_ANALYSIS, null, () => { - return startNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetwork); + return startNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetworkUuid); }, () => {}, null, @@ -208,7 +213,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.NON_EVACUATED_ENERGY_ANALYSIS, () => - stopNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetwork) + stopNonEvacuatedEnergy(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -218,7 +223,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, startComputationAsync( ComputingType.SHORT_CIRCUIT, null, - () => startShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetwork), + () => startShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid), () => {}, null, 'startShortCircuitError' @@ -226,7 +231,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.SHORT_CIRCUIT, () => - stopShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetwork) + stopShortCircuitAnalysis(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -240,7 +245,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, setShowDynamicSimulationParametersSelector(true); } else { // start server side dynamic simulation directly - return startDynamicSimulation(studyUuid, currentNode?.id, currentRootNetwork); + return startDynamicSimulation(studyUuid, currentNode?.id, currentRootNetworkUuid); } }) .catch((error) => { @@ -252,7 +257,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.DYNAMIC_SIMULATION, () => - stopDynamicSimulation(studyUuid, currentNode?.id, currentRootNetwork) + stopDynamicSimulation(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -262,7 +267,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, startComputationAsync( ComputingType.VOLTAGE_INITIALIZATION, null, - () => startVoltageInit(studyUuid, currentNode?.id, currentRootNetwork), + () => startVoltageInit(studyUuid, currentNode?.id, currentRootNetworkUuid), () => {}, null, 'startVoltageInitError' @@ -270,7 +275,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.VOLTAGE_INITIALIZATION, () => - stopVoltageInit(studyUuid, currentNode?.id, currentRootNetwork) + stopVoltageInit(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -281,7 +286,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, ComputingType.STATE_ESTIMATION, null, () => { - return startStateEstimation(studyUuid, currentNode?.id, currentRootNetwork); + return startStateEstimation(studyUuid, currentNode?.id, currentRootNetworkUuid); }, () => {}, null, @@ -290,7 +295,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, }, actionOnRunnable() { actionOnRunnables(ComputingType.STATE_ESTIMATION, () => - stopStateEstimation(studyUuid, currentNode?.id, currentRootNetwork) + stopStateEstimation(studyUuid, currentNode?.id, currentRootNetworkUuid) ); }, }, @@ -302,7 +307,7 @@ export function RunButtonContainer({ studyUuid, currentNode, currentRootNetwork, studyUuid, limitReductionParam, currentNode?.id, - currentRootNetwork, + currentRootNetworkUuid, ]); // running status is refreshed more often, so we memoize it apart diff --git a/src/components/spreadsheet/config/spreadsheet.type.ts b/src/components/spreadsheet/config/spreadsheet.type.ts index aaa7c75b3c..bb2385c085 100644 --- a/src/components/spreadsheet/config/spreadsheet.type.ts +++ b/src/components/spreadsheet/config/spreadsheet.type.ts @@ -9,7 +9,12 @@ import type { UUID } from 'crypto'; import type { EQUIPMENT_TYPES } from '../../utils/equipment-types'; import type { CustomColDef } from '../../custom-aggrid/custom-aggrid-header.type'; -export type EquipmentFetcher = (studyUuid: UUID, currentNodeUuid: UUID,currentRootNetworkUuid:UUID, substationsIds: string[]) => Promise; +export type EquipmentFetcher = ( + studyUuid: UUID, + currentNodeUuid: UUID, + currentRootNetworkUuid: UUID, + substationsIds: string[] +) => Promise; export type SpreadsheetEquipmentType = Exclude< EQUIPMENT_TYPES, diff --git a/src/components/spreadsheet/table-wrapper.tsx b/src/components/spreadsheet/table-wrapper.tsx index 623140cddc..cfac0aeda5 100644 --- a/src/components/spreadsheet/table-wrapper.tsx +++ b/src/components/spreadsheet/table-wrapper.tsx @@ -1128,7 +1128,15 @@ const TableWrapper: FunctionComponent = ({ }); } } - }, [lastModifiedEquipment, currentNode.id, studyUuid,currentRootNetworkUuid, studyUpdatedForce, formatFetchedEquipmentHandler, dispatch]); + }, [ + lastModifiedEquipment, + currentNode.id, + studyUuid, + currentRootNetworkUuid, + studyUpdatedForce, + formatFetchedEquipmentHandler, + dispatch, + ]); //this listener is called for each cell modified const handleCellEditingStopped = useCallback( diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 6a1ddca0af..1ac48b1fe3 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -81,7 +81,15 @@ function isWorthUpdate(studyUpdatedForce, fetcher, lastUpdateRef, nodeUuidRef, n return false; } -export function useNodeData(studyUuid, nodeUuid, fetcher, invalidations, defaultValue, resultConversion) { +export function useNodeData( + studyUuid, + nodeUuid, + currentRootNetworkUuid, + fetcher, + invalidations, + defaultValue, + resultConversion +) { const [result, setResult] = useState(defaultValue); const [isPending, setIsPending] = useState(false); const [errorMessage, setErrorMessage] = useState(undefined); @@ -93,7 +101,7 @@ export function useNodeData(studyUuid, nodeUuid, fetcher, invalidations, default nodeUuidRef.current = nodeUuid; setIsPending(true); setErrorMessage(undefined); - fetcher(studyUuid, nodeUuid) + fetcher(studyUuid, nodeUuid, currentRootNetworkUuid) .then((res) => { if (nodeUuidRef.current === nodeUuid) { setResult(resultConversion ? resultConversion(res) : res); @@ -104,7 +112,7 @@ export function useNodeData(studyUuid, nodeUuid, fetcher, invalidations, default setResult(RunningStatus.FAILED); }) .finally(() => setIsPending(false)); - }, [nodeUuid, fetcher, studyUuid, resultConversion]); + }, [nodeUuid, fetcher, currentRootNetworkUuid, studyUuid, resultConversion]); /* initial fetch and update */ useEffect(() => { @@ -144,7 +152,6 @@ function useStudy(studyUuidRequest) { fetchRootNetworks(studyUuidRequest) .then((rootNetworks) => { if (rootNetworks && rootNetworks.length > 0) { - console.log('======== rootNetworks[0].rootnetworkUuid', rootNetworks[0].rootNetworkUuid); // Validate that currentRootNetwork is set dispatch(setCurrentRootNetwork(rootNetworks[0].rootNetworkUuid)); @@ -622,7 +629,7 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if ( (studyUuid && currentRootNetworkUuid && !isStudyNetworkFound) || - (currentRootNetworkRef.current && currentRootNetworkRef.current != currentRootNetworkUuid) + (currentRootNetworkRef.current && currentRootNetworkRef.current !== currentRootNetworkUuid) ) { console.log('RELOADING CHECK NETWORK', currentRootNetworkUuid); checkNetworkExistenceAndRecreateIfNotFound(); @@ -675,7 +682,7 @@ export function StudyContainer({ view, onChangeTab }) { // A modification has been added to the currentNode and this one has been built incrementally. // No need to load the network because reloadImpactedSubstationsEquipments will be executed in the notification useEffect. if ( - previousCurrentRootNetwork == currentRootNetworkUuid && + previousCurrentRootNetwork === currentRootNetworkUuid && isSameNode(previousCurrentNode, currentNode) && isNodeBuilt(previousCurrentNode) ) { diff --git a/src/components/tooltips/equipment-popover.jsx b/src/components/tooltips/equipment-popover.jsx index b1180cd0f7..00f5e8029d 100644 --- a/src/components/tooltips/equipment-popover.jsx +++ b/src/components/tooltips/equipment-popover.jsx @@ -36,7 +36,7 @@ const EquipmentPopover = ({ studyUuid, anchorEl, anchorPosition, equipmentId, eq const [localAnchorEl, setLocalAnchorEl] = useState(null); const [localAnchorPosition, setLocalAnchorPosition] = useState(null); const getNetworkElementInfos = useCallback( - (equipmentId, equipmentType, currentNodeId, studyUuid) => { + (equipmentId, equipmentType, currentNodeId, studyUuid, currentRootNetworkUuid) => { fetchNetworkElementInfos( studyUuid, currentNodeId, @@ -73,7 +73,7 @@ const EquipmentPopover = ({ studyUuid, anchorEl, anchorPosition, equipmentId, eq } else { setEquipmentInfo(null); } - }, [debouncedNetworkElementInfos, equipmentId, equipmentType, currentNode.id, studyUuid]); + }, [debouncedNetworkElementInfos, equipmentId, equipmentType, currentNode.id, studyUuid, currentRootNetworkUuid]); const handlePopoverClose = () => { setEquipmentInfo(null); diff --git a/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx b/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx index eb331fdae7..0151cde13f 100644 --- a/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx +++ b/src/components/top-bar-equipment-seach-dialog/top-bar-equipment-search-dialog.tsx @@ -50,7 +50,7 @@ export const TopBarEquipmentSearchDialog: FunctionComponent { - const { studyUuid, nodeUuid,currentRootNetworkUuid, inUpstreamBuiltParentNode, equipmentType } = props; + const { studyUuid, nodeUuid, currentRootNetworkUuid, inUpstreamBuiltParentNode, equipmentType } = props; const { getUseNameParameterKey, getNameOrId } = useNameOrId(); @@ -35,7 +35,7 @@ export const useSearchMatchingEquipments = (props: UseSearchMatchingEquipmentsPr inUpstreamBuiltParentNode, equipmentType ), - [equipmentType, getUseNameParameterKey, inUpstreamBuiltParentNode, nodeUuid, studyUuid] + [equipmentType, getUseNameParameterKey, inUpstreamBuiltParentNode, nodeUuid, studyUuid, currentRootNetworkUuid] ); const { elementsFound, isLoading, searchTerm, updateSearchTerm } = useElementSearch({ diff --git a/src/components/voltage-init-result-tab.jsx b/src/components/voltage-init-result-tab.jsx index a419b3d329..bfa4dc2491 100644 --- a/src/components/voltage-init-result-tab.jsx +++ b/src/components/voltage-init-result-tab.jsx @@ -15,12 +15,13 @@ import RunningStatus from './utils/running-status'; const voltageInitResultInvalidations = ['voltageInitResult']; -export const VoltageInitResultTab = ({ studyUuid, nodeUuid, rootNetworkUuid}) => { +export const VoltageInitResultTab = ({ studyUuid, nodeUuid, currentRootNetworkUuid }) => { const voltageInitStatus = useSelector((state) => state.computingStatus[ComputingType.VOLTAGE_INITIALIZATION]); const [voltageInitResult, isWaiting] = useNodeData( studyUuid, nodeUuid, + currentRootNetworkUuid, fetchVoltageInitResult, voltageInitResultInvalidations ); diff --git a/src/hooks/use-report-fetcher.tsx b/src/hooks/use-report-fetcher.tsx index d5c83df09a..e2edeb50bb 100644 --- a/src/hooks/use-report-fetcher.tsx +++ b/src/hooks/use-report-fetcher.tsx @@ -115,7 +115,7 @@ export const useReportFetcher = ( } return Promise.resolve(undefined); }, - [currentNode, fetch, computingAndNetworkModificationType, studyUuid] + [currentNode, currentRootNetwork, fetch, computingAndNetworkModificationType, studyUuid] ); const fetchReportLogs = useCallback( @@ -126,16 +126,32 @@ export const useReportFetcher = ( let fetchPromise: (severityList: string[], reportId: string) => Promise; if (reportType === ReportType.GLOBAL) { fetchPromise = (severityList: string[]) => - fetchNodeReportLogs(studyUuid, currentNode!.id,currentRootNetwork, null, severityList, messageFilter, true); + fetchNodeReportLogs( + studyUuid, + currentNode!.id, + currentRootNetwork, + null, + severityList, + messageFilter, + true + ); } else { fetchPromise = (severityList: string[], reportId: string) => - fetchNodeReportLogs(studyUuid, currentNode!.id,currentRootNetwork, reportId, severityList, messageFilter, false); + fetchNodeReportLogs( + studyUuid, + currentNode!.id, + currentRootNetwork, + reportId, + severityList, + messageFilter, + false + ); } return fetchPromise(severityList, reportId).then((r) => { return mapReportLogs(prettifyReportLogMessage(r, nodesNames)); }); }, - [currentNode, studyUuid, nodesNames] + [currentNode, currentRootNetwork, studyUuid, nodesNames] ); return [isLoading, fetchRawParentReport, fetchReportLogs]; diff --git a/src/hooks/use-voltage-levels-list-infos.ts b/src/hooks/use-voltage-levels-list-infos.ts index ab128f80c9..0a4fd827b7 100644 --- a/src/hooks/use-voltage-levels-list-infos.ts +++ b/src/hooks/use-voltage-levels-list-infos.ts @@ -13,12 +13,12 @@ export default function useVoltageLevelsListInfos(studyUuid: UUID, nodeUuid: UUI const [voltageLevelsListInfos, setVoltageLevelsListInfos] = useState([]); useEffect(() => { if (studyUuid && nodeUuid && currentRootNetworkUuid) { - fetchVoltageLevelsListInfos(studyUuid, nodeUuid,currentRootNetworkUuid).then((values) => { + fetchVoltageLevelsListInfos(studyUuid, nodeUuid, currentRootNetworkUuid).then((values) => { setVoltageLevelsListInfos( values.sort((a: { id: string }, b: { id: string }) => a.id.localeCompare(b.id)) ); }); } - }, [studyUuid, nodeUuid,currentRootNetworkUuid ]); + }, [studyUuid, nodeUuid, currentRootNetworkUuid]); return voltageLevelsListInfos; } diff --git a/src/services/study/index.ts b/src/services/study/index.ts index b69236cac0..600e5c6784 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -151,7 +151,9 @@ export function searchEquipmentsInfos( urlSearchParams.append('equipmentType', equipmentType); } return backendFetchJson( - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/search?' + urlSearchParams.toString() + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + + '/search?' + + urlSearchParams.toString() ); } diff --git a/src/services/study/network-modifications.js b/src/services/study/network-modifications.js index 18d18287fa..91cb301921 100644 --- a/src/services/study/network-modifications.js +++ b/src/services/study/network-modifications.js @@ -13,7 +13,7 @@ import { EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { BRANCH_SIDE, OPERATING_STATUS_ACTION } from '../../components/network/constants'; function getNetworkModificationUrl(studyUuid, nodeUuid, currentRootNetworkUuid) { - return getStudyUrlWithNodeUuid(studyUuid, nodeUuid,currentRootNetworkUuid) + '/network-modifications'; + return getStudyUrlWithNodeUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/network-modifications'; } export function changeNetworkModificationOrder(studyUuid, nodeUuid, itemUuid, beforeUuid) { @@ -1623,8 +1623,16 @@ export function deleteAttachingLine( }); } -export function deleteEquipment(studyUuid, nodeUuid,currentRootNetworkUuid, equipmentType, equipmentId, modificationUuid, equipmentInfos) { - let deleteEquipmentUrl = getNetworkModificationUrl(studyUuid, nodeUuid,currentRootNetworkUuid); +export function deleteEquipment( + studyUuid, + nodeUuid, + currentRootNetworkUuid, + equipmentType, + equipmentId, + modificationUuid, + equipmentInfos +) { + let deleteEquipmentUrl = getNetworkModificationUrl(studyUuid, nodeUuid, currentRootNetworkUuid); if (modificationUuid) { deleteEquipmentUrl += '/' + encodeURIComponent(modificationUuid); diff --git a/src/services/study/network.js b/src/services/study/network.js index 012a2f4772..9ebf82c891 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -45,7 +45,7 @@ export function getVoltageLevelSingleLineDiagram( ); } -export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid,currentRootNetworkUuid, voltageLevelId) { +export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid, currentRootNetworkUuid, voltageLevelId) { console.info( `Fetching substation ID for the voltage level '${voltageLevelId}' of study '${studyUuid}' and node '${currentNodeUuid}' + ' for voltage level '${voltageLevelId}'...` ); @@ -65,7 +65,12 @@ export function fetchSubstationIdForVoltageLevel(studyUuid, currentNodeUuid,curr return backendFetchText(fetchSubstationIdUrl); } -export function fetchBusesOrBusbarSectionsForVoltageLevel(studyUuid, currentNodeUuid, currentRootNetworkUuid,voltageLevelId) { +export function fetchBusesOrBusbarSectionsForVoltageLevel( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + voltageLevelId +) { console.info( `Fetching buses or busbar sections of study '${studyUuid}' and node '${currentNodeUuid}' + ' for voltage level '${voltageLevelId}'...` ); diff --git a/src/services/study/non-evacuated-energy.js b/src/services/study/non-evacuated-energy.js index 5bbb122d64..d42952eda9 100644 --- a/src/services/study/non-evacuated-energy.js +++ b/src/services/study/non-evacuated-energy.js @@ -8,17 +8,27 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -export function startNonEvacuatedEnergy(studyUuid, currentNodeUuid) { - console.info(`Running non evacuated energy analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/non-evacuated-energy/run'; +export function startNonEvacuatedEnergy(studyUuid, currentRootNetworkUuid, currentNodeUuid) { + console.info( + `Running non evacuated energy analysis on ${studyUuid} on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/non-evacuated-energy/run'; console.debug(url); return backendFetch(url, { method: 'post' }); } -export function stopNonEvacuatedEnergy(studyUuid, currentNodeUuid) { - console.info(`Stopping non evacuated energy analysis on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/non-evacuated-energy/stop`; +export function stopNonEvacuatedEnergy(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Stopping non evacuated energy analysis on ${studyUuid} on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/non-evacuated-energy/stop`; console.debug(url); return backendFetch(url, { method: 'put' }); } @@ -37,9 +47,11 @@ export function fetchNonEvacuatedEnergyStatus(studyUuid, currentNodeUuid, curren } export function fetchNonEvacuatedEnergyResult(studyUuid, currentNodeUuid, currentRootNetworkUuid) { - console.log(currentRootNetworkUuid,`*****Fetching non evacuated energy analysis result on ${studyUuid} and node ${currentNodeUuid} ...`); - - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid)}/non-evacuated-energy/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/non-evacuated-energy/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/security-analysis.js b/src/services/study/security-analysis.js index 9657dd379c..c1dc16c5d6 100644 --- a/src/services/study/security-analysis.js +++ b/src/services/study/security-analysis.js @@ -8,7 +8,6 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchFile, backendFetchJson, backendFetchText, getRequestParamFromList } from '../utils'; - export function startSecurityAnalysis(studyUuid, currentNodeUuid, currentRootNetwork, contingencyListNames) { console.info( `Running security analysis on ${studyUuid} on root network ${currentRootNetwork} and node ${currentNodeUuid} ...` diff --git a/src/services/study/sensitivity-analysis.js b/src/services/study/sensitivity-analysis.js index 022b6d583f..ee1decf272 100644 --- a/src/services/study/sensitivity-analysis.js +++ b/src/services/study/sensitivity-analysis.js @@ -10,20 +10,26 @@ import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; const GET_PARAMETERS_PREFIX = import.meta.env.VITE_API_GATEWAY + '/sensitivity-analysis/v1/parameters'; -export function startSensitivityAnalysis(studyUuid, currentNodeUuid) { - console.info(`Running sensi on ${studyUuid} and node ${currentNodeUuid} ...`); +export function startSensitivityAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Running sensi on ${studyUuid} for root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); const startSensiAnalysisUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/sensitivity-analysis/run'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/sensitivity-analysis/run'; console.debug(startSensiAnalysisUrl); return backendFetch(startSensiAnalysisUrl, { method: 'post' }); } -export function stopSensitivityAnalysis(studyUuid, currentNodeUuid) { - console.info(`Stopping sensitivity analysis on ${studyUuid} and node ${currentNodeUuid} ...`); +export function stopSensitivityAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Stopping sensitivity analysis on ${studyUuid} for root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); const stopSensitivityAnalysisUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/sensitivity-analysis/stop`; console.debug(stopSensitivityAnalysisUrl); return backendFetch(stopSensitivityAnalysisUrl, { method: 'put' }); @@ -42,8 +48,10 @@ export function fetchSensitivityAnalysisStatus(studyUuid, currentNodeUuid, curre return backendFetchText(url); } -export function fetchSensitivityAnalysisResult(studyUuid, currentNodeUuid, selector) { - console.info(`Fetching sensitivity analysis on ${studyUuid} and node ${currentNodeUuid} ...`); +export function fetchSensitivityAnalysisResult(studyUuid, currentNodeUuid, currentRootNetworkUuid, selector) { + console.info( + `Fetching sensitivity analysis on ${studyUuid} for root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); // Add params to Url const urlSearchParams = new URLSearchParams(); @@ -52,14 +60,17 @@ export function fetchSensitivityAnalysisResult(studyUuid, currentNodeUuid, selec const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/sensitivity-analysis/result?${urlSearchParams}`; console.debug(url); return backendFetchJson(url); } -export function fetchSensitivityAnalysisFilterOptions(studyUuid, currentNodeUuid, selector) { - console.info(`Fetching sensitivity analysis filter options on ${studyUuid} and node ${currentNodeUuid} ...`); +export function fetchSensitivityAnalysisFilterOptions(studyUuid, currentNodeUuid, currentRootNetworkUuid, selector) { + console.info( + `Fetching sensitivity analysis filter options on ${studyUuid} on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); // Add params to Url const urlSearchParams = new URLSearchParams(); @@ -68,7 +79,8 @@ export function fetchSensitivityAnalysisFilterOptions(studyUuid, currentNodeUuid const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/sensitivity-analysis/result/filter-options?${urlSearchParams}`; console.debug(url); return backendFetchJson(url); @@ -109,7 +121,13 @@ export function setSensitivityAnalysisParameters(studyUuid, newParams) { }); } -export function getSensitivityAnalysisFactorsCount(studyUuid, currentNodeUuid, isInjectionsSet, newParams) { +export function getSensitivityAnalysisFactorsCount( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + isInjectionsSet, + newParams +) { console.info('get sensitivity analysis parameters computing count'); const urlSearchParams = new URLSearchParams(); const jsoned = JSON.stringify(isInjectionsSet); @@ -118,7 +136,7 @@ export function getSensitivityAnalysisFactorsCount(studyUuid, currentNodeUuid, i .filter((key) => newParams[key]) .forEach((key) => urlSearchParams.append(`ids[${key}]`, newParams[key])); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)} + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid)} /sensitivity-analysis/factors-count?${urlSearchParams}`; console.debug(url); return backendFetch(url, { @@ -126,12 +144,15 @@ export function getSensitivityAnalysisFactorsCount(studyUuid, currentNodeUuid, i }); } -export function exportSensitivityResultsAsCsv(studyUuid, currentNodeUuid, csvConfig) { - console.info(`Exporting sensitivity analysis on ${studyUuid} and node ${currentNodeUuid} as CSV ...`); +export function exportSensitivityResultsAsCsv(studyUuid, currentNodeUuid, currentRootNetworkUuid, csvConfig) { + console.info( + `Exporting sensitivity analysis on ${studyUuid} on root networ ${currentRootNetworkUuid} and node ${currentNodeUuid} as CSV ...` + ); const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/sensitivity-analysis/result/csv`; console.debug(url); return backendFetch(url, { diff --git a/src/services/study/short-circuit-analysis.js b/src/services/study/short-circuit-analysis.js index ad580f7b0a..a6bf684bf2 100644 --- a/src/services/study/short-circuit-analysis.js +++ b/src/services/study/short-circuit-analysis.js @@ -18,24 +18,29 @@ function getShortCircuitUrl() { return `${PREFIX_SHORT_CIRCUIT_SERVER_QUERIES}/v1/`; } -export function startShortCircuitAnalysis(studyUuid, currentNodeUuid, busId) { - console.info(`Running short circuit analysis on '${studyUuid}' and node '${currentNodeUuid}' ...`); +export function startShortCircuitAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid, busId) { + console.info( + `Running short circuit analysis on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const urlSearchParams = new URLSearchParams(); busId && urlSearchParams.append('busId', busId); const startShortCircuitAnalysisUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/shortcircuit/run?' + urlSearchParams.toString(); console.debug(startShortCircuitAnalysisUrl); return backendFetch(startShortCircuitAnalysisUrl, { method: 'put' }); } -export function stopShortCircuitAnalysis(studyUuid, currentNodeUuid) { - console.info(`Stopping short circuit analysis on '${studyUuid}' and node '${currentNodeUuid}' ...`); +export function stopShortCircuitAnalysis(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Stopping short circuit analysis on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const stopShortCircuitAnalysisUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/shortcircuit/stop'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/shortcircuit/stop'; console.debug(stopShortCircuitAnalysisUrl); return backendFetch(stopShortCircuitAnalysisUrl, { method: 'put' }); } @@ -69,11 +74,11 @@ export function fetchOneBusShortCircuitAnalysisStatus(studyUuid, currentNodeUuid ); } -export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, type }) { +export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, currentRootNetworkUuid, type }) { const analysisType = getShortCircuitAnalysisTypeFromEnum(type); console.info( - `Fetching ${analysisType} short circuit analysis result on '${studyUuid}' and node '${currentNodeUuid}' ...` + `Fetching ${analysisType} short circuit analysis result on '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` ); const urlSearchParams = new URLSearchParams(); if (analysisType) { @@ -81,7 +86,7 @@ export function fetchShortCircuitAnalysisResult({ studyUuid, currentNodeUuid, ty } const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/shortcircuit/result?' + urlSearchParams.toString(); console.debug(url); diff --git a/src/services/study/state-estimation.js b/src/services/study/state-estimation.js index c677b8ccfe..770914e767 100644 --- a/src/services/study/state-estimation.js +++ b/src/services/study/state-estimation.js @@ -39,7 +39,11 @@ export function fetchStateEstimationStatus(studyUuid, currentNodeUuid, currentRo export function fetchStateEstimationResult(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Fetching state estimation result on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid)}/state-estimation/result`; + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/state-estimation/result`; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/study.ts b/src/services/study/study.ts index 1e41d9b70e..f6ca25392d 100644 --- a/src/services/study/study.ts +++ b/src/services/study/study.ts @@ -18,7 +18,7 @@ interface BasicStudyInfos { export const recreateStudyNetworkFromExistingCase = ( caseUuid: UUID, studyUuid: UUID, - rootNetworkUuid: UUID, + currentRootNetworkUuid: UUID, importParameters: Record ): Promise => { const urlSearchParams = new URLSearchParams(); @@ -29,7 +29,7 @@ export const recreateStudyNetworkFromExistingCase = ( '/v1/studies/' + encodeURIComponent(studyUuid) + '/root-networks/' + - encodeURIComponent(rootNetworkUuid) + + encodeURIComponent(currentRootNetworkUuid) + '/network?' + urlSearchParams.toString(); @@ -42,13 +42,13 @@ export const recreateStudyNetworkFromExistingCase = ( }); }; -export const recreateStudyNetwork = (studyUuid: UUID, rootNetworkUuid: UUID): Promise => { +export const recreateStudyNetwork = (studyUuid: UUID, currentRootNetworkUuid: UUID): Promise => { const recreateStudyNetworkUrl = PREFIX_STUDY_QUERIES + '/v1/studies/' + encodeURIComponent(studyUuid) + '/root-networks/' + - encodeURIComponent(rootNetworkUuid) + + encodeURIComponent(currentRootNetworkUuid) + '/network'; console.debug(recreateStudyNetworkUrl); @@ -59,13 +59,13 @@ export const recreateStudyNetwork = (studyUuid: UUID, rootNetworkUuid: UUID): Pr }); }; -export const reindexAllStudy = (studyUuid: UUID, rootNetworkUuid: UUID): Promise => { +export const reindexAllStudy = (studyUuid: UUID, currentRootNetworkUuid: UUID): Promise => { const reindexAllStudyUrl = PREFIX_STUDY_QUERIES + '/v1/studies/' + encodeURIComponent(studyUuid) + '/root-networks/' + - encodeURIComponent(rootNetworkUuid) + + encodeURIComponent(currentRootNetworkUuid) + '/reindex-all'; console.debug(reindexAllStudyUrl); diff --git a/src/services/study/voltage-init.js b/src/services/study/voltage-init.js index e21c2eec60..a1e51a55db 100644 --- a/src/services/study/voltage-init.js +++ b/src/services/study/voltage-init.js @@ -8,19 +8,21 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -export function startVoltageInit(studyUuid, currentNodeUuid,currentRootNetworkUuid) { +export function startVoltageInit(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Running voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); const startVoltageInitUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/run'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/voltage-init/run'; console.debug(startVoltageInitUrl); return backendFetch(startVoltageInitUrl, { method: 'put' }); } -export function stopVoltageInit(studyUuid, currentNodeUuid,currentRootNetworkUuid) { +export function stopVoltageInit(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Stopping voltage init on '${studyUuid}' and node '${currentNodeUuid}' ...`); const stopVoltageInitUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/stop'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/voltage-init/stop'; console.debug(stopVoltageInitUrl); return backendFetch(stopVoltageInitUrl, { method: 'put' }); } @@ -36,10 +38,11 @@ export function fetchVoltageInitStatus(studyUuid, currentNodeUuid, currentRootNe return backendFetchText(url); } -export function fetchVoltageInitResult(studyUuid, currentNodeUuid, currentRootNetworkUuid - ) { +export function fetchVoltageInitResult(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info(`Fetching voltage init result on '${studyUuid}' and node '${currentNodeUuid}' ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid,currentRootNetworkUuid) + '/voltage-init/result'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/voltage-init/result'; console.debug(url); return backendFetchJson(url); } @@ -68,18 +71,20 @@ export function getVoltageInitStudyParameters(studyUuid) { return backendFetchJson(getVoltageInitParams); } -export function getVoltageInitModifications(studyUuid, currentNodeId,currentRootNetworkUuid) { +export function getVoltageInitModifications(studyUuid, currentNodeId, currentRootNetworkUuid) { console.info('get voltage init modifications'); const getVoltageInitModifications = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId,currentRootNetworkUuid) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId, currentRootNetworkUuid) + + '/voltage-init/modifications'; console.debug(getVoltageInitModifications); return backendFetchJson(getVoltageInitModifications); } -export function cloneVoltageInitModifications(studyUuid, currentNodeId,currentRootNetworkUuid) { +export function cloneVoltageInitModifications(studyUuid, currentNodeId, currentRootNetworkUuid) { console.info('cloning voltage init modifications'); const cloneVoltageInitModificationsUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId,currentRootNetworkUuid) + '/voltage-init/modifications'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeId, currentRootNetworkUuid) + + '/voltage-init/modifications'; return backendFetch(cloneVoltageInitModificationsUrl, { method: 'PUT', From cb1f09331e1a846cac843304b7fafa9496613341 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 26 Dec 2024 11:45:54 +0100 Subject: [PATCH 14/51] notifications and migrating endpoints Signed-off-by: souissimai --- .../computing-status/use-computing-status.ts | 37 ++++++++++-- src/components/diagrams/diagram-pane.tsx | 5 +- ...e-one-bus-shortcircuit-analysis-loader.tsx | 1 + src/components/dialogs/case-list-selector.jsx | 4 +- .../dialogs/contingency-list-selector.jsx | 4 +- .../equipment-id/equipment-id-selector.jsx | 11 ++-- src/components/dialogs/export-dialog.jsx | 5 +- .../delete-attaching-line-form.jsx | 24 ++++---- .../voltage-level-creation-dialog.jsx | 3 + .../creation/voltage-level-creation-form.jsx | 14 +++-- .../curve/dialog/model-filter.tsx | 27 +++++---- .../event-modification-scenario-editor.tsx | 35 ++++++++---- .../network-modification-node-editor.tsx | 2 + src/components/graph/menus/node-editor.tsx | 3 +- .../graph/menus/root-network-node-editor.tsx | 3 + .../network-modification-tree-pane.jsx | 56 +++++++++++-------- src/components/network/network-map-tab.tsx | 1 + .../hooks/useResultTimeSeries.ts | 9 ++- .../security-analysis-export-button.tsx | 6 +- .../security-analysis-result-tab.tsx | 1 + .../security-analysis-result-utils.ts | 18 +++++- .../shortcircuit-analysis-result.tsx | 23 +++++++- src/components/run-button-container.jsx | 8 ++- src/components/spreadsheet/table-wrapper.tsx | 1 + src/components/study-container.jsx | 38 +++++++++++-- src/hooks/use-get-study-impacts.ts | 1 + src/services/study/dynamic-simulation.js | 42 ++++++++++---- src/services/study/index.ts | 4 +- src/services/study/network.js | 4 +- src/services/study/non-evacuated-energy.js | 2 +- src/services/study/security-analysis.js | 11 +++- src/services/study/state-estimation.js | 22 ++++++-- 32 files changed, 307 insertions(+), 118 deletions(-) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index 7bcd2a7245..f5da6e3b63 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -40,9 +40,12 @@ function isWorthUpdate( fetcher: (studyUuid: UUID, nodeUuid: UUID) => Promise, lastUpdateRef: RefObject, nodeUuidRef: RefObject, + rootNetworkUuidRef: RefObject, nodeUuid: UUID, + currentRootNetworkUuid: UUID, invalidations: string[] ): boolean { + console.log('TEST ====== ', studyUpdatedForce); const headers = studyUpdatedForce?.eventData?.headers; const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; @@ -50,6 +53,9 @@ function isWorthUpdate( if (nodeUuidRef.current !== nodeUuid) { return true; } + if (rootNetworkUuidRef.current !== currentRootNetworkUuid) { + return true; + } if (fetcher && lastUpdateRef.current?.fetcher !== fetcher) { return true; } @@ -94,6 +100,8 @@ export const useComputingStatus: UseComputingStatusProps = ( optionalServiceAvailabilityStatus = OptionalServicesStatus.Up ) => { const nodeUuidRef = useRef(null); + const rootNetworkUuidRef = useRef(null); + const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const lastUpdateRef = useRef(null); const dispatch = useDispatch(); @@ -116,9 +124,14 @@ export const useComputingStatus: UseComputingStatusProps = ( dispatch(setLastCompletedComputation()); nodeUuidRef.current = nodeUuid; + rootNetworkUuidRef.current = currentRootNetworkUuid; fetcher(studyUuid, nodeUuid, currentRootNetworkUuid) .then((res: string) => { - if (!canceledRequest && nodeUuidRef.current === nodeUuid) { + if ( + !canceledRequest && + nodeUuidRef.current === nodeUuid && + rootNetworkUuidRef.current === currentRootNetworkUuid + ) { const status = resultConversion(res); dispatch(setComputingStatus(computingType, status)); if (isComputationCompleted(status)) { @@ -148,21 +161,37 @@ export const useComputingStatus: UseComputingStatusProps = ( /* initial fetch and update */ useEffect(() => { - if (!studyUuid || !nodeUuid || optionalServiceAvailabilityStatus !== OptionalServicesStatus.Up) { + if ( + !studyUuid || + !nodeUuid || + !currentRootNetworkUuid || + optionalServiceAvailabilityStatus !== OptionalServicesStatus.Up + ) { return; } - + console.log('!!!!!!!!!! fetcher ', fetcher); const isUpdateForUs = isWorthUpdate( studyUpdatedForce, fetcher, lastUpdateRef, nodeUuidRef, + rootNetworkUuidRef, nodeUuid, + currentRootNetworkUuid, invalidations ); lastUpdateRef.current = { studyUpdatedForce, fetcher }; if (isUpdateForUs) { update(); } - }, [update, fetcher, nodeUuid, invalidations, studyUpdatedForce, studyUuid, optionalServiceAvailabilityStatus]); + }, [ + update, + fetcher, + nodeUuid, + invalidations, + currentRootNetworkUuid, + studyUpdatedForce, + studyUuid, + optionalServiceAvailabilityStatus, + ]); }; diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index e4a6de673e..67b957d631 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -803,8 +803,9 @@ export function DiagramPane({ // This effect will trigger the diagrams' forced update useEffect(() => { - console.log('TEST', studyUpdatedForce); if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['updateType'] === 'loadflowResult') { //TODO reload data more intelligently updateDiagramsByCurrentNode(); @@ -812,6 +813,8 @@ export function DiagramPane({ // FM if we want to reload data more precisely, we need more information from notifications updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'buildCompleted') { + console.log('TEST ====== buildCompleted ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['node'] === currentNodeRef.current?.id) { updateDiagramsByCurrentNode(); } diff --git a/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx b/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx index 6be3eba70e..7e97e3ec15 100644 --- a/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx +++ b/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx @@ -83,6 +83,7 @@ export function useOneBusShortcircuitAnalysisLoader(diagramId: string, nodeId: U useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); if ( studyUpdatedForce.eventData.headers['updateType'] === 'oneBusShortCircuitAnalysisResult' || studyUpdatedForce.eventData.headers['updateType'] === 'oneBusShortCircuitAnalysis_failed' diff --git a/src/components/dialogs/case-list-selector.jsx b/src/components/dialogs/case-list-selector.jsx index 70469ab812..afc1e2abf3 100644 --- a/src/components/dialogs/case-list-selector.jsx +++ b/src/components/dialogs/case-list-selector.jsx @@ -37,6 +37,7 @@ const CaseListSelector = (props) => { const favoriteContingencyListUuids = useSelector((state) => state[PARAM_FAVORITE_CONTINGENCY_LISTS]); const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const [contingencyList, setContingencyList] = useState([]); @@ -79,6 +80,7 @@ const CaseListSelector = (props) => { fetchContingencyCount( props.studyUuid, currentNode.id, + currentRootNetworkUuid, checkedContingencyList.map((c) => c.id) ).then((contingencyCount) => { if (!discardResult) { @@ -89,7 +91,7 @@ const CaseListSelector = (props) => { return () => { discardResult = true; }; - }, [props.open, props.studyUuid, currentNode, checkedContingencyList]); + }, [props.open, props.studyUuid, currentNode, currentRootNetworkUuid, checkedContingencyList]); useEffect(() => { if (favoriteContingencyListUuids && favoriteContingencyListUuids.length > 0 && props.open) { diff --git a/src/components/dialogs/contingency-list-selector.jsx b/src/components/dialogs/contingency-list-selector.jsx index 2f8b2bf0f1..425089bd47 100644 --- a/src/components/dialogs/contingency-list-selector.jsx +++ b/src/components/dialogs/contingency-list-selector.jsx @@ -38,6 +38,7 @@ const ContingencyListSelector = (props) => { const favoriteContingencyListUuids = useSelector((state) => state[PARAM_FAVORITE_CONTINGENCY_LISTS]); const currentNode = useSelector((state) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state) => state.currentRootNetwork); const [contingencyList, setContingencyList] = useState([]); @@ -80,6 +81,7 @@ const ContingencyListSelector = (props) => { fetchContingencyCount( props.studyUuid, currentNode.id, + currentRootNetworkUuid, checkedContingencyList.map((c) => c.id) ).then((contingencyCount) => { if (!discardResult) { @@ -90,7 +92,7 @@ const ContingencyListSelector = (props) => { return () => { discardResult = true; }; - }, [props.open, props.studyUuid, currentNode, checkedContingencyList]); + }, [props.open, props.studyUuid, currentNode, checkedContingencyList, currentRootNetworkUuid]); useEffect(() => { if (favoriteContingencyListUuids && favoriteContingencyListUuids.length > 0 && props.open) { diff --git a/src/components/dialogs/equipment-id/equipment-id-selector.jsx b/src/components/dialogs/equipment-id/equipment-id-selector.jsx index b05e5e86e0..0f3b38de91 100644 --- a/src/components/dialogs/equipment-id/equipment-id-selector.jsx +++ b/src/components/dialogs/equipment-id/equipment-id-selector.jsx @@ -29,6 +29,7 @@ const styles = { export const EquipmentIdSelector = ({ studyUuid, currentNode, + currentRootNetworkUuid, defaultValue, setSelectedId, equipmentType, @@ -43,10 +44,12 @@ export const EquipmentIdSelector = ({ const [selectedValue, setSelectedValue] = useState(null); useEffect(() => { - fetchEquipmentsIds(studyUuid, currentNodeUuid, undefined, equipmentType, true).then((values) => { - setEquipmentOptions(values.sort((a, b) => a.localeCompare(b))); - }); - }, [studyUuid, currentNodeUuid, equipmentType]); + fetchEquipmentsIds(studyUuid, currentNodeUuid, currentRootNetworkUuid, undefined, equipmentType, true).then( + (values) => { + setEquipmentOptions(values.sort((a, b) => a.localeCompare(b))); + } + ); + }, [studyUuid, currentNodeUuid, currentRootNetworkUuid, equipmentType]); // We go through this effect to force a rerender and display the loading icon. useEffect(() => { diff --git a/src/components/dialogs/export-dialog.jsx b/src/components/dialogs/export-dialog.jsx index ad04428fc0..0f58990a4c 100644 --- a/src/components/dialogs/export-dialog.jsx +++ b/src/components/dialogs/export-dialog.jsx @@ -47,7 +47,7 @@ const STRING_LIST = 'STRING_LIST'; * @param {String} title Title of the dialog */ -const ExportDialog = ({ open, onClose, onClick, studyUuid, nodeUuid, title }) => { +const ExportDialog = ({ open, onClose, onClick, studyUuid, nodeUuid, rootNetworkUuid, title }) => { const [formatsWithParameters, setFormatsWithParameters] = useState([]); const [selectedFormat, setSelectedFormat] = useState(''); const [loading, setLoading] = useState(false); @@ -122,7 +122,7 @@ const ExportDialog = ({ open, onClose, onClick, studyUuid, nodeUuid, title }) => }, []); const handleExportClick = () => { if (selectedFormat) { - const downloadUrl = getExportUrl(studyUuid, nodeUuid, selectedFormat); + const downloadUrl = getExportUrl(studyUuid, nodeUuid, rootNetworkUuid, selectedFormat); let suffix; const urlSearchParams = new URLSearchParams(); if (Object.keys(currentParameters).length > 0) { @@ -245,6 +245,7 @@ ExportDialog.propTypes = { onClick: PropTypes.func.isRequired, studyUuid: PropTypes.string, nodeUuid: PropTypes.string, + rootNetworkUuid: PropTypes.string, title: PropTypes.string.isRequired, }; diff --git a/src/components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-form.jsx b/src/components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-form.jsx index faab7acd59..426ac10a35 100644 --- a/src/components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-form.jsx +++ b/src/components/dialogs/network-modifications/delete-attaching-line/delete-attaching-line-form.jsx @@ -20,20 +20,22 @@ import { fetchEquipmentsIds } from '../../../../services/study/network-map'; import GridSection from '../../commons/grid-section'; import GridItem from '../../commons/grid-item'; -const DeleteAttachingLineForm = ({ studyUuid, currentNode }) => { +const DeleteAttachingLineForm = ({ studyUuid, currentNode, currentRootNetworkUuid }) => { const [linesOptions, setLinesOptions] = useState([]); useEffect(() => { - fetchEquipmentsIds(studyUuid, currentNode.id, undefined, 'LINE', true).then((values) => { - setLinesOptions( - values - .sort((a, b) => a.localeCompare(b)) - .map((value) => { - return { id: value }; - }) - ); - }); - }, [studyUuid, currentNode?.id]); + fetchEquipmentsIds(studyUuid, currentNode.id, currentRootNetworkUuid, undefined, 'LINE', true).then( + (values) => { + setLinesOptions( + values + .sort((a, b) => a.localeCompare(b)) + .map((value) => { + return { id: value }; + }) + ); + } + ); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid]); const lineToAttachTo1Field = ( @@ -278,6 +280,7 @@ VoltageLevelCreationDialog.propTypes = { editData: PropTypes.object, studyUuid: PropTypes.string, currentNode: PropTypes.object, + currentRootNetworkUuid: PropTypes.string, isUpdate: PropTypes.bool, onCreateVoltageLevel: PropTypes.func, editDataFetchStatus: PropTypes.string, diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx index aa221b626c..cc77cf57f3 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-form.jsx @@ -34,7 +34,7 @@ import { useWatch } from 'react-hook-form'; import GridItem from '../../../commons/grid-item'; import GridSection from '../../../commons/grid-section'; -const VoltageLevelCreationForm = ({ currentNode, studyUuid }) => { +const VoltageLevelCreationForm = ({ currentNode, studyUuid, currentRootNetworkUuid }) => { const currentNodeUuid = currentNode?.id; const [substations, setSubstations] = useState([]); @@ -42,12 +42,14 @@ const VoltageLevelCreationForm = ({ currentNode, studyUuid }) => { const watchSectionCount = useWatch({ name: SECTION_COUNT }); useEffect(() => { - if (studyUuid && currentNodeUuid) { - fetchEquipmentsIds(studyUuid, currentNodeUuid, undefined, 'SUBSTATION', true).then((values) => { - setSubstations(values.sort((a, b) => a.localeCompare(b))); - }); + if (studyUuid && currentNodeUuid && currentRootNetworkUuid) { + fetchEquipmentsIds(studyUuid, currentNodeUuid, currentRootNetworkUuid, undefined, 'SUBSTATION', true).then( + (values) => { + setSubstations(values.sort((a, b) => a.localeCompare(b))); + } + ); } - }, [studyUuid, currentNodeUuid]); + }, [studyUuid, currentNodeUuid, currentRootNetworkUuid]); const voltageLevelIdField = ( diff --git a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/model-filter.tsx b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/model-filter.tsx index be6f209de4..5011ad3fbf 100644 --- a/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/model-filter.tsx +++ b/src/components/dialogs/parameters/dynamicsimulation/curve/dialog/model-filter.tsx @@ -171,6 +171,7 @@ const ModelFilter = forwardRef( const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const [allModels, setAllModels] = useState([]); const [allVariables, setAllVariables] = useState< @@ -221,19 +222,21 @@ const ModelFilter = forwardRef( if (!currentNode?.id) { return; } - fetchDynamicSimulationModels(studyUuid, currentNode.id).then((models: DynamicSimulationModelBack[]) => { - setAllModels( - models.map((model) => ({ - name: model.modelName, - equipmentType: model.equipmentType, - })) - ); + fetchDynamicSimulationModels(studyUuid, currentNode.id, currentRootNetworkUuid).then( + (models: DynamicSimulationModelBack[]) => { + setAllModels( + models.map((model) => ({ + name: model.modelName, + equipmentType: model.equipmentType, + })) + ); - // transform models to variables tree representation - const variablesTree = modelsToVariablesTree(models); - setAllVariables(variablesTree); - }); - }, [studyUuid, currentNode?.id]); + // transform models to variables tree representation + const variablesTree = modelsToVariablesTree(models); + setAllVariables(variablesTree); + } + ); + }, [studyUuid, currentNode?.id, currentRootNetworkUuid]); // expose some api for the component by using ref useImperativeHandle( diff --git a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx index 9941fb1ff3..69bf33ceed 100644 --- a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx +++ b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx @@ -34,6 +34,7 @@ const EventModificationScenarioEditor = () => { const { snackError } = useSnackMessage(); const [events, setEvents] = useState([]); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const currentNodeIdRef = useRef(); // initial empty to get first update const [pendingState, setPendingState] = useState(false); @@ -92,11 +93,11 @@ const EventModificationScenarioEditor = () => { const doFetchEvents = useCallback(() => { // Do not fetch modifications on the root node - if (currentNode?.type !== 'NETWORK_MODIFICATION' || !studyUuid) { + if (currentNode?.type !== 'NETWORK_MODIFICATION' || !studyUuid || !currentRootNetworkUuid) { return; } setLaunchLoader(true); - fetchDynamicSimulationEvents(studyUuid, currentNode.id) + fetchDynamicSimulationEvents(studyUuid, currentNode.id, currentRootNetworkUuid) .then((res) => { // Check if during asynchronous request currentNode has already changed // otherwise accept fetch results @@ -117,7 +118,15 @@ const EventModificationScenarioEditor = () => { setLaunchLoader(false); dispatch(setModificationsInProgress(false)); }); - }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); + }, [ + currentNode?.type, + currentRootNetworkUuid, + currentNode?.id, + studyUuid, + updateSelectedItems, + snackError, + dispatch, + ]); useEffect(() => { // first time with currentNode initialized then fetch events @@ -133,6 +142,8 @@ const EventModificationScenarioEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); + if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { return; } @@ -164,17 +175,19 @@ const EventModificationScenarioEditor = () => { const isAnyNodeBuilding = useIsAnyNodeBuilding(); const doDeleteEvent = useCallback(() => { - if (!studyUuid || !currentNode?.id) { + if (!studyUuid || !currentNode?.id || !currentRootNetworkUuid) { return; } const selectedEvents = [...selectedItems]; - deleteDynamicSimulationEvents(studyUuid, currentNode.id, selectedEvents).catch((errMsg) => { - snackError({ - messageTxt: errMsg, - headerId: 'DynamicSimulationEventDeleteError', - }); - }); - }, [currentNode?.id, selectedItems, snackError, studyUuid]); + deleteDynamicSimulationEvents(studyUuid, currentNode.id, currentRootNetworkUuid, selectedEvents).catch( + (errMsg) => { + snackError({ + messageTxt: errMsg, + headerId: 'DynamicSimulationEventDeleteError', + }); + } + ); + }, [currentNode?.id, selectedItems, snackError, studyUuid, currentRootNetworkUuid]); const doEditEvent = (event: Event) => { setEditDialogOpen({ diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index 580df331d3..94afb494f9 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -609,6 +609,8 @@ const NetworkModificationNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { if ( copyInfosRef.current && diff --git a/src/components/graph/menus/node-editor.tsx b/src/components/graph/menus/node-editor.tsx index 36cb725509..8660ff7b01 100644 --- a/src/components/graph/menus/node-editor.tsx +++ b/src/components/graph/menus/node-editor.tsx @@ -23,8 +23,7 @@ const styles = { display: 'flex', flexDirection: 'column', elevation: 3, - // background: "red", - + // background: "red", }), }; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 3a92db857e..dbe57d43fc 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -182,6 +182,9 @@ const RootNetworkNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { + + console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { dofetchRootNetworks(); } diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index dc14953823..fe8cbdcab6 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -190,19 +190,23 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== NETWORKMODIFTREEPANE', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['updateType'] === UpdateType.NODE_CREATED) { - fetchNetworkModificationTreeNode(studyUuid, studyUpdatedForce.eventData.headers['newNode']).then( - (node) => { - dispatch( - networkModificationTreeNodeAdded( - node, - studyUpdatedForce.eventData.headers['parentNode'], - studyUpdatedForce.eventData.headers['insertMode'], - studyUpdatedForce.eventData.headers['referenceNodeUuid'] - ) - ); - } - ); + fetchNetworkModificationTreeNode( + studyUuid, + studyUpdatedForce.eventData.headers['newNode'], + currentRootNetworkUuid + ).then((node) => { + dispatch( + networkModificationTreeNodeAdded( + node, + studyUpdatedForce.eventData.headers['parentNode'], + studyUpdatedForce.eventData.headers['insertMode'], + studyUpdatedForce.eventData.headers['referenceNodeUuid'] + ) + ); + }); if (isSubtreeImpacted([studyUpdatedForce.eventData.headers['parentNode']])) { resetNodeClipboard(); @@ -219,18 +223,20 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu } ); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeMoved') { - fetchNetworkModificationTreeNode(studyUuid, studyUpdatedForce.eventData.headers['movedNode']).then( - (node) => { - dispatch( - networkModificationTreeNodeMoved( - node, - studyUpdatedForce.eventData.headers['parentNode'], - studyUpdatedForce.eventData.headers['insertMode'], - studyUpdatedForce.eventData.headers['referenceNodeUuid'] - ) - ); - } - ); + fetchNetworkModificationTreeNode( + studyUuid, + studyUpdatedForce.eventData.headers['movedNode'], + currentRootNetworkUuid + ).then((node) => { + dispatch( + networkModificationTreeNodeMoved( + node, + studyUpdatedForce.eventData.headers['parentNode'], + studyUpdatedForce.eventData.headers['insertMode'], + studyUpdatedForce.eventData.headers['referenceNodeUuid'] + ) + ); + }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'subtreeMoved') { fetchNetworkModificationSubtree(studyUuid, studyUpdatedForce.eventData.headers['movedNode']).then( (nodes) => { @@ -295,6 +301,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu snackInfo, dispatch, broadcastChannel, + currentRootNetworkUuid, isSubtreeImpacted, resetNodeClipboard, ]); @@ -560,6 +567,7 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu onClose={() => setOpenExportDialog(false)} onClick={handleClickExportStudy} studyUuid={studyUuid} + rootNetworkUuid={currentRootNetworkUuid} nodeUuid={activeNode?.id} title={intlRef.current.formatMessage({ id: 'exportNetwork', diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 61b894e8a6..c55b0df772 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -792,6 +792,7 @@ export const NetworkMapTab = ({ useEffect(() => { if (isInitialized && studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); if (studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult') { reloadMapEquipments(currentNodeRef.current, undefined); } diff --git a/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts b/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts index 9ecb381f76..fa1ba7e9c9 100644 --- a/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts +++ b/src/components/results/dynamicsimulation/hooks/useResultTimeSeries.ts @@ -51,7 +51,12 @@ const useResultTimeSeries = (nodeUuid: UUID, studyUuid: UUID, currentRootNetwork (indexValue) => result.timeseriesMetadatas[indexValue].name ); - return fetchDynamicSimulationResultTimeSeries(studyUuid, nodeUuid, timeSeriesNamesToLoad) + return fetchDynamicSimulationResultTimeSeries( + studyUuid, + nodeUuid, + currentRootNetworkUuid, + timeSeriesNamesToLoad + ) .then((newlyLoadedTimeSeries) => { // insert one by one newly loaded timeserie into the cache for (const newSeries of newlyLoadedTimeSeries) { @@ -78,7 +83,7 @@ const useResultTimeSeries = (nodeUuid: UUID, studyUuid: UUID, currentRootNetwork }); } }, - [studyUuid, nodeUuid, result, snackError] + [studyUuid, nodeUuid, currentRootNetworkUuid, result, snackError] ); return [result, lazyLoadTimeSeriesCb, isLoading]; diff --git a/src/components/results/securityanalysis/security-analysis-export-button.tsx b/src/components/results/securityanalysis/security-analysis-export-button.tsx index 24ef42436d..10ff5d2edc 100644 --- a/src/components/results/securityanalysis/security-analysis-export-button.tsx +++ b/src/components/results/securityanalysis/security-analysis-export-button.tsx @@ -18,13 +18,14 @@ import { PERMANENT_LIMIT_NAME } from '../common/utils'; interface SecurityAnalysisExportButtonProps { studyUuid: UUID; nodeUuid: UUID; + rootNetworkUuid: UUID; csvHeaders?: string[]; resultType: RESULT_TYPE; disabled?: boolean; } export const SecurityAnalysisExportButton: FunctionComponent = (props) => { - const { studyUuid, nodeUuid, csvHeaders, disabled, resultType } = props; + const { studyUuid, nodeUuid, rootNetworkUuid, csvHeaders, disabled, resultType } = props; const { snackError } = useSnackMessage(); const [isCsvExportLoading, setIsCsvExportLoading] = useState(false); @@ -70,6 +71,7 @@ export const SecurityAnalysisExportButton: FunctionComponent setIsCsvExportLoading(false)); - }, [resultType, csvHeaders, enumValueTranslations, studyUuid, nodeUuid, snackError, intl]); + }, [resultType, csvHeaders, enumValueTranslations, studyUuid, nodeUuid, rootNetworkUuid, snackError, intl]); return ( { }); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const securityAnalysisStatus = useSelector( (state: AppState) => state.computingStatus[ComputingType.SECURITY_ANALYSIS] ); useEffect(() => { - if (securityAnalysisStatus !== RunningStatus.SUCCEED || !studyUuid || !currentNode?.id) { + if ( + securityAnalysisStatus !== RunningStatus.SUCCEED || + !studyUuid || + !currentNode?.id || + !currentRootNetworkUuid + ) { return; } @@ -600,7 +606,13 @@ export const useFetchFiltersEnums = () => { ]; const promises = filterTypes.map((filterType) => - fetchAvailableFilterEnumValues(studyUuid, currentNode.id, computingType.SECURITY_ANALYSIS, filterType) + fetchAvailableFilterEnumValues( + studyUuid, + currentNode.id, + currentRootNetworkUuid, + computingType.SECURITY_ANALYSIS, + filterType + ) ); setLoading(true); @@ -632,7 +644,7 @@ export const useFetchFiltersEnums = () => { .finally(() => { setLoading(false); }); - }, [securityAnalysisStatus, studyUuid, currentNode?.id]); + }, [securityAnalysisStatus, studyUuid, currentNode?.id, currentRootNetworkUuid]); return { loading, result, error }; }; diff --git a/src/components/results/shortcircuit/shortcircuit-analysis-result.tsx b/src/components/results/shortcircuit/shortcircuit-analysis-result.tsx index f4e04d801d..25f968c27e 100644 --- a/src/components/results/shortcircuit/shortcircuit-analysis-result.tsx +++ b/src/components/results/shortcircuit/shortcircuit-analysis-result.tsx @@ -74,6 +74,7 @@ export const ShortCircuitAnalysisResult: FunctionComponent state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const isOneBusShortCircuitAnalysisType = analysisType === ShortCircuitAnalysisType.ONE_BUS; @@ -141,6 +142,7 @@ export const ShortCircuitAnalysisResult: FunctionComponent { - if (analysisStatus !== RunningStatus.SUCCEED || !studyUuid || !currentNode?.id) { + if (analysisStatus !== RunningStatus.SUCCEED || !studyUuid || !currentNode?.id || !currentRootNetworkUuid) { return; } @@ -195,7 +198,13 @@ export const ShortCircuitAnalysisResult: FunctionComponent - fetchAvailableFilterEnumValues(studyUuid, currentNode.id, currentComputingType, filter) + fetchAvailableFilterEnumValues( + studyUuid, + currentNode.id, + currentRootNetworkUuid, + currentComputingType, + filter + ) ); Promise.all(promises) @@ -219,7 +228,15 @@ export const ShortCircuitAnalysisResult: FunctionComponent startDynamicSimulation(studyUuid, currentNode?.id, dynamicSimulationConfiguration), + () => + startDynamicSimulation( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + dynamicSimulationConfiguration + ), () => {}, null, 'DynamicSimulationRunError' diff --git a/src/components/spreadsheet/table-wrapper.tsx b/src/components/spreadsheet/table-wrapper.tsx index cfac0aeda5..046f3a8702 100644 --- a/src/components/spreadsheet/table-wrapper.tsx +++ b/src/components/spreadsheet/table-wrapper.tsx @@ -1100,6 +1100,7 @@ const TableWrapper: FunctionComponent = ({ // After the modification has been applied, we need to update the equipment data in the grid useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); if ( studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED' && studyUpdatedForce.eventData.headers['parentNode'] === currentNode.id && diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 1ac48b1fe3..15abc718b4 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -51,14 +51,28 @@ import { StudyIndexationStatus } from 'redux/reducer'; import { fetchDirectoryElementPath } from '@gridsuite/commons-ui'; import { NodeType } from './graph/tree-node.type'; -function isWorthUpdate(studyUpdatedForce, fetcher, lastUpdateRef, nodeUuidRef, nodeUuid, invalidations) { +function isWorthUpdate( + studyUpdatedForce, + fetcher, + lastUpdateRef, + nodeUuidRef, + rootNetworkUuidRef, + nodeUuid, + rootNetworkUuid, + invalidations +) { const headers = studyUpdatedForce?.eventData?.headers; const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; const nodes = headers?.['nodes']; + console.log('TEST ====== ', studyUpdatedForce); + if (nodeUuidRef.current !== nodeUuid) { return true; } + if (rootNetworkUuidRef.current !== rootNetworkUuid) { + return true; + } if (fetcher && lastUpdateRef.current?.fetcher !== fetcher) { return true; } @@ -94,16 +108,18 @@ export function useNodeData( const [isPending, setIsPending] = useState(false); const [errorMessage, setErrorMessage] = useState(undefined); const nodeUuidRef = useRef(); + const rootNetworkUuidRef = useRef(); const studyUpdatedForce = useSelector((state) => state.studyUpdated); const lastUpdateRef = useRef(); const update = useCallback(() => { nodeUuidRef.current = nodeUuid; + rootNetworkUuidRef.current = currentRootNetworkUuid; setIsPending(true); setErrorMessage(undefined); fetcher(studyUuid, nodeUuid, currentRootNetworkUuid) .then((res) => { - if (nodeUuidRef.current === nodeUuid) { + if (nodeUuidRef.current === nodeUuid && rootNetworkUuidRef.current === currentRootNetworkUuid) { setResult(resultConversion ? resultConversion(res) : res); } }) @@ -116,7 +132,7 @@ export function useNodeData( /* initial fetch and update */ useEffect(() => { - if (!studyUuid || !nodeUuid || !fetcher) { + if (!studyUuid || !nodeUuid || !currentRootNetworkUuid || !fetcher) { return; } const isUpdateForUs = isWorthUpdate( @@ -124,14 +140,20 @@ export function useNodeData( fetcher, lastUpdateRef, nodeUuidRef, + rootNetworkUuidRef, nodeUuid, + currentRootNetworkUuid, invalidations ); lastUpdateRef.current = { studyUpdatedForce, fetcher }; - if (nodeUuidRef.current !== nodeUuid || isUpdateForUs) { + if ( + nodeUuidRef.current !== nodeUuid || + rootNetworkUuidRef.current !== currentRootNetworkUuid || + isUpdateForUs + ) { update(); } - }, [update, fetcher, nodeUuid, invalidations, studyUpdatedForce, studyUuid]); + }, [update, fetcher, nodeUuid, invalidations, currentRootNetworkUuid, studyUpdatedForce, studyUuid]); return [result, isPending, setResult, errorMessage, update]; } @@ -639,6 +661,8 @@ export function StudyContainer({ view, onChangeTab }) { // study_network_recreation_done notification // checking another time if we can find network, if we do, we display a snackbar info useEffect(() => { + console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers?.[UPDATE_TYPE_HEADER] === UPDATE_TYPE_STUDY_NETWORK_RECREATION_DONE) { const successCallback = () => snackInfo({ @@ -693,6 +717,8 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult') { dispatch(resetEquipmentsPostLoadflow()); } @@ -731,6 +757,8 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUpdatedForce.eventData.headers) { + console.log('TEST ====== ', studyUpdatedForce); + if ( studyUpdatedForce.eventData.headers.studyUuid === studyUuid && studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'metadata_updated' diff --git a/src/hooks/use-get-study-impacts.ts b/src/hooks/use-get-study-impacts.ts index f6c31ad8da..090f7d3050 100644 --- a/src/hooks/use-get-study-impacts.ts +++ b/src/hooks/use-get-study-impacts.ts @@ -40,6 +40,7 @@ export const useGetStudyImpacts = (): StudyImpactsWithReset => { useEffect(() => { if (studyUpdatedForce.type === NotificationType.STUDY) { + console.log('TEST ====== ', studyUpdatedForce); const { impactedSubstationsIds: substationsIds, deletedEquipments, diff --git a/src/services/study/dynamic-simulation.js b/src/services/study/dynamic-simulation.js index 0eab42da6e..b53399bcd0 100644 --- a/src/services/study/dynamic-simulation.js +++ b/src/services/study/dynamic-simulation.js @@ -16,12 +16,20 @@ export function getDynamicMappings(studyUuid) { return backendFetchJson(url); } -export function startDynamicSimulation(studyUuid, currentNodeUuid, dynamicSimulationConfiguration) { - console.info(`Running dynamic simulation on '${studyUuid}' and node '${currentNodeUuid}' ...`); +export function startDynamicSimulation( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + dynamicSimulationConfiguration +) { + console.info( + `Running dynamic simulation on '${studyUuid}' on root nerwork '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const startDynamicSimulationUrl = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/dynamic-simulation/run`; // add body @@ -39,10 +47,13 @@ export function startDynamicSimulation(studyUuid, currentNodeUuid, dynamicSimula }); } -export function stopDynamicSimulation(studyUuid, currentNodeUuid) { - console.info(`Stopping dynamic simulation on '${studyUuid}' and node '${currentNodeUuid}' ...`); +export function stopDynamicSimulation(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Stopping dynamic simulation on '${studyUuid}' for root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}' ...` + ); const stopDynamicSimulationUrl = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/dynamic-simulation/stop'; + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/dynamic-simulation/stop'; console.debug(stopDynamicSimulationUrl); return backendFetch(stopDynamicSimulationUrl, { method: 'put' }); } @@ -58,7 +69,12 @@ export function fetchDynamicSimulationStatus(studyUuid, currentNodeUuid, current return backendFetchJson(url); } -export function fetchDynamicSimulationResultTimeSeries(studyUuid, currentNodeUuid, timeSeriesNames) { +export function fetchDynamicSimulationResultTimeSeries( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + timeSeriesNames +) { console.info(`Fetching dynamic simulation time series result on '${studyUuid}' and node '${currentNodeUuid}' ...`); // Add params to Url @@ -67,17 +83,21 @@ export function fetchDynamicSimulationResultTimeSeries(studyUuid, currentNodeUui const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( studyUuid, - currentNodeUuid + currentNodeUuid, + currentRootNetworkUuid )}/dynamic-simulation/result/timeseries?${urlSearchParams}`; console.debug(url); return backendFetchJson(url); } -export function fetchDynamicSimulationModels(studyUuid, nodeUuid) { - console.info(`Fetching dynamic simulation models on '${studyUuid}' and node '${nodeUuid}' ...`); +export function fetchDynamicSimulationModels(studyUuid, nodeUuid, rootNetworkUuid) { + console.info( + `Fetching dynamic simulation models on '${studyUuid}' on root network '${rootNetworkUuid}' and node '${nodeUuid}' ...` + ); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + '/dynamic-simulation/models'; + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, rootNetworkUuid) + '/dynamic-simulation/models'; console.debug(url); return backendFetchJson(url); } diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 600e5c6784..aa20f9058b 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -52,7 +52,9 @@ export function getNetworkAreaDiagramUrl( depth: number, withGeoData: boolean ) { - console.info(`Getting url of network area diagram of study '${studyUuid}' and node '${currentNodeUuid}'...`); + console.info( + `Getting url of network area diagram of study '${studyUuid}' on root network '${currentRootNetworkUuid}' and node '${currentNodeUuid}'...` + ); return ( getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + '/network-area-diagram?' + diff --git a/src/services/study/network.js b/src/services/study/network.js index 9ebf82c891..de4d79964a 100644 --- a/src/services/study/network.js +++ b/src/services/study/network.js @@ -494,9 +494,9 @@ export const fetchStudyIndexationStatus = (studyUuid, rootNetworkUuid) => { }; /* export-network */ -export function getExportUrl(studyUuid, nodeUuid, rootNetworkUuid, exportFormat) { +export function getExportUrl(studyUuid, nodeUuid, currentRootNetworkUuid, rootNetworkUuid, exportFormat) { const url = - getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid) + + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, currentRootNetworkUuid) + '/root-networks/' + rootNetworkUuid + '/export-network/' + diff --git a/src/services/study/non-evacuated-energy.js b/src/services/study/non-evacuated-energy.js index d42952eda9..ccb93ad9fd 100644 --- a/src/services/study/non-evacuated-energy.js +++ b/src/services/study/non-evacuated-energy.js @@ -8,7 +8,7 @@ import { getStudyUrl, getStudyUrlWithNodeUuidAndRootNetworkUuid, PREFIX_STUDY_QUERIES } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -export function startNonEvacuatedEnergy(studyUuid, currentRootNetworkUuid, currentNodeUuid) { +export function startNonEvacuatedEnergy(studyUuid, currentNodeUuid, currentRootNetworkUuid) { console.info( `Running non evacuated energy analysis on ${studyUuid} on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` ); diff --git a/src/services/study/security-analysis.js b/src/services/study/security-analysis.js index c1dc16c5d6..f5bc70a034 100644 --- a/src/services/study/security-analysis.js +++ b/src/services/study/security-analysis.js @@ -67,12 +67,19 @@ export function fetchSecurityAnalysisResult(studyUuid, currentNodeUuid, currentR export function downloadSecurityAnalysisResultZippedCsv( studyUuid, currentNodeUuid, + currentRootNetworkUuid, queryParams, headers, enumValueTranslations ) { - console.info(`Fetching security analysis zipped csv on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/security-analysis/result/csv`; + console.info( + `Fetching security analysis zipped csv on ${studyUuid} on root network ${currentRootNetworkUuid} and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/security-analysis/result/csv`; const { resultType } = queryParams || {}; diff --git a/src/services/study/state-estimation.js b/src/services/study/state-estimation.js index 770914e767..99fc665953 100644 --- a/src/services/study/state-estimation.js +++ b/src/services/study/state-estimation.js @@ -8,17 +8,27 @@ import { getStudyUrlWithNodeUuidAndRootNetworkUuid } from './index'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -export function startStateEstimation(studyUuid, currentNodeUuid) { - console.info(`Running state estimation on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid) + '/state-estimation/run'; +export function startStateEstimation(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Running state estimation on ${studyUuid} on root network '${currentRootNetworkUuid}' and node ${currentNodeUuid} ...` + ); + const url = + getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid, currentRootNetworkUuid) + + '/state-estimation/run'; console.debug(url); return backendFetch(url, { method: 'post' }); } -export function stopStateEstimation(studyUuid, currentNodeUuid) { - console.info(`Stopping state estimation on ${studyUuid} and node ${currentNodeUuid} ...`); - const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, currentNodeUuid)}/state-estimation/stop`; +export function stopStateEstimation(studyUuid, currentNodeUuid, currentRootNetworkUuid) { + console.info( + `Stopping state estimation on ${studyUuid} on root network '${currentRootNetworkUuid}' and node ${currentNodeUuid} ...` + ); + const url = `${getStudyUrlWithNodeUuidAndRootNetworkUuid( + studyUuid, + currentNodeUuid, + currentRootNetworkUuid + )}/state-estimation/stop`; console.debug(url); return backendFetch(url, { method: 'put' }); } From 506e7c2bb1433e4065365458752ae898601586a8 Mon Sep 17 00:00:00 2001 From: souissimai Date: Fri, 27 Dec 2024 10:13:16 +0100 Subject: [PATCH 15/51] fixes Signed-off-by: souissimai --- .../computing-status/use-computing-status.ts | 1 - .../event-modification-scenario-editor.tsx | 2 +- .../network-modification-node-editor.tsx | 3 +- .../network-modification-tree-pane.jsx | 21 +++++++++- src/components/network/network-map-tab.tsx | 32 ++++++++++----- src/components/spreadsheet/table-wrapper.tsx | 2 +- src/components/study-container.jsx | 39 +++++++++++++++---- src/redux/reducer.ts | 1 + src/services/study/index.ts | 4 +- src/services/study/network.ts | 2 +- 10 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index f5da6e3b63..ac129ef7ec 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -45,7 +45,6 @@ function isWorthUpdate( currentRootNetworkUuid: UUID, invalidations: string[] ): boolean { - console.log('TEST ====== ', studyUpdatedForce); const headers = studyUpdatedForce?.eventData?.headers; const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; diff --git a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx index 69bf33ceed..4e4c03159f 100644 --- a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx +++ b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx @@ -142,7 +142,7 @@ const EventModificationScenarioEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); + console.log('TEST ====== ******', studyUpdatedForce.eventData.headers); if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { return; diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index 7811a0ad88..df50b52d54 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -609,9 +609,8 @@ const NetworkModificationNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { + console.log('TEST ====== OK', studyUpdatedForce.eventData.headers); if ( copyInfosRef.current && studyUpdatedForce.eventData.headers['nodes']?.some( diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 3f864a48ea..1d175ad2ce 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -190,9 +190,9 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== NETWORKMODIFTREEPANE', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers['updateType'] === UpdateType.NODE_CREATED) { + console.log('TEST ====== >>>>>> ££££ ???? NODE_CREATED', studyUpdatedForce.eventData.headers); + fetchNetworkModificationTreeNode( studyUuid, studyUpdatedForce.eventData.headers['newNode'], @@ -215,6 +215,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu setNodesToRestore(res); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'subtreeCreated') { + console.log('TEST ====== >>>>>> ££££ ???? subtreeCreated', studyUpdatedForce.eventData.headers); + fetchNetworkModificationSubtree(studyUuid, studyUpdatedForce.eventData.headers['newNode']).then( (nodes) => { dispatch( @@ -223,6 +225,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu } ); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeMoved') { + console.log('TEST ====== >>>>>> ££££ ???? nodeMoved', studyUpdatedForce.eventData.headers); + fetchNetworkModificationTreeNode( studyUuid, studyUpdatedForce.eventData.headers['movedNode'], @@ -238,6 +242,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu ); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'subtreeMoved') { + console.log('TEST ====== >>>>>> ££££ ???? subtreeMoved', studyUpdatedForce.eventData.headers); + fetchNetworkModificationSubtree(studyUuid, studyUpdatedForce.eventData.headers['movedNode']).then( (nodes) => { dispatch( @@ -246,6 +252,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu } ); } else if (studyUpdatedForce.eventData.headers['updateType'] === UpdateType.NODE_DELETED) { + console.log('TEST ====== >>>>>> ££££ ???? NODE_DELETED', studyUpdatedForce.eventData.headers); + if ( studyUpdatedForce.eventData.headers['nodes'].some( (nodeId) => nodeId === nodeSelectionForCopyRef.current.nodeId @@ -259,6 +267,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu setNodesToRestore(res); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeUpdated') { + console.log('TEST ====== >>>>>> ££££ ???? nodeUpdated', studyUpdatedForce.eventData.headers); + updateNodes(studyUpdatedForce.eventData.headers['nodes']); if ( studyUpdatedForce.eventData.headers['nodes'].some((nodeId) => nodeId === currentNodeRef.current?.id) @@ -274,8 +284,15 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu resetNodeClipboard(); } } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeRenamed') { + console.log('TEST ====== >>>>>> ££££ ???? nodeRenamed', studyUpdatedForce.eventData.headers); + updateNodes([studyUpdatedForce.eventData.headers['node']]); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeBuildStatusUpdated') { + console.log( + 'TEST ====== >>>>>> ££££ ???? nodeBuildStatusUpdated', + studyUpdatedForce.eventData.headers + ); + updateNodes(studyUpdatedForce.eventData.headers['nodes']); if ( studyUpdatedForce.eventData.headers['nodes'].some((nodeId) => nodeId === currentNodeRef.current?.id) diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index c71f873912..9a7e959888 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -350,7 +350,14 @@ export const NetworkMapTab = ({ // only hvdc line with LCC requires a Dialog (to select MCS) handleOpenDeletionDialog(equipmentId, EquipmentType.HVDC_LINE); } else { - deleteEquipment(studyUuid, currentNode?.id, equipmentType, equipmentId, undefined).catch((error) => { + deleteEquipment( + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + equipmentType, + equipmentId, + undefined + ).catch((error) => { snackError({ messageTxt: error.message, headerId: 'UnableToDeleteEquipment', @@ -359,7 +366,14 @@ export const NetworkMapTab = ({ closeEquipmentMenu(); } }, - [studyUuid, currentNode?.id, snackError, handleOpenDeletionDialog, mapEquipments?.hvdcLinesById] + [ + studyUuid, + currentNode?.id, + currentRootNetworkUuid, + snackError, + handleOpenDeletionDialog, + mapEquipments?.hvdcLinesById, + ] ); function closeChoiceVoltageLevelMenu() { @@ -592,7 +606,7 @@ export const NetworkMapTab = ({ console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); geoDataRef.current = null; - + console.log('**== :::::::::::::::: rootNodeId ', rootNodeId); const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetworkUuid).then( (data) => { console.info(`Received substations of study '${studyUuid}'...`); @@ -815,31 +829,31 @@ export const NetworkMapTab = ({ isCurrentNodeBuiltRef.current = isNodeBuilt(currentNode); // if only renaming, do not reload geo data if (isNodeRenamed(previousCurrentNode, currentNode)) { - console.log('test 1'); + console.log('**== test 1'); return; } if (disabled) { - console.log('test 2'); + console.log('**== test 2 ', rootNodeId); return; } // as long as rootNodeId is not set, we don't fetch any geodata if (!rootNodeId) { - console.log('test 3'); + console.log('**== test 3'); return; } // Hack to avoid reload Geo Data when switching display mode to TREE then back to MAP or HYBRID // TODO REMOVE LATER if (!reloadMapNeeded) { - console.log('test 4'); + console.log('**== test 4'); return; } if (!isMapEquipmentsInitialized) { - console.log('test 5'); + console.log('**== test 5'); // load default node map equipments loadMapEquipments(); } if (!isRootNodeGeoDataLoaded) { - console.log('test 6'); + console.log('**== test 6'); // load root node geodata loadRootNodeGeoData(); diff --git a/src/components/spreadsheet/table-wrapper.tsx b/src/components/spreadsheet/table-wrapper.tsx index 5d2f8db932..dbbc2ddfe4 100644 --- a/src/components/spreadsheet/table-wrapper.tsx +++ b/src/components/spreadsheet/table-wrapper.tsx @@ -1110,7 +1110,7 @@ const TableWrapper: FunctionComponent = ({ // After the modification has been applied, we need to update the equipment data in the grid useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); + console.log('TEST ====== >>>>>> ££££ ', studyUpdatedForce.eventData.headers); if ( studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED' && studyUpdatedForce.eventData.headers['parentNode'] === currentNode.id && diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index d70acf2f95..a6814041dd 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -65,7 +65,6 @@ function isWorthUpdate( const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; const nodes = headers?.['nodes']; - console.log('TEST ====== ', studyUpdatedForce); if (nodeUuidRef.current !== nodeUuid) { return true; @@ -661,9 +660,13 @@ export function StudyContainer({ view, onChangeTab }) { // study_network_recreation_done notification // checking another time if we can find network, if we do, we display a snackbar info useEffect(() => { - console.log('TEST ====== ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers?.[UPDATE_TYPE_HEADER] === UPDATE_TYPE_STUDY_NETWORK_RECREATION_DONE) { + console.log( + 'TEST ======!!! Type ', + 'UPDATE_TYPE_STUDY_NETWORK_RECREATION_DONE', + ' rootNetwork ', + studyUpdatedForce.eventData.headers?.['rootNetwork'] + ); const successCallback = () => snackInfo({ headerId: 'studyNetworkRecovered', @@ -671,6 +674,13 @@ export function StudyContainer({ view, onChangeTab }) { checkNetworkExistenceAndRecreateIfNotFound(successCallback); } else if (studyUpdatedForce.eventData.headers?.[UPDATE_TYPE_HEADER] === UPDATE_TYPE_INDEXATION_STATUS) { + console.log( + 'TEST ======!!! Type ', + 'UPDATE_TYPE_INDEXATION_STATUS', + ' rootNetwork ', + studyUpdatedForce.eventData.headers?.['rootNetwork'] + ); + dispatch(setStudyIndexationStatus(studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS])); if (studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS] === StudyIndexationStatus.INDEXED) { snackInfo({ @@ -679,6 +689,13 @@ export function StudyContainer({ view, onChangeTab }) { } // notification that the study is not indexed anymore then ask to refresh if (studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS] === StudyIndexationStatus.NOT_INDEXED) { + console.log( + 'TEST ======!!! Type ',' OK ', + 'HEADER_INDEXATION_STATUS', + ' rootNetwork ', + studyUpdatedForce.eventData.headers?.['rootNetwork'] + ); + snackWarning({ headerId: 'studyIndexationNotIndexed', }); @@ -717,9 +734,13 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult') { + console.log( + 'TEST ======!!! Type ', + 'loadflowResult ', + ' rootNetwork ', + studyUpdatedForce.eventData.headers?.['rootNetwork'] + ); dispatch(resetEquipmentsPostLoadflow()); } } @@ -757,12 +778,16 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - if ( studyUpdatedForce.eventData.headers.studyUuid === studyUuid && studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'metadata_updated' ) { + console.log( + 'TEST ======!!! Type ', + 'metadata_updated', + ' rootNetwork ', + studyUpdatedForce.eventData.headers?.['rootNetwork'] + ); fetchStudyPath(); } } diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index c98554154c..f53c02169a 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -316,6 +316,7 @@ export interface OneBusShortCircuitAnalysisDiagram { export interface StudyUpdatedEventDataHeader { studyUuid: UUID; parentNode: UUID; + rootNetwork: UUID; timestamp: number; updateType?: string; node?: UUID; diff --git a/src/services/study/index.ts b/src/services/study/index.ts index e239a5be6d..33b5185f20 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -19,7 +19,7 @@ import { NetworkModificationCopyInfo } from '../../components/graph/menus/networ import { ComputingType } from '../../components/computing-status/computing-type'; export function safeEncodeURIComponent(value: string | null | undefined): string { - return value != null ? encodeURIComponent(value) : '??'; + return value != null ? encodeURIComponent(value) : ''; } export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; @@ -29,7 +29,7 @@ export const getStudyUrl = (studyUuid: UUID | null) => export const getStudyUrlWithNodeUuidAndRootNetworkUuid = ( studyUuid: string | null | undefined, nodeUuid: string | undefined, - rootNetworkUuid: string | undefined + rootNetworkUuid: string | undefined | null ) => `${PREFIX_STUDY_QUERIES}/v1/studies/${safeEncodeURIComponent(studyUuid)}/root-networks/${safeEncodeURIComponent( rootNetworkUuid diff --git a/src/services/study/network.ts b/src/services/study/network.ts index 7974ada06d..02cae2faa2 100644 --- a/src/services/study/network.ts +++ b/src/services/study/network.ts @@ -207,7 +207,7 @@ export function fetchNetworkElementsInfos( export function fetchNetworkElementInfos( studyUuid: string | undefined | null, currentNodeUuid: UUID | undefined, - currentRootNetworkUuid: UUID | undefined, + currentRootNetworkUuid: string | undefined | null, elementType: EquipmentType | EQUIPMENT_TYPES, infoType: string, elementId: string, From 7a28d0d420311cf190df017c8b491cc0636e87b4 Mon Sep 17 00:00:00 2001 From: souissimai Date: Sun, 29 Dec 2024 17:56:12 +0100 Subject: [PATCH 16/51] clean Signed-off-by: souissimai --- src/components/dialogs/create-case-dialog.tsx | 98 ------------------- src/components/graph/menus/node-editor.tsx | 5 +- src/components/network/network-map-tab.tsx | 5 +- src/components/study-container.jsx | 3 +- 4 files changed, 8 insertions(+), 103 deletions(-) delete mode 100644 src/components/dialogs/create-case-dialog.tsx diff --git a/src/components/dialogs/create-case-dialog.tsx b/src/components/dialogs/create-case-dialog.tsx deleted file mode 100644 index dd999b4828..0000000000 --- a/src/components/dialogs/create-case-dialog.tsx +++ /dev/null @@ -1,98 +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 { useSelector } from 'react-redux'; -import { Grid } from '@mui/material'; -import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup/dist/yup'; -import { - CustomMuiDialog, - DescriptionField, - FieldConstants, - isObjectEmpty, - useConfidentialityWarning, - useSnackMessage, -} from '@gridsuite/commons-ui'; - -import yup from '../utils/yup-config'; -import { AppState } from 'redux/reducer'; - -interface IFormData { - [FieldConstants.CASE_NAME]: string; - [FieldConstants.CASE_FILE]: File | null; -} - -export interface CreateCaseDialogProps { - onClose: (e?: unknown, nextSelectedDirectoryId?: string | null) => void; - open: boolean; -} - -const getCreateCaseDialogFormValidationDefaultValues = () => ({ - [FieldConstants.CASE_NAME]: '', - [FieldConstants.CASE_FILE]: null, -}); - -const createCaseDialogFormValidationSchema = yup.object().shape({ - [FieldConstants.CASE_NAME]: yup.string().trim().required('nameEmpty'), - [FieldConstants.CASE_FILE]: yup.mixed().nullable().required(), -}); -export default function CreateCaseDialog({ onClose, open }: Readonly) { - const { snackError } = useSnackMessage(); - const confidentialityWarningKey = useConfidentialityWarning(); - - const createCaseFormMethods = useForm({ - defaultValues: getCreateCaseDialogFormValidationDefaultValues(), - resolver: yupResolver(createCaseDialogFormValidationSchema), - }); - - const { - formState: { errors, isValid }, - getValues, // This should be destructured directly from formMethods - } = createCaseFormMethods; - - const isFormValid = isObjectEmpty(errors) && isValid && getValues(FieldConstants.CASE_FILE) !== null; - - const userId = useSelector((state: AppState) => state.user?.profile.sub); - - const handleCreateNewCase = ({ caseName, caseFile }: IFormData): void => { - // @ts-expect-error TODO: manage null cases here - createCase(caseName, description ?? '', caseFile, activeDirectory) - .then(onClose) - .catch((err: any) => { - console.log('$$$$$'); - }); - }; - - return ( - - - - {/* */} - - - - - - {/* */} - {/* */} - - ); -} diff --git a/src/components/graph/menus/node-editor.tsx b/src/components/graph/menus/node-editor.tsx index 8660ff7b01..462e2a2b22 100644 --- a/src/components/graph/menus/node-editor.tsx +++ b/src/components/graph/menus/node-editor.tsx @@ -23,7 +23,10 @@ const styles = { display: 'flex', flexDirection: 'column', elevation: 3, - // background: "red", + background: + theme.palette.mode === 'light' + ? darken(theme.palette.background.paper, 0.1) + : lighten(theme.palette.background.paper, 0.2), }), }; diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 9a7e959888..2d44eb994b 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -911,15 +911,14 @@ export const NetworkMapTab = ({ const prevRootNetworkPath = rootNetworkRef.current; rootNetworkRef.current = currentRootNetworkUuid; - if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath) { - console.log('yyyyyyyyyyyyyy'); + if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath && rootNodeId) { loadRootNodeGeoData(); // set initialized to false to trigger "missing geo-data fetching" setInitialized(false); // set isRootNodeGeoDataLoaded to false so "missing geo-data fetching" waits for root node geo-data to be fully fetched before triggering setIsRootNodeGeoDataLoaded(false); } - }, [currentRootNetworkUuid, loadRootNodeGeoData]); + }, [currentRootNetworkUuid, loadRootNodeGeoData, rootNodeId]); let choiceVoltageLevelsSubstation: EquipmentMap | null = null; if (choiceVoltageLevelsSubstationId) { diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index a6814041dd..9621294c8a 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -690,7 +690,8 @@ export function StudyContainer({ view, onChangeTab }) { // notification that the study is not indexed anymore then ask to refresh if (studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS] === StudyIndexationStatus.NOT_INDEXED) { console.log( - 'TEST ======!!! Type ',' OK ', + 'TEST ======!!! Type ', + ' OK ', 'HEADER_INDEXATION_STATUS', ' rootNetwork ', studyUpdatedForce.eventData.headers?.['rootNetwork'] From 114c8ff5b43cb768cb80c35defcf352832f3b636 Mon Sep 17 00:00:00 2001 From: souissimai Date: Sun, 29 Dec 2024 18:41:22 +0100 Subject: [PATCH 17/51] fixes clean code Signed-off-by: souissimai --- .../dialogs/element-creation-dialog.tsx | 110 ++------- .../dialogs/root-network-creation-dialog.tsx | 217 ++++++++++++++++++ .../graph/menus/root-network-editor.tsx | 11 +- .../graph/menus/root-network-node-editor.tsx | 16 +- src/components/left-drawer.jsx | 77 ------- .../network-modification-tree-pane.jsx | 2 - src/components/network-modification-tree.jsx | 4 + src/components/root-network-panel.tsx | 42 ++++ 8 files changed, 290 insertions(+), 189 deletions(-) create mode 100644 src/components/dialogs/root-network-creation-dialog.tsx delete mode 100644 src/components/left-drawer.jsx create mode 100644 src/components/root-network-panel.tsx diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx index daf23a2356..e800a0ea45 100644 --- a/src/components/dialogs/element-creation-dialog.tsx +++ b/src/components/dialogs/element-creation-dialog.tsx @@ -19,33 +19,26 @@ import { UUID } from 'crypto'; import { useCallback, useEffect, useState } from 'react'; import { Grid, Box, Button, CircularProgress, Typography } from '@mui/material'; import { UniqueNameInput } from './commons/unique-name-input'; -import { CASE_NAME, CASE_ID, DESCRIPTION, FOLDER_ID, FOLDER_NAME, NAME } from '../utils/field-constants'; +import { DESCRIPTION, FOLDER_ID, FOLDER_NAME, NAME } from '../utils/field-constants'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import yup from '../utils/yup-config'; import { useSelector } from 'react-redux'; import ModificationDialog from './commons/modificationDialog'; import { AppState } from '../../redux/reducer'; -import ImportCaseDialog from './import-case-dialog'; interface FormData { [NAME]: string; [DESCRIPTION]: string; } - export interface IElementCreationDialog extends FormData { - [FOLDER_NAME]?: string; - [FOLDER_ID]?: UUID; -} - -export interface IElementCreationDialog1 extends FormData { - [CASE_NAME]?: string; - [CASE_ID]?: UUID; + [FOLDER_NAME]: string; + [FOLDER_ID]: UUID; } interface ElementCreationDialogProps { open: boolean; - onSave: (data: IElementCreationDialog | IElementCreationDialog1) => void; + onSave: (data: IElementCreationDialog) => void; onClose: () => void; type: ElementType; titleId: string; @@ -79,36 +72,21 @@ const ElementCreationDialog: React.FC = ({ const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); const [destinationFolder, setDestinationFolder] = useState(); - const [selectedCase, setSelectedCase] = useState(null); - const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); const formMethods = useForm({ defaultValues: emptyFormData, resolver: yupResolver(formSchema), }); - // Check if the selection is valid based on element type - const isValidSelection = () => { - // add type on commons - if (type === ElementType.ROOT_NETWORK) { - return !!selectedCase; // ROOT_NETWORK requires selected case - } - return !!destinationFolder; // Other types require selected folder - }; - const { reset, - setValue, formState: { errors }, } = formMethods; - const disableSave = Object.keys(errors).length > 0 || !isValidSelection(); + const disableSave = Object.keys(errors).length > 0; - // Clear form and reset selected case const clear = useCallback(() => { reset(emptyFormData); - setSelectedCase(null); // Reset the selected case on clear }, [reset]); - // Fetch default directory based on study UUID const fetchDefaultDirectoryForStudy = useCallback(() => { // @ts-expect-error TODO: manage null case fetchDirectoryElementPath(studyUuid).then((res) => { @@ -128,7 +106,6 @@ const ElementCreationDialog: React.FC = ({ }); }, [studyUuid, snackError]); - // Auto-generate a name with prefix and current date useEffect(() => { if (prefixIdForGeneratedName) { const getCurrentDateTime = () => new Date().toISOString(); @@ -152,17 +129,10 @@ const ElementCreationDialog: React.FC = ({ } }, [fetchDefaultDirectoryForStudy, studyUuid, open]); - // Open directory selector const handleChangeFolder = () => { setDirectorySelectorOpen(true); }; - // Open case selector - const handleCaseSelection = () => { - setCaseSelectorOpen(true); - }; - - // Set selected folder when a directory is selected const setSelectedFolder = (folder: TreeViewFinderNodeProps[]) => { if (folder?.length > 0 && folder[0].id !== destinationFolder?.id) { const { id, name } = folder[0]; @@ -173,37 +143,18 @@ const ElementCreationDialog: React.FC = ({ const handleSave = useCallback( (values: FormData) => { - if (type === ElementType.ROOT_NETWORK) { - if (selectedCase) { - // Save data for ROOT_NETWORK, including CASE_NAME and CASE_ID - const creationData1: IElementCreationDialog1 = { - ...values, - [CASE_NAME]: selectedCase.name, - [CASE_ID]: selectedCase.id as UUID, - }; - onSave(creationData1); - } else { - snackError({ - messageTxt: 'Please select a case before saving.', - headerId: 'caseNotSelectedError', - }); - } - } else { - if (destinationFolder) { - // Save data for other types, including FOLDER info - const creationData: IElementCreationDialog = { - ...values, - [FOLDER_NAME]: destinationFolder.name, - [FOLDER_ID]: destinationFolder.id as UUID, - }; - onSave(creationData); - } + if (destinationFolder) { + const creationData: IElementCreationDialog = { + ...values, + [FOLDER_NAME]: destinationFolder.name, + [FOLDER_ID]: destinationFolder.id as UUID, + }; + onSave(creationData); } }, - [onSave, destinationFolder, selectedCase, snackError, type] + [onSave, destinationFolder] ); - // Folder chooser component const folderChooser = ( @@ -219,24 +170,6 @@ const ElementCreationDialog: React.FC = ({ ); - // Case selection component - const caseSelection = ( - - - - - - ); - - // Handle case selection - const onSelectCase = (selectedCase: TreeViewFinderNodeProps) => { - setSelectedCase(selectedCase); - setValue(NAME, selectedCase.name); // Set the name from the selected case - setCaseSelectorOpen(false); - }; - return ( = ({ autoFocus /> - {type !== ElementType.ROOT_NETWORK && ( - - - - )} - {type === ElementType.ROOT_NETWORK ? caseSelection : folderChooser} + + + + {folderChooser} - - setCaseSelectorOpen(false)} - onSelectCase={onSelectCase} - /> - void; + onClose: () => void; + type: ElementType; + titleId: string; + dialogProps: any; + prefixIdForGeneratedName?: string; +} + +const formSchema = yup + .object() + .shape({ + [NAME]: yup.string().trim().required(), + [CASE_NAME]: yup.string().required(), + [CASE_ID]: yup.string().required(), + }) + .required(); + +const emptyFormData: FormData = { + [NAME]: '', + [CASE_NAME]: '', + [CASE_ID]: '', +}; + +const RootNetworkCreationDialog: React.FC = ({ + open, + onSave, + onClose, + type, + titleId, + dialogProps = undefined, + prefixIdForGeneratedName, +}) => { + const intl = useIntl(); + const studyUuid = useSelector((state: AppState) => state.studyUuid); + const { snackError } = useSnackMessage(); + + const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); + const [destinationFolder, setDestinationFolder] = useState(); + const [selectedCase, setSelectedCase] = useState(null); + const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); + + const formMethods = useForm({ + defaultValues: emptyFormData, + resolver: yupResolver(formSchema), + }); + + const { + reset, + setValue, + formState: { errors }, + } = formMethods; + const disableSave = + // Form validation must pass + !selectedCase || // A case must be selected + !formMethods.getValues(NAME); // NAME must not be empty + + // Clear form and reset selected case + const clear = useCallback(() => { + reset(emptyFormData); + setSelectedCase(null); // Reset the selected case on clear + }, [reset]); + + // Fetch default directory based on study UUID + const fetchDefaultDirectoryForStudy = useCallback(() => { + fetchDirectoryElementPath(studyUuid).then((res) => { + if (!res || res.length < 2) { + snackError({ + messageTxt: 'unknown study directory', + headerId: 'studyDirectoryFetchingError', + }); + return; + } + const parentFolderIndex = res.length - 2; + const { elementUuid, elementName } = res[parentFolderIndex]; + setDestinationFolder({ + id: elementUuid, + name: elementName, + }); + }); + }, [studyUuid, snackError]); + + // Auto-generate a name with prefix and current date + useEffect(() => { + if (prefixIdForGeneratedName) { + const getCurrentDateTime = () => new Date().toISOString(); + const formattedMessage = intl.formatMessage({ + id: prefixIdForGeneratedName, + }); + const dateTime = getCurrentDateTime(); + reset( + { + ...emptyFormData, + [NAME]: `${formattedMessage}-${dateTime}`, + }, + { keepDefaultValues: true } + ); + } + }, [prefixIdForGeneratedName, intl, reset]); + + useEffect(() => { + if (open && studyUuid) { + fetchDefaultDirectoryForStudy(); + } + }, [fetchDefaultDirectoryForStudy, studyUuid, open]); + + // Open case selector + const handleCaseSelection = () => { + setCaseSelectorOpen(true); + }; + + // Set selected case when a case is selected + const onSelectCase = (selectedCase: TreeViewFinderNodeProps) => { + setSelectedCase(selectedCase); + setValue(NAME, selectedCase.name); // Set the name from the selected case + setValue(CASE_NAME, selectedCase.name); + setValue(CASE_ID, selectedCase.id as string); + setCaseSelectorOpen(false); + }; + + const handleSave = useCallback( + (values: FormData) => { + if (selectedCase) { + // Save data, including CASE_NAME and CASE_ID + const creationData1: FormData = { + ...values, + [CASE_NAME]: selectedCase.name, + [CASE_ID]: selectedCase.id as UUID, + }; + onSave(creationData1); + } else { + snackError({ + messageTxt: 'Please select a case before saving.', + headerId: 'caseNotSelectedError', + }); + } + }, + [onSave, selectedCase, snackError] + ); + + // Case selection component + const caseSelection = ( + + + + + + ); + + return ( + + + + + + + {type === ElementType.ROOT_NETWORK && caseSelection} + + + setCaseSelectorOpen(false)} + onSelectCase={onSelectCase} + /> + + + ); +}; + +export default RootNetworkCreationDialog; diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index eaa131a8bb..29028ff581 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -29,17 +29,14 @@ const styles = { }; const RootNetworkEditor = () => { - const dispatch = useDispatch(); - const currentTreeNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); - const closeModificationsDrawer = () => { - dispatch(setModificationsDrawerOpen(false)); - }; + const closeModificationsDrawer = () => {}; return ( - diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index dbe57d43fc..3486a05862 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -18,8 +18,6 @@ import { useDispatch, useSelector } from 'react-redux'; import { UUID } from 'crypto'; import { AppState } from 'redux/reducer'; -import { FetchStatus } from '../../../services/utils'; -import ElementCreationDialog, { IElementCreationDialog1 } from '../../dialogs/element-creation-dialog'; import { NetworkModificationCopyInfo, NetworkModificationData, @@ -32,10 +30,10 @@ import { getCaseImportParameters, } from 'services/network-conversion'; import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; -import { SwitchNetworkModificationActive } from './switch-network-modification-active'; import RemoveRedEyeIcon from '@mui/icons-material/RemoveRedEye'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import { setCurrentRootNetwork } from 'redux/actions'; +import RootNetworkCreationDialog, { FormData } from 'components/dialogs/root-network-creation-dialog'; export const styles = { listContainer: (theme: Theme) => ({ @@ -125,7 +123,6 @@ export function isPartial(s1: number, s2: number) { const RootNetworkNodeEditor = () => { const notificationIdList = useSelector((state: AppState) => state.notificationIdList); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const { snackInfo, snackError } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); const [saveInProgress, setSaveInProgress] = useState(false); @@ -182,7 +179,6 @@ const RootNetworkNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { @@ -264,7 +260,6 @@ const RootNetworkNodeEditor = () => { // } // }, [dispatch, dofetchRootNetworks, studyUpdatedForce, cleanClipboard]); - const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); }, []); @@ -416,12 +411,13 @@ const RootNetworkNodeEditor = () => { const renderRootNetworkCreationDialog = () => { return ( - setRootNetworkCreationDialogOpen(false)} onSave={doCreateRootNetwork} type={ElementType.ROOT_NETWORK} titleId={'CreateRootNetwork'} + dialogProps={undefined} /> ); }; @@ -446,17 +442,17 @@ const RootNetworkNodeEditor = () => { }, {} as Record); } - const doCreateRootNetwork = ({ name, caseName, caseId }: IElementCreationDialog1) => { + const doCreateRootNetwork = ({ name, caseName, caseId }: FormData) => { setSaveInProgress(true); - getCaseImportParameters(caseId) + getCaseImportParameters(caseId as UUID) .then((params: GetCaseImportParametersReturn) => { // Format the parameters const formattedParams = formatCaseImportParameters(params.parameters); const customizedCurrentParameters = customizeCurrentParameters(formattedParams as Parameter[]); // Call createRootNetwork with formatted parameters - return createRootNetwork(caseId, params.formatName, studyUuid, customizedCurrentParameters); + return createRootNetwork(caseId as UUID, params.formatName, studyUuid, customizedCurrentParameters); }) .then(() => { // Success handler diff --git a/src/components/left-drawer.jsx b/src/components/left-drawer.jsx deleted file mode 100644 index 17e4f6ed28..0000000000 --- a/src/components/left-drawer.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import Drawer from '@mui/material/Drawer'; -import PropTypes from 'prop-types'; -import { mergeSx } from './utils/functions'; -import { DRAWER_NODE_EDITOR_WIDTH } from '../utils/UIconstants'; -import RootNetworkEditor from './graph/menus/root-network-editor'; - -const styles = { - drawerPaper: { - position: 'static', - overflow: 'hidden', - flex: '1', - flexGrow: '1', - transition: 'none !important', - // backgroundColor: 'green !important', - }, - nodeEditor: (theme) => ({ - width: DRAWER_NODE_EDITOR_WIDTH + 'px', - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen, - }), - zIndex: 51, - position: 'relative', - flexShrink: 1, - overflowY: 'none', - overflowX: 'none', - }), - nodeEditorShift: (theme) => ({ - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen, - }), - pointerEvents: 'none', - marginRight: -DRAWER_NODE_EDITOR_WIDTH + 'px', // Shift out of view when closed - }), - leftDrawer: (theme) => ({ - width: DRAWER_NODE_EDITOR_WIDTH + 'px', - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen, - }), - zIndex: 51, - position: 'relative', - flexShrink: 1, - overflowY: 'none', - overflowX: 'none', - }), - leftDrawerShift: (theme) => ({ - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen, - }), - pointerEvents: 'none', - marginLeft: DRAWER_NODE_EDITOR_WIDTH + 'px', // Shift right when open - }), -}; - -// LeftDrawer Component -export const LeftDrawer = ({ open }) => { - return ( - - - - ); -}; - -LeftDrawer.propTypes = { - open: PropTypes.bool.isRequired, -}; diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 1d175ad2ce..88a0791766 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -43,7 +43,6 @@ import { buildNode, getUniqueNodeName, unbuildNode } from '../services/study/ind import RestoreNodesDialog from './dialogs/restore-node-dialog'; import ScenarioEditor from './graph/menus/dynamic-simulation/scenario-editor'; import { StudyDisplayMode, CopyType, UpdateType } from './network-modification.type'; -import { LeftDrawer } from './left-drawer'; const styles = { container: { @@ -539,7 +538,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu return ( <> - {isMinimapOpen && } + + {/* root Network Panel */} + ); diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx new file mode 100644 index 0000000000..705fdfa2d6 --- /dev/null +++ b/src/components/root-network-panel.tsx @@ -0,0 +1,42 @@ +import React, { FunctionComponent } from 'react'; +import { Paper, Box } from '@mui/material'; +import RootNetworkEditor from './graph/menus/root-network-editor'; +import { Theme } from '@mui/material/styles'; + +type RootNetworkPanelProps = { + studyId: string; +}; + +const styles = (theme: Theme) => ({ + paper: { + position: 'absolute', + top: 16, + left: 16, + width: '320px', + height: '420px', + display: 'flex', + flexDirection: 'column', + borderRadius: '8px', + boxShadow: '0 6px 15px rgba(0,0,0,0.15)', // Softer shadow + zIndex: 10, + overflow: 'hidden', // Ensure no overflow + }, + contentBox: { + flex: 1, // Take up all available space + display: 'flex', + flexDirection: 'column', + position: 'relative', // Enable absolute positioning for child elements + }, +}); + +const RootNetworkPanel: FunctionComponent = ({ studyId }) => { + return ( + styles(theme).paper}> + styles(theme).contentBox}> + + + + ); +}; + +export default RootNetworkPanel; From 06f1dd9afac6ef0d88ccaadacfcfa1eccd7db8eb Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 2 Jan 2025 12:50:06 +0100 Subject: [PATCH 18/51] fix search endpoint migrating Signed-off-by: souissimai --- .../substation/creation/substation-creation-dialog.jsx | 2 ++ .../graph/menus/network-modification-node-editor.tsx | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx b/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx index 8a9eda91bc..e7d4d04f4b 100644 --- a/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx @@ -49,6 +49,7 @@ const SubstationCreationDialog = ({ editData, currentNode, studyUuid, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -158,6 +159,7 @@ const SubstationCreationDialog = ({ equipmentType={EQUIPMENT_TYPES.SUBSTATION} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index df50b52d54..8fe14bbd44 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -204,7 +204,8 @@ const NetworkModificationNodeEditor = () => { const [deleteInProgress, setDeleteInProgress] = useState(false); const [modificationsToRestore, setModificationsToRestore] = useState([]); const currentNode = useSelector((state: AppState) => state.currentTreeNode); - + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); + const currentNodeIdRef = useRef(); // initial empty to get first update const [pendingState, setPendingState] = useState(false); @@ -263,6 +264,7 @@ const NetworkModificationNodeEditor = () => { onValidated={handleValidatedDialog} currentNode={currentNode} studyUuid={studyUuid} + currentRootNetworkUuid={currentRootNetworkUuid} editData={editData} isUpdate={isUpdate} editDataFetchStatus={editDataFetchStatus} From 298ddbde029e2e2a6d42ea07a03cb7969df5ad23 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 2 Jan 2025 16:31:43 +0100 Subject: [PATCH 19/51] changes: clean + migrating endpoints Signed-off-by: souissimai --- .../creation/battery-creation-dialog.jsx | 19 ++++- .../creation/generator-creation-dialog.jsx | 2 + .../lcc/creation/lcc-creation-dialog.tsx | 3 + .../vsc/creation/vsc-creation-dialog.jsx | 11 ++- .../line/creation/line-creation-dialog.jsx | 2 + .../load/creation/load-creation-dialog.tsx | 10 ++- .../shunt-compensator-creation-dialog.jsx | 3 + ...o-windings-transformer-creation-dialog.jsx | 4 ++ .../dialogs/root-network-creation-dialog.tsx | 9 +-- .../network-modification-node-editor.tsx | 2 +- .../graph/menus/root-network-editor.tsx | 11 +-- .../graph/menus/root-network-node-editor.tsx | 69 ++++--------------- 12 files changed, 69 insertions(+), 76 deletions(-) diff --git a/src/components/dialogs/network-modifications/battery/creation/battery-creation-dialog.jsx b/src/components/dialogs/network-modifications/battery/creation/battery-creation-dialog.jsx index d1cf5d35a1..340ce8abf7 100644 --- a/src/components/dialogs/network-modifications/battery/creation/battery-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/battery/creation/battery-creation-dialog.jsx @@ -93,7 +93,15 @@ const formSchema = yup .concat(creationPropertiesSchema) .required(); -const BatteryCreationDialog = ({ editData, currentNode, studyUuid, isUpdate, editDataFetchStatus, ...dialogProps }) => { +const BatteryCreationDialog = ({ + editData, + currentNode, + studyUuid, + currentRootNetworkUuid, + isUpdate, + editDataFetchStatus, + ...dialogProps +}) => { const currentNodeUuid = currentNode.id; const { snackError } = useSnackMessage(); @@ -135,6 +143,7 @@ const BatteryCreationDialog = ({ editData, currentNode, studyUuid, isUpdate, edi const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.BATTERY, @@ -235,7 +244,11 @@ const BatteryCreationDialog = ({ editData, currentNode, studyUuid, isUpdate, edi isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - + @@ -253,6 +267,7 @@ BatteryCreationDialog.propTypes = { editData: PropTypes.object, studyUuid: PropTypes.string, currentNode: PropTypes.object, + currentRootNetworkUuid: PropTypes.string, isUpdate: PropTypes.bool, editDataFetchStatus: PropTypes.string, }; diff --git a/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx b/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx index da967689ed..7235c3b050 100644 --- a/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx @@ -127,6 +127,7 @@ const GeneratorCreationDialog = ({ editData, currentNode, studyUuid, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -336,6 +337,7 @@ const GeneratorCreationDialog = ({ equipmentType={'GENERATOR'} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> diff --git a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx index 3ab63a1239..d8b8c3e2ff 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx @@ -114,6 +114,7 @@ export interface LccCreationDialogProps extends Partial { editData: LccCreationInfos; currentNode: CurrentTreeNode; studyUuid: UUID; + currentRootNetworkUuid: UUID; isUpdate: boolean; editDataFetchStatus: FetchStatus; } @@ -122,6 +123,7 @@ export function LccCreationDialog({ editData, currentNode, studyUuid, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -274,6 +276,7 @@ export function LccCreationDialog({ onSelectionChange={searchCopy.handleSelectionChange} equipmentType={EquipmentType.HVDC_LINE} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> diff --git a/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx b/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx index dbbcd3be6f..4b0a6ee116 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx @@ -86,7 +86,15 @@ export const VSC_CREATION_TABS = { CONVERTER_STATION_2: 2, }; -const VscCreationDialog = ({ editData, currentNode, studyUuid, isUpdate, editDataFetchStatus, ...dialogProps }) => { +const VscCreationDialog = ({ + editData, + currentNode, + studyUuid, + currentRootNetworkUuid, + isUpdate, + editDataFetchStatus, + ...dialogProps +}) => { const currentNodeUuid = currentNode.id; const { snackError } = useSnackMessage(); const [tabIndex, setTabIndex] = useState(VSC_CREATION_TABS.HVDC_LINE_TAB); @@ -260,6 +268,7 @@ const VscCreationDialog = ({ editData, currentNode, studyUuid, isUpdate, editDat equipmentType={EQUIPMENT_TYPES.HVDC_LINE} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> diff --git a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx index 14f013adb4..be3bd10900 100644 --- a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx @@ -104,6 +104,7 @@ const LineCreationDialog = ({ editData, studyUuid, currentNode, + currentRootNetworkUuid, onCreateLine = createLine, displayConnectivity = true, isUpdate, @@ -420,6 +421,7 @@ const LineCreationDialog = ({ equipmentType={EQUIPMENT_TYPES.LINE} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> { editData: LoadCreationInfos; currentNode: CurrentTreeNode; studyUuid: UUID; + currentRootNetworkUuid: UUID; isUpdate: boolean; editDataFetchStatus: FetchStatus; disabledSave: boolean; @@ -84,6 +85,7 @@ export function LoadCreationDialog({ editData, currentNode, studyUuid, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -209,14 +211,18 @@ export function LoadCreationDialog({ isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - - + diff --git a/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx b/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx index 6f44c848bc..1d53c80fa2 100644 --- a/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx @@ -88,6 +88,7 @@ const formSchema = yup const ShuntCompensatorCreationDialog = ({ studyUuid, currentNode, + currentRootNetworkUuid, editData, isUpdate, editDataFetchStatus, @@ -243,6 +244,7 @@ const ShuntCompensatorCreationDialog = ({ equipmentType={EQUIPMENT_TYPES.SHUNT_COMPENSATOR} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> @@ -258,6 +260,7 @@ ShuntCompensatorCreationDialog.propTypes = { studyUuid: PropTypes.string, currentNode: PropTypes.object, isUpdate: PropTypes.bool, + currentRootNetworkUuid: PropTypes.string, editDataFetchStatus: PropTypes.string, }; diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx index e59cd0ba9d..5d12bb9815 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx @@ -152,6 +152,7 @@ const TwoWindingsTransformerCreationDialog = ({ editData, studyUuid, currentNode, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -673,6 +674,7 @@ const TwoWindingsTransformerCreationDialog = ({ equipmentType={EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER} onSelectionChange={searchCopy.handleSelectionChange} currentNodeUuid={currentNodeUuid} + currentRootNetworkUuid={currentRootNetworkUuid} /> @@ -683,6 +685,8 @@ TwoWindingsTransformerCreationDialog.propTypes = { editData: PropTypes.object, studyUuid: PropTypes.string, currentNode: PropTypes.object, + currentRootNetworkUuid: PropTypes.string, + isUpdate: PropTypes.bool, editDataFetchStatus: PropTypes.string, }; diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index 256a596116..4d3a93c2f5 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -8,7 +8,7 @@ import { } from '@gridsuite/commons-ui'; import { UUID } from 'crypto'; import { useCallback, useEffect, useState } from 'react'; -import { Grid, Button} from '@mui/material'; +import { Grid, Button } from '@mui/material'; import { UniqueNameInput } from './commons/unique-name-input'; import { CASE_NAME, CASE_ID, NAME } from '../utils/field-constants'; import { useForm } from 'react-hook-form'; @@ -63,7 +63,6 @@ const RootNetworkCreationDialog: React.FC = ({ const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackError } = useSnackMessage(); - const [directorySelectorOpen, setDirectorySelectorOpen] = useState(false); const [destinationFolder, setDestinationFolder] = useState(); const [selectedCase, setSelectedCase] = useState(null); const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); @@ -73,11 +72,7 @@ const RootNetworkCreationDialog: React.FC = ({ resolver: yupResolver(formSchema), }); - const { - reset, - setValue, - formState: { errors }, - } = formMethods; + const { reset, setValue } = formMethods; const disableSave = // Form validation must pass !selectedCase || // A case must be selected diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index 8fe14bbd44..a28e9d49b7 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -205,7 +205,7 @@ const NetworkModificationNodeEditor = () => { const [modificationsToRestore, setModificationsToRestore] = useState([]); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); - + const currentNodeIdRef = useRef(); // initial empty to get first update const [pendingState, setPendingState] = useState(false); diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index 29028ff581..62aa37c0ca 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -6,25 +6,18 @@ */ import PropTypes from 'prop-types'; -import { lighten, darken } from '@mui/material/styles'; -import NetworkModificationNodeEditor from './network-modification-node-editor'; -import { useSnackMessage } from '@gridsuite/commons-ui'; import { EditableTitle } from './editable-title'; -import { useDispatch, useSelector } from 'react-redux'; -import { setModificationsDrawerOpen } from '../../../redux/actions'; -import { updateTreeNode } from '../../../services/study/tree-subtree'; import { Box } from '@mui/material'; import { AppState } from '../../../redux/reducer'; -import { Theme } from '@mui/material/styles'; import RootNetworkNodeEditor from './root-network-node-editor'; +import { useSelector } from 'react-redux'; const styles = { - paper: (theme: Theme) => ({ + paper: () => ({ height: '100%', display: 'flex', flexDirection: 'column', elevation: 3, - // background: "red", }), }; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 3486a05862..a49f9684b4 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -12,15 +12,13 @@ import DeleteIcon from '@mui/icons-material/Delete'; import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography } from '@mui/material'; import IconButton from '@mui/material/IconButton'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; import { UUID } from 'crypto'; import { AppState } from 'redux/reducer'; import { - NetworkModificationCopyInfo, - NetworkModificationData, RootNetworkMetadata, } from './network-modification-menu.type'; @@ -45,15 +43,15 @@ export const styles = { }), listItem: { paddingLeft: 0, paddingTop: 0, paddingBottom: 0 }, checkBoxLabel: { flexGrow: '1' }, - disabledModification: { opacity: 0.4 }, + disabledRootNetwork: { opacity: 0.4 }, checkBoxIcon: { minWidth: 0, padding: 0 }, checkboxButton: { - padding: 0, + padding: 0.5, margin: 0, display: 'flex', alignItems: 'center', }, - modificationsTitle: (theme: Theme) => ({ + rootNetworksTitle: (theme: Theme) => ({ display: 'flex', alignItems: 'center', margin: theme.spacing(0), @@ -133,14 +131,8 @@ const RootNetworkNodeEditor = () => { const [pendingState, setPendingState] = useState(false); const [selectedItems, setSelectedItems] = useState([]); - const [copiedModifications, setCopiedModifications] = useState([]); - const [copyInfos, setCopyInfos] = useState(null); - const copyInfosRef = useRef(); - copyInfosRef.current = copyInfos; - - const [editDialogOpen, setEditDialogOpen] = useState(undefined); - const [editData, setEditData] = useState(undefined); - const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); + + const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); const dispatch = useDispatch(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const [messageId, setMessageId] = useState(''); @@ -155,14 +147,9 @@ const RootNetworkNodeEditor = () => { setLaunchLoader(true); if (studyUuid) { fetchRootNetworks(studyUuid) - .then((res: RootNetworkMetadata[]) => { - // Check if during asynchronous request currentNode has already changed - // otherwise accept fetch results - // if (currentNode.id === currentNodeIdRef.current) { - + .then((res: RootNetworkMetadata[]) => { updateSelectedItems(res); setRootNetworks(res); - // } }) .catch((error) => { snackError({ @@ -179,18 +166,13 @@ const RootNetworkNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { dofetchRootNetworks(); } } }, [studyUpdatedForce, dofetchRootNetworks]); - useEffect(() => { - setEditDialogOpen(editData?.type); - }, [editData]); - + useEffect(() => { // first time with currentNode initialized then fetch modifications // (because if currentNode is not initialized, dofetchNetworkModifications silently does nothing) @@ -278,23 +260,7 @@ const RootNetworkNodeEditor = () => { }); }); } - }, [currentNode?.id, selectedItems, snackError, studyUuid, copiedModifications]); - - const removeNullFields = useCallback((data: NetworkModificationData) => { - let dataTemp = data; - if (dataTemp) { - Object.keys(dataTemp).forEach((key) => { - if (dataTemp[key] && dataTemp[key] !== null && typeof dataTemp[key] === 'object') { - dataTemp[key] = removeNullFields(dataTemp[key]); - } - - if (dataTemp[key] === null) { - delete dataTemp[key]; - } - }); - } - return dataTemp; - }, []); + }, [currentNode?.id, selectedItems, snackError, studyUuid]); const toggleSelectAllRootNetworks = useCallback(() => { setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); @@ -318,7 +284,7 @@ const RootNetworkNodeEditor = () => { sx={{ items: (rootNetwork) => ({ label: { - ...(rootNetwork.isCreating && { ...styles.disabledModification }), + ...(rootNetwork.isCreating && { ...styles.disabledRootNetwork }), ...styles.checkBoxLabel, }, checkBoxIcon: styles.checkBoxIcon, @@ -326,19 +292,14 @@ const RootNetworkNodeEditor = () => { }), // dragAndDropContainer: styles.listContainer, }} - onItemClick={(modification) => { - console.log(modification.rootNetworkUuid, 'on click'); + onItemClick={(rootNetwork) => { + console.log(rootNetwork.rootNetworkUuid, 'on click'); }} selectedItems={selectedItems} onSelectionChange={setSelectedItems} items={rootNetworks} getItemId={(val) => val.rootNetworkUuid} getItemLabel={getRootNetworkLabel} - // isDndDragAndDropActive - // isDragDisable={isLoading() || isAnyNodeBuilding || mapDataLoading || deleteInProgress} - // secondaryAction={handleSecondaryAction} - // onDragEnd={commit} - // onDragStart={() => setIsDragging(true)} divider secondaryAction={(rootNetwork) => { const isCurrentRootNetwork = rootNetwork.rootNetworkUuid === currentRootNetwork; @@ -366,7 +327,7 @@ const RootNetworkNodeEditor = () => { const renderRootNetworksListTitleLoading = () => { return ( - + @@ -379,7 +340,7 @@ const RootNetworkNodeEditor = () => { const renderRootNetworksListTitleUpdating = () => { return ( - + @@ -392,7 +353,7 @@ const RootNetworkNodeEditor = () => { const renderRootNetworksListTitle = () => { return ( - + {pendingState && } From 02e144d8a652fde122c038efa33871001d6fe1fc Mon Sep 17 00:00:00 2001 From: souissimai Date: Fri, 3 Jan 2025 11:26:11 +0100 Subject: [PATCH 20/51] add labes when updating root network Signed-off-by: souissimai --- .../graph/menus/root-network-node-editor.tsx | 86 +++---------------- src/services/root-network.ts | 12 +-- src/translations/en.json | 8 +- src/translations/fr.json | 8 +- 4 files changed, 31 insertions(+), 83 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index a49f9684b4..b62bf4b3c6 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -18,9 +18,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { UUID } from 'crypto'; import { AppState } from 'redux/reducer'; -import { - RootNetworkMetadata, -} from './network-modification-menu.type'; +import { RootNetworkMetadata } from './network-modification-menu.type'; import { CaseImportParameters, @@ -131,8 +129,8 @@ const RootNetworkNodeEditor = () => { const [pendingState, setPendingState] = useState(false); const [selectedItems, setSelectedItems] = useState([]); - - const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); + + const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); const dispatch = useDispatch(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const [messageId, setMessageId] = useState(''); @@ -147,7 +145,7 @@ const RootNetworkNodeEditor = () => { setLaunchLoader(true); if (studyUuid) { fetchRootNetworks(studyUuid) - .then((res: RootNetworkMetadata[]) => { + .then((res: RootNetworkMetadata[]) => { updateSelectedItems(res); setRootNetworks(res); }) @@ -159,7 +157,6 @@ const RootNetworkNodeEditor = () => { .finally(() => { setPendingState(false); setLaunchLoader(false); - // dispatch(setModificationsInProgress(false)); }); } }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); @@ -167,81 +164,19 @@ const RootNetworkNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { + setMessageId('updateRootNetworksList'); // creatingRootNetwork to do distinct creation:deletion action on notification dofetchRootNetworks(); } } }, [studyUpdatedForce, dofetchRootNetworks]); - useEffect(() => { - // first time with currentNode initialized then fetch modifications - // (because if currentNode is not initialized, dofetchNetworkModifications silently does nothing) - // OR next time if currentNodeId changed then fetch modifications - // if (currentNode && currentRootNetwork) { - if (!currentRootNetwork) { - // currentNodeIdRef.current = currentNode.id; - // Current node has changed then clear the modifications list setRootNetworks([]); - - // reset the network modification and computing logs filter when the user changes the current node - // dispatch(resetLogsFilter()); } dofetchRootNetworks(); }, [currentRootNetwork, dofetchRootNetworks]); - // TODO MANAGE NOTIFICATION - // useEffect(() => { - // if (studyUpdatedForce.eventData.headers) { - // if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { - // if ( - // copyInfosRef.current && - // studyUpdatedForce.eventData.headers['nodes']?.some( - // (nodeId) => nodeId === copyInfosRef.current?.originNodeUuid - // ) - // ) { - // // Must clean modifications clipboard if the origin Node is removed - // cleanClipboard(); - // } - // } - // if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { - // return; - // } - - // if ( - // studyUpdatedForce.eventData.headers['updateType'] && - // // @ts-expect-error TS2345: Argument of type string is not assignable to parameter of type UPDATE_TYPE (a restrained array of strings) - // UPDATE_TYPE.includes(studyUpdatedForce.eventData.headers['updateType']) - // ) { - // if (studyUpdatedForce.eventData.headers['updateType'] === 'deletingInProgress') { - // // deleting means removing from trashcan (stashed elements) so there is no network modification - // setDeleteInProgress(true); - // } else { - // dispatch(setModificationsInProgress(true)); - // setPendingState(true); - // } - // } - // // notify finished action (success or error => we remove the loader) - // // error handling in dialog for each equipment (snackbar with specific error showed only for current user) - // if (studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED') { - // // fetch modifications because it must have changed - // // Do not clear the modifications list, because currentNode is the concerned one - // // this allows to append new modifications to the existing list. - // dofetchRootNetworks(); - // dispatch( - // removeNotificationByNode([ - // studyUpdatedForce.eventData.headers['parentNode'], - // ...(studyUpdatedForce.eventData.headers.nodes ?? []), - // ]) - // ); - // } - // if (studyUpdatedForce.eventData.headers['updateType'] === 'DELETE_FINISHED') { - // setDeleteInProgress(false); - // dofetchRootNetworks(); - // } - // } - // }, [dispatch, dofetchRootNetworks, studyUpdatedForce, cleanClipboard]); - const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); }, []); @@ -251,14 +186,15 @@ const RootNetworkNodeEditor = () => { if (studyUuid) { deleteRootNetworks(studyUuid, selectedRootNetworksUuid) .then(() => { - //if one of the deleted element was in the clipboard we invalidate the clipboard + setDeleteInProgress(true); }) .catch((errmsg) => { snackError({ messageTxt: errmsg, headerId: 'errDeleteModificationMsg', }); - }); + }) + .finally(() => setDeleteInProgress(false)); } }, [currentNode?.id, selectedItems, snackError, studyUuid]); @@ -345,7 +281,7 @@ const RootNetworkNodeEditor = () => { - + ); @@ -359,7 +295,7 @@ const RootNetworkNodeEditor = () => { { {deleteInProgress ?? ( - }> + }> diff --git a/src/services/root-network.ts b/src/services/root-network.ts index d119e63e68..9e36eefa0f 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -48,16 +48,16 @@ export const createRootNetwork = ( }; export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { - // Assuming we want to delete each root network individually: - const rootNetworkUuid = rootNetworkUuids[0]; // Modify as needed if deleting multiple root networks - + const urlSearchParams = new URLSearchParams(); + urlSearchParams.append('rootNetworkUuids', String(rootNetworkUuids)); const rootNetworkDeleteUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent( studyUuid - )}/root-networks/${encodeURIComponent(rootNetworkUuid)}`; + )}/root-networks`; - console.debug(rootNetworkDeleteUrl); // Debugging the URL + const modificationDeleteUrl = rootNetworkDeleteUrl + '?' + urlSearchParams.toString(); - return backendFetch(rootNetworkDeleteUrl, { + console.debug(modificationDeleteUrl); + return backendFetch(modificationDeleteUrl, { method: 'DELETE', }); } diff --git a/src/translations/en.json b/src/translations/en.json index 1a990b7c0a..0a9205d14f 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1451,5 +1451,11 @@ "qualityPerRegionResults": "Quality region", "StateEstimationStatus": "Status : ", "StateEstimationQuality": "Quality : ", - "Or": "or" + "Or": "or", + "rootNetworksCount":"{hide, select, false {{count, plural, =0 {aucun réseau racine} =1 {# réseau racine} other {# réseaux racine}}} other {...}}", + "updateRootNetworksList": "Updating modification list ...", + "deletingRootNetwork": "Deleting root network ...", + "creatingRootNetwork": "Creating root network ..." + + } diff --git a/src/translations/fr.json b/src/translations/fr.json index 145503b275..84b3124ad8 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1452,5 +1452,11 @@ "qualityPerRegionResults": "Qualité par région", "StateEstimationStatus": "Statut : ", "StateEstimationQuality": "Qualité: ", - "Or": "ou" + "Or": "ou", + "rootNetworksCount":"{hide, select, false {{count, plural, =0 {no root network} =1 {{count} root network} other {{count} root networks}}} other {...}}", + "updateRootNetworksList": "Mise à jour de la liste des réseaux racine cours ...", + "deletingRootNetwork": "Suppression du réseau racine en cours ...", + "creatingRootNetwork": "Création du réseau racine en cours ..." + + } \ No newline at end of file From d63e9a6bce338bbd2d0dd81606a470b46cd60fb1 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Fri, 3 Jan 2025 15:19:55 +0100 Subject: [PATCH 21/51] fix: when switching of root network, reset nominal voltages and center map around new network Signed-off-by: LE SAULNIER Kevin --- src/components/network/network-map-tab.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 2d44eb994b..cf1587a257 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -630,6 +630,12 @@ export const NetworkMapTab = ({ Promise.all([substationPositionsDone, linePositionsDone]) .then(() => { temporaryGeoDataIdsRef.current = new Set(); + networkMapRef.current?.centerMapNetwork(); + // when reloading root node map equipments (when switching of root network), nominal voltages are reloaded + // we check them all in NominalVoltageFilter by default + if (mapEquipments) { + handleChange(mapEquipments.getNominalVoltages()); + } setIsRootNodeGeoDataLoaded(true); }) .catch(function (error) { @@ -642,7 +648,7 @@ export const NetworkMapTab = ({ .finally(() => { dispatch(setMapDataLoading(false)); }); - }, [rootNodeId, currentRootNetworkUuid, lineFullPath, studyUuid, dispatch, snackError]); + }, [mapEquipments, rootNodeId, currentRootNetworkUuid, lineFullPath, studyUuid, dispatch, snackError]); const loadGeoData = useCallback(() => { if (studyUuid && currentNodeRef.current) { From e377afcf13642b23abbc0f93afea267042d3230b Mon Sep 17 00:00:00 2001 From: souissimai Date: Fri, 3 Jan 2025 15:47:03 +0100 Subject: [PATCH 22/51] manage notifications Signed-off-by: souissimai --- src/components/diagrams/diagram-pane.tsx | 11 ++-- .../graph/menus/root-network-node-editor.tsx | 4 +- .../network-modification-tree-pane.jsx | 27 ++------- src/components/study-container.jsx | 56 ++++++------------- src/services/root-network.ts | 6 +- src/translations/en.json | 2 +- 6 files changed, 34 insertions(+), 72 deletions(-) diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index fbd532441b..e31d069d87 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -371,7 +371,8 @@ export function DiagramPane({ const { openDiagramView, closeDiagramView, closeDiagramViews } = useDiagram(); const currentNodeRef = useRef(); currentNodeRef.current = currentNode; - + const currentRootNetworkRef = useRef(); + currentRootNetworkRef.current = currentRootNetworkUuid; const viewsRef = useRef([]); viewsRef.current = views; /** @@ -794,11 +795,11 @@ export function DiagramPane({ updateDiagramsByIds(allDiagramIds, true); }, [currentNode, updateDiagramsByIds]); + // This effect will trigger the diagrams' forced update // This effect will trigger the diagrams' forced update useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - + console.log('???????? ', studyUpdatedForce.eventData.headers['updateType']); if (studyUpdatedForce.eventData.headers['updateType'] === 'loadflowResult') { //TODO reload data more intelligently updateDiagramsByCurrentNode(); @@ -806,9 +807,9 @@ export function DiagramPane({ // FM if we want to reload data more precisely, we need more information from notifications updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'buildCompleted') { - console.log('TEST ====== buildCompleted ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers['node'] === currentNodeRef.current?.id) { + console.log(' ???????? buildCompleted ', studyUpdatedForce.eventData.headers['rootNetwork']); + updateDiagramsByCurrentNode(); } } diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index b62bf4b3c6..14d24d0b35 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -159,7 +159,7 @@ const RootNetworkNodeEditor = () => { setLaunchLoader(false); }); } - }, [currentNode?.type, currentNode?.id, studyUuid, updateSelectedItems, snackError, dispatch]); + }, [studyUuid, updateSelectedItems, snackError]); useEffect(() => { if (studyUpdatedForce.eventData.headers) { @@ -196,7 +196,7 @@ const RootNetworkNodeEditor = () => { }) .finally(() => setDeleteInProgress(false)); } - }, [currentNode?.id, selectedItems, snackError, studyUuid]); + }, [selectedItems, snackError, studyUuid]); const toggleSelectAllRootNetworks = useCallback(() => { setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 88a0791766..002c5dda84 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -133,7 +133,8 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu const currentNode = useSelector((state) => state.currentTreeNode); const currentNodeRef = useRef(); currentNodeRef.current = currentNode; - + const currentRootNetworkRef = useRef(); + currentRootNetworkRef.current = currentRootNetworkUuid; const selectionForCopy = useSelector((state) => state.nodeSelectionForCopy); const nodeSelectionForCopyRef = useRef(); nodeSelectionForCopyRef.current = selectionForCopy; @@ -190,8 +191,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu useEffect(() => { if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === UpdateType.NODE_CREATED) { - console.log('TEST ====== >>>>>> ££££ ???? NODE_CREATED', studyUpdatedForce.eventData.headers); - fetchNetworkModificationTreeNode( studyUuid, studyUpdatedForce.eventData.headers['newNode'], @@ -214,8 +213,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu setNodesToRestore(res); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'subtreeCreated') { - console.log('TEST ====== >>>>>> ££££ ???? subtreeCreated', studyUpdatedForce.eventData.headers); - fetchNetworkModificationSubtree(studyUuid, studyUpdatedForce.eventData.headers['newNode']).then( (nodes) => { dispatch( @@ -224,8 +221,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu } ); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeMoved') { - console.log('TEST ====== >>>>>> ££££ ???? nodeMoved', studyUpdatedForce.eventData.headers); - fetchNetworkModificationTreeNode( studyUuid, studyUpdatedForce.eventData.headers['movedNode'], @@ -241,8 +236,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu ); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'subtreeMoved') { - console.log('TEST ====== >>>>>> ££££ ???? subtreeMoved', studyUpdatedForce.eventData.headers); - fetchNetworkModificationSubtree(studyUuid, studyUpdatedForce.eventData.headers['movedNode']).then( (nodes) => { dispatch( @@ -251,8 +244,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu } ); } else if (studyUpdatedForce.eventData.headers['updateType'] === UpdateType.NODE_DELETED) { - console.log('TEST ====== >>>>>> ££££ ???? NODE_DELETED', studyUpdatedForce.eventData.headers); - if ( studyUpdatedForce.eventData.headers['nodes'].some( (nodeId) => nodeId === nodeSelectionForCopyRef.current.nodeId @@ -266,8 +257,6 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu setNodesToRestore(res); }); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeUpdated') { - console.log('TEST ====== >>>>>> ££££ ???? nodeUpdated', studyUpdatedForce.eventData.headers); - updateNodes(studyUpdatedForce.eventData.headers['nodes']); if ( studyUpdatedForce.eventData.headers['nodes'].some((nodeId) => nodeId === currentNodeRef.current?.id) @@ -283,15 +272,11 @@ export const NetworkModificationTreePane = ({ studyUuid, studyMapTreeDisplay, cu resetNodeClipboard(); } } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeRenamed') { - console.log('TEST ====== >>>>>> ££££ ???? nodeRenamed', studyUpdatedForce.eventData.headers); - updateNodes([studyUpdatedForce.eventData.headers['node']]); - } else if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeBuildStatusUpdated') { - console.log( - 'TEST ====== >>>>>> ££££ ???? nodeBuildStatusUpdated', - studyUpdatedForce.eventData.headers - ); - + } else if ( + studyUpdatedForce.eventData.headers['updateType'] === 'nodeBuildStatusUpdated' && + studyUpdatedForce.eventData.headers['rootNetwork'] === currentRootNetworkRef.current + ) { updateNodes(studyUpdatedForce.eventData.headers['nodes']); if ( studyUpdatedForce.eventData.headers['nodes'].some((nodeId) => nodeId === currentNodeRef.current?.id) diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 9621294c8a..459294497f 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -174,13 +174,12 @@ function useStudy(studyUuidRequest) { .then((rootNetworks) => { if (rootNetworks && rootNetworks.length > 0) { // Validate that currentRootNetwork is set - dispatch(setCurrentRootNetwork(rootNetworks[0].rootNetworkUuid)); } else { // Handle case where no root networks are available setErrMessage( intlRef.current.formatMessage( - { id: 'noRootNetworksFound' }, + { id: 'rootNetworkNotFound' }, { studyUuid: studyUuidRequest } ) ); @@ -189,7 +188,7 @@ function useStudy(studyUuidRequest) { .catch((error) => { // Handle errors when fetching root networks setErrMessage( - intlRef.current.formatMessage({ id: 'fetchRootNetworksError' }, { error: error.message }) + intlRef.current.formatMessage({ id: 'rootNetworkNotFound' }, { error: error.message }) ); }); }) @@ -270,10 +269,16 @@ export function StudyContainer({ view, onChangeTab }) { (eventData) => { const updateTypeHeader = eventData.headers[UPDATE_TYPE_HEADER]; const errorMessage = eventData.headers[ERROR_HEADER]; + const currentRootNetwork = eventData.headers['rootNetwork']; + const userId = eventData.headers[USER_HEADER]; if (userId != null && userId !== userName) { return; } + if (currentRootNetwork !== currentRootNetworkRef.current) { + return; + } + if (updateTypeHeader === 'loadflow_failed') { snackError({ headerId: 'LoadFlowError', @@ -343,6 +348,10 @@ export function StudyContainer({ view, onChangeTab }) { const sendAlert = useCallback( (eventData) => { const userId = eventData.headers[USER_HEADER]; + const currentRootNetwork = eventData.headers['rootNetwork']; + if (currentRootNetworkRef.current !== currentRootNetwork && currentRootNetwork) { + return; + } if (userId !== userName) { return; } @@ -652,7 +661,6 @@ export function StudyContainer({ view, onChangeTab }) { (studyUuid && currentRootNetworkUuid && !isStudyNetworkFound) || (currentRootNetworkRef.current && currentRootNetworkRef.current !== currentRootNetworkUuid) ) { - console.log('RELOADING CHECK NETWORK', currentRootNetworkUuid); checkNetworkExistenceAndRecreateIfNotFound(); } }, [isStudyNetworkFound, currentRootNetworkUuid, checkNetworkExistenceAndRecreateIfNotFound, studyUuid]); @@ -661,12 +669,6 @@ export function StudyContainer({ view, onChangeTab }) { // checking another time if we can find network, if we do, we display a snackbar info useEffect(() => { if (studyUpdatedForce.eventData.headers?.[UPDATE_TYPE_HEADER] === UPDATE_TYPE_STUDY_NETWORK_RECREATION_DONE) { - console.log( - 'TEST ======!!! Type ', - 'UPDATE_TYPE_STUDY_NETWORK_RECREATION_DONE', - ' rootNetwork ', - studyUpdatedForce.eventData.headers?.['rootNetwork'] - ); const successCallback = () => snackInfo({ headerId: 'studyNetworkRecovered', @@ -674,13 +676,6 @@ export function StudyContainer({ view, onChangeTab }) { checkNetworkExistenceAndRecreateIfNotFound(successCallback); } else if (studyUpdatedForce.eventData.headers?.[UPDATE_TYPE_HEADER] === UPDATE_TYPE_INDEXATION_STATUS) { - console.log( - 'TEST ======!!! Type ', - 'UPDATE_TYPE_INDEXATION_STATUS', - ' rootNetwork ', - studyUpdatedForce.eventData.headers?.['rootNetwork'] - ); - dispatch(setStudyIndexationStatus(studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS])); if (studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS] === StudyIndexationStatus.INDEXED) { snackInfo({ @@ -689,14 +684,6 @@ export function StudyContainer({ view, onChangeTab }) { } // notification that the study is not indexed anymore then ask to refresh if (studyUpdatedForce.eventData.headers?.[HEADER_INDEXATION_STATUS] === StudyIndexationStatus.NOT_INDEXED) { - console.log( - 'TEST ======!!! Type ', - ' OK ', - 'HEADER_INDEXATION_STATUS', - ' rootNetwork ', - studyUpdatedForce.eventData.headers?.['rootNetwork'] - ); - snackWarning({ headerId: 'studyIndexationNotIndexed', }); @@ -735,13 +722,11 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - if (studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult') { - console.log( - 'TEST ======!!! Type ', - 'loadflowResult ', - ' rootNetwork ', - studyUpdatedForce.eventData.headers?.['rootNetwork'] - ); + const currentRootNetwork = studyUpdatedForce.eventData.headers['rootNetwork']; + if ( + studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult' && + currentRootNetwork === currentRootNetworkRef.current + ) { dispatch(resetEquipmentsPostLoadflow()); } } @@ -783,12 +768,6 @@ export function StudyContainer({ view, onChangeTab }) { studyUpdatedForce.eventData.headers.studyUuid === studyUuid && studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'metadata_updated' ) { - console.log( - 'TEST ======!!! Type ', - 'metadata_updated', - ' rootNetwork ', - studyUpdatedForce.eventData.headers?.['rootNetwork'] - ); fetchStudyPath(); } } @@ -797,7 +776,6 @@ export function StudyContainer({ view, onChangeTab }) { useEffect(() => { if (studyUuid) { websocketExpectedCloseRef.current = false; - //dispatch root network uuid dispatch(openStudy(studyUuid)); const ws = connectNotifications(studyUuid); diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 9e36eefa0f..828602a618 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -48,11 +48,9 @@ export const createRootNetwork = ( }; export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { - const urlSearchParams = new URLSearchParams(); + const urlSearchParams = new URLSearchParams(); urlSearchParams.append('rootNetworkUuids', String(rootNetworkUuids)); - const rootNetworkDeleteUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent( - studyUuid - )}/root-networks`; + const rootNetworkDeleteUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks`; const modificationDeleteUrl = rootNetworkDeleteUrl + '?' + urlSearchParams.toString(); diff --git a/src/translations/en.json b/src/translations/en.json index 0a9205d14f..21e04df2cf 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -53,7 +53,7 @@ "SingleLineDiagram": "Single line diagram", "NetworkAreaDiagram": "Network area diagram", "studyNotFound": "Study with id \"{studyUuid}\" has not been found", - "RootNetworkNotFound": "No root network was found for the study with ID \"{studyUuid}\"", + "rootNetworkNotFound": "No root network was not found for the study with ID \"{studyUuid}\"", "svgNotFound": "Diagram has not been found: {error}; {svgUrl}", "svgLoadingFail": "The diagram couldn't be loaded", From ebf0d0b7c8808471c527b7d17cbf695f643051a5 Mon Sep 17 00:00:00 2001 From: souissimai Date: Fri, 3 Jan 2025 16:36:50 +0100 Subject: [PATCH 23/51] fix fetchnetworkelement endpoint ith current root network uuid Signed-off-by: souissimai --- .../single-line-diagram-content.tsx | 3 +- .../dialogs/form-search-copy-hook.js | 10 +++- .../battery-modification-dialog.jsx | 4 +- .../equipment-deletion-dialog.jsx | 3 +- .../creation/generator-creation-dialog.jsx | 1 + .../generator-modification-dialog.jsx | 4 +- .../lcc/creation/lcc-creation-dialog.tsx | 1 + .../vsc/creation/vsc-creation-dialog.jsx | 1 + .../modification/vsc-modification-dialog.tsx | 13 ++++- .../line/creation/line-creation-dialog.jsx | 1 + .../modification/line-modification-dialog.jsx | 14 +++++- .../load/creation/load-creation-dialog.tsx | 1 + .../modification/load-modification-dialog.jsx | 4 +- .../shunt-compensator-creation-dialog.jsx | 2 + .../shunt-compensator-modification-dialog.jsx | 4 +- ...static-var-compensator-creation-dialog.tsx | 2 + .../creation/substation-creation-dialog.jsx | 1 + .../substation-modification-dialog.jsx | 4 +- ...o-windings-transformer-creation-dialog.jsx | 1 + ...ndings-transformer-modification-dialog.jsx | 13 ++++- .../voltage-level-creation-dialog.jsx | 1 + .../voltage-level-modification-dialog.jsx | 4 +- src/components/menus/bus-menu.tsx | 4 +- src/components/network/network-map-tab.tsx | 47 +++++-------------- src/components/tooltips/equipment-popover.jsx | 4 +- src/services/study/network-modifications.ts | 11 +---- src/services/study/short-circuit-analysis.ts | 2 +- 27 files changed, 97 insertions(+), 63 deletions(-) diff --git a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx index 1f249294fa..c85f28d1a4 100644 --- a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx +++ b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx @@ -352,6 +352,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { fetchNetworkElementInfos( studyUuid, currentNode?.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.HVDC_LINE, EQUIPMENT_INFOS_TYPES.MAP.type, equipmentId, @@ -373,7 +374,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { }); } }, - [studyUuid, currentNode?.id, snackError, handleOpenDeletionDialog, removeEquipment] + [studyUuid, currentNode?.id, currentRootNetworkUuid, snackError, handleOpenDeletionDialog, removeEquipment] ); const handleOpenDynamicSimulationEventDialog = useCallback( diff --git a/src/components/dialogs/form-search-copy-hook.js b/src/components/dialogs/form-search-copy-hook.js index 9c41e7cff6..7f7a911a15 100644 --- a/src/components/dialogs/form-search-copy-hook.js +++ b/src/components/dialogs/form-search-copy-hook.js @@ -11,7 +11,14 @@ import { useSnackMessage } from '@gridsuite/commons-ui'; import { EQUIPMENT_INFOS_TYPES } from '../utils/equipment-types'; import { fetchNetworkElementInfos } from '../../services/study/network'; -export const useFormSearchCopy = ({ studyUuid, currentNodeUuid, toFormValues, setFormValues, elementType }) => { +export const useFormSearchCopy = ({ + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + toFormValues, + setFormValues, + elementType, +}) => { const intl = useIntl(); const { snackInfo, snackError } = useSnackMessage(); @@ -23,6 +30,7 @@ export const useFormSearchCopy = ({ studyUuid, currentNodeUuid, toFormValues, se const fetchElementPromise = fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, elementType, EQUIPMENT_INFOS_TYPES.FORM.type, element.id, diff --git a/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx b/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx index ff73c17176..f1d6d728e2 100644 --- a/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx @@ -110,6 +110,7 @@ const BatteryModificationDialog = ({ editData, defaultIdValue, currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -199,6 +200,7 @@ const BatteryModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNode.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.BATTERY, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -245,7 +247,7 @@ const BatteryModificationDialog = ({ setBatteryToModify(null); } }, - [studyUuid, currentNode, getValues, setValue, setValuesAndEmptyOthers, reset, editData] + [studyUuid, currentNode, currentRootNetworkUuid, getValues, setValue, setValuesAndEmptyOthers, reset, editData] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx index 289a030f1e..36c8e9951c 100644 --- a/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx +++ b/src/components/dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog.jsx @@ -99,7 +99,6 @@ const EquipmentDeletionDialog = ({ deleteEquipment( studyUuid, currentNodeUuid, - currentRootNetworkUuid, formData[TYPE], formData[EQUIPMENT_ID], editData?.uuid, @@ -111,7 +110,7 @@ const EquipmentDeletionDialog = ({ }); }); }, - [currentNodeUuid, editData, currentRootNetworkUuid, snackError, studyUuid] + [currentNodeUuid, editData, snackError, studyUuid] ); const clear = useCallback(() => { diff --git a/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx b/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx index 7235c3b050..dee749311d 100644 --- a/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/generator/creation/generator-creation-dialog.jsx @@ -194,6 +194,7 @@ const GeneratorCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.GENERATOR, diff --git a/src/components/dialogs/network-modifications/generator/modification/generator-modification-dialog.jsx b/src/components/dialogs/network-modifications/generator/modification/generator-modification-dialog.jsx index da501f240f..3bae197d34 100644 --- a/src/components/dialogs/network-modifications/generator/modification/generator-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/generator/modification/generator-modification-dialog.jsx @@ -135,6 +135,7 @@ const GeneratorModificationDialog = ({ editData, // contains data when we try to edit an existing hypothesis from the current node's list defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the SLD currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -242,6 +243,7 @@ const GeneratorModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNode.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.GENERATOR, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -284,7 +286,7 @@ const GeneratorModificationDialog = ({ setGeneratorToModify(null); } }, - [studyUuid, currentNode, reset, getValues, setValue, setValuesAndEmptyOthers, editData] + [studyUuid, currentNode, currentRootNetworkUuid, reset, getValues, setValue, setValuesAndEmptyOthers, editData] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx index d8b8c3e2ff..f321a38c1f 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx @@ -161,6 +161,7 @@ export function LccCreationDialog({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: fromSearchCopyToFormValues, setFormValues: (data: LccCreationSchemaForm) => { reset(data, { keepDefaultValues: true }); diff --git a/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx b/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx index 4b0a6ee116..10c6bc079f 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/hvdc-line/vsc/creation/vsc-creation-dialog.jsx @@ -139,6 +139,7 @@ const VscCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.HVDC_LINE, diff --git a/src/components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog.tsx b/src/components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog.tsx index 7e315958e3..079ad522dc 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/vsc/modification/vsc-modification-dialog.tsx @@ -101,6 +101,7 @@ const VscModificationDialog: React.FC = ({ editData, currentNode, studyUuid, + currentRootNetworkUuid, isUpdate, editDataFetchStatus, ...dialogProps @@ -162,6 +163,7 @@ const VscModificationDialog: React.FC = ({ fetchNetworkElementInfos( studyUuid, currentNode.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.HVDC_LINE, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -233,7 +235,16 @@ const VscModificationDialog: React.FC = ({ }); } }, - [setValuesAndEmptyOthers, studyUuid, currentNode, setValue, reset, getValues, editData?.equipmentId] + [ + setValuesAndEmptyOthers, + currentRootNetworkUuid, + studyUuid, + currentNode, + setValue, + reset, + getValues, + editData?.equipmentId, + ] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx index be3bd10900..452f5d4b43 100644 --- a/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/line/creation/line-creation-dialog.jsx @@ -247,6 +247,7 @@ const LineCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.LINE, diff --git a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx index 1868d36416..6e6ea529bd 100644 --- a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx @@ -104,6 +104,7 @@ const LineModificationDialog = ({ defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the SLD or network map studyUuid, currentNode, + currentRootNetworkUuid, displayConnectivity = false, isUpdate, editDataFetchStatus, @@ -291,6 +292,7 @@ const LineModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, EQUIPMENT_TYPES.LINE, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -332,7 +334,17 @@ const LineModificationDialog = ({ reset(emptyFormData, { keepDefaultValues: true }); } }, - [studyUuid, currentNodeUuid, selectedId, editData, reset, emptyFormData, getValues, setConnectivityValue] + [ + studyUuid, + currentRootNetworkUuid, + currentNodeUuid, + selectedId, + editData, + reset, + emptyFormData, + getValues, + setConnectivityValue, + ] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/load/creation/load-creation-dialog.tsx b/src/components/dialogs/network-modifications/load/creation/load-creation-dialog.tsx index fee6c51dae..7347fad699 100644 --- a/src/components/dialogs/network-modifications/load/creation/load-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/load/creation/load-creation-dialog.tsx @@ -146,6 +146,7 @@ export function LoadCreationDialog({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: fromSearchCopyToFormValues, setFormValues: (data: LoadCreationSchemaForm) => { reset(data, { keepDefaultValues: true }); diff --git a/src/components/dialogs/network-modifications/load/modification/load-modification-dialog.jsx b/src/components/dialogs/network-modifications/load/modification/load-modification-dialog.jsx index 16857fb6b1..a410f8a523 100644 --- a/src/components/dialogs/network-modifications/load/modification/load-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/load/modification/load-modification-dialog.jsx @@ -84,6 +84,7 @@ const LoadModificationDialog = ({ editData, // contains data when we try to edit an existing hypothesis from the current node's list defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the SLD currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -143,6 +144,7 @@ const LoadModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, EQUIPMENT_TYPES.LOAD, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -169,7 +171,7 @@ const LoadModificationDialog = ({ }); } }, - [studyUuid, currentNodeUuid, reset, getValues, setValue, editData] + [studyUuid, currentRootNetworkUuid, currentNodeUuid, reset, getValues, setValue, editData] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx b/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx index 1d53c80fa2..4509c90e36 100644 --- a/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/shunt-compensator/creation/shunt-compensator-creation-dialog.jsx @@ -163,6 +163,8 @@ const ShuntCompensatorCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, + toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.SHUNT_COMPENSATOR, diff --git a/src/components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog.jsx b/src/components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog.jsx index 0e405a8fb8..28f766178a 100644 --- a/src/components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/shunt-compensator/modification/shunt-compensator-modification-dialog.jsx @@ -78,6 +78,7 @@ const ShuntCompensatorModificationDialog = ({ editData, // contains data when we try to edit an existing hypothesis from the current node's list defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the network map currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -164,6 +165,7 @@ const ShuntCompensatorModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNode?.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.SHUNT_COMPENSATOR, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -207,7 +209,7 @@ const ShuntCompensatorModificationDialog = ({ setShuntCompensatorInfos(null); } }, - [currentNode.id, snackError, studyUuid, reset, getValues, setValue, editData] + [currentNode.id, currentRootNetworkUuid, snackError, studyUuid, reset, getValues, setValue, editData] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog.tsx b/src/components/dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog.tsx index 15aeeb46fd..f1e60b5307 100644 --- a/src/components/dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/static-var-compensator/creation/static-var-compensator-creation-dialog.tsx @@ -287,6 +287,8 @@ const StaticVarCompensatorCreationDialog: FC = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, + toFormValues: (data: StaticVarCompensatorCreationSchemaForm) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.STATIC_VAR_COMPENSATOR, diff --git a/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx b/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx index e7d4d04f4b..3c3d5317ae 100644 --- a/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/substation/creation/substation-creation-dialog.jsx @@ -79,6 +79,7 @@ const SubstationCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.SUBSTATION, diff --git a/src/components/dialogs/network-modifications/substation/modification/substation-modification-dialog.jsx b/src/components/dialogs/network-modifications/substation/modification/substation-modification-dialog.jsx index e3b220e43c..a7385895d2 100644 --- a/src/components/dialogs/network-modifications/substation/modification/substation-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/substation/modification/substation-modification-dialog.jsx @@ -57,6 +57,7 @@ const SubstationModificationDialog = ({ editData, // contains data when we try to edit an existing hypothesis from the current node's list defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the network map currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -101,6 +102,7 @@ const SubstationModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, EQUIPMENT_TYPES.SUBSTATION, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -125,7 +127,7 @@ const SubstationModificationDialog = ({ }); } }, - [studyUuid, currentNodeUuid, reset, getValues, editData] + [studyUuid, currentRootNetworkUuid, currentNodeUuid, reset, getValues, editData] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx index 5d12bb9815..0172505323 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx @@ -404,6 +404,7 @@ const TwoWindingsTransformerCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromSearchCopyToFormValues, elementType: EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER, diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx index 8ade7f66a3..b4942c4057 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx @@ -527,7 +527,6 @@ const TwoWindingsTransformerModificationDialog = ({ currentNode, studyUuid, currentNodeUuid, - // currentRootNetworkUuid, selectedId, fillRatioTapChangerRegulationAttributes, fillPhaseTapChangerRegulationAttributes, @@ -584,6 +583,7 @@ const TwoWindingsTransformerModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, EQUIPMENT_TYPES.TWO_WINDINGS_TRANSFORMER, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -636,7 +636,16 @@ const TwoWindingsTransformerModificationDialog = ({ reset(emptyFormData, { keepDefaultValues: true }); } }, - [studyUuid, currentNodeUuid, selectedId, editData, reset, getValues, setConnectivityValue] + [ + studyUuid, + currentNodeUuid, + currentRootNetworkUuid, + selectedId, + editData, + reset, + getValues, + setConnectivityValue, + ] ); useEffect(() => { diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx index 545d216e3c..690e2e0f17 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx @@ -194,6 +194,7 @@ const VoltageLevelCreationDialog = ({ const searchCopy = useFormSearchCopy({ studyUuid, currentNodeUuid, + currentRootNetworkUuid, toFormValues: (data) => data, setFormValues: fromExternalDataToFormValues, elementType: EQUIPMENT_TYPES.VOLTAGE_LEVEL, diff --git a/src/components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog.jsx b/src/components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog.jsx index cdbb0ab781..4358b7ce6b 100644 --- a/src/components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/modification/voltage-level-modification-dialog.jsx @@ -76,6 +76,7 @@ const VoltageLevelModificationDialog = ({ editData, // contains data when we try to edit an existing hypothesis from the current node's list defaultIdValue, // Used to pre-select an equipmentId when calling this dialog from the network map currentNode, + currentRootNetworkUuid, studyUuid, isUpdate, editDataFetchStatus, @@ -119,6 +120,7 @@ const VoltageLevelModificationDialog = ({ fetchNetworkElementInfos( studyUuid, currentNodeUuid, + currentRootNetworkUuid, EQUIPMENT_TYPES.VOLTAGE_LEVEL, EQUIPMENT_INFOS_TYPES.FORM.type, equipmentId, @@ -156,7 +158,7 @@ const VoltageLevelModificationDialog = ({ reset(emptyFormData, { keepDefaultValues: true }); } }, - [studyUuid, currentNodeUuid, reset, getValues, editData] + [studyUuid, currentNodeUuid, currentRootNetworkUuid, reset, getValues, editData] ); useEffect(() => { diff --git a/src/components/menus/bus-menu.tsx b/src/components/menus/bus-menu.tsx index d5cfdb9f46..05ecd19d4e 100644 --- a/src/components/menus/bus-menu.tsx +++ b/src/components/menus/bus-menu.tsx @@ -75,6 +75,7 @@ export const BusMenu: FunctionComponent = ({ // to check is node editable const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const studyUuid = useSelector((state: AppState) => state.studyUuid); const isAnyNodeBuilding = useIsAnyNodeBuilding(); const isNodeEditable = useMemo( @@ -86,6 +87,7 @@ export const BusMenu: FunctionComponent = ({ fetchNetworkElementInfos( studyUuid, currentNode?.id, + currentRootNetworkUuid, EQUIPMENT_TYPES.BUSBAR_SECTION, EQUIPMENT_INFOS_TYPES.OPERATING_STATUS.type, busId, @@ -95,7 +97,7 @@ export const BusMenu: FunctionComponent = ({ setEquipmentInfos(value); } }); - }, [studyUuid, currentNode?.id, busId]); + }, [studyUuid, currentRootNetworkUuid, currentNode?.id, busId]); const computationStarting = useSelector((state: AppState) => state.computationStarting); diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index cf1587a257..880f1d300a 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -350,14 +350,7 @@ export const NetworkMapTab = ({ // only hvdc line with LCC requires a Dialog (to select MCS) handleOpenDeletionDialog(equipmentId, EquipmentType.HVDC_LINE); } else { - deleteEquipment( - studyUuid, - currentNode?.id, - currentRootNetworkUuid, - equipmentType, - equipmentId, - undefined - ).catch((error) => { + deleteEquipment(studyUuid, currentNode?.id, equipmentType, equipmentId, undefined).catch((error) => { snackError({ messageTxt: error.message, headerId: 'UnableToDeleteEquipment', @@ -366,14 +359,7 @@ export const NetworkMapTab = ({ closeEquipmentMenu(); } }, - [ - studyUuid, - currentNode?.id, - currentRootNetworkUuid, - snackError, - handleOpenDeletionDialog, - mapEquipments?.hvdcLinesById, - ] + [studyUuid, currentNode?.id, snackError, handleOpenDeletionDialog, mapEquipments?.hvdcLinesById] ); function closeChoiceVoltageLevelMenu() { @@ -606,7 +592,6 @@ export const NetworkMapTab = ({ console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); geoDataRef.current = null; - console.log('**== :::::::::::::::: rootNodeId ', rootNodeId); const substationPositionsDone = fetchSubstationPositions(studyUuid, rootNodeId, currentRootNetworkUuid).then( (data) => { console.info(`Received substations of study '${studyUuid}'...`); @@ -648,7 +633,16 @@ export const NetworkMapTab = ({ .finally(() => { dispatch(setMapDataLoading(false)); }); - }, [mapEquipments, rootNodeId, currentRootNetworkUuid, lineFullPath, studyUuid, dispatch, snackError]); + }, [ + mapEquipments, + rootNodeId, + currentRootNetworkUuid, + lineFullPath, + studyUuid, + dispatch, + snackError, + networkMapRef, + ]); const loadGeoData = useCallback(() => { if (studyUuid && currentNodeRef.current) { @@ -835,32 +829,25 @@ export const NetworkMapTab = ({ isCurrentNodeBuiltRef.current = isNodeBuilt(currentNode); // if only renaming, do not reload geo data if (isNodeRenamed(previousCurrentNode, currentNode)) { - console.log('**== test 1'); return; } if (disabled) { - console.log('**== test 2 ', rootNodeId); return; } // as long as rootNodeId is not set, we don't fetch any geodata if (!rootNodeId) { - console.log('**== test 3'); return; } // Hack to avoid reload Geo Data when switching display mode to TREE then back to MAP or HYBRID // TODO REMOVE LATER if (!reloadMapNeeded) { - console.log('**== test 4'); return; } if (!isMapEquipmentsInitialized) { - console.log('**== test 5'); // load default node map equipments loadMapEquipments(); } if (!isRootNodeGeoDataLoaded) { - console.log('**== test 6'); - // load root node geodata loadRootNodeGeoData(); } @@ -983,16 +970,6 @@ export const NetworkMapTab = ({ /> ); - console.log('EQUIPMENT TO DISPLAY', mapEquipments); - console.log('GEODATA TO DISPLAY', geoData); - console.log('lineFullPath TO DISPLAY', lineFullPath); - console.log('lineFullPath TO DISPLAY', lineFullPath); - console.log( - 'COMPARE DISPLAY', - [...(updatedLines ?? []), ...(updatedTieLines ?? []), ...(updatedHvdcLines ?? [])], - visible, - disabled - ); const renderMap = () => ( { + (equipmentId, equipmentType, currentRootNetworkUuid, currentNodeId, studyUuid) => { fetchNetworkElementInfos( studyUuid, currentNodeId, @@ -69,7 +69,7 @@ const EquipmentPopover = ({ studyUuid, anchorEl, anchorPosition, equipmentId, eq useEffect(() => { if (equipmentId && equipmentId !== '') { - debouncedNetworkElementInfos(equipmentId, equipmentType, currentNode.id, studyUuid); + debouncedNetworkElementInfos(equipmentId, equipmentType, currentRootNetworkUuid, currentNode.id, studyUuid); } else { setEquipmentInfo(null); } diff --git a/src/services/study/network-modifications.ts b/src/services/study/network-modifications.ts index 6c55c6c023..53cef5f36f 100644 --- a/src/services/study/network-modifications.ts +++ b/src/services/study/network-modifications.ts @@ -47,14 +47,6 @@ function getNetworkModificationUrl(studyUuid: string | null | undefined, nodeUui return getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/network-modifications'; } -function getNetworkModificationUrl1( - studyUuid: string | null | undefined, - nodeUuid: string | undefined, - rootNetworkUuid: string | undefined -) { - return getStudyUrlWithNodeUuidAndRootNetworkUuid(studyUuid, nodeUuid, rootNetworkUuid) + '/network-modifications'; -} - export function changeNetworkModificationOrder( studyUuid: UUID | null, nodeUuid: UUID | undefined, @@ -1725,13 +1717,12 @@ export function deleteAttachingLine({ export function deleteEquipment( studyUuid: string, nodeUuid: UUID | undefined, - currentRootNetworkUuid: UUID | undefined, equipmentType: EquipmentType | string | null, equipmentId: string, modificationUuid: UUID | undefined, equipmentInfos: any = undefined ) { - let deleteEquipmentUrl = getNetworkModificationUrl1(studyUuid, nodeUuid, currentRootNetworkUuid); + let deleteEquipmentUrl = getNetworkModificationUrl(studyUuid, nodeUuid); if (modificationUuid) { deleteEquipmentUrl += '/' + encodeURIComponent(modificationUuid); diff --git a/src/services/study/short-circuit-analysis.ts b/src/services/study/short-circuit-analysis.ts index a830d83417..a1444c9583 100644 --- a/src/services/study/short-circuit-analysis.ts +++ b/src/services/study/short-circuit-analysis.ts @@ -59,7 +59,7 @@ function getShortCircuitUrl() { export function startShortCircuitAnalysis( studyUuid: string, currentNodeUuid: UUID | undefined, - currentRootNetworkUuid: UUID | undefined, + currentRootNetworkUuid: UUID | null, busId: string ) { console.info( From 8c31c7f6fb24723dfcf03cd2592649b056cf6381 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 6 Jan 2025 09:41:56 +0100 Subject: [PATCH 24/51] add currentRootnetworkUuid props, limit notifs Signed-off-by: souissimai --- src/components/diagrams/diagram-pane.tsx | 11 ++++++++--- .../single-line-diagram-content.tsx | 2 +- .../use-one-bus-shortcircuit-analysis-loader.tsx | 12 +++++++++--- .../modification/battery-modification-dialog.jsx | 1 + .../modification/generator-modification-dialog.jsx | 1 + .../vsc/modification/vsc-modification-dialog.tsx | 1 + .../line/modification/line-modification-dialog.jsx | 1 + .../load/modification/load-modification-dialog.jsx | 1 + .../shunt-compensator-modification-dialog.jsx | 1 + .../modification/substation-modification-dialog.jsx | 1 + .../two-windings-transformer-modification-dialog.jsx | 1 + .../voltage-level-modification-dialog.jsx | 1 + .../graph/menus/root-network-node-editor.tsx | 2 +- src/components/network/network-map-tab.tsx | 12 +++++++++--- src/components/spreadsheet/table-wrapper.tsx | 1 - src/services/root-network.ts | 12 ++++++------ src/services/study/network-modifications.ts | 2 +- 17 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index e31d069d87..c55e247c4f 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -799,17 +799,22 @@ export function DiagramPane({ // This effect will trigger the diagrams' forced update useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('???????? ', studyUpdatedForce.eventData.headers['updateType']); + if ( + studyUpdatedForce.eventData.headers['rootNetwork'] !== currentRootNetworkRef.current && + currentRootNetworkRef + ) { + return; + } if (studyUpdatedForce.eventData.headers['updateType'] === 'loadflowResult') { //TODO reload data more intelligently + updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'study') { // FM if we want to reload data more precisely, we need more information from notifications + updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'buildCompleted') { if (studyUpdatedForce.eventData.headers['node'] === currentNodeRef.current?.id) { - console.log(' ???????? buildCompleted ', studyUpdatedForce.eventData.headers['rootNetwork']); - updateDiagramsByCurrentNode(); } } diff --git a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx index c85f28d1a4..794b500aa5 100644 --- a/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx +++ b/src/components/diagrams/singleLineDiagram/single-line-diagram-content.tsx @@ -149,7 +149,7 @@ function SingleLineDiagramContent(props: SingleLineDiagramContentProps) { isDiagramRunningOneBusShortcircuitAnalysis, displayOneBusShortcircuitAnalysisLoader, resetOneBusShortcircuitAnalysisLoader, - ] = useOneBusShortcircuitAnalysisLoader(props.diagramId, currentNode?.id!); + ] = useOneBusShortcircuitAnalysisLoader(props.diagramId, currentNode?.id!, currentRootNetworkUuid!); // dynamic simulation event configuration states const [equipmentToConfigDynamicSimulationEvent, setEquipmentToConfigDynamicSimulationEvent] = diff --git a/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx b/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx index 7e97e3ec15..fdc1485673 100644 --- a/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx +++ b/src/components/diagrams/use-one-bus-shortcircuit-analysis-loader.tsx @@ -43,7 +43,11 @@ const styles = { //the first function submits the sld data on hand to the redux store and the second function reset the redux store state type oneBusShortcircuitAnalysisLoader = [ReactElement, boolean, () => void, () => void]; -export function useOneBusShortcircuitAnalysisLoader(diagramId: string, nodeId: UUID): oneBusShortcircuitAnalysisLoader { +export function useOneBusShortcircuitAnalysisLoader( + diagramId: string, + nodeId: UUID, + rootNetworkUuid: UUID +): oneBusShortcircuitAnalysisLoader { const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); const oneBusShortCircuitAnalysisDiagram = useSelector((state: AppState) => state.oneBusShortCircuitAnalysisDiagram); @@ -83,7 +87,9 @@ export function useOneBusShortcircuitAnalysisLoader(diagramId: string, nodeId: U useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); + if (studyUpdatedForce.eventData.headers['rootNetwork'] !== rootNetworkUuid) { + return; + } if ( studyUpdatedForce.eventData.headers['updateType'] === 'oneBusShortCircuitAnalysisResult' || studyUpdatedForce.eventData.headers['updateType'] === 'oneBusShortCircuitAnalysis_failed' @@ -91,7 +97,7 @@ export function useOneBusShortcircuitAnalysisLoader(diagramId: string, nodeId: U resetOneBusShortcircuitAnalysisLoader(); } } - }, [resetOneBusShortcircuitAnalysisLoader, studyUpdatedForce]); + }, [resetOneBusShortcircuitAnalysisLoader, studyUpdatedForce, rootNetworkUuid]); return [ oneBusShortcircuitAnalysisLoaderMessage, diff --git a/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx b/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx index f1d6d728e2..2d900b99d8 100644 --- a/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/battery/modification/battery-modification-dialog.jsx @@ -325,6 +325,7 @@ const BatteryModificationDialog = ({ = ({ studyUuid={studyUuid} currentNode={currentNode} defaultValue={equipmentId} + currentRootNetworkUuid={currentRootNetworkUuid} setSelectedId={setEquipmentId} equipmentType={EQUIPMENT_TYPES.HVDC_LINE} fillerHeight={17} diff --git a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx index 6e6ea529bd..d56187ef18 100644 --- a/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/line/modification/line-modification-dialog.jsx @@ -438,6 +438,7 @@ const LineModificationDialog = ({ { useEffect(() => { if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { - setMessageId('updateRootNetworksList'); // creatingRootNetwork to do distinct creation:deletion action on notification + setMessageId('updateRootNetworksList'); dofetchRootNetworks(); } } diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 880f1d300a..1e158b47a2 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -212,6 +212,7 @@ export const NetworkMapTab = ({ open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} isUpdate={true} defaultIdValue={equipmentToModify?.id} onClose={() => closeModificationDialog()} @@ -225,6 +226,7 @@ export const NetworkMapTab = ({ open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} isUpdate={true} defaultIdValue={equipmentToModify?.id} onClose={() => closeModificationDialog()} @@ -238,6 +240,7 @@ export const NetworkMapTab = ({ open={true} studyUuid={studyUuid} currentNode={currentNode} + currentRootNetworkUuid={currentRootNetworkUuid} defaultIdValue={equipmentToModify?.id} isUpdate={true} onClose={() => closeModificationDialog()} @@ -803,12 +806,15 @@ export const NetworkMapTab = ({ useEffect(() => { if (isInitialized && studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ', studyUpdatedForce); - if (studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult') { + const currentRootNetwork = studyUpdatedForce.eventData.headers['rootNetwork']; + if ( + studyUpdatedForce.eventData.headers[UPDATE_TYPE_HEADER] === 'loadflowResult' && + currentRootNetwork === currentRootNetworkUuid + ) { reloadMapEquipments(currentNodeRef.current, undefined); } } - }, [isInitialized, studyUpdatedForce, reloadMapEquipments]); + }, [isInitialized, studyUpdatedForce, currentRootNetworkUuid, reloadMapEquipments]); useEffect(() => { if (!mapEquipments || refIsMapManualRefreshEnabled.current) { diff --git a/src/components/spreadsheet/table-wrapper.tsx b/src/components/spreadsheet/table-wrapper.tsx index dbbc2ddfe4..3a57ff8554 100644 --- a/src/components/spreadsheet/table-wrapper.tsx +++ b/src/components/spreadsheet/table-wrapper.tsx @@ -1110,7 +1110,6 @@ const TableWrapper: FunctionComponent = ({ // After the modification has been applied, we need to update the equipment data in the grid useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== >>>>>> ££££ ', studyUpdatedForce.eventData.headers); if ( studyUpdatedForce.eventData.headers['updateType'] === 'UPDATE_FINISHED' && studyUpdatedForce.eventData.headers['parentNode'] === currentNode.id && diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 828602a618..221ce084cc 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -48,14 +48,14 @@ export const createRootNetwork = ( }; export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { - const urlSearchParams = new URLSearchParams(); - urlSearchParams.append('rootNetworkUuids', String(rootNetworkUuids)); const rootNetworkDeleteUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks`; - const modificationDeleteUrl = rootNetworkDeleteUrl + '?' + urlSearchParams.toString(); - - console.debug(modificationDeleteUrl); - return backendFetch(modificationDeleteUrl, { + console.debug(rootNetworkDeleteUrl); + return backendFetch(rootNetworkDeleteUrl, { method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(rootNetworkUuids), }); } diff --git a/src/services/study/network-modifications.ts b/src/services/study/network-modifications.ts index 53cef5f36f..1ca88c4af2 100644 --- a/src/services/study/network-modifications.ts +++ b/src/services/study/network-modifications.ts @@ -8,7 +8,7 @@ import { MODIFICATION_TYPES, EquipmentInfos, EquipmentType } from '@gridsuite/commons-ui'; import { toModificationOperation, toModificationUnsetOperation } from '../../components/utils/utils'; import { backendFetch, backendFetchJson, backendFetchText } from '../utils'; -import { getStudyUrlWithNodeUuid, getStudyUrlWithNodeUuidAndRootNetworkUuid, safeEncodeURIComponent } from './index'; +import { getStudyUrlWithNodeUuid, safeEncodeURIComponent } from './index'; import { EQUIPMENT_TYPES } from '../../components/utils/equipment-types'; import { BRANCH_SIDE, OPERATING_STATUS_ACTION } from '../../components/network/constants'; import { UUID } from 'crypto'; From c2b1605cdc479f738f0504eb0e12de3df50dd06b Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 6 Jan 2025 15:52:07 +0100 Subject: [PATCH 25/51] fixes Signed-off-by: souissimai --- src/components/computing-status/use-computing-status.ts | 1 - .../dynamic-simulation/event-modification-scenario-editor.tsx | 2 -- src/components/graph/menus/network-modification-node-editor.tsx | 1 - 3 files changed, 4 deletions(-) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index ac129ef7ec..9dbd3abdb5 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -168,7 +168,6 @@ export const useComputingStatus: UseComputingStatusProps = ( ) { return; } - console.log('!!!!!!!!!! fetcher ', fetcher); const isUpdateForUs = isWorthUpdate( studyUpdatedForce, fetcher, diff --git a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx index 4e4c03159f..4ebf6fbdde 100644 --- a/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx +++ b/src/components/graph/menus/dynamic-simulation/event-modification-scenario-editor.tsx @@ -142,8 +142,6 @@ const EventModificationScenarioEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { - console.log('TEST ====== ******', studyUpdatedForce.eventData.headers); - if (currentNodeIdRef.current !== studyUpdatedForce.eventData.headers['parentNode']) { return; } diff --git a/src/components/graph/menus/network-modification-node-editor.tsx b/src/components/graph/menus/network-modification-node-editor.tsx index a28e9d49b7..9d057245f3 100644 --- a/src/components/graph/menus/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modification-node-editor.tsx @@ -612,7 +612,6 @@ const NetworkModificationNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === 'nodeDeleted') { - console.log('TEST ====== OK', studyUpdatedForce.eventData.headers); if ( copyInfosRef.current && studyUpdatedForce.eventData.headers['nodes']?.some( From 971603070b9ef900c5a54b895256dc57f4672118 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 6 Jan 2025 15:54:45 +0100 Subject: [PATCH 26/51] add licence Signed-off-by: souissimai --- src/components/dialogs/import-case-dialog.tsx | 7 +++++++ src/components/graph/menus/root-network-editor.tsx | 2 +- src/services/root-network.ts | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/dialogs/import-case-dialog.tsx b/src/components/dialogs/import-case-dialog.tsx index e39a6ab2a2..0c2949231c 100644 --- a/src/components/dialogs/import-case-dialog.tsx +++ b/src/components/dialogs/import-case-dialog.tsx @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2024, 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 { useIntl } from 'react-intl'; import { ElementType, DirectoryItemSelector, TreeViewFinderNodeProps } from '@gridsuite/commons-ui'; import { FunctionComponent } from 'react'; diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index 62aa37c0ca..e31ccd625d 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021, RTE (http://www.rte-france.com) + * Copyright (c) 2024, 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/. diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 221ce084cc..4d31ced499 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023, RTE (http://www.rte-france.com) + * Copyright (c) 2024, 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/. From bd4de3bbce09b0f1fbf557cadf985afb4b4dd849 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 6 Jan 2025 15:59:07 +0100 Subject: [PATCH 27/51] license add Signed-off-by: souissimai --- src/components/dialogs/root-network-creation-dialog.tsx | 7 +++++++ src/components/root-network-panel.tsx | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index 4d3a93c2f5..fd07c21680 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2024, 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 { FormattedMessage, useIntl } from 'react-intl'; import { CustomFormProvider, diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx index 705fdfa2d6..bffa1e097b 100644 --- a/src/components/root-network-panel.tsx +++ b/src/components/root-network-panel.tsx @@ -1,3 +1,10 @@ +/** + * Copyright (c) 2024, 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 React, { FunctionComponent } from 'react'; import { Paper, Box } from '@mui/material'; import RootNetworkEditor from './graph/menus/root-network-editor'; From 92ab30781624af4dc9b33d9909b42e8ef33ffa23 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 6 Jan 2025 17:21:37 +0100 Subject: [PATCH 28/51] fix prettiers Signed-off-by: souissimai --- .../graph/menus/root-network-node-editor.tsx | 6 +++--- src/components/network/network-map-tab.tsx | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 0ac06ce291..872fd2c92a 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -121,7 +121,7 @@ const RootNetworkNodeEditor = () => { const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackInfo, snackError } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); - const [saveInProgress, setSaveInProgress] = useState(false); + // const [saveInProgress, setSaveInProgress] = useState(false); const [deleteInProgress, setDeleteInProgress] = useState(false); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); @@ -164,7 +164,7 @@ const RootNetworkNodeEditor = () => { useEffect(() => { if (studyUpdatedForce.eventData.headers) { if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { - setMessageId('updateRootNetworksList'); + setMessageId('updateRootNetworksList'); dofetchRootNetworks(); } } @@ -340,7 +340,7 @@ const RootNetworkNodeEditor = () => { } const doCreateRootNetwork = ({ name, caseName, caseId }: FormData) => { - setSaveInProgress(true); + // setSaveInProgress(true); getCaseImportParameters(caseId as UUID) .then((params: GetCaseImportParametersReturn) => { diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 71740ccc9a..128f50f019 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -589,6 +589,14 @@ export const NetworkMapTab = ({ updateLinesTemporaryGeoData, ]); + const handleChange = useCallback( + (newValues: unknown[]) => { + setFilteredNominalVoltages(newValues); + onNominalVoltagesChange(newValues); + }, + [setFilteredNominalVoltages, onNominalVoltagesChange] + ); + // loads all root node geo-data then saves them in redux // it will be considered as the source of truth to check whether we need to fetch geo-data for a specific equipment or not const loadRootNodeGeoData = useCallback(() => { @@ -645,6 +653,7 @@ export const NetworkMapTab = ({ dispatch, snackError, networkMapRef, + handleChange, ]); const loadGeoData = useCallback(() => { @@ -1047,11 +1056,6 @@ export const NetworkMapTab = ({ /> ); - function handleChange(newValues: unknown[]) { - setFilteredNominalVoltages(newValues); - onNominalVoltagesChange(newValues); - } - function renderNominalVoltageFilter() { return ( From 75f0e9724818a4825dddce8d67defd98192dfd8a Mon Sep 17 00:00:00 2001 From: souissimai Date: Tue, 7 Jan 2025 11:27:18 +0100 Subject: [PATCH 29/51] fix errors Signed-off-by: souissimai --- .../event/dynamic-simulation-event-dialog.tsx | 23 ++++++++++++++----- .../lcc/creation/lcc-creation-dialog.tsx | 7 +++++- .../lcc/creation/lcc-creation-form.tsx | 10 +++++++- .../vsc/creation/vsc-creation-form.tsx | 10 +++++++- .../modification/vsc-modification-dialog.tsx | 1 + .../modification/vsc-modification-from.tsx | 4 ++++ .../curve/dialog/model-filter.tsx | 2 +- .../sensi/sensitivity-analysis-parameters.tsx | 2 +- .../dialogs/root-network-creation-dialog.tsx | 3 +++ src/components/graph/menus/editable-title.tsx | 4 ++-- .../graph/menus/root-network-node-editor.tsx | 2 +- .../use-security-analysis-column-defs.tsx | 7 +++--- .../shortcircuit-analysis-result.tsx | 4 +++- .../utils/equipment-table-editors.tsx | 2 ++ .../custom-suffix-renderer.tsx | 12 +++++++--- 15 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/components/dialogs/dynamicsimulation/event/dynamic-simulation-event-dialog.tsx b/src/components/dialogs/dynamicsimulation/event/dynamic-simulation-event-dialog.tsx index cfb3921a52..b5ea5e4f95 100644 --- a/src/components/dialogs/dynamicsimulation/event/dynamic-simulation-event-dialog.tsx +++ b/src/components/dialogs/dynamicsimulation/event/dynamic-simulation-event-dialog.tsx @@ -38,6 +38,7 @@ export const DynamicSimulationEventDialog = (props: DynamicSimulationEventDialog const { snackError } = useSnackMessage(); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const currentNodeId = currentNode?.id; const [dataFetchStatus, setDataFetchStatus] = useState(FetchStatus.IDLE); const [event, setEvent] = useState(); @@ -86,15 +87,15 @@ export const DynamicSimulationEventDialog = (props: DynamicSimulationEventDialog // load event for equipment useEffect(() => { - if (!studyUuid || !currentNodeId) { + if (!studyUuid || !currentNodeId || !currentRootNetworkUuid) { return; } setDataFetchStatus(FetchStatus.RUNNING); - fetchDynamicSimulationEvent(studyUuid, currentNodeId, equipmentId).then((event) => { + fetchDynamicSimulationEvent(studyUuid, currentNodeId, currentRootNetworkUuid, equipmentId).then((event) => { setDataFetchStatus(FetchStatus.SUCCEED); setEvent(event); }); - }, [currentNodeId, equipmentId, studyUuid, reset]); + }, [currentNodeId, equipmentId, currentRootNetworkUuid, studyUuid, reset]); // reset form data when event available after fetch useEffect(() => { @@ -117,7 +118,7 @@ export const DynamicSimulationEventDialog = (props: DynamicSimulationEventDialog // submit form const handleSubmit = useCallback( (formObj: { [KEY in EventPropertyName]: any }) => { - if (!studyUuid || !currentNodeId) { + if (!studyUuid || !currentNodeId || !currentRootNetworkUuid) { return; } // formObj to EventProperty[] @@ -160,14 +161,24 @@ export const DynamicSimulationEventDialog = (props: DynamicSimulationEventDialog properties, }; - saveDynamicSimulationEvent(studyUuid, currentNodeId, submitEvent).catch((error) => { + saveDynamicSimulationEvent(studyUuid, currentNodeId, currentRootNetworkUuid, submitEvent).catch((error) => { snackError({ messageTxt: error.message, headerId: 'DynamicSimulationEventSaveError', }); }); }, - [currentNodeId, equipmentId, equipmentType, snackError, studyUuid, eventType, event, eventDefinition] + [ + currentNodeId, + equipmentId, + currentRootNetworkUuid, + equipmentType, + snackError, + studyUuid, + eventType, + event, + eventDefinition, + ] ); const waitingOpen = useOpenShortWaitFetching({ diff --git a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx index f321a38c1f..75463ba9d3 100644 --- a/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx +++ b/src/components/dialogs/network-modifications/hvdc-line/lcc/creation/lcc-creation-dialog.tsx @@ -270,7 +270,12 @@ export function LccCreationDialog({ }} {...dialogProps} > - + ) { +export default function LccCreationForm({ + tabIndex, + studyUuid, + currentRootNetworkUuid, + currentNode, +}: Readonly) { return ( <> diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx index bffa1e097b..dd457f9096 100644 --- a/src/components/root-network-panel.tsx +++ b/src/components/root-network-panel.tsx @@ -19,8 +19,8 @@ const styles = (theme: Theme) => ({ position: 'absolute', top: 16, left: 16, - width: '320px', - height: '420px', + width: '40%', + height: '40%', display: 'flex', flexDirection: 'column', borderRadius: '8px', diff --git a/src/translations/en.json b/src/translations/en.json index f1ea061180..ea93ddc5eb 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1459,7 +1459,10 @@ "rootNetworksCount":"{hide, select, false {{count, plural, =0 {aucun réseau racine} =1 {# réseau racine} other {# réseaux racine}}} other {...}}", "updateRootNetworksList": "Updating root network list ...", "deletingRootNetwork": "Deleting root network ...", - "creatingRootNetwork": "Creating root network ..." + "creatingRootNetwork": "Creating root network ...", + "rootNetworkCreated": "Root Network has been created successfully", + "errDeleteRootNetworkMsg": "Root Networks deletion error", + "warnDeleteCurrentRootNetwork" : "Current root network can not be delete" } diff --git a/src/translations/fr.json b/src/translations/fr.json index fb847a6708..c8cc0bdd92 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1461,7 +1461,10 @@ "rootNetworksCount":"{hide, select, false {{count, plural, =0 {no root network} =1 {{count} root network} other {{count} root networks}}} other {...}}", "updateRootNetworksList": "Mise à jour de la liste des réseaux racine cours ...", "deletingRootNetwork": "Suppression du réseau racine en cours ...", - "creatingRootNetwork": "Création du réseau racine en cours ..." + "creatingRootNetwork": "Création du réseau racine en cours ...", + "rootNetworkCreated": "Le réseau racine a été créé avec succès", + "errDeleteRootNetworkMsg": "Une erreur est survenue lors de la suppression des réseaux racine", + "warnDeleteCurrentRootNetwork": "Le réseau racine actuel ne peut pas être supprimé" } \ No newline at end of file From 99a6ea4a66424f1ce5fc46a95c6f970854f012a5 Mon Sep 17 00:00:00 2001 From: souissimai Date: Wed, 8 Jan 2025 20:46:07 +0100 Subject: [PATCH 32/51] do not fetch root networks when switching root network Signed-off-by: souissimai --- .../graph/menus/root-network-node-editor.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 2adb9d35e4..1d3038191c 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -122,7 +122,7 @@ const RootNetworkNodeEditor = () => { const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackInfo, snackError, snackWarning } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); - // const [saveInProgress, setSaveInProgress] = useState(false); + const [createInProgress, setCreateInProgress] = useState(false); const [deleteInProgress, setDeleteInProgress] = useState(false); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); @@ -172,11 +172,10 @@ const RootNetworkNodeEditor = () => { }, [studyUpdatedForce, dofetchRootNetworks]); useEffect(() => { - if (!currentRootNetwork) { - setRootNetworks([]); + if (rootNetworks.length === 0) { + dofetchRootNetworks(); } - dofetchRootNetworks(); - }, [currentRootNetwork, dofetchRootNetworks]); + }, [dofetchRootNetworks, rootNetworks]); const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); @@ -227,7 +226,7 @@ const RootNetworkNodeEditor = () => { if (!rootNetwork) { return ''; } - return intl.formatMessage({ id: 'RootNetwork' }) + ' ' + rootNetwork.rootNetworkUuid; + return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.rootNetworkUuid; }; const handleSecondaryAction = useCallback( @@ -365,7 +364,7 @@ const RootNetworkNodeEditor = () => { } const doCreateRootNetwork = ({ name, caseName, caseId }: FormData) => { - // setSaveInProgress(true); + setCreateInProgress(true); getCaseImportParameters(caseId as UUID) .then((params: GetCaseImportParametersReturn) => { @@ -388,6 +387,9 @@ const RootNetworkNodeEditor = () => { messageTxt: error.message, headerId: 'errCreateRootNetworksMsg', }); + }) + .finally(() => { + setCreateInProgress(false); }); }; const renderPaneSubtitle = () => { From 618d22e47aaf6b6e5bbe7e85b9861bdcd38245d5 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 9 Jan 2025 14:18:38 +0100 Subject: [PATCH 33/51] fix creation form voltage level Signed-off-by: souissimai --- .../creation/voltage-level-creation-dialog.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx index 690e2e0f17..a85e6a8a91 100644 --- a/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/voltage-level/creation/voltage-level-creation-dialog.jsx @@ -263,7 +263,11 @@ const VoltageLevelCreationDialog = ({ isDataFetching={isUpdate && editDataFetchStatus === FetchStatus.RUNNING} {...dialogProps} > - + Date: Thu, 9 Jan 2025 23:07:51 +0100 Subject: [PATCH 34/51] improve visual :panel Signed-off-by: souissimai --- src/components/graph/menus/editable-title.tsx | 17 +++--------- src/components/graph/menus/node-editor.tsx | 1 - .../graph/menus/root-network-editor.tsx | 26 ++++++++++++------- .../graph/menus/root-network-node-editor.tsx | 21 +++++++-------- src/translations/en.json | 2 +- src/translations/fr.json | 2 +- 6 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/components/graph/menus/editable-title.tsx b/src/components/graph/menus/editable-title.tsx index 7aa4089c61..3a1a4d44a7 100644 --- a/src/components/graph/menus/editable-title.tsx +++ b/src/components/graph/menus/editable-title.tsx @@ -40,30 +40,19 @@ interface EditableTitleProps { name: string; onClose: () => void; onChange?: (value: string) => void; - isCloseIconVisible?: boolean; } -export const EditableTitle: FunctionComponent = ({ - name, - isCloseIconVisible = true, - onClose, - onChange, -}) => { +export const EditableTitle: FunctionComponent = ({ name, onClose, onChange }) => { const [openEditTitle, setOpenEditTitle] = useState(false); const intl = useIntl(); return ( - setOpenEditTitle(true)} - disabled={onChange === undefined} - > + setOpenEditTitle(true)} disabled={onChange === undefined}> - + { name={currentTreeNode?.data?.label ?? ''} onClose={closeModificationsDrawer} onChange={changeNodeName} - isCloseIconVisible={true} /> diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index e16612c4c2..82a127915d 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -7,10 +7,12 @@ import PropTypes from 'prop-types'; import { EditableTitle } from './editable-title'; -import { Box } from '@mui/material'; +import { Box, Theme } from '@mui/material'; import { AppState } from '../../../redux/reducer'; import RootNetworkNodeEditor from './root-network-node-editor'; import { useSelector } from 'react-redux'; +import { OverflowableText } from '@gridsuite/commons-ui'; +import { useIntl } from 'react-intl'; const styles = { paper: () => ({ @@ -19,20 +21,26 @@ const styles = { flexDirection: 'column', elevation: 3, }), + header: (theme: Theme) => ({ + padding: theme.spacing(1), + display: 'flex', + alignItems: 'center', + }), + rootNameTitle: (theme: Theme) => ({ + flexGrow: 1, + fontWeight: 'bold', + marginLeft: theme.spacing(2), + }), }; const RootNetworkEditor = () => { - const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); - - const closeModificationsDrawer = () => {}; + const intl = useIntl(); return ( - + + + ); diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 1d3038191c..c8251086d4 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -40,10 +40,9 @@ export const styles = { flexGrow: 1, paddingBottom: theme.spacing(8), }), - listItem: { paddingLeft: 0, paddingTop: 0, paddingBottom: 0 }, checkBoxLabel: { flexGrow: '1' }, disabledRootNetwork: { opacity: 0.4 }, - checkBoxIcon: { minWidth: 0, padding: 0 }, + checkBoxIcon: { minWidth: 0, padding: 0, marginLeft: 2 }, checkboxButton: { padding: 0.5, margin: 0, @@ -52,12 +51,12 @@ export const styles = { }, rootNetworksTitle: (theme: Theme) => ({ display: 'flex', - alignItems: 'center', - margin: theme.spacing(0), + marginLeft: 2, padding: theme.spacing(1), - backgroundColor: theme.palette.primary.main, - color: theme.palette.primary.contrastText, overflow: 'hidden', + borderTop: `1px solid ${theme.palette.divider}`, + borderBottom: `1px solid ${theme.palette.divider}`, + marginRight: '8px', }), toolbar: (theme: Theme) => ({ '&': { @@ -66,7 +65,6 @@ export const styles = { minHeight: 0, }, border: theme.spacing(1), - margin: 0, flexShrink: 0, }), toolbarIcon: (theme: Theme) => ({ @@ -234,10 +232,9 @@ const RootNetworkNodeEditor = () => { const isCurrentRootNetwork = rootNetwork.rootNetworkUuid === currentRootNetwork; return ( - + { if (rootNetwork.rootNetworkUuid !== currentRootNetwork) { dispatch(setCurrentRootNetwork(rootNetwork.rootNetworkUuid)); @@ -422,7 +419,7 @@ const RootNetworkNodeEditor = () => { onClick={openRootNetworkCreationDialog} size={'small'} sx={styles.toolbarIcon} - disabled={false} //TODO + disabled={rootNetworks.length >= 3} > @@ -433,7 +430,9 @@ const RootNetworkNodeEditor = () => { onClick={doDeleteRootNetwork} size={'small'} sx={styles.toolbarIcon} - disabled={selectedItems.length === 0 || !currentNode} + disabled={ + selectedItems.length === 0 || !currentNode || rootNetworks.length === selectedItems.length + } > diff --git a/src/translations/en.json b/src/translations/en.json index ea93ddc5eb..2a2e17bdea 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1456,7 +1456,7 @@ "StateEstimationStatus": "Status : ", "StateEstimationQuality": "Quality : ", "Or": "or", - "rootNetworksCount":"{hide, select, false {{count, plural, =0 {aucun réseau racine} =1 {# réseau racine} other {# réseaux racine}}} other {...}}", + "rootNetworksCount":"{hide, select, false {{count, plural, =0 {no root} =1 {{count} Root} other {{count} Roots}}} other {...}}", "updateRootNetworksList": "Updating root network list ...", "deletingRootNetwork": "Deleting root network ...", "creatingRootNetwork": "Creating root network ...", diff --git a/src/translations/fr.json b/src/translations/fr.json index c8cc0bdd92..f543a2e491 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1458,7 +1458,7 @@ "StateEstimationStatus": "Statut : ", "StateEstimationQuality": "Qualité: ", "Or": "ou", - "rootNetworksCount":"{hide, select, false {{count, plural, =0 {no root network} =1 {{count} root network} other {{count} root networks}}} other {...}}", + "rootNetworksCount":"{hide, select, false {{count, plural, =0 {aucun réseau} =1 {# Réseau} other {# Réseaux}}} other {...}}", "updateRootNetworksList": "Mise à jour de la liste des réseaux racine cours ...", "deletingRootNetwork": "Suppression du réseau racine en cours ...", "creatingRootNetwork": "Création du réseau racine en cours ...", From 2b4216360cc4430edb4b7dc3fee25d0696511e96 Mon Sep 17 00:00:00 2001 From: souissimai Date: Sun, 12 Jan 2025 22:06:39 +0100 Subject: [PATCH 35/51] load status only for current rootnetwork when needed Signed-off-by: souissimai --- src/components/computing-status/use-computing-status.ts | 4 ++++ src/components/study-container.jsx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/components/computing-status/use-computing-status.ts b/src/components/computing-status/use-computing-status.ts index cf9207e1c3..c0dc366112 100644 --- a/src/components/computing-status/use-computing-status.ts +++ b/src/components/computing-status/use-computing-status.ts @@ -49,12 +49,16 @@ function isWorthUpdate( const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; const nodes = headers?.['nodes']; + const rootNetworkUuid = studyUpdatedForce?.eventData?.headers?.['rootNetwork']; if (nodeUuidRef.current !== nodeUuid) { return true; } if (rootNetworkUuidRef.current !== currentRootNetworkUuid) { return true; } + if (rootNetworkUuid && rootNetworkUuid !== currentRootNetworkUuid) { + return false; + } if (fetcher && lastUpdateRef.current?.fetcher !== fetcher) { return true; } diff --git a/src/components/study-container.jsx b/src/components/study-container.jsx index 459294497f..397813e805 100644 --- a/src/components/study-container.jsx +++ b/src/components/study-container.jsx @@ -65,7 +65,11 @@ function isWorthUpdate( const updateType = headers?.[UPDATE_TYPE_HEADER]; const node = headers?.['node']; const nodes = headers?.['nodes']; + const rootNetworkFromNotif = headers?.['rootNetwork']; + if (rootNetworkFromNotif && rootNetworkFromNotif !== rootNetworkUuid) { + return false; + } if (nodeUuidRef.current !== nodeUuid) { return true; } From a1fa4decd291159709aa3070e5b244895be240b1 Mon Sep 17 00:00:00 2001 From: souissimai Date: Sun, 12 Jan 2025 22:08:11 +0100 Subject: [PATCH 36/51] failed modification apply for diffrent root networks Signed-off-by: souissimai --- src/hooks/use-get-study-impacts.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hooks/use-get-study-impacts.ts b/src/hooks/use-get-study-impacts.ts index 090f7d3050..910e9bb178 100644 --- a/src/hooks/use-get-study-impacts.ts +++ b/src/hooks/use-get-study-impacts.ts @@ -20,6 +20,7 @@ interface StudyImpactsWithReset extends NetworkImpactsInfos { */ export const useGetStudyImpacts = (): StudyImpactsWithReset => { const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); + const currentRootNetworkUuid = useSelector((state: AppState) => state.currentRootNetwork); const dispatch = useDispatch(); const [impactedSubstationsIds, setImpactedSubstationsIds] = useState([]); @@ -40,7 +41,10 @@ export const useGetStudyImpacts = (): StudyImpactsWithReset => { useEffect(() => { if (studyUpdatedForce.type === NotificationType.STUDY) { - console.log('TEST ====== ', studyUpdatedForce); + const rootNetworkUuid = studyUpdatedForce?.eventData?.headers?.['rootNetwork']; + if (rootNetworkUuid && rootNetworkUuid !== currentRootNetworkUuid) { + return; + } const { impactedSubstationsIds: substationsIds, deletedEquipments, @@ -60,7 +64,7 @@ export const useGetStudyImpacts = (): StudyImpactsWithReset => { setImpactedSubstationsIds(substationsIds); } } - }, [dispatch, studyUpdatedForce]); + }, [dispatch, studyUpdatedForce, currentRootNetworkUuid]); return { impactedSubstationsIds, From e97f1a4e090fee2098fa2e2956d4a5a7784bb7d4 Mon Sep 17 00:00:00 2001 From: souissimai Date: Sun, 12 Jan 2025 22:09:25 +0100 Subject: [PATCH 37/51] fixed : panel root network Signed-off-by: souissimai --- .../graph/menus/root-network-editor.tsx | 3 -- .../graph/menus/root-network-node-editor.tsx | 29 +++++++++---------- src/components/result-view-tab.tsx | 1 - src/translations/en.json | 3 +- src/translations/fr.json | 4 +-- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx index 82a127915d..54f9c7da11 100644 --- a/src/components/graph/menus/root-network-editor.tsx +++ b/src/components/graph/menus/root-network-editor.tsx @@ -6,11 +6,8 @@ */ import PropTypes from 'prop-types'; -import { EditableTitle } from './editable-title'; import { Box, Theme } from '@mui/material'; -import { AppState } from '../../../redux/reducer'; import RootNetworkNodeEditor from './root-network-node-editor'; -import { useSelector } from 'react-redux'; import { OverflowableText } from '@gridsuite/commons-ui'; import { useIntl } from 'react-intl'; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index c8251086d4..a292a9bc2a 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -51,7 +51,6 @@ export const styles = { }, rootNetworksTitle: (theme: Theme) => ({ display: 'flex', - marginLeft: 2, padding: theme.spacing(1), overflow: 'hidden', borderTop: `1px solid ${theme.palette.divider}`, @@ -118,7 +117,7 @@ export function isPartial(s1: number, s2: number) { const RootNetworkNodeEditor = () => { const notificationIdList = useSelector((state: AppState) => state.notificationIdList); const studyUuid = useSelector((state: AppState) => state.studyUuid); - const { snackInfo, snackError, snackWarning } = useSnackMessage(); + const { snackInfo, snackError } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); const [createInProgress, setCreateInProgress] = useState(false); const [deleteInProgress, setDeleteInProgress] = useState(false); @@ -181,16 +180,19 @@ const RootNetworkNodeEditor = () => { const doDeleteRootNetwork = useCallback(() => { const selectedRootNetworksUuid = selectedItems.map((item) => item.rootNetworkUuid); - const itemsToDelete = selectedRootNetworksUuid.filter((uuid) => uuid !== currentRootNetwork); - - // If there are no items to delete, show warning - if (itemsToDelete.length === 0) { - snackWarning({ headerId: 'warnDeleteCurrentRootNetwork' }); - return; - } if (studyUuid && currentRootNetwork) { - deleteRootNetworks(studyUuid, itemsToDelete) + if (selectedRootNetworksUuid.length === 1) { + // Find the first root network in the list that is not being deleted + const newRootNetwork = rootNetworks.find( + (network) => network.rootNetworkUuid !== selectedRootNetworksUuid[0] + ); + if (newRootNetwork) { + dispatch(setCurrentRootNetwork(newRootNetwork.rootNetworkUuid)); + } + } + + deleteRootNetworks(studyUuid, selectedRootNetworksUuid) .then(() => { setDeleteInProgress(true); }) @@ -202,14 +204,9 @@ const RootNetworkNodeEditor = () => { }) .finally(() => { setDeleteInProgress(false); - if (selectedRootNetworksUuid.includes(currentRootNetwork)) { - snackWarning({ - headerId: 'warnDeleteCurrentRootNetwork', - }); - } }); } - }, [selectedItems, snackError, snackWarning, studyUuid, currentRootNetwork]); + }, [selectedItems, dispatch, rootNetworks, snackError, studyUuid, currentRootNetwork]); const toggleSelectAllRootNetworks = useCallback(() => { setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); diff --git a/src/components/result-view-tab.tsx b/src/components/result-view-tab.tsx index 6061a10e39..8278d67f56 100644 --- a/src/components/result-view-tab.tsx +++ b/src/components/result-view-tab.tsx @@ -142,7 +142,6 @@ export const ResultViewTab: FunctionComponent = ({ }, [studyUuid, currentNode, currentRootNetworkUuid]); const renderNonEvacuatedEnergyResult = useMemo(() => { - console.log('ùùùùùù renderNonEvacuatedEnergyResult ', currentRootNetworkUuid); return ( Date: Tue, 14 Jan 2025 10:39:54 +0100 Subject: [PATCH 38/51] fix: prevent multiple load of elements when changing root network Signed-off-by: LE SAULNIER Kevin --- .../graph/menus/root-network-node-editor.tsx | 13 +++--- src/components/network/network-map-tab.tsx | 40 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index a292a9bc2a..88226c2e2d 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -7,11 +7,14 @@ import { CheckBoxList, ElementType, Parameter, useSnackMessage } from '@gridsuite/commons-ui'; -import FileUpload from '@mui/icons-material/FileUpload'; +import { + FileUpload, + Delete as DeleteIcon, + RemoveRedEye as RemoveRedEyeIcon, + VisibilityOff as VisibilityOffIcon, +} from '@mui/icons-material'; -import DeleteIcon from '@mui/icons-material/Delete'; -import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography, Badge } from '@mui/material'; -import IconButton from '@mui/material/IconButton'; +import { Box, Checkbox, CircularProgress, Theme, Toolbar, Tooltip, Typography, Badge, IconButton } from '@mui/material'; import { useCallback, useEffect, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -27,8 +30,6 @@ import { getCaseImportParameters, } from 'services/network-conversion'; import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; -import RemoveRedEyeIcon from '@mui/icons-material/RemoveRedEye'; -import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import { setCurrentRootNetwork } from 'redux/actions'; import RootNetworkCreationDialog, { FormData } from 'components/dialogs/root-network-creation-dialog'; diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 128f50f019..c9af59f1a2 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -157,7 +157,6 @@ export const NetworkMapTab = ({ const basicDataReady = mapEquipments && geoData; const lineFullPathRef = useRef(); - const rootNetworkRef = useRef(); /* This Set stores the geo data that are collected from the server AFTER the initialization. @@ -191,6 +190,7 @@ export const NetworkMapTab = ({ const [position, setPosition] = useState([-1, -1]); const currentNodeRef = useRef(null); + const currentRootNetworkUuidRef = useRef(null); const [updatedLines, setUpdatedLines] = useState([]); const [updatedTieLines, setUpdatedTieLines] = useState([]); const [updatedHvdcLines, setUpdatedHvdcLines] = useState([]); @@ -432,18 +432,18 @@ export const NetworkMapTab = ({ equipmentIds: string[] ) => Promise ) => { - if (notFoundEquipmentsIds.length === 0 || !currentNodeRef.current) { + if (notFoundEquipmentsIds.length === 0 || !currentNodeRef.current || !currentRootNetworkUuidRef.current) { return Promise.resolve([]); } return fetchEquipmentCB( studyUuid, currentNodeRef.current!.id, - currentRootNetworkUuid, + currentRootNetworkUuidRef.current, notFoundEquipmentsIds ); }, - [studyUuid, currentRootNetworkUuid] + [studyUuid] ); const updateSubstationsTemporaryGeoData = useCallback( @@ -577,6 +577,7 @@ export const NetworkMapTab = ({ }); } }, [ + geoData, dispatch, lineFullPath, snackError, @@ -626,7 +627,7 @@ export const NetworkMapTab = ({ Promise.all([substationPositionsDone, linePositionsDone]) .then(() => { temporaryGeoDataIdsRef.current = new Set(); - networkMapRef.current?.centerMapNetwork(); + networkMapRef.current?.resetZoomAndPosition(); // when reloading root node map equipments (when switching of root network), nominal voltages are reloaded // we check them all in NominalVoltageFilter by default if (mapEquipments) { @@ -752,10 +753,13 @@ export const NetworkMapTab = ({ } }); return Promise.all([updatedSubstations, updatedLines, updatedTieLines, updatedHvdcLines]).finally(() => { + if (mapEquipments) { + handleChange(mapEquipments.getNominalVoltages()); + } dispatch(setMapDataLoading(false)); }); }, - [currentNode, currentRootNetworkUuid, dispatch, mapEquipments, studyUuid] + [currentNode, handleChange, currentRootNetworkUuid, dispatch, mapEquipments, studyUuid] ); const updateMapEquipments = useCallback( @@ -850,6 +854,8 @@ export const NetworkMapTab = ({ useEffect(() => { let previousCurrentNode = currentNodeRef.current; currentNodeRef.current = currentNode; + let previousCurrentRootNetworkUuid = currentRootNetworkUuidRef.current; + currentRootNetworkUuidRef.current = currentRootNetworkUuid; let previousNodeStatus = isCurrentNodeBuiltRef.current; isCurrentNodeBuiltRef.current = isNodeBuilt(currentNode); // if only renaming, do not reload geo data @@ -872,15 +878,20 @@ export const NetworkMapTab = ({ // load default node map equipments loadMapEquipments(); } - if (!isRootNodeGeoDataLoaded) { + if (!isRootNodeGeoDataLoaded || previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { // load root node geodata loadRootNodeGeoData(); + //TODO: kevin make it cleaner + if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { + return; + } } // manual reload if (refIsMapManualRefreshEnabled.current && isInitialized) { // this reloads the mapEquipments when, in manual refresh mode, the current node is built. if ( isSameNode(previousCurrentNode, currentNode) && // must be the same node + previousCurrentRootNetworkUuid === currentRootNetworkUuid && // must be the same root network !previousNodeStatus && // must change from unbuilt ... isCurrentNodeBuiltRef.current // ... to built ) { @@ -897,6 +908,7 @@ export const NetworkMapTab = ({ disabled, studyUuid, currentNode, + currentRootNetworkUuid, loadMapEquipments, updateMapEquipmentsAndGeoData, loadRootNodeGeoData, @@ -924,20 +936,6 @@ export const NetworkMapTab = ({ } }, [isInitialized, lineFullPath, loadGeoData, currentRootNetworkUuid]); - // Effect to handle changes in currentRootNetworkUuid - useEffect(() => { - const prevRootNetworkPath = rootNetworkRef.current; - rootNetworkRef.current = currentRootNetworkUuid; - - if (currentRootNetworkUuid && currentRootNetworkUuid !== prevRootNetworkPath && rootNodeId) { - loadRootNodeGeoData(); - // set initialized to false to trigger "missing geo-data fetching" - setInitialized(false); - // set isRootNodeGeoDataLoaded to false so "missing geo-data fetching" waits for root node geo-data to be fully fetched before triggering - setIsRootNodeGeoDataLoaded(false); - } - }, [currentRootNetworkUuid, loadRootNodeGeoData, rootNodeId]); - let choiceVoltageLevelsSubstation: EquipmentMap | null = null; if (choiceVoltageLevelsSubstationId) { choiceVoltageLevelsSubstation = mapEquipments?.getSubstation(choiceVoltageLevelsSubstationId); From 590122852482ff9810ffdb66d27efaf27a298c05 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Tue, 14 Jan 2025 15:10:39 +0100 Subject: [PATCH 39/51] fix: add name to root network creation Signed-off-by: LE SAULNIER Kevin --- .../dialogs/root-network-creation-dialog.tsx | 5 +++-- .../graph/menus/root-network-node-editor.tsx | 10 +++++++-- src/services/root-network.ts | 22 ++++++++++--------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index a1ed735034..3afe9251de 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -25,6 +25,7 @@ import { useSelector } from 'react-redux'; import BasicModificationDialog from './commons/basicModificationDialog'; import { AppState } from 'redux/reducer'; import ImportCaseDialog from './import-case-dialog'; +import ModificationDialog from './commons/modificationDialog'; export interface FormData { [NAME]: string; @@ -184,7 +185,7 @@ const RootNetworkCreationDialog: React.FC = ({ return ( - = ({ onClose={() => setCaseSelectorOpen(false)} onSelectCase={onSelectCase} /> - + ); }; diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 88226c2e2d..d37c20273f 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -222,7 +222,7 @@ const RootNetworkNodeEditor = () => { if (!rootNetwork) { return ''; } - return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.rootNetworkUuid; + return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.name; }; const handleSecondaryAction = useCallback( @@ -367,7 +367,13 @@ const RootNetworkNodeEditor = () => { const formattedParams = formatCaseImportParameters(params.parameters); const customizedCurrentParameters = customizeCurrentParameters(formattedParams as Parameter[]); // Call createRootNetwork with formatted parameters - return createRootNetwork(caseId as UUID, params.formatName, studyUuid, customizedCurrentParameters); + return createRootNetwork( + caseId as UUID, + params.formatName, + name, + studyUuid, + customizedCurrentParameters + ); }) .then(() => { snackInfo({ diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 4d31ced499..081829726d 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -12,30 +12,32 @@ export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; export function fetchRootNetworks(studyUuid: UUID) { console.info('Fetching root network for studyUuid : ', studyUuid); - const urlSearchParams = new URLSearchParams(); - const rootNetworkssGetUrl = - `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks` + - urlSearchParams.toString(); + const rootNetworksGetUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks`; - console.debug(rootNetworkssGetUrl); - return backendFetchJson(rootNetworkssGetUrl); + console.debug(rootNetworksGetUrl); + return backendFetchJson(rootNetworksGetUrl); } export const createRootNetwork = ( caseUuid: UUID | undefined, caseFormat: string, + rootNetworkName: string, studyUuid: UUID | null, importParameters: Record ) => { - if (!studyUuid || !caseUuid) { - throw new Error('studyUuid and caseUuid are required parameters.'); + if (!studyUuid || !caseUuid || !rootNetworkName) { + throw new Error('rootNetworkName, studyUuid and caseUuid are required parameters.'); } + const urlSearchParams = new URLSearchParams(); + urlSearchParams.append('caseUuid', caseUuid); + urlSearchParams.append('caseFormat', caseFormat); + urlSearchParams.append('name', rootNetworkName); + const createRootNetworkUrl = PREFIX_STUDY_QUERIES + `/v1/studies/${encodeURIComponent(studyUuid)}/root-networks?` + - `caseUuid=${encodeURIComponent(caseUuid)}&` + - `caseFormat=${encodeURIComponent(caseFormat)}`; + urlSearchParams.toString(); console.debug(createRootNetworkUrl); return backendFetch(createRootNetworkUrl, { From 33b89b0a3540f79a6f76fc98a04de26dd7b98317 Mon Sep 17 00:00:00 2001 From: souissimai Date: Wed, 15 Jan 2025 00:12:41 +0100 Subject: [PATCH 40/51] refactor + css clean Signed-off-by: souissimai --- .../graph/menus/root-network-editor.tsx | 50 ------------------- src/components/network-modification-tree.jsx | 2 +- src/components/root-network-panel.tsx | 47 +++++++++-------- 3 files changed, 28 insertions(+), 71 deletions(-) delete mode 100644 src/components/graph/menus/root-network-editor.tsx diff --git a/src/components/graph/menus/root-network-editor.tsx b/src/components/graph/menus/root-network-editor.tsx deleted file mode 100644 index 54f9c7da11..0000000000 --- a/src/components/graph/menus/root-network-editor.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2024, 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 PropTypes from 'prop-types'; -import { Box, Theme } from '@mui/material'; -import RootNetworkNodeEditor from './root-network-node-editor'; -import { OverflowableText } from '@gridsuite/commons-ui'; -import { useIntl } from 'react-intl'; - -const styles = { - paper: () => ({ - height: '100%', - display: 'flex', - flexDirection: 'column', - elevation: 3, - }), - header: (theme: Theme) => ({ - padding: theme.spacing(1), - display: 'flex', - alignItems: 'center', - }), - rootNameTitle: (theme: Theme) => ({ - flexGrow: 1, - fontWeight: 'bold', - marginLeft: theme.spacing(2), - }), -}; - -const RootNetworkEditor = () => { - const intl = useIntl(); - - return ( - - - - - - - ); -}; - -RootNetworkEditor.propTypes = { - className: PropTypes.string, -}; - -export default RootNetworkEditor; diff --git a/src/components/network-modification-tree.jsx b/src/components/network-modification-tree.jsx index 497d5d7988..4313050fb1 100644 --- a/src/components/network-modification-tree.jsx +++ b/src/components/network-modification-tree.jsx @@ -358,7 +358,7 @@ const NetworkModificationTree = ({ {isMinimapOpen && } {/* root Network Panel */} - + ); diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx index dd457f9096..2414e595d0 100644 --- a/src/components/root-network-panel.tsx +++ b/src/components/root-network-panel.tsx @@ -6,42 +6,49 @@ */ import React, { FunctionComponent } from 'react'; -import { Paper, Box } from '@mui/material'; -import RootNetworkEditor from './graph/menus/root-network-editor'; -import { Theme } from '@mui/material/styles'; +import { Paper, Box, Theme } from '@mui/material'; +import { OverflowableText } from '@gridsuite/commons-ui'; +import { useIntl } from 'react-intl'; +import RootNetworkNodeEditor from './graph/menus/root-network-node-editor'; -type RootNetworkPanelProps = { - studyId: string; -}; - -const styles = (theme: Theme) => ({ +const styles = { paper: { position: 'absolute', top: 16, left: 16, - width: '40%', - height: '40%', - display: 'flex', + width: '300px', + height: '300px', flexDirection: 'column', borderRadius: '8px', - boxShadow: '0 6px 15px rgba(0,0,0,0.15)', // Softer shadow + boxShadow: '0 6px 15px rgba(0,0,0,0.15)', zIndex: 10, - overflow: 'hidden', // Ensure no overflow + overflow: 'hidden', }, contentBox: { - flex: 1, // Take up all available space display: 'flex', flexDirection: 'column', - position: 'relative', // Enable absolute positioning for child elements + position: 'relative', }, -}); + header: (theme: Theme) => ({ + padding: theme.spacing(1), + display: 'flex', + alignItems: 'center', + }), + rootNameTitle: (theme: Theme) => ({ + flexGrow: 1, + fontWeight: 'bold', + marginLeft: theme.spacing(2), + }), +}; +const RootNetworkPanel: FunctionComponent = () => { + const intl = useIntl(); -const RootNetworkPanel: FunctionComponent = ({ studyId }) => { return ( - styles(theme).paper}> - styles(theme).contentBox}> - + + + + ); }; From 9d850fab0ff829d32caf3af683fee6539c2ad223 Mon Sep 17 00:00:00 2001 From: souissimai Date: Wed, 15 Jan 2025 09:51:15 +0100 Subject: [PATCH 41/51] fix prettiers + current node when switching currentrootnetwork Signed-off-by: souissimai --- .../dialogs/root-network-creation-dialog.tsx | 3 +-- .../graph/menus/network-modification-menu.type.ts | 1 + src/components/network/network-map-tab.tsx | 4 ++++ src/components/study-container.jsx | 15 ++++++++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index 3afe9251de..ad374fdc0d 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -22,7 +22,6 @@ import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import yup from '../utils/yup-config'; import { useSelector } from 'react-redux'; -import BasicModificationDialog from './commons/basicModificationDialog'; import { AppState } from 'redux/reducer'; import ImportCaseDialog from './import-case-dialog'; import ModificationDialog from './commons/modificationDialog'; @@ -207,7 +206,7 @@ const RootNetworkCreationDialog: React.FC = ({ autoFocus /> - {type === ElementType.ROOT_NETWORK && caseSelection} + {caseSelection} { console.info(`Loading network modification tree of study '${studyUuid}'...`); @@ -530,6 +532,14 @@ export function StudyContainer({ view, onChangeTab }) { }); }); + if (previousCurrentRootNetwork !== currentRootNetworkUuid && currentNode) { + const ModelLastSelectedNode = { + ...networkModificationTreeModel.treeNodes.find((node) => node.id === currentNode?.id), + }; + dispatch(setCurrentTreeNode(ModelLastSelectedNode)); + return; + } + // Select root node by default let firstSelectedNode = getFirstNodeOfType(tree, NodeType.ROOT); // if reindexation is ongoing then stay on root node, all variants will be removed @@ -559,7 +569,7 @@ export function StudyContainer({ view, onChangeTab }) { .finally(() => console.debug('Network modification tree loading finished')); // Note: studyUuid and dispatch don't change }, - [studyUuid, currentRootNetworkUuid, dispatch, snackError, snackWarning] + [studyUuid, currentRootNetworkUuid, currentNode, previousCurrentRootNetwork, dispatch, snackError, snackWarning] ); const checkStudyIndexation = useCallback(() => { @@ -703,7 +713,6 @@ export function StudyContainer({ view, onChangeTab }) { let previousCurrentNode = currentNodeRef.current; currentNodeRef.current = currentNode; - let previousCurrentRootNetwork = currentRootNetworkRef.current; currentRootNetworkRef.current = currentRootNetworkUuid; // if only node renaming, do not reload network if (isNodeRenamed(previousCurrentNode, currentNode)) { @@ -722,7 +731,7 @@ export function StudyContainer({ view, onChangeTab }) { return; } dispatch(resetEquipments()); - }, [currentNode, currentRootNetworkUuid, wsConnected, dispatch]); + }, [currentNode, currentRootNetworkUuid, previousCurrentRootNetwork, wsConnected, dispatch]); useEffect(() => { if (studyUpdatedForce.eventData.headers) { From a82a9040676cee2c86b71f87e4277d84a6e739e4 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 16 Jan 2025 11:35:04 +0100 Subject: [PATCH 42/51] create dialog with input check existance name Signed-off-by: souissimai --- .../commons/unique-check--name-input.tsx | 128 ++++++++++++++++++ .../dialogs/root-network-creation-dialog.tsx | 113 +++++----------- .../graph/menus/root-network-node-editor.tsx | 3 +- src/services/root-network.ts | 28 ++++ src/translations/en.json | 3 +- src/translations/fr.json | 4 +- 6 files changed, 192 insertions(+), 87 deletions(-) create mode 100644 src/components/dialogs/commons/unique-check--name-input.tsx diff --git a/src/components/dialogs/commons/unique-check--name-input.tsx b/src/components/dialogs/commons/unique-check--name-input.tsx new file mode 100644 index 0000000000..42dc3ddd46 --- /dev/null +++ b/src/components/dialogs/commons/unique-check--name-input.tsx @@ -0,0 +1,128 @@ +import { ChangeEvent, FunctionComponent, useCallback, useEffect } from 'react'; +import { useDebounce } from '@gridsuite/commons-ui'; +import { FormattedMessage } from 'react-intl'; +import { InputAdornment, TextFieldProps } from '@mui/material'; +import CheckIcon from '@mui/icons-material/Check'; +import { useController, useFormContext } from 'react-hook-form'; +import CircularProgress from '@mui/material/CircularProgress'; +import TextField from '@mui/material/TextField'; +import { UUID } from 'crypto'; + +interface UniqueCheckNameInputProps { + name: string; + label?: string; + studyUuid: UUID | null; + elementExists: (studyUuid: UUID, elementName: string) => Promise; + + autoFocus?: boolean; + onManualChangeCallback?: () => void; + formProps?: Omit< + TextFieldProps, + 'value' | 'onChange' | 'name' | 'label' | 'inputRef' | 'inputProps' | 'InputProps' + >; +} + +/** + * Input component that constantly checks if the field's value is available or not + */ +export const UniqueCheckNameInput: FunctionComponent = (props) => { + const { + field: { onChange, onBlur, value, name, ref }, + fieldState: { error, isDirty }, + } = useController({ + name: props.name, + }); + + const { + setError, + clearErrors, + formState: { errors }, + } = useFormContext(); + + // This is a trick to share the custom validation state among the form: while this error is present, we can't validate the form + const isValidating = errors.root?.isValidating; + + const handleCheckName = useCallback( + (value: string) => { + if (value && props.studyUuid) { + props + .elementExists(props.studyUuid, value) + .then((alreadyExist) => { + if (alreadyExist) { + setError(props.name, { + type: 'validate', + message: 'nameAlreadyUsed', + }); + } + }) + .catch((error) => { + setError(props.name, { + type: 'validate', + message: 'rootNetworknameValidityCheckErrorMsg', + }); + console.error(error?.message); + }) + .finally(() => { + clearErrors('root.isValidating'); + }); + } + }, + [setError, clearErrors, props] + ); + + const debouncedHandleCheckName = useDebounce(handleCheckName, 700); + + // We have to use an useEffect because the name can change from outside of this component (e.g. when a case file is uploaded) + useEffect(() => { + // if the name is unchanged, we don't do custom validation + const trimmedValue = value.trim(); + if (trimmedValue) { + clearErrors(props.name); + setError('root.isValidating', { + type: 'validate', + message: 'cantSubmitWhileValidating', + }); + debouncedHandleCheckName(trimmedValue); + } else { + clearErrors('root.isValidating'); + } + }, [debouncedHandleCheckName, setError, clearErrors, props.name, value, isDirty]); + + // Handle on user's change + const handleManualChange = (e: ChangeEvent) => { + const newValue = e.target.value; + onChange(newValue); + props.onManualChangeCallback && props.onManualChangeCallback(); + }; + + const translatedLabel = ; + + const translatedError = error && ; + + const showOk = value?.trim() && !isValidating && !error; + const endAdornment = ( + + {isValidating && } + {showOk && } + + ); + + return ( + + ); +}; diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index ad374fdc0d..2e161baa0a 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -5,18 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { FormattedMessage, useIntl } from 'react-intl'; -import { - CustomFormProvider, - ElementType, - fetchDirectoryElementPath, - TreeViewFinderNodeProps, - useSnackMessage, -} from '@gridsuite/commons-ui'; -import { UUID } from 'crypto'; -import { useCallback, useEffect, useState } from 'react'; -import { Grid, Button } from '@mui/material'; -import { UniqueNameInput } from './commons/unique-name-input'; +import { FormattedMessage } from 'react-intl'; +import { CustomFormProvider, isObjectEmpty, TreeViewFinderNodeProps, useSnackMessage } from '@gridsuite/commons-ui'; +import { useCallback, useState } from 'react'; +import { Grid, Button, Typography, Box } from '@mui/material'; import { CASE_NAME, CASE_ID, NAME } from '../utils/field-constants'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; @@ -25,6 +17,8 @@ import { useSelector } from 'react-redux'; import { AppState } from 'redux/reducer'; import ImportCaseDialog from './import-case-dialog'; import ModificationDialog from './commons/modificationDialog'; +import { rootNetworkNameExists } from 'services/root-network'; +import { UniqueCheckNameInput } from './commons/unique-check--name-input'; export interface FormData { [NAME]: string; @@ -36,10 +30,8 @@ interface RootNetworkCreationDialogProps { open: boolean; onSave: (data: FormData) => void; onClose: () => void; - type: ElementType; titleId: string; dialogProps: any; - prefixIdForGeneratedName?: string; } const formSchema = yup @@ -61,16 +53,12 @@ const RootNetworkCreationDialog: React.FC = ({ open, onSave, onClose, - type, titleId, dialogProps = undefined, - prefixIdForGeneratedName, }) => { - const intl = useIntl(); const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackError } = useSnackMessage(); - const [destinationFolder, setDestinationFolder] = useState(); const [selectedCase, setSelectedCase] = useState(null); const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); @@ -79,11 +67,11 @@ const RootNetworkCreationDialog: React.FC = ({ resolver: yupResolver(formSchema), }); - const { reset, setValue } = formMethods; - const disableSave = - // Form validation must pass - !selectedCase || // A case must be selected - !formMethods.getValues(NAME); // NAME must not be empty + const { + reset, + setValue, + formState: { errors }, + } = formMethods; // Clear form and reset selected case const clear = useCallback(() => { @@ -91,52 +79,6 @@ const RootNetworkCreationDialog: React.FC = ({ setSelectedCase(null); // Reset the selected case on clear }, [reset]); - // Fetch default directory based on study UUID - const fetchDefaultDirectoryForStudy = useCallback(() => { - if (!studyUuid) { - return; - } - fetchDirectoryElementPath(studyUuid).then((res) => { - if (!res || res.length < 2) { - snackError({ - messageTxt: 'unknown study directory', - headerId: 'studyDirectoryFetchingError', - }); - return; - } - const parentFolderIndex = res.length - 2; - const { elementUuid, elementName } = res[parentFolderIndex]; - setDestinationFolder({ - id: elementUuid, - name: elementName, - }); - }); - }, [studyUuid, snackError]); - - // Auto-generate a name with prefix and current date - useEffect(() => { - if (prefixIdForGeneratedName) { - const getCurrentDateTime = () => new Date().toISOString(); - const formattedMessage = intl.formatMessage({ - id: prefixIdForGeneratedName, - }); - const dateTime = getCurrentDateTime(); - reset( - { - ...emptyFormData, - [NAME]: `${formattedMessage}-${dateTime}`, - }, - { keepDefaultValues: true } - ); - } - }, [prefixIdForGeneratedName, intl, reset]); - - useEffect(() => { - if (open && studyUuid) { - fetchDefaultDirectoryForStudy(); - } - }, [fetchDefaultDirectoryForStudy, studyUuid, open]); - // Open case selector const handleCaseSelection = () => { setCaseSelectorOpen(true); @@ -145,9 +87,16 @@ const RootNetworkCreationDialog: React.FC = ({ // Set selected case when a case is selected const onSelectCase = (selectedCase: TreeViewFinderNodeProps) => { setSelectedCase(selectedCase); - setValue(NAME, selectedCase.name); // Set the name from the selected case - setValue(CASE_NAME, selectedCase.name); - setValue(CASE_ID, selectedCase.id as string); + + setValue(NAME, selectedCase.name, { + shouldDirty: true, + }); // Set the name from the selected case + setValue(CASE_NAME, selectedCase.name, { + shouldDirty: true, + }); + setValue(CASE_ID, selectedCase.id, { + shouldDirty: true, + }); setCaseSelectorOpen(false); }; @@ -155,12 +104,8 @@ const RootNetworkCreationDialog: React.FC = ({ (values: FormData) => { if (selectedCase) { // Save data, including CASE_NAME and CASE_ID - const creationData1: FormData = { - ...values, - [CASE_NAME]: selectedCase.name, - [CASE_ID]: selectedCase.id as UUID, - }; - onSave(creationData1); + + onSave(values); } else { snackError({ messageTxt: 'Please select a case before saving.', @@ -179,8 +124,12 @@ const RootNetworkCreationDialog: React.FC = ({ + + {selectedCase ? selectedCase.name : ''} + ); + const isFormValid = isObjectEmpty(errors) && selectedCase; return ( @@ -194,16 +143,16 @@ const RootNetworkCreationDialog: React.FC = ({ aria-labelledby="dialog-root-network-creation" {...dialogProps} titleId={titleId} - disabledSave={disableSave} + disabledSave={!isFormValid} > - {caseSelection} diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index d37c20273f..6292faf32e 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { CheckBoxList, ElementType, Parameter, useSnackMessage } from '@gridsuite/commons-ui'; +import { CheckBoxList, Parameter, useSnackMessage } from '@gridsuite/commons-ui'; import { FileUpload, @@ -331,7 +331,6 @@ const RootNetworkNodeEditor = () => { open={rootNetworkCreationDialogOpen} onClose={() => setRootNetworkCreationDialogOpen(false)} onSave={doCreateRootNetwork} - type={ElementType.ROOT_NETWORK} titleId={'CreateRootNetwork'} dialogProps={undefined} /> diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 081829726d..f189369ae2 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +import { getStudyUrl } from './study'; import { backendFetch, backendFetchJson } from './utils'; import { UUID } from 'crypto'; @@ -61,3 +62,30 @@ export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { body: JSON.stringify(rootNetworkUuids), }); } +// export function rootNetworkNameExists(studyUuid: UUID, name: string) { +// const existsElementUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks/${encodeURIComponent(name)}`; + +// console.debug(existsElementUrl); +// return backendFetch(existsElementUrl, { method: 'head' }).then((response) => { +// return response.status !== 204; // HTTP 204 : No-content +// }); +// } + +export function rootNetworkNameExists(studyUuid: UUID, name: string): Promise { + const existsElementUrl = + getStudyUrl(studyUuid) + + '/root-networks?' + + new URLSearchParams({ + name: name, + }); + return backendFetch(existsElementUrl, { method: 'head' }); +} + +export function rootNetworkNameExists1(studyUuid: UUID, rootNetworkName: string) { + const existsElementUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/elements/${rootNetworkName}`; + + console.debug(existsElementUrl); + return backendFetch(existsElementUrl, { method: 'head' }).then((response) => { + return response.status !== 204; // HTTP 204 : No-content + }); +} diff --git a/src/translations/en.json b/src/translations/en.json index 5e3de64790..d844b110c2 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1462,7 +1462,8 @@ "deletingRootNetwork": "Deleting root network ...", "creatingRootNetwork": "Creating root network ...", "rootNetworkCreated": "Root Network has been created successfully", - "errDeleteRootNetworkMsg": "Root Networks deletion error" + "errDeleteRootNetworkMsg": "Root Networks deletion error", + "rootNetworknameValidityCheckErrorMsg": "Error while checking name validity" } diff --git a/src/translations/fr.json b/src/translations/fr.json index a5259fd89d..0c86362d03 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1464,6 +1464,6 @@ "deletingRootNetwork": "Suppression du réseau racine en cours ...", "creatingRootNetwork": "Création du réseau racine en cours ...", "rootNetworkCreated": "Le réseau racine a été créé avec succès", - "errDeleteRootNetworkMsg": "Une erreur est survenue lors de la suppression des réseaux racine" - + "errDeleteRootNetworkMsg": "Une erreur est survenue lors de la suppression des réseaux racine", + "rootNetworknameValidityCheckErrorMsg": "Erreur à la vérification du nom de réseau racine" } \ No newline at end of file From a871a9c65d7730665b29ba968973a68d73982424 Mon Sep 17 00:00:00 2001 From: souissimai Date: Thu, 16 Jan 2025 15:08:37 +0100 Subject: [PATCH 43/51] use unique input check name existance of root networks Signed-off-by: souissimai --- .../commons/unique-check--name-input.tsx | 128 ------------------ .../dialogs/root-network-creation-dialog.tsx | 11 +- src/services/root-network.ts | 21 +-- 3 files changed, 10 insertions(+), 150 deletions(-) delete mode 100644 src/components/dialogs/commons/unique-check--name-input.tsx diff --git a/src/components/dialogs/commons/unique-check--name-input.tsx b/src/components/dialogs/commons/unique-check--name-input.tsx deleted file mode 100644 index 42dc3ddd46..0000000000 --- a/src/components/dialogs/commons/unique-check--name-input.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { ChangeEvent, FunctionComponent, useCallback, useEffect } from 'react'; -import { useDebounce } from '@gridsuite/commons-ui'; -import { FormattedMessage } from 'react-intl'; -import { InputAdornment, TextFieldProps } from '@mui/material'; -import CheckIcon from '@mui/icons-material/Check'; -import { useController, useFormContext } from 'react-hook-form'; -import CircularProgress from '@mui/material/CircularProgress'; -import TextField from '@mui/material/TextField'; -import { UUID } from 'crypto'; - -interface UniqueCheckNameInputProps { - name: string; - label?: string; - studyUuid: UUID | null; - elementExists: (studyUuid: UUID, elementName: string) => Promise; - - autoFocus?: boolean; - onManualChangeCallback?: () => void; - formProps?: Omit< - TextFieldProps, - 'value' | 'onChange' | 'name' | 'label' | 'inputRef' | 'inputProps' | 'InputProps' - >; -} - -/** - * Input component that constantly checks if the field's value is available or not - */ -export const UniqueCheckNameInput: FunctionComponent = (props) => { - const { - field: { onChange, onBlur, value, name, ref }, - fieldState: { error, isDirty }, - } = useController({ - name: props.name, - }); - - const { - setError, - clearErrors, - formState: { errors }, - } = useFormContext(); - - // This is a trick to share the custom validation state among the form: while this error is present, we can't validate the form - const isValidating = errors.root?.isValidating; - - const handleCheckName = useCallback( - (value: string) => { - if (value && props.studyUuid) { - props - .elementExists(props.studyUuid, value) - .then((alreadyExist) => { - if (alreadyExist) { - setError(props.name, { - type: 'validate', - message: 'nameAlreadyUsed', - }); - } - }) - .catch((error) => { - setError(props.name, { - type: 'validate', - message: 'rootNetworknameValidityCheckErrorMsg', - }); - console.error(error?.message); - }) - .finally(() => { - clearErrors('root.isValidating'); - }); - } - }, - [setError, clearErrors, props] - ); - - const debouncedHandleCheckName = useDebounce(handleCheckName, 700); - - // We have to use an useEffect because the name can change from outside of this component (e.g. when a case file is uploaded) - useEffect(() => { - // if the name is unchanged, we don't do custom validation - const trimmedValue = value.trim(); - if (trimmedValue) { - clearErrors(props.name); - setError('root.isValidating', { - type: 'validate', - message: 'cantSubmitWhileValidating', - }); - debouncedHandleCheckName(trimmedValue); - } else { - clearErrors('root.isValidating'); - } - }, [debouncedHandleCheckName, setError, clearErrors, props.name, value, isDirty]); - - // Handle on user's change - const handleManualChange = (e: ChangeEvent) => { - const newValue = e.target.value; - onChange(newValue); - props.onManualChangeCallback && props.onManualChangeCallback(); - }; - - const translatedLabel = ; - - const translatedError = error && ; - - const showOk = value?.trim() && !isValidating && !error; - const endAdornment = ( - - {isValidating && } - {showOk && } - - ); - - return ( - - ); -}; diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index 2e161baa0a..6305a83983 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -6,7 +6,13 @@ */ import { FormattedMessage } from 'react-intl'; -import { CustomFormProvider, isObjectEmpty, TreeViewFinderNodeProps, useSnackMessage } from '@gridsuite/commons-ui'; +import { + CustomFormProvider, + isObjectEmpty, + TreeViewFinderNodeProps, + UniqueNameCheckInput, + useSnackMessage, +} from '@gridsuite/commons-ui'; import { useCallback, useState } from 'react'; import { Grid, Button, Typography, Box } from '@mui/material'; import { CASE_NAME, CASE_ID, NAME } from '../utils/field-constants'; @@ -18,7 +24,6 @@ import { AppState } from 'redux/reducer'; import ImportCaseDialog from './import-case-dialog'; import ModificationDialog from './commons/modificationDialog'; import { rootNetworkNameExists } from 'services/root-network'; -import { UniqueCheckNameInput } from './commons/unique-check--name-input'; export interface FormData { [NAME]: string; @@ -147,7 +152,7 @@ const RootNetworkCreationDialog: React.FC = ({ > - { -// return response.status !== 204; // HTTP 204 : No-content -// }); -// } export function rootNetworkNameExists(studyUuid: UUID, name: string): Promise { - const existsElementUrl = + const rootNetworkNameExistsUrl = getStudyUrl(studyUuid) + '/root-networks?' + new URLSearchParams({ name: name, }); - return backendFetch(existsElementUrl, { method: 'head' }); -} - -export function rootNetworkNameExists1(studyUuid: UUID, rootNetworkName: string) { - const existsElementUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${studyUuid}/elements/${rootNetworkName}`; - - console.debug(existsElementUrl); - return backendFetch(existsElementUrl, { method: 'head' }).then((response) => { - return response.status !== 204; // HTTP 204 : No-content - }); + return backendFetch(rootNetworkNameExistsUrl, { method: 'head' }); } From ee6158a11d7ab8130388652f79b5f7646e358181 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 20 Jan 2025 14:39:47 +0100 Subject: [PATCH 44/51] improve visual: panel Signed-off-by: souissimai --- src/components/dialogs/import-case-dialog.tsx | 2 +- src/components/dialogs/root-network-creation-dialog.tsx | 6 +++--- src/components/graph/menus/root-network-node-editor.tsx | 6 +++--- src/components/root-network-panel.tsx | 5 ++--- src/services/root-network.ts | 7 +++++-- src/translations/en.json | 4 +--- src/translations/fr.json | 4 +--- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/components/dialogs/import-case-dialog.tsx b/src/components/dialogs/import-case-dialog.tsx index 0c2949231c..7a18a7809d 100644 --- a/src/components/dialogs/import-case-dialog.tsx +++ b/src/components/dialogs/import-case-dialog.tsx @@ -32,7 +32,7 @@ const ImportCaseDialog: FunctionComponent = ({ open, onCl onClose={processSelectedElements} types={[ElementType.CASE]} title={intl.formatMessage({ - id: 'ChooseSituation', + id: 'ChooseCase', })} multiSelect={false} /> diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network-creation-dialog.tsx index 6305a83983..7dfaf69592 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network-creation-dialog.tsx @@ -23,7 +23,7 @@ import { useSelector } from 'react-redux'; import { AppState } from 'redux/reducer'; import ImportCaseDialog from './import-case-dialog'; import ModificationDialog from './commons/modificationDialog'; -import { rootNetworkNameExists } from 'services/root-network'; +import { checkRootNetworkNameExistence } from 'services/root-network'; export interface FormData { [NAME]: string; @@ -126,7 +126,7 @@ const RootNetworkCreationDialog: React.FC = ({ @@ -157,7 +157,7 @@ const RootNetworkCreationDialog: React.FC = ({ label={'Name'} autoFocus studyUuid={studyUuid} - elementExists={rootNetworkNameExists} + elementExists={checkRootNetworkNameExistence} /> {caseSelection} diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 6292faf32e..86c7c2eecf 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -56,7 +56,8 @@ export const styles = { overflow: 'hidden', borderTop: `1px solid ${theme.palette.divider}`, borderBottom: `1px solid ${theme.palette.divider}`, - marginRight: '8px', + marginRight: theme.spacing(1), + marginLeft: theme.spacing(1), }), toolbar: (theme: Theme) => ({ '&': { @@ -222,7 +223,7 @@ const RootNetworkNodeEditor = () => { if (!rootNetwork) { return ''; } - return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.name; + return intl.formatMessage({ id: 'root' }) + ' ' + rootNetwork.name; }; const handleSecondaryAction = useCallback( @@ -274,7 +275,6 @@ const RootNetworkNodeEditor = () => { items={rootNetworks} getItemId={(val) => val.rootNetworkUuid} getItemLabel={getRootNetworkLabel} - divider secondaryAction={handleSecondaryAction} /> ); diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx index 2414e595d0..cfc8dffae6 100644 --- a/src/components/root-network-panel.tsx +++ b/src/components/root-network-panel.tsx @@ -16,11 +16,10 @@ const styles = { position: 'absolute', top: 16, left: 16, - width: '300px', - height: '300px', + width: '60%', + height: '35%', flexDirection: 'column', borderRadius: '8px', - boxShadow: '0 6px 15px rgba(0,0,0,0.15)', zIndex: 10, overflow: 'hidden', }, diff --git a/src/services/root-network.ts b/src/services/root-network.ts index af9f939a7d..c87afbf0cc 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -63,12 +63,15 @@ export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { }); } -export function rootNetworkNameExists(studyUuid: UUID, name: string): Promise { +export function checkRootNetworkNameExistence(studyUuid: UUID, name: string): Promise { const rootNetworkNameExistsUrl = getStudyUrl(studyUuid) + '/root-networks?' + new URLSearchParams({ name: name, }); - return backendFetch(rootNetworkNameExistsUrl, { method: 'head' }); + console.debug(rootNetworkNameExistsUrl); + return backendFetch(rootNetworkNameExistsUrl, { method: 'head' }).then((response) => { + return response.status !== 204; + }); } diff --git a/src/translations/en.json b/src/translations/en.json index d844b110c2..c9a114a8ec 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -373,8 +373,7 @@ "TwoSides.ONE": "Origin side", "TwoSides.TWO": "Extremity side", - "selectCase": "Select case", - "ChooseSituation": "Select a case", + "ChooseCase": "Select a case", "ContingencyListsSelection": "Contingency lists selection", "Execute": "Execute", @@ -610,7 +609,6 @@ "NodeBuildingError": "An error occurred while building node", "NodeUnbuildingError": "An error occurred while unbuilding node", "NetworkModifications": "Network modifications", - "RootNetwork": "Root Network", "CreateLoad": "Create load", "ModifyLoad": "Modify load", "NameOptional": "Name (optional)", diff --git a/src/translations/fr.json b/src/translations/fr.json index 0c86362d03..f6786790bb 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -374,8 +374,7 @@ "TwoSides.ONE": "Côté 1", "TwoSides.TWO": "Côté 2", - "selectCase": "Sélectionner une situation", - "ChooseSituation": "Choisir une situation", + "ChooseCase": "Choisir une situation", "ContingencyListsSelection": "Sélection des listes d'aléas", "Execute": "Exécuter", @@ -613,7 +612,6 @@ "NodeBuildingError": "Une erreur est survenue lors de la réalisation du nœud", "NodeUnbuildingError": "Une erreur est survenue lors de la déréalisation du nœud", "NetworkModifications": "Modifications de réseau", - "RootNetwork": "Réseau racine", "CreateLoad": "Créer une consommation", "ModifyLoad": "Modifier une consommation", From 7efda55af63205e96f383f1641efa438e0f3c24b Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 14:46:29 +0100 Subject: [PATCH 45/51] fix: PR remarks Signed-off-by: LE SAULNIER Kevin --- camarche.patch | 162 ------------------ src/components/diagrams/diagram-pane.tsx | 3 - ...o-windings-transformer-creation-dialog.jsx | 1 - ...ndings-transformer-modification-dialog.jsx | 2 +- .../root-network-case-selection.tsx | 48 ++++++ .../root-network-creation-dialog.tsx | 66 ++----- .../graph/menus/root-network-node-editor.tsx | 4 +- .../network-modification-tree-pane.jsx | 1 - src/components/network-modification-tree.jsx | 1 - src/components/network/network-map-tab.tsx | 10 +- src/services/network-conversion.ts | 2 +- src/services/root-network.ts | 18 +- src/translations/en.json | 12 +- src/translations/fr.json | 10 +- 14 files changed, 85 insertions(+), 255 deletions(-) delete mode 100644 camarche.patch create mode 100644 src/components/dialogs/root-network/root-network-case-selection.tsx rename src/components/dialogs/{ => root-network}/root-network-creation-dialog.tsx (62%) diff --git a/camarche.patch b/camarche.patch deleted file mode 100644 index ce1e21f92a..0000000000 --- a/camarche.patch +++ /dev/null @@ -1,162 +0,0 @@ -diff --git a/src/components/dialogs/commons/unique-name-input.tsx b/src/components/dialogs/commons/unique-name-input.tsx -index eba1a7ed..278f143b 100644 ---- a/src/components/dialogs/commons/unique-name-input.tsx -+++ b/src/components/dialogs/commons/unique-name-input.tsx -@@ -7,7 +7,7 @@ - - import { ChangeEvent, FunctionComponent, useCallback, useEffect } from 'react'; - import { ElementType, useDebounce } from '@gridsuite/commons-ui'; --import { elementExists } from 'services/explore'; -+import { elementExists, elementExistss } from 'services/explore'; - import { FormattedMessage } from 'react-intl'; - import { InputAdornment, TextFieldProps } from '@mui/material'; - import CheckIcon from '@mui/icons-material/Check'; -@@ -51,27 +51,18 @@ export const UniqueNameInput: FunctionComponent = (props) - - const handleCheckName = useCallback( - (value: string) => { -- if (value && props.activeDirectory) { -- elementExists(props.activeDirectory, value, props.elementType) -- .then((alreadyExist) => { -- if (alreadyExist) { -+ if (value ) { -+ -+ if (elementExistss( value )) { - setError(props.name, { - type: 'validate', - message: 'nameAlreadyUsed', - }); - } -- }) -- .catch((error) => { -- setError(props.name, { -- type: 'validate', -- message: 'nameValidityCheckErrorMsg', -- }); -- console.error(error?.message); -- }) -- .finally(() => { -- clearErrors('root.isValidating'); -- }); -- } -+ -+ -+ clearErrors('root.isValidating'); -+ } - }, - [setError, clearErrors, props.activeDirectory, props.name, props.elementType] - ); -diff --git a/src/components/dialogs/element-creation-dialog.tsx b/src/components/dialogs/element-creation-dialog.tsx -index e800a0ea..669aaa90 100644 ---- a/src/components/dialogs/element-creation-dialog.tsx -+++ b/src/components/dialogs/element-creation-dialog.tsx -@@ -1,10 +1,3 @@ --/** -- * Copyright (c) 2024, 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 { FormattedMessage, useIntl } from 'react-intl'; - import { - CustomFormProvider, -@@ -29,7 +22,6 @@ import { AppState } from '../../redux/reducer'; - - interface FormData { - [NAME]: string; -- [DESCRIPTION]: string; - } - export interface IElementCreationDialog extends FormData { - [FOLDER_NAME]: string; -@@ -49,13 +41,11 @@ const formSchema = yup - .object() - .shape({ - [NAME]: yup.string().trim().required(), -- [DESCRIPTION]: yup.string().optional().max(500, 'descriptionLimitError'), - }) - .required(); - - const emptyFormData: FormData = { - [NAME]: '', -- [DESCRIPTION]: '', - }; - - const ElementCreationDialog: React.FC = ({ -@@ -79,9 +69,12 @@ const ElementCreationDialog: React.FC = ({ - }); - const { - reset, -+ trigger, -+ setValue, // Added setValue to update specific form fields - formState: { errors }, -+ watch, // To observe changes in form fields - } = formMethods; -- const disableSave = Object.keys(errors).length > 0; -+ const disableSave = Object.keys(errors).length > 0 || !watch(NAME); // Disable save if NAME is empty - - const clear = useCallback(() => { - reset(emptyFormData); -@@ -134,9 +127,15 @@ const ElementCreationDialog: React.FC = ({ - }; - - const setSelectedFolder = (folder: TreeViewFinderNodeProps[]) => { -- if (folder?.length > 0 && folder[0].id !== destinationFolder?.id) { -+ if (folder?.length > 0) { - const { id, name } = folder[0]; - setDestinationFolder({ id, name }); -+ console.log('========== ', folder); -+ -+ // Prefill the input with the folder name -+ setValue(NAME, name, { -+ shouldDirty: true, -+ }); - } - setDirectorySelectorOpen(false); - }; -@@ -193,15 +192,12 @@ const ElementCreationDialog: React.FC = ({ - autoFocus - /> - -- -- -- - {folderChooser} - - { - temporaryGeoDataIdsRef.current = new Set(); -- networkMapRef.current?.resetZoomAndPosition(); -+ //networkMapRef.current?.resetZoomAndPosition(); - // when reloading root node map equipments (when switching of root network), nominal voltages are reloaded - // we check them all in NominalVoltageFilter by default - if (mapEquipments) { -diff --git a/src/services/explore.ts b/src/services/explore.ts -index 58831c9b..7f20042f 100644 ---- a/src/services/explore.ts -+++ b/src/services/explore.ts -@@ -32,7 +32,10 @@ export function createParameter( - body: JSON.stringify(newParameter), - }); - } -- -+export function elementExistss( elementName: string ) { -+ -+ return elementName === "cc"; -+} - export function elementExists(directoryUuid: UUID, elementName: string, type: ElementType) { - const existsElementUrl = `${PREFIX_DIRECTORY_SERVER_QUERIES}/v1/directories/${directoryUuid}/elements/${elementName}/types/${type}`; - diff --git a/src/components/diagrams/diagram-pane.tsx b/src/components/diagrams/diagram-pane.tsx index cc32e58651..6a69aef48d 100644 --- a/src/components/diagrams/diagram-pane.tsx +++ b/src/components/diagrams/diagram-pane.tsx @@ -816,7 +816,6 @@ export function DiagramPane({ updateDiagramsByIds(allDiagramIds, true); }, [currentNode, updateDiagramsByIds]); - // This effect will trigger the diagrams' forced update // This effect will trigger the diagrams' forced update useEffect(() => { if (studyUpdatedForce.eventData.headers) { @@ -828,11 +827,9 @@ export function DiagramPane({ } if (studyUpdatedForce.eventData.headers['updateType'] === 'loadflowResult') { //TODO reload data more intelligently - updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'study') { // FM if we want to reload data more precisely, we need more information from notifications - updateDiagramsByCurrentNode(); } else if (studyUpdatedForce.eventData.headers['updateType'] === 'buildCompleted') { if (studyUpdatedForce.eventData.headers['node'] === currentNodeRef.current?.id) { diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx index 2d54862610..b0fc8e3787 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/creation/two-windings-transformer-creation-dialog.jsx @@ -692,7 +692,6 @@ TwoWindingsTransformerCreationDialog.propTypes = { studyUuid: PropTypes.string, currentNode: PropTypes.object, currentRootNetworkUuid: PropTypes.string, - isUpdate: PropTypes.bool, editDataFetchStatus: PropTypes.string, }; diff --git a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx index 9fad8837aa..dff2e301cf 100644 --- a/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx +++ b/src/components/dialogs/network-modifications/two-windings-transformer/modification/two-windings-transformer-modification-dialog.jsx @@ -167,7 +167,7 @@ export const TwoWindingsTransformerModificationDialogTab = { * @param studyUuid the study we are currently working on * @param defaultIdValue the default two windings transformer id * @param currentNode The node we are currently working on - * @param currentRootNetworkUuid The current root network uuid we are currently working on + * @param currentRootNetworkUuid The root network uuid we are currently working on * @param isUpdate check if edition form * @param editData the data to edit * @param editDataFetchStatus indicates the status of fetching EditData diff --git a/src/components/dialogs/root-network/root-network-case-selection.tsx b/src/components/dialogs/root-network/root-network-case-selection.tsx new file mode 100644 index 0000000000..50be5a2252 --- /dev/null +++ b/src/components/dialogs/root-network/root-network-case-selection.tsx @@ -0,0 +1,48 @@ +import { Box, Button, Grid, Typography } from '@mui/material'; +import { CASE_NAME } from 'components/utils/field-constants'; +import ReadOnlyInput from 'components/utils/rhf-inputs/read-only/read-only-input'; +import { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import ImportCaseDialog from '../import-case-dialog'; +import { TreeViewFinderNodeProps } from '@gridsuite/commons-ui'; +import { useWatch } from 'react-hook-form'; + +interface RootNetworkCaseSelectionProps { + onSelectCase: (selectedCase: TreeViewFinderNodeProps) => void; +} + +export const RootNetworkCaseSelection = ({ onSelectCase }: RootNetworkCaseSelectionProps) => { + const [isDialogOpen, setIsDialogOpen] = useState(false); + const caseNameWatch = useWatch({ name: CASE_NAME }); + + const handleSelectCase = (selectedCase: TreeViewFinderNodeProps) => { + onSelectCase(selectedCase); + setIsDialogOpen(false); + }; + + return ( + <> + + + + + + + + + + + setIsDialogOpen(false)} + onSelectCase={handleSelectCase} + /> + + ); +}; diff --git a/src/components/dialogs/root-network-creation-dialog.tsx b/src/components/dialogs/root-network/root-network-creation-dialog.tsx similarity index 62% rename from src/components/dialogs/root-network-creation-dialog.tsx rename to src/components/dialogs/root-network/root-network-creation-dialog.tsx index 7dfaf69592..ea0d19f5c3 100644 --- a/src/components/dialogs/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network/root-network-creation-dialog.tsx @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { FormattedMessage } from 'react-intl'; import { CustomFormProvider, isObjectEmpty, @@ -13,17 +12,17 @@ import { UniqueNameCheckInput, useSnackMessage, } from '@gridsuite/commons-ui'; -import { useCallback, useState } from 'react'; -import { Grid, Button, Typography, Box } from '@mui/material'; -import { CASE_NAME, CASE_ID, NAME } from '../utils/field-constants'; +import { useCallback } from 'react'; +import { Grid } from '@mui/material'; +import { CASE_NAME, CASE_ID, NAME } from '../../utils/field-constants'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; -import yup from '../utils/yup-config'; +import yup from '../../utils/yup-config'; import { useSelector } from 'react-redux'; import { AppState } from 'redux/reducer'; -import ImportCaseDialog from './import-case-dialog'; -import ModificationDialog from './commons/modificationDialog'; +import ModificationDialog from '../commons/modificationDialog'; import { checkRootNetworkNameExistence } from 'services/root-network'; +import { RootNetworkCaseSelection } from './root-network-case-selection'; export interface FormData { [NAME]: string; @@ -36,7 +35,7 @@ interface RootNetworkCreationDialogProps { onSave: (data: FormData) => void; onClose: () => void; titleId: string; - dialogProps: any; + dialogProps?: any; } const formSchema = yup @@ -59,14 +58,11 @@ const RootNetworkCreationDialog: React.FC = ({ onSave, onClose, titleId, - dialogProps = undefined, + dialogProps, }) => { const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackError } = useSnackMessage(); - const [selectedCase, setSelectedCase] = useState(null); - const [caseSelectorOpen, setCaseSelectorOpen] = useState(false); - const formMethods = useForm({ defaultValues: emptyFormData, resolver: yupResolver(formSchema), @@ -81,18 +77,10 @@ const RootNetworkCreationDialog: React.FC = ({ // Clear form and reset selected case const clear = useCallback(() => { reset(emptyFormData); - setSelectedCase(null); // Reset the selected case on clear }, [reset]); - // Open case selector - const handleCaseSelection = () => { - setCaseSelectorOpen(true); - }; - // Set selected case when a case is selected const onSelectCase = (selectedCase: TreeViewFinderNodeProps) => { - setSelectedCase(selectedCase); - setValue(NAME, selectedCase.name, { shouldDirty: true, }); // Set the name from the selected case @@ -102,39 +90,17 @@ const RootNetworkCreationDialog: React.FC = ({ setValue(CASE_ID, selectedCase.id, { shouldDirty: true, }); - setCaseSelectorOpen(false); }; const handleSave = useCallback( (values: FormData) => { - if (selectedCase) { - // Save data, including CASE_NAME and CASE_ID - - onSave(values); - } else { - snackError({ - messageTxt: 'Please select a case before saving.', - headerId: 'caseNotSelectedError', - }); - } + // Save data, including CASE_NAME and CASE_ID + onSave(values); }, - [onSave, selectedCase, snackError] + [onSave, snackError] ); - // Case selection component - const caseSelection = ( - - - - - - {selectedCase ? selectedCase.name : ''} - - - ); - const isFormValid = isObjectEmpty(errors) && selectedCase; + const isFormValid = isObjectEmpty(errors); return ( @@ -160,14 +126,8 @@ const RootNetworkCreationDialog: React.FC = ({ elementExists={checkRootNetworkNameExistence} /> - {caseSelection} + - - setCaseSelectorOpen(false)} - onSelectCase={onSelectCase} - /> ); diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 86c7c2eecf..52d7facea1 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -31,7 +31,7 @@ import { } from 'services/network-conversion'; import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; import { setCurrentRootNetwork } from 'redux/actions'; -import RootNetworkCreationDialog, { FormData } from 'components/dialogs/root-network-creation-dialog'; +import RootNetworkCreationDialog, { FormData } from 'components/dialogs/root-network/root-network-creation-dialog'; export const styles = { listContainer: (theme: Theme) => ({ @@ -370,7 +370,7 @@ const RootNetworkNodeEditor = () => { caseId as UUID, params.formatName, name, - studyUuid, + studyUuid as UUID, customizedCurrentParameters ); }) diff --git a/src/components/network-modification-tree-pane.jsx b/src/components/network-modification-tree-pane.jsx index 8edf91e237..96b91945a4 100644 --- a/src/components/network-modification-tree-pane.jsx +++ b/src/components/network-modification-tree-pane.jsx @@ -51,7 +51,6 @@ const styles = { height: '100%', display: 'flex', flexDirection: 'row', - // backgroundColor: 'yellow', }, }; diff --git a/src/components/network-modification-tree.jsx b/src/components/network-modification-tree.jsx index 4313050fb1..334a9209e7 100644 --- a/src/components/network-modification-tree.jsx +++ b/src/components/network-modification-tree.jsx @@ -357,7 +357,6 @@ const NetworkModificationTree = ({ {isMinimapOpen && } - {/* root Network Panel */} diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 2ed8bbb113..f2acc81fc6 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -45,7 +45,6 @@ import LineModificationDialog from '../dialogs/network-modifications/line/modifi import { deleteEquipment } from '../../services/study/network-modifications'; import EquipmentDeletionDialog from '../dialogs/network-modifications/equipment-deletion/equipment-deletion-dialog'; import { fetchLinePositions, fetchSubstationPositions } from '../../services/study/geo-data'; - import { useMapBoxToken } from './network-map/use-mapbox-token'; import EquipmentPopover from '../tooltips/equipment-popover'; import RunningStatus from 'components/utils/running-status'; @@ -859,7 +858,8 @@ export const NetworkMapTab = ({ if (isNodeRenamed(previousCurrentNode, currentNode)) { return; } - if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid && currentNode !== null) { + // when root network has just been changed, we reload root node geodata to match its root node geodata + if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { loadRootNodeGeoData(); return; } @@ -879,13 +879,9 @@ export const NetworkMapTab = ({ // load default node map equipments loadMapEquipments(); } - if (!isRootNodeGeoDataLoaded || previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { + if (!isRootNodeGeoDataLoaded) { // load root node geodata loadRootNodeGeoData(); - //TODO: kevin make it cleaner - if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { - return; - } } // manual reload if (refIsMapManualRefreshEnabled.current && isInitialized) { diff --git a/src/services/network-conversion.ts b/src/services/network-conversion.ts index 4f497df213..ffa815c369 100644 --- a/src/services/network-conversion.ts +++ b/src/services/network-conversion.ts @@ -23,7 +23,7 @@ export interface GetCaseImportParametersReturn { parameters: CaseImportParameters[]; } -export function getCaseImportParameters(caseUuid: UUID | undefined): Promise { +export function getCaseImportParameters(caseUuid: UUID): Promise { console.info(`get import parameters for case '${caseUuid}' ...`); const getExportFormatsUrl = PREFIX_NETWORK_CONVERSION_SERVER_QUERIES + '/v1/cases/' + caseUuid + '/import-parameters'; diff --git a/src/services/root-network.ts b/src/services/root-network.ts index c87afbf0cc..1c68f9adb7 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -5,14 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { getStudyUrl } from './study'; +import { PREFIX_STUDY_QUERIES, getStudyUrl } from './study'; import { backendFetch, backendFetchJson } from './utils'; import { UUID } from 'crypto'; -export const PREFIX_STUDY_QUERIES = import.meta.env.VITE_API_GATEWAY + '/study'; - export function fetchRootNetworks(studyUuid: UUID) { - console.info('Fetching root network for studyUuid : ', studyUuid); + console.info('Fetching root networks for studyUuid : ', studyUuid); const rootNetworksGetUrl = `${PREFIX_STUDY_QUERIES}/v1/studies/${encodeURIComponent(studyUuid)}/root-networks`; console.debug(rootNetworksGetUrl); @@ -20,16 +18,12 @@ export function fetchRootNetworks(studyUuid: UUID) { } export const createRootNetwork = ( - caseUuid: UUID | undefined, + caseUuid: UUID, caseFormat: string, rootNetworkName: string, - studyUuid: UUID | null, + studyUuid: UUID, importParameters: Record ) => { - if (!studyUuid || !caseUuid || !rootNetworkName) { - throw new Error('rootNetworkName, studyUuid and caseUuid are required parameters.'); - } - const urlSearchParams = new URLSearchParams(); urlSearchParams.append('caseUuid', caseUuid); urlSearchParams.append('caseFormat', caseFormat); @@ -64,13 +58,13 @@ export function deleteRootNetworks(studyUuid: UUID, rootNetworkUuids: UUID[]) { } export function checkRootNetworkNameExistence(studyUuid: UUID, name: string): Promise { - const rootNetworkNameExistsUrl = + const checkRootNetworkNameExistenceUrl = getStudyUrl(studyUuid) + '/root-networks?' + new URLSearchParams({ name: name, }); - console.debug(rootNetworkNameExistsUrl); + console.debug(checkRootNetworkNameExistenceUrl); return backendFetch(rootNetworkNameExistsUrl, { method: 'head' }).then((response) => { return response.status !== 204; }); diff --git a/src/translations/en.json b/src/translations/en.json index c9a114a8ec..4491c2e7c5 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -55,7 +55,7 @@ "SingleLineDiagram": "Single line diagram", "NetworkAreaDiagram": "Network area diagram", "studyNotFound": "Study with id \"{studyUuid}\" has not been found", - "rootNetworkNotFound": "No root network was not found for the study with ID \"{studyUuid}\"", + "rootNetworkNotFound": "No root network was found for the study with ID \"{studyUuid}\"", "svgNotFound": "Diagram has not been found: {error}; {svgUrl}", "svgLoadingFail": "The diagram couldn't be loaded", @@ -1236,7 +1236,7 @@ "SaveModificationTo": "Save to GridExplore", "ModificationsSelection": "Modification selection", "errCreateModificationsMsg": "Network modifications creation error", - "errCreateRootNetworksMsg": "Root Networks creation error", + "errCreateRootNetworksMsg": "An error occurred while creating the root network", "infoCreateModificationsMsg": "Composite modification of {nbModifications} unitary network modifications created in {studyDirectory}", "idSelector.idNeeded": "Please select an ID", "SpreadsheetFetchError": "An error occurred while fetching equipments in the spreadsheet", @@ -1455,13 +1455,13 @@ "StateEstimationStatus": "Status : ", "StateEstimationQuality": "Quality : ", "Or": "or", - "rootNetworksCount":"{hide, select, false {{count, plural, =0 {no root} =1 {{count} Root} other {{count} Roots}}} other {...}}", + "rootNetworksCount":"{count, plural, =1 {# network} other {# networks}}", "updateRootNetworksList": "Updating root network list ...", "deletingRootNetwork": "Deleting root network ...", "creatingRootNetwork": "Creating root network ...", - "rootNetworkCreated": "Root Network has been created successfully", - "errDeleteRootNetworkMsg": "Root Networks deletion error", - "rootNetworknameValidityCheckErrorMsg": "Error while checking name validity" + "rootNetworkCreated": "The root network has been created successfully", + "errDeleteRootNetworkMsg": "An error occurred while deleting root networks", + "rootNetworknameValidityCheckErrorMsg": "An error occurred while checking root network name" } diff --git a/src/translations/fr.json b/src/translations/fr.json index f6786790bb..937f4fed49 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -56,7 +56,7 @@ "NetworkAreaDiagram": "Image nodale de zone", "studyNotFound": "L'étude avec l'identifiant \"{studyUuid}\" n'a pas été trouvée", - "RootNetworkNotFound": "Aucun réseau racine n'a été trouvé pour l'étude avec l'ID \"{studyUuid}\"", + "RootNetworkNotFound": "Aucun réseau racine n'a été trouvé pour l'étude avec l'identifiant \"{studyUuid}\"", "svgNotFound": "L'image poste n'a pas été trouvée : {error}; {svgUrl}", "svgLoadingFail": "L'image n'a pas pu être chargée", @@ -1457,11 +1457,11 @@ "StateEstimationStatus": "Statut : ", "StateEstimationQuality": "Qualité: ", "Or": "ou", - "rootNetworksCount":"{hide, select, false {{count, plural, =0 {aucun réseau} =1 {# Réseau} other {# Réseaux}}} other {...}}", - "updateRootNetworksList": "Mise à jour de la liste des réseaux racine cours ...", + "rootNetworksCount":"{count, plural, =1 {# réseau} other {# réseaux}}", + "updateRootNetworksList": "Mise à jour de la liste des réseaux racines cours ...", "deletingRootNetwork": "Suppression du réseau racine en cours ...", "creatingRootNetwork": "Création du réseau racine en cours ...", "rootNetworkCreated": "Le réseau racine a été créé avec succès", - "errDeleteRootNetworkMsg": "Une erreur est survenue lors de la suppression des réseaux racine", - "rootNetworknameValidityCheckErrorMsg": "Erreur à la vérification du nom de réseau racine" + "errDeleteRootNetworkMsg": "Une erreur est survenue lors de la suppression des réseaux racines", + "rootNetworknameValidityCheckErrorMsg": "Une erreur est survenue lors de la vérification du nom de réseau racine" } \ No newline at end of file From 38c680eb5235c8f36b8380a8a3136492117c4724 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 14:55:30 +0100 Subject: [PATCH 46/51] fix: PR remarks Signed-off-by: LE SAULNIER Kevin --- .../graph/menus/root-network-node-editor.tsx | 123 ++++-------------- 1 file changed, 26 insertions(+), 97 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index 52d7facea1..a70d8c1bde 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -32,15 +32,9 @@ import { import { createRootNetwork, deleteRootNetworks, fetchRootNetworks } from 'services/root-network'; import { setCurrentRootNetwork } from 'redux/actions'; import RootNetworkCreationDialog, { FormData } from 'components/dialogs/root-network/root-network-creation-dialog'; +import { isChecked, isPartial } from './network-modification-node-editor'; -export const styles = { - listContainer: (theme: Theme) => ({ - overflowY: 'auto', - display: 'flex', - flexDirection: 'column', - flexGrow: 1, - paddingBottom: theme.spacing(8), - }), +const styles = { checkBoxLabel: { flexGrow: '1' }, disabledRootNetwork: { opacity: 0.4 }, checkBoxIcon: { minWidth: 0, padding: 0, marginLeft: 2 }, @@ -56,8 +50,7 @@ export const styles = { overflow: 'hidden', borderTop: `1px solid ${theme.palette.divider}`, borderBottom: `1px solid ${theme.palette.divider}`, - marginRight: theme.spacing(1), - marginLeft: theme.spacing(1), + marginRight: '8px', }), toolbar: (theme: Theme) => ({ '&': { @@ -89,52 +82,25 @@ export const styles = { marginRight: theme.spacing(2), color: theme.palette.secondary.main, }), - notification: (theme: Theme) => ({ - flex: 1, - alignContent: 'center', - justifyContent: 'center', - marginTop: theme.spacing(4), - textAlign: 'center', - color: theme.palette.primary.main, - }), icon: (theme: Theme) => ({ width: theme.spacing(3), }), - iconEdit: (theme: Theme) => ({ - marginRight: theme.spacing(1), - }), }; -export function isChecked(s1: number) { - return s1 !== 0; -} - -export function isPartial(s1: number, s2: number) { - if (s1 === 0) { - return false; - } - return s1 !== s2; -} - const RootNetworkNodeEditor = () => { - const notificationIdList = useSelector((state: AppState) => state.notificationIdList); const studyUuid = useSelector((state: AppState) => state.studyUuid); const { snackInfo, snackError } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); - const [createInProgress, setCreateInProgress] = useState(false); const [deleteInProgress, setDeleteInProgress] = useState(false); const currentNode = useSelector((state: AppState) => state.currentTreeNode); const currentRootNetwork = useSelector((state: AppState) => state.currentRootNetwork); - const [pendingState, setPendingState] = useState(false); - const [selectedItems, setSelectedItems] = useState([]); const [rootNetworkCreationDialogOpen, setRootNetworkCreationDialogOpen] = useState(false); const dispatch = useDispatch(); const studyUpdatedForce = useSelector((state: AppState) => state.studyUpdated); - const [messageId, setMessageId] = useState(''); - const [launchLoader, setLaunchLoader] = useState(false); + const [isLoading, setIsLoading] = useState(false); const updateSelectedItems = useCallback((rootNetworks: RootNetworkMetadata[]) => { const toKeepIdsSet = new Set(rootNetworks.map((e) => e.rootNetworkUuid)); @@ -142,7 +108,7 @@ const RootNetworkNodeEditor = () => { }, []); const dofetchRootNetworks = useCallback(() => { - setLaunchLoader(true); + setIsLoading(true); if (studyUuid) { fetchRootNetworks(studyUuid) .then((res: RootNetworkMetadata[]) => { @@ -155,26 +121,20 @@ const RootNetworkNodeEditor = () => { }); }) .finally(() => { - setPendingState(false); - setLaunchLoader(false); + setIsLoading(false); }); } }, [studyUuid, updateSelectedItems, snackError]); useEffect(() => { - if (studyUpdatedForce.eventData.headers) { - if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { - setMessageId('updateRootNetworksList'); - dofetchRootNetworks(); - } + if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { + dofetchRootNetworks(); } }, [studyUpdatedForce, dofetchRootNetworks]); useEffect(() => { - if (rootNetworks.length === 0) { - dofetchRootNetworks(); - } - }, [dofetchRootNetworks, rootNetworks]); + dofetchRootNetworks(); + }, [dofetchRootNetworks]); const openRootNetworkCreationDialog = useCallback(() => { setRootNetworkCreationDialogOpen(true); @@ -183,7 +143,7 @@ const RootNetworkNodeEditor = () => { const doDeleteRootNetwork = useCallback(() => { const selectedRootNetworksUuid = selectedItems.map((item) => item.rootNetworkUuid); - if (studyUuid && currentRootNetwork) { + if (studyUuid) { if (selectedRootNetworksUuid.length === 1) { // Find the first root network in the list that is not being deleted const newRootNetwork = rootNetworks.find( @@ -193,11 +153,10 @@ const RootNetworkNodeEditor = () => { dispatch(setCurrentRootNetwork(newRootNetwork.rootNetworkUuid)); } } + setDeleteInProgress(true); deleteRootNetworks(studyUuid, selectedRootNetworksUuid) - .then(() => { - setDeleteInProgress(true); - }) + .then(() => {}) .catch((errmsg) => { snackError({ messageTxt: errmsg, @@ -208,22 +167,15 @@ const RootNetworkNodeEditor = () => { setDeleteInProgress(false); }); } - }, [selectedItems, dispatch, rootNetworks, snackError, studyUuid, currentRootNetwork]); + }, [selectedItems, dispatch, rootNetworks, snackError, studyUuid]); const toggleSelectAllRootNetworks = useCallback(() => { setSelectedItems((oldVal) => (oldVal.length === 0 ? rootNetworks : [])); }, [rootNetworks]); - const isLoading = useCallback(() => { - return notificationIdList.filter((notification) => notification === currentNode?.id).length > 0; - }, [notificationIdList, currentNode?.id]); - const intl = useIntl(); const getRootNetworkLabel = (rootNetwork: RootNetworkMetadata): string => { - if (!rootNetwork) { - return ''; - } - return intl.formatMessage({ id: 'root' }) + ' ' + rootNetwork.name; + return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.name; }; const handleSecondaryAction = useCallback( @@ -275,25 +227,13 @@ const RootNetworkNodeEditor = () => { items={rootNetworks} getItemId={(val) => val.rootNetworkUuid} getItemLabel={getRootNetworkLabel} + divider secondaryAction={handleSecondaryAction} /> ); }; const renderRootNetworksListTitleLoading = () => { - return ( - - - - - - - - - ); - }; - - const renderRootNetworksListTitleUpdating = () => { return ( @@ -309,15 +249,11 @@ const RootNetworkNodeEditor = () => { const renderRootNetworksListTitle = () => { return ( - - {pendingState && } - @@ -332,7 +268,6 @@ const RootNetworkNodeEditor = () => { onClose={() => setRootNetworkCreationDialogOpen(false)} onSave={doCreateRootNetwork} titleId={'CreateRootNetwork'} - dialogProps={undefined} /> ); }; @@ -358,7 +293,11 @@ const RootNetworkNodeEditor = () => { } const doCreateRootNetwork = ({ name, caseName, caseId }: FormData) => { - setCreateInProgress(true); + if (!studyUuid) { + return; + } + + setIsLoading(true); getCaseImportParameters(caseId as UUID) .then((params: GetCaseImportParametersReturn) => { @@ -370,18 +309,10 @@ const RootNetworkNodeEditor = () => { caseId as UUID, params.formatName, name, - studyUuid as UUID, + studyUuid, customizedCurrentParameters ); }) - .then(() => { - snackInfo({ - headerId: 'rootNetworkCreated', - headerValues: { - rootNetworkName: name, - }, - }); - }) .catch((error) => { snackError({ messageTxt: error.message, @@ -389,16 +320,14 @@ const RootNetworkNodeEditor = () => { }); }) .finally(() => { - setCreateInProgress(false); + setIsLoading(false); }); }; + const renderPaneSubtitle = () => { - if (isLoading() && messageId) { + if (isLoading) { return renderRootNetworksListTitleLoading(); } - if (launchLoader) { - return renderRootNetworksListTitleUpdating(); - } return renderRootNetworksListTitle(); }; From 9d3be2c33446c578d481639eab3dbe8429fefd23 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 15:06:28 +0100 Subject: [PATCH 47/51] fix: prettier Signed-off-by: LE SAULNIER Kevin --- .../dialogs/root-network/root-network-creation-dialog.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/dialogs/root-network/root-network-creation-dialog.tsx b/src/components/dialogs/root-network/root-network-creation-dialog.tsx index ea0d19f5c3..b02d480345 100644 --- a/src/components/dialogs/root-network/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network/root-network-creation-dialog.tsx @@ -10,7 +10,6 @@ import { isObjectEmpty, TreeViewFinderNodeProps, UniqueNameCheckInput, - useSnackMessage, } from '@gridsuite/commons-ui'; import { useCallback } from 'react'; import { Grid } from '@mui/material'; @@ -61,7 +60,6 @@ const RootNetworkCreationDialog: React.FC = ({ dialogProps, }) => { const studyUuid = useSelector((state: AppState) => state.studyUuid); - const { snackError } = useSnackMessage(); const formMethods = useForm({ defaultValues: emptyFormData, @@ -97,7 +95,7 @@ const RootNetworkCreationDialog: React.FC = ({ // Save data, including CASE_NAME and CASE_ID onSave(values); }, - [onSave, snackError] + [onSave] ); const isFormValid = isObjectEmpty(errors); From bbbc33b3500faab94ba3d6da12db0d4c016dd001 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 15:10:23 +0100 Subject: [PATCH 48/51] fix: initial loading Signed-off-by: LE SAULNIER Kevin --- src/components/network/network-map-tab.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index f2acc81fc6..2f1bc51a57 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -858,11 +858,6 @@ export const NetworkMapTab = ({ if (isNodeRenamed(previousCurrentNode, currentNode)) { return; } - // when root network has just been changed, we reload root node geodata to match its root node geodata - if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { - loadRootNodeGeoData(); - return; - } if (disabled) { return; } @@ -870,6 +865,11 @@ export const NetworkMapTab = ({ if (!rootNodeId) { return; } + // when root network has just been changed, we reload root node geodata to match its root node geodata + if (previousCurrentRootNetworkUuid !== currentRootNetworkUuid) { + loadRootNodeGeoData(); + return; + } // Hack to avoid reload Geo Data when switching display mode to TREE then back to MAP or HYBRID // TODO REMOVE LATER if (!reloadMapNeeded) { From 03cfbbd884b229f8d909b27d75b25b1af3e2eb4a Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 15:30:25 +0100 Subject: [PATCH 49/51] fix: header can actually be nullish Signed-off-by: LE SAULNIER Kevin --- src/components/graph/menus/root-network-node-editor.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/graph/menus/root-network-node-editor.tsx b/src/components/graph/menus/root-network-node-editor.tsx index a70d8c1bde..220234e3f3 100644 --- a/src/components/graph/menus/root-network-node-editor.tsx +++ b/src/components/graph/menus/root-network-node-editor.tsx @@ -127,7 +127,7 @@ const RootNetworkNodeEditor = () => { }, [studyUuid, updateSelectedItems, snackError]); useEffect(() => { - if (studyUpdatedForce.eventData.headers['updateType'] === 'rootNetworksUpdated') { + if (studyUpdatedForce.eventData.headers?.['updateType'] === 'rootNetworksUpdated') { dofetchRootNetworks(); } }, [studyUpdatedForce, dofetchRootNetworks]); @@ -219,9 +219,6 @@ const RootNetworkNodeEditor = () => { checkboxButton: styles.checkboxButton, }), }} - onItemClick={(rootNetwork) => { - console.log(rootNetwork.rootNetworkUuid, 'on click'); - }} selectedItems={selectedItems} onSelectionChange={setSelectedItems} items={rootNetworks} From 89146e371ece18b155a6f19c997fedb116ee0975 Mon Sep 17 00:00:00 2001 From: souissimai Date: Mon, 20 Jan 2025 15:56:09 +0100 Subject: [PATCH 50/51] some fixes : requested remarks Signed-off-by: souissimai --- .../root-network-creation-dialog.tsx | 6 +- .../graph/menus/root-network-node-editor.tsx | 8 +- .../graph/menus/unique-check-name-input.tsx | 151 ++++++++++++++++++ src/components/root-network-panel.tsx | 2 +- src/services/root-network.ts | 2 +- 5 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 src/components/graph/menus/unique-check-name-input.tsx diff --git a/src/components/dialogs/root-network/root-network-creation-dialog.tsx b/src/components/dialogs/root-network/root-network-creation-dialog.tsx index b02d480345..db1d3f08f9 100644 --- a/src/components/dialogs/root-network/root-network-creation-dialog.tsx +++ b/src/components/dialogs/root-network/root-network-creation-dialog.tsx @@ -9,7 +9,6 @@ import { CustomFormProvider, isObjectEmpty, TreeViewFinderNodeProps, - UniqueNameCheckInput, } from '@gridsuite/commons-ui'; import { useCallback } from 'react'; import { Grid } from '@mui/material'; @@ -22,7 +21,8 @@ import { AppState } from 'redux/reducer'; import ModificationDialog from '../commons/modificationDialog'; import { checkRootNetworkNameExistence } from 'services/root-network'; import { RootNetworkCaseSelection } from './root-network-case-selection'; - +import { UniqueCheckNameInput } from 'components/graph/menus/unique-check-name-input'; + export interface FormData { [NAME]: string; [CASE_NAME]: string; @@ -116,7 +116,7 @@ const RootNetworkCreationDialog: React.FC = ({ > - ({ '&': { @@ -89,7 +90,7 @@ const styles = { const RootNetworkNodeEditor = () => { const studyUuid = useSelector((state: AppState) => state.studyUuid); - const { snackInfo, snackError } = useSnackMessage(); + const { snackError } = useSnackMessage(); const [rootNetworks, setRootNetworks] = useState([]); const [deleteInProgress, setDeleteInProgress] = useState(false); const currentNode = useSelector((state: AppState) => state.currentTreeNode); @@ -175,7 +176,7 @@ const RootNetworkNodeEditor = () => { const intl = useIntl(); const getRootNetworkLabel = (rootNetwork: RootNetworkMetadata): string => { - return intl.formatMessage({ id: 'RootNetwork' }) + ': ' + rootNetwork.name; + return intl.formatMessage({ id: 'root' }) + ': ' + rootNetwork.name; }; const handleSecondaryAction = useCallback( @@ -224,7 +225,6 @@ const RootNetworkNodeEditor = () => { items={rootNetworks} getItemId={(val) => val.rootNetworkUuid} getItemLabel={getRootNetworkLabel} - divider secondaryAction={handleSecondaryAction} /> ); diff --git a/src/components/graph/menus/unique-check-name-input.tsx b/src/components/graph/menus/unique-check-name-input.tsx new file mode 100644 index 0000000000..10b3d1283c --- /dev/null +++ b/src/components/graph/menus/unique-check-name-input.tsx @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2024, 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 { ChangeEvent, useCallback, useEffect } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { InputAdornment, TextFieldProps } from '@mui/material'; +import CheckIcon from '@mui/icons-material/Check'; +import { useController, useFormContext } from 'react-hook-form'; +import CircularProgress from '@mui/material/CircularProgress'; +import TextField from '@mui/material/TextField'; +import { UUID } from 'crypto'; +import { useDebounce } from '@gridsuite/commons-ui'; + +export interface UniqueCheckNameInputProps { + name: string; + label?: string; + studyUuid: UUID | null; + autoFocus?: boolean; + onManualChangeCallback?: () => void; + formProps?: Omit< + TextFieldProps, + 'value' | 'onChange' | 'name' | 'label' | 'inputRef' | 'inputProps' | 'InputProps' + >; + elementExists: (studyUuid: UUID, elementName: string) => Promise; +} + +/** + * Input component that constantly check if the field's value is available or not + */ +export function UniqueCheckNameInput({ + name, + label, + studyUuid, + autoFocus, + onManualChangeCallback, + formProps, + elementExists, +}: Readonly) { + const { + field: { onChange, onBlur, value, ref }, + fieldState: { error, isDirty }, + } = useController({ + name, + }); + + const { + setError, + clearErrors, + trigger, + formState: { errors }, + } = useFormContext(); + + // This is a trick to share the custom validation state among the form : while this error is present, we can't validate the form + const isValidating = errors.root?.isValidating; + + const handleCheckName = useCallback( + (nameValue: string) => { + console.log('here ',nameValue) + if (nameValue && studyUuid) { + elementExists?.(studyUuid, nameValue) + .then((alreadyExist) => { + if (alreadyExist) { + setError(name, { + type: 'validate', + message: 'nameAlreadyUsed', + }); + } + }) + .catch((e) => { + setError(name, { + type: 'validate', + message: 'rootNetworknameValidityCheckErrorMsg', + }); + console.error(e?.message); + }) + .finally(() => { + clearErrors('root.isValidating'); + /* force form to validate, otherwise form + will remain invalid (setError('root.isValidating') invalid form and clearErrors does not affect form isValid state : + see documentation : https://react-hook-form.com/docs/useform/clearerrors) */ + trigger('root.isValidating'); + }); + } + }, + [setError, clearErrors, name, elementExists, trigger, studyUuid] + ); + + const debouncedHandleCheckName = useDebounce(handleCheckName, 700); + + // We have to use an useEffect because the name can change from outside of this component (when we upload a case file for instance) + useEffect(() => { + const trimmedValue = value.trim(); + + // if the name is unchanged, we don't do custom validation + if (!isDirty) { + clearErrors(name); + return; + } + if (trimmedValue) { + clearErrors(name); + setError('root.isValidating', { + type: 'validate', + message: 'cantSubmitWhileValidating', + }); + debouncedHandleCheckName(trimmedValue); + } else { + clearErrors('root.isValidating'); + } + }, [debouncedHandleCheckName, setError, clearErrors, name, value, isDirty]); + + // Handle on user's change + const handleManualChange = (e: ChangeEvent) => { + onChange(e.target.value); + onManualChangeCallback?.(); + }; + + const translatedLabel = ; + + const translatedError = error && ; + + const showOk = value?.trim() && !isValidating && !error; + const endAdornment = ( + + {isValidating && } + {showOk && } + + ); + + return ( + + ); +} diff --git a/src/components/root-network-panel.tsx b/src/components/root-network-panel.tsx index cfc8dffae6..1a1dc93b0f 100644 --- a/src/components/root-network-panel.tsx +++ b/src/components/root-network-panel.tsx @@ -16,7 +16,7 @@ const styles = { position: 'absolute', top: 16, left: 16, - width: '60%', + width: '40%', height: '35%', flexDirection: 'column', borderRadius: '8px', diff --git a/src/services/root-network.ts b/src/services/root-network.ts index 1c68f9adb7..1a78e76d85 100644 --- a/src/services/root-network.ts +++ b/src/services/root-network.ts @@ -65,7 +65,7 @@ export function checkRootNetworkNameExistence(studyUuid: UUID, name: string): Pr name: name, }); console.debug(checkRootNetworkNameExistenceUrl); - return backendFetch(rootNetworkNameExistsUrl, { method: 'head' }).then((response) => { + return backendFetch(checkRootNetworkNameExistenceUrl, { method: 'head' }).then((response) => { return response.status !== 204; }); } From ee68b4a95bce557a684107e6c4988ee62b121003 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Mon, 20 Jan 2025 17:12:43 +0100 Subject: [PATCH 51/51] fix: geo data reloading when switching of root network Signed-off-by: LE SAULNIER Kevin --- src/components/network/network-map-tab.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/components/network/network-map-tab.tsx b/src/components/network/network-map-tab.tsx index 2f1bc51a57..ac8a8adf88 100644 --- a/src/components/network/network-map-tab.tsx +++ b/src/components/network/network-map-tab.tsx @@ -580,8 +580,7 @@ export const NetworkMapTab = ({ studyUuid, getEquipmentsNotFoundIds, getMissingEquipmentsPositions, - mapEquipments?.substations, - mapEquipments?.lines, + mapEquipments, updateSubstationsTemporaryGeoData, updateLinesTemporaryGeoData, ]); @@ -597,6 +596,7 @@ export const NetworkMapTab = ({ const loadRootNodeGeoData = useCallback(() => { console.info(`Loading geo data of study '${studyUuid}'...`); dispatch(setMapDataLoading(true)); + setGeoData(undefined); geoDataRef.current = null; // @ts-expect-error TODO: manage rootNodeId undefined case @@ -625,11 +625,6 @@ export const NetworkMapTab = ({ .then(() => { temporaryGeoDataIdsRef.current = new Set(); networkMapRef.current?.resetZoomAndPosition(); - // when reloading root node map equipments (when switching of root network), nominal voltages are reloaded - // we check them all in NominalVoltageFilter by default - if (mapEquipments) { - handleFilteredNominalVoltagesChange(mapEquipments.getNominalVoltages()); - } setIsRootNodeGeoDataLoaded(true); }) .catch(function (error) { @@ -749,7 +744,7 @@ export const NetworkMapTab = ({ } }); return Promise.all([updatedSubstations, updatedLines, updatedTieLines, updatedHvdcLines]).finally(() => { - if (mapEquipments) { + if (isFullReload) { handleFilteredNominalVoltagesChange(mapEquipments.getNominalVoltages()); } dispatch(setMapDataLoading(false)); @@ -811,7 +806,6 @@ export const NetworkMapTab = ({ dispatch(resetMapReloaded()); return; } - updateMapEquipments(currentNodeAtReloadCalling).then(() => { if (checkNodeConsistency(currentNodeAtReloadCalling)) { loadGeoData();