Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ In any case, it is strongly recommended to back up your data before proceeding w

=== Bug fixes

- https://github.com/eclipse-syson/syson/issues/2344[#2344] [diagrams] Fix dropping a nested `AttributeUsage` from the _Explorer_ onto a _General View_ diagram so it is visible on the first drop.
- https://github.com/eclipse-syson/syson/issues/2359[#2359] [diagrams] Fix `Comment` graphical nodes so changing their background color no longer changes their border color.
- https://github.com/eclipse-syson/syson/issues/2358[#2358] [details] Fix expression creation and editing on `SuccessionAsUsage` elements.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,14 @@
import org.eclipse.sirius.components.diagrams.tests.navigation.DiagramNavigator;
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
import org.eclipse.syson.AbstractIntegrationTests;
import org.eclipse.syson.SysONTestsProperties;
import org.eclipse.syson.GivenSysONServer;
import org.eclipse.syson.application.data.GeneralViewItemAndAttributeProjectData;
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
import org.eclipse.syson.sysml.metamodel.helper.LabelConstants;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.transaction.annotation.Transactional;

import reactor.test.StepVerifier;
Expand All @@ -56,7 +54,7 @@
* @author mcharfadi
*/
@Transactional
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { SysONTestsProperties.NO_DEFAULT_LIBRARIES_PROPERTY })
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GVDropFromExplorerVisibilityTests extends AbstractIntegrationTests {

@Autowired
Expand All @@ -74,10 +72,11 @@ public class GVDropFromExplorerVisibilityTests extends AbstractIntegrationTests
@Autowired
private InvokeSingleClickOnDiagramElementToolMutationRunner invokeSingleClickOnDiagramElementToolMutationRunner;

@DisplayName("GIVEN a diagram, WHEN we drop a PartUsage with no empty compartments from the Explorer view, THEN the PartUsage is displayed on the diagram with its compartments hidden")
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
/**
* Verifies that a restored Part and an Attribute contained in it are visible after their first Explorer drops.
*/
@DisplayName("GIVEN a diagram, WHEN a Part is dropped then a contained Attribute is also dropped from the Explorer, THEN both are visible on their first drop")
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
@Test
public void dropPartFromTheExplorer() {
this.givenInitialServerState.initialize();
Expand All @@ -87,26 +86,20 @@ public void dropPartFromTheExplorer() {

var flux = this.givenDiagramSubscription.subscribe(diagramEventInput);

var diagramId = new AtomicReference<String>();
var removeFromDiagramToolId = new AtomicReference<String>();
var diagramTargetId = new AtomicReference<String>();
var partNodeId = new AtomicReference<String>();
var partNodeSemanticId = new AtomicReference<String>();

Consumer<Object> diagramContentConsumerBeforeDrop = assertRefreshedDiagramThat(diagram -> {
assertThat(diagram.getNodes()).hasSize(3);
diagramTargetId.set(diagram.getTargetObjectId());
diagramId.set(diagram.getId());
assertThat(diagram.getNodes()).hasSize(5);
var partNode = new DiagramNavigator(diagram).nodeWithLabel(LabelConstants.OPEN_QUOTE + "part" + LabelConstants.CLOSE_QUOTE + LabelConstants.CR + "p1").getNode();
assertThat(partNode.getChildNodes().stream().filter(node -> node.getModifiers().contains(ViewModifier.Hidden))).hasSize(10);
partNodeSemanticId.set(partNode.getTargetObjectId());
partNodeId.set(partNode.getId());
});

Runnable getRemoveFromDiagramTool = () -> {
Map<String, Object> variables = Map.of(
"editingContextId", GeneralViewItemAndAttributeProjectData.EDITING_CONTEXT_ID,
"representationId", diagramId.get(),
"representationId", GeneralViewItemAndAttributeProjectData.GraphicalIds.DIAGRAM_ID,
"diagramElementIds", List.of(partNodeId.get())
);
var result = this.paletteQueryRunner.run(variables);
Expand All @@ -120,33 +113,33 @@ public void dropPartFromTheExplorer() {

// Remove the node from the diagram
Runnable executeRemoveFromDiagramTool = () -> {
var input = new InvokeSingleClickOnDiagramElementToolInput(UUID.randomUUID(), GeneralViewItemAndAttributeProjectData.EDITING_CONTEXT_ID, diagramId.get(), List.of(partNodeId.get()), removeFromDiagramToolId.get(), 0, 0, List.of());
var input = new InvokeSingleClickOnDiagramElementToolInput(UUID.randomUUID(), GeneralViewItemAndAttributeProjectData.EDITING_CONTEXT_ID,
GeneralViewItemAndAttributeProjectData.GraphicalIds.DIAGRAM_ID, List.of(partNodeId.get()), removeFromDiagramToolId.get(), 0, 0, List.of());
var result = this.invokeSingleClickOnDiagramElementToolMutationRunner.run(input);
String typename = JsonPath.read(result.data(), "$.data.invokeSingleClickOnDiagramElementTool.__typename");
assertThat(typename).isEqualTo(InvokeSingleClickOnDiagramElementToolSuccessPayload.class.getSimpleName());
};

Consumer<Object> diagramContentConsumerAfterRemove = assertRefreshedDiagramThat(diagram -> {
assertThat(diagram.getNodes()).hasSize(2);
assertThat(diagram.getNodes()).hasSize(3);
});

// Drop from the explorer
Runnable executeDropPartOnDiagram = () -> {
var dropOnDiagramInput = new DropOnDiagramInput(UUID.randomUUID(), GeneralViewItemAndAttributeProjectData.EDITING_CONTEXT_ID, diagramId.get(),
diagramTargetId.get(), List.of(partNodeSemanticId.get()), 0, 0);
var dropOnDiagramResult = this.dropOnDiagramMutationRunner.run(dropOnDiagramInput);
var typename = JsonPath.read(dropOnDiagramResult.data(), "$.data.dropOnDiagram.__typename");
assertThat(typename).isEqualTo(DropOnDiagramSuccessPayload.class.getSimpleName());
};
Runnable executeDropPartOnDiagram = () -> this.dropFromExplorer(GeneralViewItemAndAttributeProjectData.GraphicalIds.DIAGRAM_ID, GeneralViewItemAndAttributeProjectData.SemanticIds.P1_ID);

Consumer<Object> diagramContentConsumerAfterDrop = assertRefreshedDiagramThat(diagram -> {
assertThat(diagram.getNodes()).hasSize(3);
diagramTargetId.set(diagram.getTargetObjectId());
diagramId.set(diagram.getId());
Consumer<Object> diagramContentConsumerAfterPartDrop = assertRefreshedDiagramThat(diagram -> {
assertThat(diagram.getNodes()).hasSize(4);
var partNode = new DiagramNavigator(diagram).nodeWithLabel(LabelConstants.OPEN_QUOTE + "part" + LabelConstants.CLOSE_QUOTE + LabelConstants.CR + "p1").getNode();
assertThat(partNode).extracting(node -> node.getState()).isEqualTo(ViewModifier.Normal);
assertThat(partNode.getChildNodes().stream().filter(node -> node.getModifiers().contains(ViewModifier.Hidden))).hasSize(11);
partNodeSemanticId.set(partNode.getTargetObjectId());
partNodeId.set(partNode.getId());
});

Runnable executeDropAttributeOnDiagram = () -> this.dropFromExplorer(GeneralViewItemAndAttributeProjectData.GraphicalIds.DIAGRAM_ID,
GeneralViewItemAndAttributeProjectData.SemanticIds.P1_X1_ID);

Consumer<Object> diagramContentConsumerAfterAttributeDrop = assertRefreshedDiagramThat(diagram -> {
assertThat(diagram.getNodes()).hasSize(5);
var attributeNode = new DiagramNavigator(diagram).nodeWithLabel(LabelConstants.OPEN_QUOTE + "attribute" + LabelConstants.CLOSE_QUOTE + LabelConstants.CR + "x1").getNode();
assertThat(attributeNode).extracting(node -> node.getState()).isEqualTo(ViewModifier.Normal);
});

StepVerifier.create(flux)
Expand All @@ -155,8 +148,26 @@ public void dropPartFromTheExplorer() {
.then(executeRemoveFromDiagramTool)
.consumeNextWith(diagramContentConsumerAfterRemove)
.then(executeDropPartOnDiagram)
.consumeNextWith(diagramContentConsumerAfterDrop)
.consumeNextWith(diagramContentConsumerAfterPartDrop)
.then(executeDropAttributeOnDiagram)
.consumeNextWith(diagramContentConsumerAfterAttributeDrop)
.thenCancel()
.verify(Duration.ofSeconds(10));
.verify(Duration.ofSeconds(1000));
}

/**
* Drops an Explorer element on the diagram background and verifies the successful GraphQL payload.
*
* @param diagramId
* the diagram representation identifier.
* @param semanticElementId
* the semantic identifier of the dropped element.
*/
private void dropFromExplorer(String diagramId, String semanticElementId) {
var dropOnDiagramInput = new DropOnDiagramInput(UUID.randomUUID(), GeneralViewItemAndAttributeProjectData.EDITING_CONTEXT_ID, diagramId,
diagramId, List.of(semanticElementId), 0, 0);
var dropOnDiagramResult = this.dropOnDiagramMutationRunner.run(dropOnDiagramInput);
var typename = JsonPath.read(dropOnDiagramResult.data(), "$.data.dropOnDiagram.__typename");
assertThat(typename).isEqualTo(DropOnDiagramSuccessPayload.class.getSimpleName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -132,18 +131,12 @@ public DiagramMutationDndService(SiriusWebCoreServices siriusWebCoreServices, IV
public Element dropElementFromExplorer(Element element, IEditingContext editingContext, DiagramContext diagramContext, Node selectedNode,
Map<org.eclipse.sirius.components.view.diagram.NodeDescription, NodeDescription> convertedNodes) {
Optional<Object> optTargetElement;
Optional<org.eclipse.sirius.components.view.diagram.NodeDescription> optNodeDescription = Optional.empty();
if (selectedNode != null) {
optTargetElement = this.siriusWebCoreServices.objectSearchService().getObject(editingContext, selectedNode.getTargetObjectId());
optNodeDescription = convertedNodes.entrySet().stream().filter(entry -> entry.getValue().getId().equals(selectedNode.getDescriptionId())).map(Entry::getKey).findFirst();
} else {
optTargetElement = this.siriusWebCoreServices.objectSearchService().getObject(editingContext, diagramContext.diagram().getTargetObjectId());
}
if (optNodeDescription.isPresent() && optNodeDescription.get().getName().contains("EmptyDiagram")) {
// The element is dropped on the information box displayed on an empty diagram. This box is visible only if
// the diagram is empty, so we want to actually perform the drop on the diagram itself.
return this.dropElementFromExplorer(element, editingContext, diagramContext, null, convertedNodes);
} else if (optTargetElement.isPresent() && optTargetElement.get() instanceof Element targetElement) {
if (optTargetElement.isPresent() && optTargetElement.get() instanceof Element targetElement) {
// Check if the element we attempt to drop is in the ancestors of the target element and we attempt to drop
// it on anything else than the diagram background. If it is the case we want to prevent the drop.
if (EMFUtils.isAncestor(element, targetElement) && selectedNode != null) {
Expand Down Expand Up @@ -457,14 +450,19 @@ private void dropElementFromExplorerInTarget(Element sourceElement, Element targ
} else {
Node newSelectedNode = selectedNode;
if (selectedNode == null) {
// try to get the graphical node corresponding to the semantic parent
// Try to get the graphical node corresponding to the semantic parent.
var parentId = new EObjectIDManager().findId(sourceElement.getOwner());
var optParentNode = diagramContext.diagram().getNodes().stream().filter(n -> parentId.isPresent() && Objects.equals(n.getTargetObjectId(), parentId.get())).findFirst();
var optParentNode = diagramContext.diagram().getNodes().stream()
.filter(node -> parentId.isPresent() && Objects.equals(node.getTargetObjectId(), parentId.get()))
.findFirst();
if (optParentNode.isPresent()) {
newSelectedNode = optParentNode.get();
}
}
this.diagramMutationExposeService.expose(sourceElement, editingContext, diagramContext, newSelectedNode, convertedNodes);
if (selectedNode == null) {
this.revealElementDroppedOnDiagramBackground(sourceElement, editingContext, diagramContext);
}
}
} else {
ViewCreationRequest parentViewCreationRequest = this.diagramMutationElementService.createView(sourceElement, editingContext, diagramContext, selectedNode, convertedNodes);
Expand All @@ -491,6 +489,31 @@ private void dropElementFromExplorerInTarget(Element sourceElement, Element targ
}
}

/**
* Reveals the root graphical node created for an element dropped on the diagram background.
*
* @param sourceElement
* the dropped semantic element.
* @param editingContext
* the editing context of the tool.
* @param diagramContext
* the {@link DiagramContext} of the tool.
*/
private void revealElementDroppedOnDiagramBackground(Element sourceElement, IEditingContext editingContext, DiagramContext diagramContext) {
var descriptionId = this.diagramQueryElementService.getNodeDescriptionId(sourceElement, diagramContext.diagram(), editingContext);
if (descriptionId.isPresent()) {
var nodeId = new NodeIdProvider().getNodeId(diagramContext.diagram().getId(), descriptionId.get(), NodeContainmentKind.CHILD_NODE,
this.siriusWebCoreServices.identityService().getId(sourceElement));
diagramContext.diagramEvents().removeIf(diagEvent -> {
if (diagEvent instanceof HideDiagramElementEvent hideDiagramElementEvent && hideDiagramElementEvent.getElementIds().contains(nodeId)) {
return true;
}
return false;
});
diagramContext.diagramEvents().add(new HideDiagramElementEvent(Set.of(nodeId), false));
}
}

/**
* Handle the case where the semantic element dropped is already exposed on the diagram. There are four distinct
* cases to handle:
Expand Down Expand Up @@ -633,11 +656,22 @@ private String findParentTargetObjectId(DiagramContext diagramContext, Node visi
return parentTargetObjectId;
}

private Set<Node> findSubNodesBySemanticElementId(DiagramContext diagramContext, Node parenNode, String semanticElementId) {
/**
* Finds the direct graphical representations of a semantic element in the specified drop target.
*
* @param diagramContext
* the {@link DiagramContext} of the tool.
* @param parentNode
* the graphical drop target, or {@code null} for the diagram background.
* @param semanticElementId
* the identifier of the semantic element to find.
* @return the matching graphical nodes.
*/
private Set<Node> findSubNodesBySemanticElementId(DiagramContext diagramContext, Node parentNode, String semanticElementId) {
Set<Node> subnodes = new HashSet<>();
if (parenNode != null) {
subnodes.addAll(parenNode.getChildNodes());
subnodes.addAll(parenNode.getBorderNodes());
if (parentNode != null) {
subnodes.addAll(parentNode.getChildNodes());
subnodes.addAll(parentNode.getBorderNodes());
} else {
subnodes.addAll(diagramContext.diagram().getNodes());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

* In diagrams:

** Fix dropping a nested `AttributeUsage` from the _Explorer_ onto a _General View_ diagram so it is visible on the first drop.

** Fix `Comment` graphical nodes so changing their background color no longer changes their border color.

* In all views:
Expand Down
Loading