diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index 0f5be0c319..1ea3aa8ab9 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -6,10 +6,12 @@ */ import { + ArrowsInputIcon, ComposedModificationMetadata, ElementSaveDialog, ElementType, EquipmentType, + ErrorMessage, ExcludedNetworkModifications, fetchNetworkModification, IElementCreationDialog, @@ -70,7 +72,12 @@ import NetworkModificationsMenu from 'components/graph/menus/network-modificatio import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; -import { addNotification, removeNotificationByNode, setModificationsInProgress } from '../../../../redux/actions'; +import { + addNotification, + removeNotificationByNode, + setHighlightModification, + 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'; @@ -84,6 +91,7 @@ import { copyOrMoveModifications } from '../../../../services/study'; import { fetchExcludedNetworkModifications, fetchNetworkModifications, + mergeModificationsIntoComposite, setModificationMetadata, stashModifications, } from '../../../../services/study/network-modifications'; @@ -182,6 +190,7 @@ const NetworkModificationNodeEditor = () => { const [isFetchingModifications, setIsFetchingModifications] = useState(false); const [isUpdate, setIsUpdate] = useState(false); const buttonAddRef = useRef(null); + const [modificationUuidsToReset, setModificationUuidsToReset] = useState([]); const highlightedModificationUuid = useSelector((state: AppState) => state.highlightedModificationUuid); const { @@ -733,14 +742,10 @@ const NetworkModificationNodeEditor = () => { // 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 - ); + const liveModifications = res.filter((networkModification) => !networkModification.stashed); updateSelectedItems(liveModifications); setModifications(liveModifications); - setModificationsToRestore( - res.filter((networkModification) => networkModification.stashed === true) - ); + setModificationsToRestore(res.filter((networkModification) => networkModification.stashed)); } }) .catch((error) => { @@ -961,6 +966,23 @@ const NetworkModificationNodeEditor = () => { networkModificationsToCopy, ]); + const doMergeModificationsIntoComposite = useCallback(() => { + const selectedModUuids: UUID[] = selectedNetworkModifications.map((item) => item.uuid); + setSaveInProgress(true); + mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModUuids) + .then((compositeUuid: UUID) => { + dispatch(setHighlightModification(compositeUuid)); + setModificationUuidsToReset(selectedModUuids); + // TODO : la mettre en édition (après GRD-4232) + }) + .catch((error: ErrorMessage) => { + snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); + }) + .finally(() => { + setSaveInProgress(false); + }); + }, [currentNode?.id, dispatch, selectedNetworkModifications, snackError, studyUuid]); + const doCreateCompositeModificationsElements = ({ name, description, @@ -1168,6 +1190,7 @@ const NetworkModificationNodeEditor = () => { pendingState={pendingState} columns={columns} highlightedModificationUuid={highlightedModificationUuid} + modificationUuidsToReset={modificationUuidsToReset} studyUuid={studyUuid} currentNodeId={currentNode?.id} /> @@ -1252,6 +1275,41 @@ const NetworkModificationNodeEditor = () => { + + ) : ( + + ) + } + > + + + + + + + + }> { + const url = `${getStudyUrlWithNodeUuid(studyUuid, nodeUuid)}/composite-modification`; + return backendFetchJson(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(modificationUuids), + }); +} + export function getNetworkModificationsFromComposite( compositeModificationUuids: string[], onlyMetadata: boolean = true diff --git a/src/translations/en.json b/src/translations/en.json index 99619bfd91..1e99bb877b 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1036,6 +1036,9 @@ "importAndReplaceFromGridExplore": "Import and replace from GridExplore", "SaveToGridexplore": "Save to GridExplore", "SaveToGridexploreError": "An error occurred while saving to GridExplore", + "MergeIntoComposite": "Create a composite modification", + "MergeIntoCompositeError": "An error occurred during the creation of the composite modification", + "DefaultCompositeName": "Composite modification", "CompositeNestingLimitReached": "Saving to GridExplore is not possible : would exceed nesting limit ({limit})", "diagramConfigCreationMsg": "Network area diagram created in {directory}", "diagramConfigUpdateMsg": "Network area diagram {item} updated", diff --git a/src/translations/fr.json b/src/translations/fr.json index a07fdd1d5b..e474d3bb6e 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1035,6 +1035,9 @@ "importAndReplaceFromGridExplore": "Importer et remplacer à partir de GridExplore", "SaveToGridexplore": "Enregistrer dans GridExplore", "SaveToGridexploreError": "Une erreur est survenue lors de la sauvegarde dans GridExplore", + "MergeIntoComposite": "Créer une modification composite", + "MergeIntoCompositeError": "Une erreur est survenue lors de la création de la modification composite", + "DefaultCompositeName": "Modification Composite", "CompositeNestingLimitReached": "Enregistrement dans Gridexplore Impossible : dépasserait la limite d'imbrication ({limit})", "diagramConfigCreationMsg": "Création de l'image nodale de zone dans {directory}", "diagramConfigUpdateMsg": "Mise à jour de l'image nodale de zone {item}",