Skip to content

Commit 866621d

Browse files
committed
[5300] Add support for undo redo node layout data
Bug: #5300 Signed-off-by: Michaël Charfadi <michael.charfadi@obeosoft.com>
1 parent 47f908d commit 866621d

File tree

22 files changed

+567
-40
lines changed

22 files changed

+567
-40
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
=== New Features
3434

35+
- https://github.com/eclipse-sirius/sirius-web/issues/5300[#5300] [diagram] Add undo redo for node layout
3536

3637

3738
=== Improvements

packages/core/backend/sirius-components-collaborative/src/main/java/org/eclipse/sirius/components/collaborative/api/ChangeKind.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public final class ChangeKind {
2929

3030
public static final String SEMANTIC_CHANGE = "SEMANTIC_CHANGE";
3131

32+
public static final String UNDO_REDO_CHANGE = "UNDO_REDO_CHANGE";
33+
34+
public static final String LAYOUT = "LAYOUT";
35+
3236
public static final String RELOAD_REPRESENTATION = "RELOAD_REPRESENTATION";
3337

3438
public static final String REPRESENTATION_METADATA_UPDATE = "REPRESENTATION_METADATA_UPDATE";

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/DiagramCreationService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.eclipse.sirius.components.diagrams.components.DiagramComponentProps.Builder;
3636
import org.eclipse.sirius.components.diagrams.description.DiagramDescription;
3737
import org.eclipse.sirius.components.diagrams.events.IDiagramEvent;
38+
import org.eclipse.sirius.components.diagrams.events.undoredo.DiagramNodeLayoutEvent;
3839
import org.eclipse.sirius.components.diagrams.layoutdata.DiagramLayoutData;
3940
import org.eclipse.sirius.components.diagrams.renderer.DiagramRenderer;
4041
import org.eclipse.sirius.components.diagrams.renderer.IEdgeAppearanceHandler;
@@ -149,7 +150,14 @@ private Diagram doRender(Object targetObject, IEditingContext editingContext, Di
149150

150151
Diagram newDiagram = new DiagramRenderer().render(element);
151152

153+
List<DiagramNodeLayoutEvent> diagramNodeLayoutEvents = diagramEvents.stream()
154+
.filter(DiagramNodeLayoutEvent.class::isInstance)
155+
.map(DiagramNodeLayoutEvent.class::cast).toList();
156+
152157
var newLayoutData = optionalPreviousDiagram.map(Diagram::getLayoutData).orElse(new DiagramLayoutData(Map.of(), Map.of(), Map.of()));
158+
159+
diagramNodeLayoutEvents.forEach(nodeLayoutDataEvent -> newLayoutData.nodeLayoutData().put(nodeLayoutDataEvent.nodeId(), nodeLayoutDataEvent.nodeLayoutData()));
160+
153161
newDiagram = Diagram.newDiagram(newDiagram)
154162
.layoutData(newLayoutData)
155163
.build();

packages/diagrams/backend/sirius-components-collaborative-diagrams/src/main/java/org/eclipse/sirius/components/collaborative/diagrams/DiagramEventProcessor.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ public ISubscriptionManager getSubscriptionManager() {
135135
public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDescriptionSink, IRepresentationInput representationInput) {
136136
if (representationInput instanceof LayoutDiagramInput layoutDiagramInput) {
137137
if (LayoutDiagramInput.CAUSE_LAYOUT.equals(layoutDiagramInput.cause()) || layoutDiagramInput.id().equals(this.currentRevisionId)) {
138+
changeDescriptionSink.tryEmitNext(new ChangeDescription(ChangeKind.LAYOUT, layoutDiagramInput.representationId(), layoutDiagramInput));
138139
var diagram = this.diagramContext.diagram();
139140
var nodeLayoutData = layoutDiagramInput.diagramLayoutData().nodeLayoutData().stream()
140141
.collect(Collectors.toMap(
@@ -165,10 +166,8 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDesc
165166
this.representationPersistenceService.save(layoutDiagramInput, this.editingContext, laidOutDiagram);
166167
this.diagramContext = new DiagramContext(laidOutDiagram);
167168
this.diagramEventFlux.diagramRefreshed(layoutDiagramInput.id(), laidOutDiagram, DiagramRefreshedEventPayload.CAUSE_LAYOUT, null);
168-
169169
this.currentRevisionCause = DiagramRefreshedEventPayload.CAUSE_LAYOUT;
170170
this.currentRevisionId = layoutDiagramInput.id();
171-
172171
payloadSink.tryEmitValue(new SuccessPayload(layoutDiagramInput.id()));
173172
} else {
174173
payloadSink.tryEmitValue(new SuccessPayload(layoutDiagramInput.id()));
@@ -218,6 +217,24 @@ public void refresh(ChangeDescription changeDescription) {
218217
ReferencePosition referencePosition = this.getReferencePosition(changeDescription.getInput());
219218
this.diagramEventFlux.diagramRefreshed(changeDescription.getInput().id(), reloadedDiagram, DiagramRefreshedEventPayload.CAUSE_LAYOUT, referencePosition);
220219
}
220+
} else if (changeDescription.getKind().equals(ChangeKind.LAYOUT)) {
221+
this.diagramEventConsumers.forEach(consumer -> consumer.accept(this.editingContext, this.diagramContext.diagram(), this.diagramContext.diagramEvents(), this.diagramContext.viewDeletionRequests(), this.diagramContext.viewCreationRequests(), changeDescription));
222+
} else if (changeDescription.getKind().equals(ChangeKind.UNDO_REDO_CHANGE)) {
223+
Optional<Diagram> reloadedDiagram = this.representationSearchService.findById(this.editingContext, this.diagramContext.diagram().getId(), Diagram.class);
224+
if (reloadedDiagram.isPresent()) {
225+
Diagram refreshedDiagram = this.diagramCreationService.refresh(this.editingContext, this.diagramContext).orElse(null);
226+
this.representationPersistenceService.save(changeDescription.getInput(), this.editingContext, refreshedDiagram);
227+
228+
if (refreshedDiagram != null) {
229+
this.logger.trace("Diagram refreshed: {}", refreshedDiagram.getId());
230+
}
231+
232+
this.diagramContext = new DiagramContext(refreshedDiagram);
233+
this.currentRevisionId = changeDescription.getInput().id();
234+
this.currentRevisionCause = DiagramRefreshedEventPayload.CAUSE_LAYOUT;
235+
ReferencePosition referencePosition = this.getReferencePosition(changeDescription.getInput());
236+
this.diagramEventFlux.diagramRefreshed(changeDescription.getInput().id(), refreshedDiagram, DiagramRefreshedEventPayload.CAUSE_LAYOUT, referencePosition);
237+
}
221238
}
222239
}
223240

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Obeo.
3+
* This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Obeo - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.sirius.components.diagrams.events.undoredo;
14+
15+
import org.eclipse.sirius.components.diagrams.events.IDiagramEvent;
16+
import org.eclipse.sirius.components.diagrams.layoutdata.NodeLayoutData;
17+
18+
/**
19+
* Diagram node layout position change.
20+
*
21+
* @author mcharfadi
22+
*/
23+
public record DiagramNodeLayoutEvent(String nodeId, NodeLayoutData nodeLayoutData) implements IDiagramEvent {
24+
}

packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout-events/useLayoutOnBoundsChange.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,26 @@ export const useLayoutOnBoundsChange = (): UseLayoutOnBoundsChangeValue => {
131131
edges: laidOutDiagram.edges,
132132
};
133133

134-
synchronizeLayoutData(crypto.randomUUID(), 'layout', finalDiagram);
134+
var id = crypto.randomUUID();
135+
synchronizeLayoutData(id, 'layout', finalDiagram);
136+
addUndoForLayout(id);
135137
});
136138
}
137139
},
138140
[synchronizeLayoutData, getNodes]
139141
);
140142

143+
const addUndoForLayout = (mutationId: string) => {
144+
var storedUndoStack = sessionStorage.getItem('undoStack');
145+
var storedRedoStack = sessionStorage.getItem('redoStack');
146+
147+
if (storedUndoStack && storedRedoStack) {
148+
var undoStack: String[] = JSON.parse(storedUndoStack);
149+
if (!undoStack.find((id) => id === mutationId)) {
150+
sessionStorage.setItem('undoStack', JSON.stringify([mutationId, ...undoStack]));
151+
}
152+
}
153+
};
154+
141155
return { layoutOnBoundsChange };
142156
};

packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorEventProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2022, 2024 Obeo.
2+
* Copyright (c) 2022, 2025 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -150,7 +150,7 @@ private boolean shouldRefresh(ChangeDescription changeDescription) {
150150
}
151151

152152
private IRepresentationRefreshPolicy getDefaultRefreshPolicy() {
153-
return (changeDescription) -> ChangeKind.SEMANTIC_CHANGE.equals(changeDescription.getKind());
153+
return (changeDescription) -> ChangeKind.SEMANTIC_CHANGE.equals(changeDescription.getKind()) || changeDescription.getKind().equals(ChangeKind.UNDO_REDO_CHANGE);
154154
}
155155

156156
@Override

packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/FormEventProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ private boolean shouldReload(ChangeDescription changeDescription) {
246246
}
247247

248248
private IRepresentationRefreshPolicy getDefaultRefreshPolicy() {
249-
return (changeDescription) -> ChangeKind.SEMANTIC_CHANGE.equals(changeDescription.getKind());
249+
return (changeDescription) -> ChangeKind.SEMANTIC_CHANGE.equals(changeDescription.getKind()) || changeDescription.getKind().equals(ChangeKind.UNDO_REDO_CHANGE);
250250
}
251251

252252
private Form refreshForm() {

packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/diagram/services/filter/DiagramFilterRefreshPolicyProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2024 Obeo.
2+
* Copyright (c) 2024, 2025 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -38,6 +38,7 @@ public IRepresentationRefreshPolicy getRepresentationRefreshPolicy(IRepresentati
3838
return changeDescription -> {
3939
boolean shouldRefresh = false;
4040
shouldRefresh = shouldRefresh || ChangeKind.SEMANTIC_CHANGE.equals(changeDescription.getKind());
41+
shouldRefresh = shouldRefresh || ChangeKind.UNDO_REDO_CHANGE.equals(changeDescription.getKind());
4142
shouldRefresh = shouldRefresh || DiagramChangeKind.DIAGRAM_LAYOUT_CHANGE.equals(changeDescription.getKind());
4243
shouldRefresh = shouldRefresh || DiagramChangeKind.DIAGRAM_ELEMENT_VISIBILITY_CHANGE.equals(changeDescription.getKind());
4344
shouldRefresh = shouldRefresh || DiagramChangeKind.DIAGRAM_ELEMENT_COLLAPSING_STATE_CHANGE.equals(changeDescription.getKind());

packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/representation/services/RepresentationMetadataDetailsViewRefreshPolicyProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class RepresentationMetadataDetailsViewRefreshPolicyProvider implements I
3434
ChangeKind.REPRESENTATION_DELETION,
3535
ChangeKind.REPRESENTATION_RENAMING,
3636
ChangeKind.REPRESENTATION_METADATA_UPDATE,
37+
ChangeKind.UNDO_REDO_CHANGE,
3738
ChangeKind.SEMANTIC_CHANGE);
3839

3940

0 commit comments

Comments
 (0)