Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
710a663
Unify move endpoints
May 28, 2026
cb11203
Fix cut move
May 28, 2026
1bb3275
Fix notification handling
May 28, 2026
26aea2e
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo May 28, 2026
92e688c
Lint
May 28, 2026
cae9f8a
Fix rebuild tests
May 28, 2026
fe69c22
Checkstyle
May 28, 2026
99ddc98
Remove unused path
May 28, 2026
d28f0a1
Fix exclusion tests
May 28, 2026
bbbdd0b
Fix modifications tests
May 28, 2026
88f0a05
Revert endpoint resource label
May 29, 2026
aab2a27
Merge remote-tracking branch 'origin/main' into marcellinh/unify_move…
Jun 2, 2026
58d8335
Coderabbit suggestions
Jun 2, 2026
0064243
Fix test
Jun 2, 2026
fd07c3f
Coderabbit suggestion
Jun 2, 2026
6ec4a78
Sonar transaction issue
Jun 2, 2026
20bbbd9
Sonar issues
Jun 2, 2026
f9be565
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo Jun 2, 2026
4150a18
Restore tests
Jun 2, 2026
fe0bc86
Lint
Jun 2, 2026
d0bee1d
Restore check
Jun 3, 2026
793dff2
Restore statement
Jun 3, 2026
da31dd7
Merge remote-tracking branch 'origin/main' into marcellinh/unify_move…
Jun 10, 2026
985d236
Restore missing function
Jun 10, 2026
7dd3248
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo Jun 15, 2026
cc265f6
Merge main
Jun 18, 2026
cfe6a08
Fix test
Jun 18, 2026
88219f4
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo Jun 23, 2026
646ae0a
Merge main
Jun 30, 2026
b5946ae
Fix
Jun 30, 2026
f9431f4
Fix
Jun 30, 2026
cf3984b
Fix checkstyle issue
Jun 30, 2026
c8cae45
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo Jul 13, 2026
becef07
Pass containers types
Jul 21, 2026
8da7984
Fix import
Jul 21, 2026
094d878
Merge branch 'main' into marcellinh/unify_move_endpoints
Meklo Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.filter.globalfilter.GlobalFilter;
import org.gridsuite.filter.utils.EquipmentType;
Expand Down Expand Up @@ -627,35 +626,28 @@ public ResponseEntity<String> getAllMapData(
}

@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network-modification/{modificationUuid}")
@Operation(summary = "move network modification before another")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The modification order is updated")})
public ResponseEntity<Void> moveModification(@PathVariable("studyUuid") UUID studyUuid,
@PathVariable("nodeUuid") UUID nodeUuid,
@PathVariable("modificationUuid") UUID modificationUuid,
@Nullable @Parameter(description = "move before, if no value move to end") @RequestParam(value = "beforeUuid") UUID beforeUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid);
studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid);
rebuildNodeService.moveNetworkModification(studyUuid, nodeUuid, modificationUuid, beforeUuid, userId);
return ResponseEntity.ok().build();
}

@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-sub-modification/{modificationUuid}")
@Operation(summary = "Move a composite sub-modification within/between composites or to/from root level")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The sub-modification order has been updated")})
public ResponseEntity<Void> moveSubModification(
@Operation(summary = "Move a modification within or between containers (groups or composites)")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The modification order has been updated")})
public ResponseEntity<Void> moveModification(
@PathVariable("studyUuid") UUID studyUuid,
@PathVariable("nodeUuid") UUID nodeUuid,
@PathVariable("modificationUuid") UUID modificationUuid,
@Nullable @Parameter(description = "Source composite UUID; absent when moving from root level") @RequestParam(value = "sourceCompositeUuid", required = false) UUID sourceCompositeUuid,
@Nullable @Parameter(description = "Target composite UUID; absent when moving to root level") @RequestParam(value = "targetCompositeUuid", required = false) UUID targetCompositeUuid,
@Nullable @Parameter(description = "Insert before this UUID; absent means append at end") @RequestParam(value = "beforeUuid", required = false) UUID beforeUuid,
@Parameter(description = "source container UUID; for GROUP source the node's group is used when absent") @RequestParam(value = "sourceContainerId", required = false) UUID sourceContainerId,
@Parameter(description = "target container UUID; for GROUP target the node's group is used when absent") @RequestParam(value = "targetContainerId", required = false) UUID targetContainerId,
@Parameter(description = "insert before this modification (empty = at end)") @RequestParam(value = "beforeUuid", required = false) UUID beforeUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid);
studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid);
rebuildNodeService.moveSubModification(
studyUuid, nodeUuid,
sourceCompositeUuid, targetCompositeUuid,
// For GROUP containers without an explicit id, fall back to the node's group.
UUID resolvedSourceId = sourceContainerId == null
? networkModificationTreeService.getModificationGroupUuid(nodeUuid) : sourceContainerId;
UUID resolvedTargetId = targetContainerId == null
? networkModificationTreeService.getModificationGroupUuid(nodeUuid) : targetContainerId;
rebuildNodeService.moveNetworkModification(
studyUuid,
nodeUuid,
resolvedTargetId,
resolvedSourceId,
modificationUuid, beforeUuid, userId);
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,27 @@ public void stopBuild(@NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid) {
restTemplate.put(getNetworkModificationServerURI(false) + path, null);
}

public NetworkModificationsResult moveModifications(UUID originGroupUuid, UUID targetGroupUuid, UUID beforeUuid, Pair<List<UUID>, List<ModificationApplicationContext>> modificationContextInfos, boolean buildTargetNode) {
public NetworkModificationsResult moveModifications(
UUID sourceContainerId, UUID targetContainerId,
UUID beforeUuid,
Pair<List<UUID>, List<ModificationApplicationContext>> body,
boolean buildTargetNode) {

var path = UriComponentsBuilder.fromPath(GROUP_PATH)
.queryParam(QUERY_PARAM_ACTION, ModificationsActionType.MOVE.name())
.queryParam("originGroupUuid", originGroupUuid)
.queryParam("build", buildTargetNode);
.queryParam(QUERY_PARAM_ACTION, ModificationsActionType.MOVE.name())
.queryParam("originGroupUuid", sourceContainerId)
.queryParam("build", buildTargetNode);
if (beforeUuid != null) {
path.queryParam("before", beforeUuid);
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Pair<List<UUID>, List<ModificationApplicationContext>>> httpEntity = new HttpEntity<>(modificationContextInfos, headers);
HttpEntity<Pair<List<UUID>, List<ModificationApplicationContext>>> httpEntity = new HttpEntity<>(body, headers);

return restTemplate.exchange(
getNetworkModificationServerURI(false) + path.buildAndExpand(targetGroupUuid).toUriString(),
HttpMethod.PUT,
httpEntity,
NetworkModificationsResult.class).getBody();
getNetworkModificationServerURI(false) + path.buildAndExpand(targetContainerId).toUriString(),
HttpMethod.PUT, httpEntity, NetworkModificationsResult.class).getBody();
}

public NetworkModificationsResult duplicateModifications(UUID groupUuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1294,4 +1294,10 @@ public ExportNetworkStatus getExportNetworkStatus(UUID exportUuid) {
.map(ExportNetworkStatus::valueOf)
.orElseThrow(() -> new StudyException(NOT_FOUND, "No export found for exportUuid=" + exportUuid));
}

@Transactional(readOnly = true)
public UUID getNodeUuidByModificationGroup(UUID groupUuid) {
var node = networkModificationNodeInfoRepository.findByModificationGroupUuidIn(List.of(groupUuid));
return node.isEmpty() ? null : node.getFirst().getIdNode();
}
Comment thread
Meklo marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
package org.gridsuite.study.server.service;

import lombok.NonNull;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
import org.springframework.stereotype.Service;

Expand Down Expand Up @@ -66,61 +65,17 @@ public void restoreNetworkModifications(UUID studyUuid, UUID nodeUuid, List<UUID
() -> studyService.restoreNetworkModifications(studyUuid, nodeUuid, modificationsUuids, userId));
}

public void moveNetworkModification(UUID studyUuid, UUID nodeUuid, UUID modificationUuid, UUID beforeUuid, String userId) {
handleRebuildNode(studyUuid, nodeUuid, userId,
() -> handleMoveNetworkModification(studyUuid, nodeUuid, modificationUuid, beforeUuid, userId));
}

private void handleMoveNetworkModification(UUID studyUuid, UUID nodeUuid, UUID modificationUuid, UUID beforeUuid, String userId) {
studyService.invalidateNodeTreeWhenMoveModification(studyUuid, nodeUuid);
try {
studyService.moveNetworkModifications(studyUuid, nodeUuid, nodeUuid, List.of(modificationUuid), beforeUuid, false, userId);
} finally {
studyService.unblockNodeTree(studyUuid, nodeUuid);
}
}

public void moveNetworkModifications(UUID studyUuid, UUID targetNodeUuid, UUID originNodeUuid, List<UUID> modificationsToCopyUuidList, String userId) {
handleRebuildNode(studyUuid, targetNodeUuid, originNodeUuid, userId,
() -> handleMoveNetworkModifications(studyUuid, targetNodeUuid, originNodeUuid, modificationsToCopyUuidList, userId));
}

public void moveSubModification(
UUID studyUuid,
UUID nodeUuid,
UUID sourceCompositeUuid,
UUID targetCompositeUuid,
UUID modificationUuid,
UUID beforeUuid,
String userId) {
handleRebuildNode(studyUuid, nodeUuid, userId,
() -> handleMoveNetworkSubmodification(
studyUuid, nodeUuid,
sourceCompositeUuid, targetCompositeUuid,
modificationUuid, beforeUuid, userId));
}

private void handleMoveNetworkSubmodification(@NonNull UUID studyUuid,
@NonNull UUID nodeUuid,
UUID sourceCompositeUuid,
UUID targetCompositeUuid,
@NonNull UUID modificationUuid,
UUID beforeUuid,
String userId) {
studyService.invalidateNodeTreeWhenMoveModification(studyUuid, nodeUuid);
try {
studyService.moveSubModification(studyUuid, nodeUuid,
sourceCompositeUuid, targetCompositeUuid,
modificationUuid, beforeUuid, userId);
} finally {
studyService.unblockNodeTree(studyUuid, nodeUuid);
}
() -> handleMoveNetworkModifications(studyUuid, targetNodeUuid, originNodeUuid, modificationsToCopyUuidList, userId));
}

private void handleMoveNetworkModifications(UUID studyUuid, UUID targetNodeUuid, UUID originNodeUuid, List<UUID> modificationsToCopyUuidList, String userId) {
boolean isTargetInDifferentNodeTree = studyService.invalidateNodeTreeWhenMoveModifications(studyUuid, targetNodeUuid, originNodeUuid);
try {
studyService.moveNetworkModifications(studyUuid, targetNodeUuid, originNodeUuid, modificationsToCopyUuidList, null, isTargetInDifferentNodeTree, userId);
UUID sourceContainerId = networkModificationTreeService.getModificationGroupUuid(originNodeUuid);
UUID targetContainerId = networkModificationTreeService.getModificationGroupUuid(targetNodeUuid);
studyService.moveNetworkModifications(studyUuid, targetNodeUuid, targetContainerId, sourceContainerId, modificationsToCopyUuidList, null, isTargetInDifferentNodeTree, userId);
} finally {
studyService.unblockNodeTree(studyUuid, originNodeUuid);
if (isTargetInDifferentNodeTree) {
Expand All @@ -129,6 +84,29 @@ private void handleMoveNetworkModifications(UUID studyUuid, UUID targetNodeUuid,
}
}

public void moveNetworkModification(
UUID studyUuid,
UUID nodeUuid,
UUID targetContainerId,
UUID sourceContainerId,
UUID modificationUuid, UUID beforeUuid, String userId) {
handleRebuildNode(studyUuid, nodeUuid, userId,
() -> {
studyService.invalidateNodeTreeWhenMoveModification(studyUuid, nodeUuid);
try {
studyService.moveNetworkModifications(
studyUuid,
nodeUuid,
targetContainerId,
sourceContainerId,
List.of(modificationUuid), beforeUuid,
false, userId);
} finally {
studyService.unblockNodeTree(studyUuid, nodeUuid);
}
});
Comment thread
Meklo marked this conversation as resolved.
}

private void handleRebuildNode(UUID studyUuid, UUID nodeUuid, String userId, Runnable action) {
handleRebuildNode(studyUuid, nodeUuid, nodeUuid, userId, action);
}
Expand Down
68 changes: 25 additions & 43 deletions src/main/java/org/gridsuite/study/server/service/StudyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2238,69 +2238,51 @@
}

@Transactional
public void moveNetworkModifications(

Check warning on line 2241 in src/main/java/org/gridsuite/study/server/service/StudyService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Method has 8 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Astudy-server&issues=AZ5veWPSljYF4tVlRgQY&open=AZ5veWPSljYF4tVlRgQY&pullRequest=1000
@NonNull UUID studyUuid,
UUID targetNodeUuid,
@NonNull UUID originNodeUuid,
@NonNull UUID targetNodeUuid,
@NonNull UUID targetContainerId,
@NonNull UUID sourceContainerId,
List<UUID> modificationUuidList,
UUID beforeUuid,
boolean isTargetInDifferentNodeTree,
String userId) {
boolean isTargetDifferentNode = !targetNodeUuid.equals(originNodeUuid);
UUID originNodeUuid = networkModificationTreeService.getNodeUuidByModificationGroup(sourceContainerId);

List<UUID> originNodeChildrenUuids = List.of();
List<UUID> childrenUuids = networkModificationTreeService.getChildrenUuids(targetNodeUuid);
List<UUID> originNodeChildrenUuids = new ArrayList<>();
notificationService.emitStartModificationEquipmentNotification(studyUuid, targetNodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
if (isTargetDifferentNode) {
if (isTargetInDifferentNodeTree) {
originNodeChildrenUuids = networkModificationTreeService.getChildrenUuids(originNodeUuid);
notificationService.emitStartModificationEquipmentNotification(studyUuid, originNodeUuid, originNodeChildrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
}
try {
checkStudyContainsNode(studyUuid, targetNodeUuid);

try {
StudyEntity studyEntity = getStudy(studyUuid);
List<RootNetworkEntity> studyRootNetworkEntities = studyEntity.getRootNetworks();
UUID originGroupUuid = networkModificationTreeService.getModificationGroupUuid(originNodeUuid);
UUID targetGroupUuid = networkModificationTreeService.getModificationGroupUuid(targetNodeUuid);

List<ModificationApplicationContext> modificationApplicationContexts = studyRootNetworkEntities.stream()
.map(rootNetworkEntity -> rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), targetNodeUuid, rootNetworkEntity.getNetworkUuid()))
.toList();

NetworkModificationsResult networkModificationsResult = networkModificationService.moveModifications(originGroupUuid, targetGroupUuid, beforeUuid, Pair.of(modificationUuidList, modificationApplicationContexts), isTargetInDifferentNodeTree);
rootNetworkNodeInfoService.moveModificationsToExclude(originNodeUuid, targetNodeUuid, networkModificationsResult.modificationUuids());

// Target node
if (isTargetInDifferentNodeTree) {
emitNetworkModificationImpactsForAllRootNetworks(networkModificationsResult.modificationResults(), studyEntity, targetNodeUuid);
checkStudyContainsNode(studyUuid, targetNodeUuid);
List<ModificationApplicationContext> applicationContexts = studyEntity.getRootNetworks().stream()
.map(rn -> rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rn.getId(), targetNodeUuid, rn.getNetworkUuid()))
.toList();

NetworkModificationsResult result = networkModificationService.moveModifications(
sourceContainerId,
targetContainerId,
beforeUuid,
Pair.of(modificationUuidList, applicationContexts),
isTargetInDifferentNodeTree);

if (result != null && originNodeUuid != null) {
rootNetworkNodeInfoService.moveModificationsToExclude(originNodeUuid, targetNodeUuid, result.modificationUuids());
}
if (result != null && isTargetInDifferentNodeTree) {
emitNetworkModificationImpactsForAllRootNetworks(result.modificationResults(), studyEntity, targetNodeUuid);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} finally {
notificationService.emitEndModificationEquipmentNotification(studyUuid, targetNodeUuid, childrenUuids);
if (isTargetDifferentNode) {
if (originNodeUuid != null && !originNodeUuid.equals(targetNodeUuid)) {
notificationService.emitEndModificationEquipmentNotification(studyUuid, originNodeUuid, originNodeChildrenUuids);
}
}
notificationService.emitElementUpdated(studyUuid, userId);
}

public void moveSubModification(
@NonNull UUID studyUuid,
@NonNull UUID nodeUuid,
UUID sourceCompositeUuid,
UUID targetCompositeUuid,
@NonNull UUID modificationUuid,
UUID beforeUuid,
String userId) {

List<UUID> childrenUuids = networkModificationTreeService.getChildrenUuids(nodeUuid);
try {
notificationService.emitStartModificationEquipmentNotification(studyUuid, nodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
checkStudyContainsNode(studyUuid, nodeUuid);
UUID groupUuid = networkModificationTreeService.getModificationGroupUuid(nodeUuid);
networkModificationService.moveSubModification(
groupUuid, sourceCompositeUuid, targetCompositeUuid, modificationUuid, beforeUuid);
} finally {
notificationService.emitEndModificationEquipmentNotification(studyUuid, nodeUuid, childrenUuids);
}
notificationService.emitElementUpdated(studyUuid, userId);
}
Expand Down
Loading
Loading