From 6aec0229d14853c0c64d36b1a3d3ce73ba8e2b33 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Thu, 30 Apr 2026 16:56:23 +0200 Subject: [PATCH 1/7] draft Signed-off-by: Mathieu DEHARBE --- .../network-modification-node-editor.tsx | 35 +++++++++++++++++++ src/services/study/network-modifications.ts | 17 +++++++++ src/translations/en.json | 2 ++ src/translations/fr.json | 2 ++ 4 files changed, 56 insertions(+) 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 391cc41eb9..e67187fa2c 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, @@ -84,6 +86,7 @@ import { copyOrMoveModifications } from '../../../../services/study'; import { fetchExcludedNetworkModifications, fetchNetworkModifications, + mergeModificationsIntoComposite, stashModifications, } from '../../../../services/study/network-modifications'; import { @@ -913,6 +916,25 @@ const NetworkModificationNodeEditor = () => { networkModificationsToCopy, ]); + const doMergeModificationsIntoComposite = useCallback(() => { + const selectedModificationsUuid = selectedNetworkModifications.map((item) => item.uuid); + + // TODO : check max depth 5 + + setSaveInProgress(true); + mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModificationsUuid) + .then(() => { + // TODO : glisser vers la composite + // TODO : la mettre en édition (après GRD-4232) + }) + .catch((error: ErrorMessage) => { + snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); // TODO : tester ça + }) + .finally(() => { + setSaveInProgress(false); + }); + }, [currentNode?.id, selectedNetworkModifications, snackError, studyUuid]); + const doCreateCompositeModificationsElements = ({ name, description, @@ -1205,6 +1227,19 @@ const NetworkModificationNodeEditor = () => { + }> + + + + + + }> Date: Tue, 5 May 2026 10:24:27 +0200 Subject: [PATCH 2/7] modificationUuids in the body Signed-off-by: Mathieu DEHARBE --- src/services/study/network-modifications.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/services/study/network-modifications.ts b/src/services/study/network-modifications.ts index 149491e02f..71e8610afc 100644 --- a/src/services/study/network-modifications.ts +++ b/src/services/study/network-modifications.ts @@ -2001,15 +2001,14 @@ export function mergeModificationsIntoComposite( nodeUuid: UUID | undefined, modificationUuids: UUID[] ) { - const urlSearchParams = new URLSearchParams(); - urlSearchParams.append('uuids', String(modificationUuids)); - const url = `${getStudyUrlWithNodeUuid(studyUuid, nodeUuid)}/composite-modification?${urlSearchParams}`; + const url = `${getStudyUrlWithNodeUuid(studyUuid, nodeUuid)}/composite-modification`; return backendFetchJson(url, { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, + body: JSON.stringify(modificationUuids), }); } From 131cc75041f7d98216a58f213875cb580f7b58bf Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Fri, 15 May 2026 17:33:37 +0200 Subject: [PATCH 3/7] slide to the new composite Signed-off-by: Mathieu DEHARBE --- .../network-modification-node-editor.tsx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 da7680aa71..e62328d55e 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 @@ -73,7 +73,12 @@ import NetworkModificationsMenu from 'components/graph/menus/network-modificatio import { SetStateAction, 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'; @@ -962,15 +967,17 @@ const NetworkModificationNodeEditor = () => { ]); const doMergeModificationsIntoComposite = useCallback(() => { - const selectedModificationsUuid = selectedNetworkModifications.map((item) => item.uuid); - + const selectedModUuids: UUID[] = selectedNetworkModifications.map((item) => item.uuid); // TODO : check max depth 5 setSaveInProgress(true); - mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModificationsUuid) - .then(() => { - // TODO : glisser vers la composite + mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModUuids) + .then((compositeUuid: UUID) => { + dispatch(setHighlightModification(compositeUuid)); // TODO : la mettre en édition (après GRD-4232) + // TODO : tout désélectionner : ce qui suit ne fonctionne pas.... + setSelectedNetworkModifications([]); + // TODO : tout "refermer" }) .catch((error: ErrorMessage) => { snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); // TODO : tester ça @@ -978,7 +985,7 @@ const NetworkModificationNodeEditor = () => { .finally(() => { setSaveInProgress(false); }); - }, [currentNode?.id, selectedNetworkModifications, snackError, studyUuid]); + }, [currentNode?.id, dispatch, selectedNetworkModifications, snackError, studyUuid]); const doCreateCompositeModificationsElements = ({ name, From 0ecec23591de3465e1752ecd7651dfb11db993ed Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Fri, 15 May 2026 17:34:28 +0200 Subject: [PATCH 4/7] slide to the new composite Signed-off-by: Mathieu DEHARBE --- src/services/study/network-modifications.ts | 2 +- src/translations/en.json | 1 + src/translations/fr.json | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/study/network-modifications.ts b/src/services/study/network-modifications.ts index dbdb290118..fe55793baa 100644 --- a/src/services/study/network-modifications.ts +++ b/src/services/study/network-modifications.ts @@ -1994,7 +1994,7 @@ export function mergeModificationsIntoComposite( studyUuid: UUID | null, nodeUuid: UUID | undefined, modificationUuids: UUID[] -) { +): Promise { const url = `${getStudyUrlWithNodeUuid(studyUuid, nodeUuid)}/composite-modification`; return backendFetchJson(url, { method: 'POST', diff --git a/src/translations/en.json b/src/translations/en.json index 0ef5e4addf..1e99bb877b 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1038,6 +1038,7 @@ "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 17cbe3c31d..e474d3bb6e 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -1037,6 +1037,7 @@ "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}", From c0cb09cebb7c72c3883af9a173eaa210849332a2 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 18 May 2026 17:19:43 +0200 Subject: [PATCH 5/7] disable when isCompositeNestingLimitReached Signed-off-by: Mathieu DEHARBE --- .../network-modification-node-editor.tsx | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) 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 e62328d55e..e384bb9614 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 @@ -742,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) => { @@ -968,8 +964,6 @@ const NetworkModificationNodeEditor = () => { const doMergeModificationsIntoComposite = useCallback(() => { const selectedModUuids: UUID[] = selectedNetworkModifications.map((item) => item.uuid); - // TODO : check max depth 5 - setSaveInProgress(true); mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModUuids) .then((compositeUuid: UUID) => { @@ -980,7 +974,7 @@ const NetworkModificationNodeEditor = () => { // TODO : tout "refermer" }) .catch((error: ErrorMessage) => { - snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); // TODO : tester ça + snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); }) .finally(() => { setSaveInProgress(false); @@ -1290,17 +1284,39 @@ const NetworkModificationNodeEditor = () => { - }> + + ) : ( + + ) + } + > - - - + + + + }> From 6fa7594f989d89669c2bc14390b670088d3fb2b7 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 19 May 2026 18:34:06 +0200 Subject: [PATCH 6/7] =?UTF-8?q?d=C3=A9slection=20when=20merging=20netmods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mathieu DEHARBE --- .../network-modification-node-editor.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 e384bb9614..37e28f7c17 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 @@ -191,6 +191,7 @@ const NetworkModificationNodeEditor = () => { const [isFetchingModifications, setIsFetchingModifications] = useState(false); const [isUpdate, setIsUpdate] = useState(false); const buttonAddRef = useRef(null); + const [selectionResetKey, setSelectionResetKey] = useState(0); const highlightedModificationUuid = useSelector((state: AppState) => state.highlightedModificationUuid); const { @@ -968,10 +969,9 @@ const NetworkModificationNodeEditor = () => { mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModUuids) .then((compositeUuid: UUID) => { dispatch(setHighlightModification(compositeUuid)); + setSelectionResetKey((k) => k + 1); // TODO : la mettre en édition (après GRD-4232) - // TODO : tout désélectionner : ce qui suit ne fonctionne pas.... - setSelectedNetworkModifications([]); - // TODO : tout "refermer" + // TODO : tout "refermer" -> les composites restent }) .catch((error: ErrorMessage) => { snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); @@ -1200,6 +1200,7 @@ const NetworkModificationNodeEditor = () => { pendingState={pendingState} createAllColumns={createAllColumns} highlightedModificationUuid={highlightedModificationUuid} + selectionResetKey={selectionResetKey} studyUuid={studyUuid} currentNodeId={currentNode?.id} /> From 2c39de96260cfb058b5e63dcaf2c3c15294d6c7f Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Wed, 20 May 2026 10:24:42 +0200 Subject: [PATCH 7/7] modificationUuidsToReset Signed-off-by: Mathieu DEHARBE --- .../network-modification-node-editor.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 4a04cd1a8e..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 @@ -190,7 +190,7 @@ const NetworkModificationNodeEditor = () => { const [isFetchingModifications, setIsFetchingModifications] = useState(false); const [isUpdate, setIsUpdate] = useState(false); const buttonAddRef = useRef(null); - const [selectionResetKey, setSelectionResetKey] = useState(0); + const [modificationUuidsToReset, setModificationUuidsToReset] = useState([]); const highlightedModificationUuid = useSelector((state: AppState) => state.highlightedModificationUuid); const { @@ -972,9 +972,8 @@ const NetworkModificationNodeEditor = () => { mergeModificationsIntoComposite(studyUuid, currentNode?.id, selectedModUuids) .then((compositeUuid: UUID) => { dispatch(setHighlightModification(compositeUuid)); - setSelectionResetKey((k) => k + 1); + setModificationUuidsToReset(selectedModUuids); // TODO : la mettre en édition (après GRD-4232) - // TODO : tout "refermer" -> les composites restent }) .catch((error: ErrorMessage) => { snackWithFallback(snackError, error, { headerId: 'MergeIntoCompositeError' }); @@ -1191,7 +1190,7 @@ const NetworkModificationNodeEditor = () => { pendingState={pendingState} columns={columns} highlightedModificationUuid={highlightedModificationUuid} - selectionResetKey={selectionResetKey} + modificationUuidsToReset={modificationUuidsToReset} studyUuid={studyUuid} currentNodeId={currentNode?.id} />