From 6cefdfa26f7edf826c98283a07554f69bbb5db66 Mon Sep 17 00:00:00 2001 From: Guillaume Coutable Date: Mon, 5 Oct 2026 15:23:08 +0200 Subject: [PATCH] [2518] Fix element numbering in diagrams on root namespaces Bug: https://github.com/eclipse-syson/syson/issues/2518 Signed-off-by: Guillaume Coutable --- CHANGELOG.adoc | 1 + .../general/view/GVTopNodeCreationTests.java | 85 +++++++++++++++++++ .../MetamodelMutationElementService.java | 3 +- .../pages/release-notes/2026.11.0.adoc | 1 + 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d2f0b34bb..121553dc4 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -41,6 +41,7 @@ A separate customizer annotated with Spring `@Primary` does not replace this fil - https://github.com/eclipse-syson/syson/issues/2510[#2510] [import] Report syntax errors that may leave an uploaded SysML file partially imported. The parsed elements are still imported, and the loading report includes the parser diagnostics and a warning about possibly missing elements. - https://github.com/eclipse-syson/syson/issues/2527[#2527] [export] Export connector ends whose feature chain is only owned by the `ReferenceSubsetting`, and export `InterfaceUsage` with the `interface` keyword instead of `connection`. +- https://github.com/eclipse-syson/syson/issues/2518[#2518] [diagrams] Fix the numbering of node labels when creating elements in a diagram on a root `Namespace`. === Improvements diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java index 80658bb87..65616323c 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/diagrams/general/view/GVTopNodeCreationTests.java @@ -13,6 +13,7 @@ package org.eclipse.syson.application.controllers.diagrams.general.view; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.type; import static org.eclipse.sirius.components.diagrams.tests.DiagramEventPayloadConsumer.assertRefreshedDiagramThat; import java.time.Duration; @@ -26,6 +27,7 @@ import org.assertj.core.api.Assertions; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.edit.domain.EditingDomain; @@ -33,6 +35,7 @@ import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload; import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariable; import org.eclipse.sirius.components.collaborative.diagrams.dto.ToolVariableType; +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; import org.eclipse.sirius.components.collaborative.selection.dto.SelectionDialogTreeEventInput; import org.eclipse.sirius.components.collaborative.trees.dto.TreeRefreshedEventPayload; import org.eclipse.sirius.components.core.api.IEditingContext; @@ -53,6 +56,7 @@ import org.eclipse.sirius.components.view.diagram.SelectionDialogDescription; import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider; import org.eclipse.sirius.components.view.emf.diagram.api.IViewDiagramDescriptionSearchService; +import org.eclipse.sirius.web.tests.services.api.IGivenCreatedDiagramSubscription; import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState; import org.eclipse.sirius.web.tests.services.representation.RepresentationIdBuilder; import org.eclipse.sirius.web.tests.services.selection.SelectionDialogTreeEventSubscriptionRunner; @@ -63,6 +67,7 @@ import org.eclipse.syson.application.controllers.diagrams.testers.ToolTester; import org.eclipse.syson.application.controllers.utils.TestNameGenerator; import org.eclipse.syson.application.data.GeneralViewEmptyTestProjectData; +import org.eclipse.syson.application.data.GeneralViewWithTopNodesTestProjectData; import org.eclipse.syson.services.SemanticRunnableFactory; import org.eclipse.syson.services.diagrams.DiagramComparator; import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider; @@ -115,6 +120,9 @@ public class GVTopNodeCreationTests extends AbstractIntegrationTests { @Autowired private IGivenDiagramSubscription givenDiagramSubscription; + @Autowired + private IGivenCreatedDiagramSubscription givenCreatedDiagramSubscription; + @Autowired private IDiagramIdProvider diagramIdProvider; @@ -194,6 +202,17 @@ private Flux givenSubscriptionToDiagram() { return this.givenDiagramSubscription.subscribe(diagramEventInput); } + private Flux createAndSubscribeToDiagram() { + var input = new CreateRepresentationInput( + UUID.randomUUID(), + GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, + SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID, + GeneralViewWithTopNodesTestProjectData.SemanticIds.ROOT_NAMESPACE_ID, + "root Namespace diagram" + ); + return this.givenCreatedDiagramSubscription.createAndSubscribe(input).flux(); + } + @BeforeEach public void setUp() { this.givenInitialServerState.initialize(); @@ -267,6 +286,72 @@ public void createTopNode(EClass eClass, int totalCompartmentCount, int visibleC .verify(Duration.ofSeconds(10)); } + @Test + @GivenSysONServer({ GeneralViewWithTopNodesTestProjectData.SCRIPT_PATH }) + @DisplayName("GIVEN a general view diagram on a root namespace, WHEN creating two successive PartUsage, THEN the index in their label increments correctly") + public void checkLabelSuffixForElementCreatedOnRootNamespace() { + var flux = this.createAndSubscribeToDiagram(); + + AtomicReference diagram = new AtomicReference<>(); + Consumer initialDiagramConsumer = assertRefreshedDiagramThat(diagram::set); + + var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, + SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID); + var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider); + + String creationToolId = diagramDescriptionIdProvider.getDiagramCreationToolId(this.descriptionNameGenerator.getCreationToolName(SysmlPackage.eINSTANCE.getPartUsage())); + + Runnable createNodeRunnable = () -> { + this.nodeCreationTester.invokeTool(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, diagram, null, creationToolId); + }; + + AtomicReference lastCreatedSemanticElementId = new AtomicReference<>(); + Consumer firstPartCreatedDiagramChecker = assertRefreshedDiagramThat(newDiagram -> { + var initialDiagram = diagram.get(); + var newNodes = this.diagramComparator.newNodes(initialDiagram, newDiagram); + assertThat(newNodes).anySatisfy(node -> { + assertThat(node.getInsideLabel().getText()).contains("part1"); + lastCreatedSemanticElementId.set(node.getTargetObjectId()); + }); + diagram.set(newDiagram); + }); + + Runnable semanticChecker = this.semanticRunnableFactory.createQueryRunnable(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, (editingContext, executeEditingContextFunctionInput) -> { + var object = this.objectSearchService.getObject(editingContext, lastCreatedSemanticElementId.get()); + assertThat(object).isPresent() + .get() + .isInstanceOf(EObject.class) + .asInstanceOf(type(EObject.class)) + .satisfies(eObject -> { + var container = eObject.eContainer(); + assertThat(container.eClass()).isEqualTo(SysmlPackage.eINSTANCE.getOwningMembership()); + }); + return new ExecuteEditingContextFunctionSuccessPayload(executeEditingContextFunctionInput.id(), true); + }); + + Consumer secondPartCreatedDiagramChecker = assertRefreshedDiagramThat(newDiagram -> { + var initialDiagram = diagram.get(); + var newNodes = this.diagramComparator.newNodes(initialDiagram, newDiagram); + assertThat(newNodes).anySatisfy(node -> { + assertThat(node.getInsideLabel().getText()).contains("part2"); + lastCreatedSemanticElementId.set(node.getTargetObjectId()); + }); + diagram.set(newDiagram); + }); + + StepVerifier.create(flux) + .consumeNextWith(initialDiagramConsumer) + .then(createNodeRunnable) + .consumeNextWith(firstPartCreatedDiagramChecker) + .then(semanticChecker) + .then(createNodeRunnable) + .consumeNextWith(secondPartCreatedDiagramChecker) + .then(semanticChecker) + .thenCancel() + .verify(Duration.ofSeconds(10)); + + } + @DisplayName("GIVEN an empty SysML Project, WHEN New Namespace Import tool on diagram is requested, THEN a new NamespaceImport is created") @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test diff --git a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelMutationElementService.java b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelMutationElementService.java index b446a4e64..f4a6ed006 100644 --- a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelMutationElementService.java +++ b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelMutationElementService.java @@ -13,6 +13,7 @@ package org.eclipse.syson.sysml.metamodel.services; import java.util.List; +import java.util.Objects; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; @@ -75,7 +76,7 @@ public MetamodelMutationElementService() { */ public Membership createMembership(Element element) { Membership membership = null; - if (element instanceof Package) { + if (element instanceof Package || Objects.equals(element.eClass(), SysmlPackage.eINSTANCE.getNamespace())) { membership = SysmlFactory.eINSTANCE.createOwningMembership(); } else { membership = SysmlFactory.eINSTANCE.createFeatureMembership(); diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.11.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.11.0.adoc index 84d445737..ced8dab6c 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.11.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.11.0.adoc @@ -27,6 +27,7 @@ Use the existing content tools to display these elements. Existing representatio ** In standard view diagrams, the connector palette now shows only edge creation tools compatible with the selected target node. For example, _New Feature Typing_ is no longer offered between two `Usage` graphical nodes, but remains available from a `Usage` to its corresponding `Definition`. _New Satisfy Requirement_ remains available when the target is a `RequirementUsage` or `SatisfyRequirementUsage`. +** Elements created in a diagram on a root `Namespace` are now named sequentially. * In textual import/export: