Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
dab4a3f
copy cut paste reference modification and add ref with target infos
Aug 12, 2026
a421f4a
fix
Aug 12, 2026
eefec9d
fix tests
Aug 12, 2026
11e5328
fix tests
Aug 12, 2026
2d449d6
Merge branch 'main' into reference-modification-actions
souissimai Aug 13, 2026
6a4fcce
Merge branch 'main' into reference-modification-actions
souissimai Aug 13, 2026
1ea9dd4
update references when moving
Aug 14, 2026
83dc1d0
adjust tests
Aug 14, 2026
c3b48dd
test coverage
Aug 16, 2026
a6142ba
test coverage
Aug 16, 2026
baa0d39
Merge branch 'main' into reference-modification-actions
souissimai Aug 19, 2026
b4d3037
fixes
Aug 19, 2026
9449685
Merge branch 'main' into reference-modification-actions
souissimai Aug 20, 2026
3e9d6ba
missing..
Aug 21, 2026
4eb2684
copy paste , refernce creation
Aug 21, 2026
8d02e81
Merge branch 'main' into reference-modification-actions
souissimai Aug 21, 2026
f72c30b
clean code
Aug 22, 2026
223bda0
clean
Aug 22, 2026
53edf56
Merge branch 'main' into reference-modification-actions
souissimai Aug 24, 2026
0f7b3c6
renaming
Aug 26, 2026
4f1ea88
emit notif, update ref
Aug 26, 2026
0db27db
fix
Aug 26, 2026
3c1c369
Merge remote-tracking branch 'origin/reference-modification-actions' …
Aug 26, 2026
67e2c80
notifications
Aug 26, 2026
0df9090
resolve conflicts
Aug 26, 2026
2023f5e
some changess , resolve conflicts
Aug 26, 2026
a4c0ea4
Merge branch 'reference-modification-actions' into emit-notif-references
Aug 27, 2026
6d1f167
add UT
Aug 27, 2026
9d0caf6
send shared element notification sendStudyUpdateMessage
Aug 27, 2026
4585b8f
resolev conflicts
Aug 30, 2026
26f21e2
clean
Sep 1, 2026
8621513
Merge branch 'main' into emit-notif-references
souissimai Sep 1, 2026
a4002e9
fix
Sep 1, 2026
7901c31
adapt code
Sep 2, 2026
1b5d2d3
Merge branch 'main' into emit-notif-references
souissimai Sep 2, 2026
2b425d0
add tu
Sep 2, 2026
3f337c1
Merge branch 'main' into emit-notif-references
souissimai Sep 2, 2026
29c0b97
fix sonar issues
Sep 2, 2026
8c09183
Merge branch 'main' into emit-notif-references
souissimai Sep 4, 2026
c3aba9e
Review
Sep 7, 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 @@ -40,6 +40,7 @@ public class NotificationService {
public static final String HEADER_NODE = "node";
public static final String HEADER_ROOT_NETWORK_UUID = "rootNetworkUuid";
public static final String HEADER_NODES = "nodes";
public static final String HEADER_NETWORK_MODIFICATION_UUIDS = "networkModificationUuids";
public static final String HEADER_ROOT_NETWORKS_UUIDS = "rootNetworksUuids";
public static final String HEADER_STUDY_UUID = "studyUuid";
public static final String HEADER_UPDATE_TYPE = "updateType";
Expand Down Expand Up @@ -124,6 +125,7 @@ public class NotificationService {

public static final String MODIFICATIONS_UPDATING_FINISHED = "UPDATE_FINISHED";
public static final String MODIFICATIONS_DELETING_FINISHED = "DELETE_FINISHED";
public static final String SHARED_ELEMENT_UPDATED = "sharedElementUpdate";

public static final String EVENTS_CRUD_FINISHED = "EVENT_CRUD_FINISHED";

Expand Down Expand Up @@ -471,6 +473,19 @@ public void emitModificationsDeleted(UUID studyUuid, UUID parentNodeUuid, Collec
);
}

/**
* Notifies the front that a shared element referenced by some of {@code parentNodeUuid}'s network
* modifications ({@code networkModificationUuids}) has changed. The front should refresh the
* modifications list of that node so the affected modifications display the up-to-date reference.
*/
@PostCompletion
public void emitSharedElementUpdated(UUID studyUuid, UUID parentNodeUuid, Collection<UUID> networkModificationUuids) {
sendStudyUpdateMessage(studyUuid, SHARED_ELEMENT_UPDATED, MessageBuilder.withPayload("")
.setHeader(HEADER_PARENT_NODE, parentNodeUuid)
.setHeader(HEADER_NETWORK_MODIFICATION_UUIDS, networkModificationUuids)
);
}

@PostCompletion
public void emitEventsUpdated(UUID studyUuid, UUID parentNodeUuid, Collection<UUID> childrenUuids) {
sendStudyUpdateMessage(studyUuid, EVENTS_CRUD_FINISHED, MessageBuilder.withPayload("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class ConsumerService {
private final CaseService caseService;
private final LoadFlowRestService loadFlowRestService;
private final NetworkModificationTreeService networkModificationTreeService;
private final NetworkModificationService networkModificationService;
private final StudyConfigService studyConfigService;
private final RootNetworkNodeInfoService rootNetworkNodeInfoService;
private final RootNetworkService rootNetworkService;
Expand All @@ -86,6 +87,7 @@ public ConsumerService(ObjectMapper objectMapper,
CaseService caseService,
LoadFlowRestService loadFlowRestService,
NetworkModificationTreeService networkModificationTreeService,
NetworkModificationService networkModificationService,
StudyConfigService studyConfigService,
RootNetworkNodeInfoService rootNetworkNodeInfoService,
RootNetworkService rootNetworkService,
Expand All @@ -101,6 +103,7 @@ public ConsumerService(ObjectMapper objectMapper,
this.caseService = caseService;
this.loadFlowRestService = loadFlowRestService;
this.networkModificationTreeService = networkModificationTreeService;
this.networkModificationService = networkModificationService;
this.studyConfigService = studyConfigService;
this.rootNetworkNodeInfoService = rootNetworkNodeInfoService;
this.rootNetworkService = rootNetworkService;
Expand Down Expand Up @@ -856,4 +859,32 @@ public void createCase(String s3Key, NodeExportInfos nodeExport, String userId,
public Consumer<Message<String>> consumeNetworkExportFinished() {
return this::consumeNetworkExportFinished;
}

@Bean
public Consumer<Message<Map<ReferenceAttributes.ReferenceType, List<ReferenceAttributes>>>> consumeSharedElementUpdate() {
return message -> handleSharedElementUpdate(message.getPayload());
}

// TODO need to handle by type and not group modifications list
private void handleSharedElementUpdate(Map<ReferenceAttributes.ReferenceType, List<ReferenceAttributes>> referencesByType) {
List<UUID> studyNodeUuids = extractReferenceIds(referencesByType, ReferenceAttributes.ReferenceType.STUDY_NODE);
List<UUID> networkModificationUuids = extractReferenceIds(referencesByType, ReferenceAttributes.ReferenceType.NETWORK_MODIFICATION);

Set<UUID> nodeUuidsToInvalidate = new HashSet<>(studyNodeUuids);

if (!networkModificationUuids.isEmpty()) {
Collection<UUID> rootGroupUuids = networkModificationService.findRootGroupByModification(networkModificationUuids).values();
if (!rootGroupUuids.isEmpty()) {
nodeUuidsToInvalidate.addAll(networkModificationTreeService.getNodeUuidsByModificationGroups(List.copyOf(rootGroupUuids)).values());
}
}

nodeUuidsToInvalidate.forEach(nodeUuid -> {
studyService.sharedElementUpdatedNotification(nodeUuid, networkModificationUuids);
});
}

private static List<UUID> extractReferenceIds(Map<ReferenceAttributes.ReferenceType, List<ReferenceAttributes>> referencesByType, ReferenceAttributes.ReferenceType type) {
return referencesByType.getOrDefault(type, List.of()).stream().map(ReferenceAttributes::getReferenceId).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public boolean elementExists(UUID directoryUuid, String elementName, String type
* creates references and add them to shared composite modifications stored in directory server
* @param elementsUuids element uuids of the shared composites in directory server
* @param userId id of the user who creates the references
* @param targetReferenceUuid where the new references will point
* @param targetReferenceUuid where the new references will point to
* @param targetReferenceType type of the target the new references point to
*/
public void createsReferencesToSharedComposites(@NonNull List<UUID> elementsUuids, String userId, UUID targetReferenceUuid, ReferenceAttributes.ReferenceType targetReferenceType) {
// TODO : instead of multiple calls, an endpoint in directory server should be created to handle multiple references creation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public NetworkModificationsResult createModification(UUID groupUuid,
return restTemplate.exchange(path, HttpMethod.POST, httpEntity, NetworkModificationsResult.class).getBody();
}

public void updateModification(String createEquipmentAttributes, UUID modificationUuid) {
public void updateModification(String createEquipmentAttributes, UUID modificationUuid, String userId) {
Objects.requireNonNull(createEquipmentAttributes);

var path = UriComponentsBuilder
Expand All @@ -221,6 +221,7 @@ public void updateModification(String createEquipmentAttributes, UUID modificati

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set(HEADER_USER_ID, userId);

HttpEntity<String> httpEntity = new HttpEntity<>(createEquipmentAttributes, headers);

Expand All @@ -245,7 +246,7 @@ public void stashModifications(UUID groupUUid, List<UUID> modificationsUuids) {
restTemplate.exchange(path, HttpMethod.PUT, httpEntity, Void.class);
}

public void updateModificationsMetadata(UUID groupUUid, List<UUID> modificationsUuids, NetworkModificationMetadata metadata) {
public void updateModificationsMetadata(UUID groupUUid, List<UUID> modificationsUuids, NetworkModificationMetadata metadata, String userId) {
Objects.requireNonNull(groupUUid);
Objects.requireNonNull(modificationsUuids);
var path = UriComponentsBuilder
Expand All @@ -257,6 +258,7 @@ public void updateModificationsMetadata(UUID groupUUid, List<UUID> modifications

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set(HEADER_USER_ID, userId);

HttpEntity<NetworkModificationMetadata> httpEntity = new HttpEntity<>(metadata, headers);
restTemplate.exchange(path, HttpMethod.PUT, httpEntity, Void.class);
Expand Down Expand Up @@ -330,6 +332,35 @@ public Map<UUID, UUID> findParentComposites(List<UUID> modificationsUuids) {
).getBody();
}

/**
* Resolves, for each given modification, the modification group it ultimately belongs to.
* @param modificationsUuids the modifications to resolve; each may sit directly in a group or be nested
* inside one or more composite modifications
* @return a map from modification uuid to the uuid of its enclosing root group (the outermost group,
* found by walking up through every level of nested composite modifications). A modification that is
* not reachable from any group is absent from the map.
*/
public Map<UUID, UUID> findRootGroupByModification(List<UUID> modificationsUuids) {
Objects.requireNonNull(modificationsUuids);
var path = UriComponentsBuilder
.fromUriString(getNetworkModificationServerURI(false) + COMPOSITE_PATH + "root-groups")
.queryParam(UUIDS, modificationsUuids)
.buildAndExpand()
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<Void> httpEntity = new HttpEntity<>(headers);

return restTemplate.exchange(
path,
HttpMethod.GET,
httpEntity,
new ParameterizedTypeReference<Map<UUID, UUID>>() { }
).getBody();
}

/**
* @return references data of the modifications in the group :
* - element uuid in directory server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1460,4 +1460,10 @@ public UUID getNodeUuidByModificationGroup(UUID groupUuid) {
var node = networkModificationNodeInfoRepository.findByModificationGroupUuidIn(List.of(groupUuid));
return node.isEmpty() ? null : node.getFirst().getIdNode();
}

@Transactional(readOnly = true)
public Map<UUID, UUID> getNodeUuidsByModificationGroups(List<UUID> groupUuids) {
return networkModificationNodeInfoRepository.findByModificationGroupUuidIn(groupUuids).stream()
.collect(Collectors.toMap(NetworkModificationNodeInfoEntity::getModificationGroupUuid, NetworkModificationNodeInfoEntity::getIdNode));
}
}
20 changes: 16 additions & 4 deletions src/main/java/org/gridsuite/study/server/service/StudyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ public void createNetworkModification(UUID studyUuid, UUID nodeUuid, String crea
public void updateNetworkModification(UUID studyUuid, String updateModificationAttributes, UUID nodeUuid, UUID modificationUuid, String userId) {
List<UUID> childrenUuids = networkModificationTreeService.getChildrenUuids(nodeUuid);
try {
networkModificationService.updateModification(updateModificationAttributes, modificationUuid);
networkModificationService.updateModification(updateModificationAttributes, modificationUuid, userId);
invalidateNodeTree(studyUuid, nodeUuid);
} finally {
notificationService.emitModificationsUpdated(studyUuid, nodeUuid, childrenUuids);
Expand Down Expand Up @@ -1466,6 +1466,18 @@ public void invalidateNodeTreeWhenMoveModification(UUID studyUuid, UUID nodeUuid
invalidateNodeTree(studyUuid, nodeUuid, InvalidateNodeTreeParameters.ALL);
}

@Transactional
public void invalidateNodeTreeWhenSharedModificationChanged(UUID studyUuid, UUID nodeUuid) {
invalidateNodeTree(studyUuid, nodeUuid, InvalidateNodeTreeParameters.ALL);
}

@Transactional
public void sharedElementUpdatedNotification(UUID nodeUuid, List<UUID> networkModificationUuids) {
UUID studyUuid = networkModificationTreeService.getStudyUuidForNodeId(nodeUuid);
invalidateNodeTree(studyUuid, nodeUuid);
notificationService.emitSharedElementUpdated(studyUuid, nodeUuid, networkModificationUuids);
}

@Transactional
public boolean invalidateNodeTreeWhenMoveModifications(UUID studyUuid, UUID targetNodeUuid, UUID originNodeUuid) {
boolean isTargetInDifferentNodeTree = !targetNodeUuid.equals(originNodeUuid)
Expand Down Expand Up @@ -1500,11 +1512,11 @@ private void invalidateNodeTreeWithLF(UUID studyUuid, UUID nodeUuid, UUID rootNe
invalidateNodeTree(studyUuid, nodeUuid, rootNetworkUuid, invalidateNodeTreeParameters);
}

public void invalidateNodeTree(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid) {
private void invalidateNodeTree(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid) {
invalidateNodeTree(studyUuid, nodeUuid, rootNetworkUuid, InvalidateNodeTreeParameters.ALL);
}

public void invalidateNodeTree(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid, InvalidateNodeTreeParameters invalidateTreeParameters) {
private void invalidateNodeTree(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid, InvalidateNodeTreeParameters invalidateTreeParameters) {
networkModificationTreeService.invalidateNodeTree(studyUuid, nodeUuid, rootNetworkUuid, invalidateTreeParameters, false);
}

Expand Down Expand Up @@ -1562,7 +1574,7 @@ public void updateNetworkModificationsMetadata(UUID studyUuid, UUID nodeUuid, Li
throw new StudyException(NOT_ALLOWED);
}
UUID groupId = networkModificationTreeService.getModificationGroupUuid(nodeUuid);
networkModificationService.updateModificationsMetadata(groupId, modificationsUuids, metadata);
networkModificationService.updateModificationsMetadata(groupId, modificationsUuids, metadata, userId);
if (metadata.getActivated() != null || metadata.getName() != null) {
invalidateNodeTree(studyUuid, nodeUuid);
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/resources/config/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ spring:
consumeLoadFlowResult;consumeLoadFlowStopped;consumeLoadFlowFailed;consumeLoadFlowCancelFailed;\
consumeStateEstimationResult;consumeStateEstimationDebug;consumeStateEstimationStopped;consumeStateEstimationFailed;\
consumePccMinResult;consumePccMinStopped;consumePccMinFailed;\
consumeNetworkExportFinished"
consumeNetworkExportFinished;\
consumeSharedElementUpdate"
stream:
bindings:
publishStudyUpdate-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}study.update
publishElementUpdate-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}element.update
consumeSharedElementUpdate-in-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}element.shared.update
group: studySharedElementUpdateGroup
consumeSaResult-in-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}sa.result
group: studySaResultGroup
Expand Down
Loading
Loading