Skip to content

Commit 38d90fb

Browse files
pcdavidAxelRICHARD
authored andcommitted
[2056] Fix feedback when dropping already exposed elements
Bug: #2056 Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
1 parent f54a422 commit 38d90fb

File tree

6 files changed

+255
-30
lines changed

6 files changed

+255
-30
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Now the _end_ keyword is not displayed anymore in the label of these graphical n
102102
- https://github.com/eclipse-syson/syson/issues/2053[#2053] [diagrams] Prevent incoming and outgoing graphical edges of a graphical `ForkNode` or `JoinNode` to point empty space.
103103
- https://github.com/eclipse-syson/syson/issues/2059[#2059] [diagrams] Fix an issue where the _Add existing elements_ tool was not working correctly on the _action flow_ compartment of `ActionUsage` graphical nodes.
104104
- https://github.com/eclipse-syson/syson/issues/2043[#2043] [explorer] Prevent user libraries from being moved to the root of the project when a child is created in it.
105+
- https://github.com/eclipse-syson/syson/issues/2056[#2056] [diagams] Fix the user feedback when dropping an `Element` which is already exposed on a diagram.
105106

106107
=== Improvements
107108

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVDropFromExplorerTests.java

Lines changed: 143 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.time.Duration;
2222
import java.util.List;
23+
import java.util.Map;
2324
import java.util.Objects;
2425
import java.util.Optional;
2526
import java.util.UUID;
@@ -28,21 +29,27 @@
2829

2930
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
3031
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
32+
import org.eclipse.sirius.components.collaborative.diagrams.dto.InvokeSingleClickOnDiagramElementToolInput;
33+
import org.eclipse.sirius.components.collaborative.diagrams.dto.InvokeSingleClickOnDiagramElementToolSuccessPayload;
3134
import org.eclipse.sirius.components.collaborative.dto.CreateChildInput;
3235
import org.eclipse.sirius.components.collaborative.dto.CreateChildSuccessPayload;
3336
import org.eclipse.sirius.components.core.api.IEditingContext;
37+
import org.eclipse.sirius.components.core.api.IFeedbackMessageService;
3438
import org.eclipse.sirius.components.core.api.IIdentityService;
3539
import org.eclipse.sirius.components.core.api.IObjectSearchService;
3640
import org.eclipse.sirius.components.diagrams.Diagram;
3741
import org.eclipse.sirius.components.diagrams.Node;
42+
import org.eclipse.sirius.components.diagrams.ViewModifier;
43+
import org.eclipse.sirius.components.diagrams.tests.graphql.InvokeSingleClickOnDiagramElementToolMutationRunner;
44+
import org.eclipse.sirius.components.diagrams.tests.graphql.PaletteQueryRunner;
45+
import org.eclipse.sirius.components.diagrams.tests.navigation.DiagramNavigator;
3846
import org.eclipse.sirius.components.graphql.tests.ExecuteEditingContextFunctionSuccessPayload;
3947
import org.eclipse.sirius.components.representations.MessageLevel;
4048
import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider;
4149
import org.eclipse.sirius.web.tests.graphql.CreateChildMutationRunner;
4250
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
4351
import org.eclipse.syson.AbstractIntegrationTests;
4452
import org.eclipse.syson.GivenSysONServer;
45-
import org.eclipse.syson.SysONTestsProperties;
4653
import org.eclipse.syson.application.controllers.diagrams.checkers.CheckDiagramElementCount;
4754
import org.eclipse.syson.application.controllers.diagrams.checkers.CheckNodeOnDiagram;
4855
import org.eclipse.syson.application.controllers.diagrams.testers.DropFromExplorerTester;
@@ -79,7 +86,7 @@
7986
* @author gdaniel
8087
*/
8188
@Transactional
82-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { SysONTestsProperties.NO_DEFAULT_LIBRARIES_PROPERTY })
89+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
8390
public class GVDropFromExplorerTests extends AbstractIntegrationTests {
8491

8592
@Autowired
@@ -112,8 +119,18 @@ public class GVDropFromExplorerTests extends AbstractIntegrationTests {
112119
@Autowired
113120
private CreateChildMutationRunner createChildMutationRunner;
114121

122+
@Autowired
123+
private PaletteQueryRunner paletteQueryRunner;
124+
125+
@Autowired
126+
private InvokeSingleClickOnDiagramElementToolMutationRunner invokeSingleClickOnDiagramElementToolMutationRunner;
127+
128+
@Autowired
129+
private IFeedbackMessageService feedbackMessageService;
130+
115131
private final IDescriptionNameGenerator descriptionNameGenerator = new SDVDescriptionNameGenerator();
116132

133+
117134
private Flux<DiagramRefreshedEventPayload> givenSubscriptionToDiagram() {
118135
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
119136
GeneralViewAddExistingElementsTestProjectData.EDITING_CONTEXT_ID,
@@ -198,9 +215,9 @@ public void dropFromExplorerOnEmptyDiagram() {
198215
.verify(Duration.ofSeconds(10));
199216
}
200217

218+
@DisplayName("GIVEN an Element with no declared name but having a declared short name, WHEN drag and dropping this element on a diagram, THEN graphical node should be created")
201219
@GivenSysONServer({ GeneralViewAddExistingElementsTestProjectData.SCRIPT_PATH })
202220
@Test
203-
@DisplayName("GIVEN an Element with no declared name but having a declared short name, WHEN drag and dropping this element on a diagram, THEN graphical node should be created")
204221
public void dropFromExplorerShortNameOnlyOnEmptyDiagram() {
205222
var flux = this.givenSubscriptionToDiagram();
206223

@@ -358,7 +375,7 @@ public void dropFromExplorerTwiceShouldNotExposeElementTwice() {
358375
List<Object> messages = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[*]");
359376
assertThat(messages).as("We should receive at least one message when dropping an already visible element").hasSizeGreaterThanOrEqualTo(1);
360377
String messageBody = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[0].body");
361-
assertThat(messageBody).isEqualTo("The element part1 is already visible in its parent General View");
378+
assertThat(messageBody).isEqualTo("The element part1 is already visible in its parent Package 1");
362379
String messageLevel = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[0].level");
363380
assertThat(messageLevel).isEqualTo(MessageLevel.WARNING.toString());
364381
};
@@ -376,6 +393,128 @@ public void dropFromExplorerTwiceShouldNotExposeElementTwice() {
376393
.verify(Duration.ofSeconds(10));
377394
}
378395

396+
@DisplayName("GIVEN a diagram WHEN dropping a semantic element from the explorer on various targets THEN the user gets the appropriate feedback message")
397+
@GivenSysONServer({ GeneralViewAddExistingElementsTestProjectData.SCRIPT_PATH })
398+
@Test
399+
public void dropFromExplorerFeedback() {
400+
AtomicReference<Diagram> diagram = new AtomicReference<>();
401+
AtomicReference<String> packageNodeId = new AtomicReference<>();
402+
AtomicReference<String> attributeNodeId = new AtomicReference<>();
403+
AtomicReference<String> hideToolId = new AtomicReference<>();
404+
405+
String package1Id = GeneralViewAddExistingElementsTestProjectData.SemanticIds.PACKAGE1_ID;
406+
String attributeDefinition1Id = GeneralViewAddExistingElementsTestProjectData.SemanticIds.ATTRIBUTE_DEFINITION_1_ID;
407+
408+
var flux = this.givenSubscriptionToDiagram();
409+
410+
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set);
411+
412+
Runnable dropPackageOnDiagramBackground = () -> this.dropFromExplorer(diagram, null, package1Id, Optional.empty());
413+
414+
Consumer<Object> diagramWithPackageNodeConsumer = assertRefreshedDiagramThat(newDiagram -> {
415+
new CheckDiagramElementCount(this.diagramComparator).hasNewNodeCount(1).check(diagram.get(), newDiagram);
416+
var packageNode = new DiagramNavigator(newDiagram).nodeWithTargetObjectId(package1Id).getNode();
417+
assertThat(packageNode).isNotNull();
418+
packageNodeId.set(packageNode.getId());
419+
diagram.set(newDiagram);
420+
});
421+
422+
Runnable dropAttributeOnPackage = () -> this.dropFromExplorer(diagram, packageNodeId.get(), attributeDefinition1Id, Optional.empty());
423+
424+
Consumer<Object> diagramWithAttributeNodeConsumer = assertRefreshedDiagramThat(newDiagram -> {
425+
// 3 new nodes: AttributeDefinition container and its 2 compartments
426+
new CheckDiagramElementCount(this.diagramComparator).hasNewNodeCount(3).check(diagram.get(), newDiagram);
427+
var attributeNode = new DiagramNavigator(newDiagram).nodeWithTargetObjectId(attributeDefinition1Id).getNode();
428+
assertThat(attributeNode).isNotNull().extracting(Node::getState).isEqualTo(ViewModifier.Normal);
429+
attributeNodeId.set(attributeNode.getId());
430+
diagram.set(newDiagram);
431+
});
432+
433+
Runnable getHideTool = () -> hideToolId.set(this.getQuickToolIdByLabel(diagram.get().getId(), attributeNodeId.get(), "Hide"));
434+
435+
Runnable dropAttributeOnDiagram = () -> this.dropFromExplorer(diagram,
436+
null, attributeDefinition1Id,
437+
Optional.of("The element AttributeDefinition1 is already visible in its parent Package1"));
438+
439+
Consumer<Object> diagramNotChangeConsumer = assertRefreshedDiagramThat(newDiagram -> {
440+
new CheckDiagramElementCount(this.diagramComparator).check(diagram.get(), newDiagram);
441+
diagram.set(newDiagram);
442+
});
443+
444+
Runnable hideAttributeNode = () -> {
445+
var input = new InvokeSingleClickOnDiagramElementToolInput(UUID.randomUUID(), GeneralViewAddExistingElementsTestProjectData.EDITING_CONTEXT_ID, diagram.get().getId(),
446+
List.of(attributeNodeId.get()), hideToolId.get(), 0, 0, List.of());
447+
var result = this.invokeSingleClickOnDiagramElementToolMutationRunner.run(input);
448+
String typename = JsonPath.read(result.data(), "$.data.invokeSingleClickOnDiagramElementTool.__typename");
449+
assertThat(typename).isEqualTo(InvokeSingleClickOnDiagramElementToolSuccessPayload.class.getSimpleName());
450+
};
451+
452+
Consumer<Object> atributeNodeHiddenConsumer = assertRefreshedDiagramThat(newDiagram -> {
453+
new CheckDiagramElementCount(this.diagramComparator).check(diagram.get(), newDiagram);
454+
var attributeNode = new DiagramNavigator(newDiagram).nodeWithTargetObjectId(attributeDefinition1Id).getNode();
455+
assertThat(attributeNode).isNotNull().extracting(Node::getState).isEqualTo(ViewModifier.Hidden);
456+
diagram.set(newDiagram);
457+
});
458+
459+
Runnable dropAttributeOnDiagramNoMessage = () -> this.dropFromExplorer(diagram, null, attributeDefinition1Id, Optional.empty());
460+
461+
Runnable dropAttributeOnPackageAgain = () -> this.dropFromExplorer(diagram, packageNodeId.get(), attributeDefinition1Id, Optional.empty());
462+
463+
Consumer<Object> diagramWithAttributeNodeRevealedConsumer = assertRefreshedDiagramThat(newDiagram -> {
464+
new CheckDiagramElementCount(this.diagramComparator).check(diagram.get(), newDiagram);
465+
var attributeNode = new DiagramNavigator(newDiagram).nodeWithTargetObjectId(GeneralViewAddExistingElementsTestProjectData.SemanticIds.ATTRIBUTE_DEFINITION_1_ID).getNode();
466+
assertThat(attributeNode).isNotNull().extracting(Node::getState).isEqualTo(ViewModifier.Normal);
467+
});
468+
469+
StepVerifier.create(flux)
470+
.consumeNextWith(initialDiagramContentConsumer)
471+
.then(dropPackageOnDiagramBackground)
472+
.consumeNextWith(diagramWithPackageNodeConsumer)
473+
.then(dropAttributeOnPackage)
474+
.consumeNextWith(diagramWithAttributeNodeConsumer)
475+
.then(getHideTool)
476+
.then(dropAttributeOnDiagram)
477+
.consumeNextWith(diagramNotChangeConsumer)
478+
.then(hideAttributeNode)
479+
.consumeNextWith(atributeNodeHiddenConsumer)
480+
.then(dropAttributeOnDiagramNoMessage)
481+
.consumeNextWith(diagramNotChangeConsumer)
482+
.then(dropAttributeOnPackageAgain)
483+
.consumeNextWith(diagramWithAttributeNodeRevealedConsumer)
484+
.thenCancel()
485+
.verify(Duration.ofSeconds(10));
486+
}
487+
488+
private void dropFromExplorer(AtomicReference<Diagram> diagram, String targetId, String elementId, Optional<String> expectedWarning) {
489+
// Workaround: clear the messages left by the previous tool's execution
490+
this.feedbackMessageService.getFeedbackMessages().clear();
491+
var result = this.dropFromExplorerTester.dropFromExplorer(GeneralViewAddExistingElementsTestProjectData.EDITING_CONTEXT_ID, diagram,
492+
targetId, elementId);
493+
List<Object> messages = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[*]");
494+
if (expectedWarning.isPresent()) {
495+
assertThat(messages).hasSize(1);
496+
String messageBody = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[0].body");
497+
assertThat(messageBody).isEqualTo(expectedWarning.get());
498+
String messageLevel = JsonPath.read(result.data(), "$.data.dropOnDiagram.messages[0].level");
499+
assertThat(messageLevel).isEqualTo(MessageLevel.WARNING.toString());
500+
} else {
501+
assertThat(messages).isEmpty();
502+
}
503+
}
504+
505+
private String getQuickToolIdByLabel(String diagramId, String nodeId, String toolName) {
506+
Map<String, Object> variables = Map.of(
507+
"editingContextId", GeneralViewAddExistingElementsTestProjectData.EDITING_CONTEXT_ID,
508+
"representationId", diagramId,
509+
"diagramElementIds", List.of(nodeId));
510+
var result = this.paletteQueryRunner.run(variables);
511+
List<String> labels = JsonPath.read(result.data(), "$.data.viewer.editingContext.representation.description.palette.quickAccessTools[*].label");
512+
assertThat(labels).contains(toolName);
513+
int toolIndex = labels.indexOf(toolName);
514+
List<String> ids = JsonPath.read(result.data(), "$.data.viewer.editingContext.representation.description.palette.quickAccessTools[*].id");
515+
return ids.get(toolIndex);
516+
}
517+
379518
@GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH })
380519
@Test
381520
public void dropLibraryPackageFromExplorerOnDiagram() {

backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/testers/DropFromExplorerTester.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.eclipse.sirius.components.collaborative.diagrams.dto.DropOnDiagramInput;
2424
import org.eclipse.sirius.components.collaborative.diagrams.dto.DropOnDiagramSuccessPayload;
2525
import org.eclipse.sirius.components.diagrams.Diagram;
26-
import org.eclipse.sirius.components.diagrams.tests.navigation.DiagramNavigator;
2726
import org.eclipse.sirius.components.graphql.tests.api.GraphQLResult;
2827
import org.springframework.beans.factory.annotation.Autowired;
2928
import org.springframework.stereotype.Service;
@@ -54,12 +53,9 @@ public void dropFromExplorerOnDiagramElement(String projectId, AtomicReference<D
5453
}
5554

5655
public GraphQLResult dropFromExplorer(String projectId, AtomicReference<Diagram> diagram, String targetNodeId, String semanticElementId) {
57-
DiagramNavigator diagramNavigator = new DiagramNavigator(diagram.get());
58-
final String targetId;
56+
String targetId = targetNodeId;
5957
if (targetNodeId == null) {
6058
targetId = diagram.get().getId();
61-
} else {
62-
targetId = diagramNavigator.nodeWithId(targetNodeId).getNode().getId();
6359
}
6460
var dropOnDiagramInput = new DropOnDiagramInput(
6561
UUID.randomUUID(),

backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/GeneralViewAddExistingElementsTestProjectData.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2025 Obeo.
2+
* Copyright (c) 2025, 2026 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
@@ -39,6 +39,10 @@ public static final class SemanticIds {
3939

4040
public static final String PACKAGE_1_ID = "8d4123ac-3ac5-412d-90f2-49282b923003";
4141

42+
public static final String PACKAGE1_ID = "98a777a3-15df-400f-a8d6-b5033e37e082";
43+
44+
public static final String ATTRIBUTE_DEFINITION_1_ID = "f42f0e49-8f00-49b4-b1ce-f4b0a98d3eb8";
45+
4246
public static final String GENERAL_VIEW_VIEW_USAGE_ID = "b67872fa-5900-48d3-88f0-e6ced193c8ec";
4347

4448
public static final String PART_1_ELEMENT_ID = "67a57df8-2995-41ea-a838-dfb3a9a8ee7f";

0 commit comments

Comments
 (0)