diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 9d5cb97f3..81d28a642 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -46,6 +46,7 @@ Stakeholders are by default represented with a dedicated graphical node connecte - https://github.com/eclipse-syson/syson/issues/2111[#2111] [diagrams] Leverage the latest change of the selection dialog to allow creating a `Stakeholder` graphical node without specialization. - https://github.com/eclipse-syson/syson/issues/2122[#2122] [diagrams] Leverage the latest change of the selection dialog to allow creating a `Subject` graphical node without specialization. - https://github.com/eclipse-syson/syson/issues/2129[#2129] [diagrams] Leverage the latest change of the selection dialog to allow creating a `FlowUsage` from a `ConnectionUsage` without selection a `PayloadFeature` +- https://github.com/eclipse-syson/syson/issues/2105[#2105] [explorer] In the _Explorer_ view, `Expression` elements now display their full textual representation. === New features diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controller/explorer/view/SysONExplorerTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controller/explorer/view/SysONExplorerTests.java index 6b813fe08..a9a8a1177 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controller/explorer/view/SysONExplorerTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controller/explorer/view/SysONExplorerTests.java @@ -46,9 +46,11 @@ import org.eclipse.sirius.web.tests.services.explorer.ExplorerEventSubscriptionRunner; import org.eclipse.sirius.web.tests.services.representation.RepresentationIdBuilder; import org.eclipse.syson.AbstractIntegrationTests; +import org.eclipse.syson.GivenSysONServer; import org.eclipse.syson.application.controller.explorer.testers.ExpandAllTreeItemTester; import org.eclipse.syson.application.controller.explorer.testers.TreeItemContextMenuTester; import org.eclipse.syson.application.controller.explorer.testers.TreePathTester; +import org.eclipse.syson.application.data.ActionTransitionUsagesProjectData; import org.eclipse.syson.application.data.GeneralViewEmptyTestProjectData; import org.eclipse.syson.application.data.ProjectWithLibraryDependencyContainingCommentAndLibraryPackageTestProjectData; import org.eclipse.syson.application.data.ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData; @@ -67,8 +69,6 @@ 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.test.context.transaction.TestTransaction; import org.springframework.transaction.annotation.Transactional; @@ -135,8 +135,7 @@ public void beforeEach() { } @DisplayName("GIVEN an empty SysML Project, WHEN the available explorers are requested, THEN the SysON explorer is returned") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void getAvailableExplorersForSysMLv2Project() { Map explorerVariables = Map.of( @@ -150,8 +149,7 @@ public void getAvailableExplorersForSysMLv2Project() { } @DisplayName("GIVEN a SysON Studio Project, WHEN the available explorers are requested, THEN the Sirius Web explorer is returned") - @Sql(scripts = { SysonStudioTestProjectData.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)) + @GivenSysONServer({ SysonStudioTestProjectData.SCRIPT_PATH }) @Test public void getAvailableExplorersForStudioProject() { TestTransaction.flagForCommit(); @@ -166,8 +164,7 @@ public void getAvailableExplorersForStudioProject() { } @DisplayName("GIVEN an empty SysML Project, WHEN the explorer is displayed, THEN the libraries are visible and the root namespace and memberships are not visible") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithDefaultFilters() { var optionalEditingContext = this.editingContextSearchService.findById(GeneralViewEmptyTestProjectData.EDITING_CONTEXT); @@ -257,8 +254,7 @@ public void getExplorerContentWithDefaultFilters() { } @DisplayName("GIVEN an empty SysML Project, WHEN the explorer is displayed with KerML and SysML libraries expanded, THEN the library models are visible") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithKerMLAndSysMLExpanded() { var optionalEditingContext = this.editingContextSearchService.findById(GeneralViewEmptyTestProjectData.EDITING_CONTEXT); @@ -319,8 +315,7 @@ public void getExplorerContentWithKerMLAndSysMLExpanded() { } @DisplayName("GIVEN an empty SysML Project, WHEN the explorer is displayed with its root model expanded and the hide memberships and hide KerML libraries filters, THEN the root model is visible and is expanded") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void getRootContentWithHideMembershipsAndHideKerMLStandardLibraries() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID, SysONTreeFilterConstants.HIDE_KERML_STANDARD_LIBRARIES_TREE_FILTER_ID); @@ -352,8 +347,7 @@ public void getRootContentWithHideMembershipsAndHideKerMLStandardLibraries() { } @DisplayName("GIVEN an empty SysML Project, WHEN context menu is queried, THEN the menu is returned") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void getContextMenuOfModelAndLibraryDirectories() { var optionalEditingContext = this.editingContextSearchService.findById(GeneralViewEmptyTestProjectData.EDITING_CONTEXT); @@ -422,8 +416,7 @@ public void getContextMenuOfModelAndLibraryDirectories() { } @DisplayName("GIVEN an empty SysML Project, WHEN the tree path is queried, THEN the returned tree path should take into accounts the Explorer filters.") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void treePathQueryApplyExplorerFilters() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID, SysONTreeFilterConstants.HIDE_ROOT_NAMESPACES_ID); @@ -472,8 +465,7 @@ public void treePathQueryApplyExplorerFilters() { *

*/ @DisplayName("GIVEN an empty SysML Project, WHEN the tree path is queried in the Sirius Web default Explorer, THEN the returned tree path should not take into accounts the Explorer filters.") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void treePathQueryInSiriusWebDefaultExplorerDoesNotApplyExplorerFilters() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID, SysONTreeFilterConstants.HIDE_ROOT_NAMESPACES_ID); @@ -543,9 +535,7 @@ public void treePathQueryInSiriusWebDefaultExplorerDoesNotApplyExplorerFilters() } @DisplayName("GIVEN a SysML Project with a dependency to a library containing one Package, WHEN the explorer is displayed, THEN the library model is visible at the root of the explorer") - @Sql(scripts = { ProjectWithUsedBatmobileLibraryDependencyTestProjectData.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)) + @GivenSysONServer({ ProjectWithUsedBatmobileLibraryDependencyTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithImportedLibraryContainingOnePackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -573,9 +563,7 @@ public void getExplorerContentWithImportedLibraryContainingOnePackage() { } @DisplayName("GIVEN a SysML Project with a dependency to a library containing one Package and one LibraryPackage, WHEN the explorer is displayed, THEN the library model is visible at the root of the explorer") - @Sql(scripts = { ProjectWithLibraryDependencyContainingPackageAndLibraryPackageTestProjectData.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)) + @GivenSysONServer({ ProjectWithLibraryDependencyContainingPackageAndLibraryPackageTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithImportedLibraryContainingPackageAndLibraryPackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -603,9 +591,7 @@ public void getExplorerContentWithImportedLibraryContainingPackageAndLibraryPack } @DisplayName("GIVEN a SysML Project with a dependency to a library containing one LibraryPackage, WHEN the explorer is displayed, THEN the library model is visible under the user libraries directory of the explorer") - @Sql(scripts = { ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData.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)) + @GivenSysONServer({ ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithImportedLibraryContainingLibraryPackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -658,9 +644,7 @@ public void getExplorerContentWithImportedLibraryContainingLibraryPackage() { } @DisplayName("GIVEN a SysML Project with a dependency to a library containing a Comment and a LibraryPackage, WHEN the explorer is displayed, THEN the library model is visible under the user libraries directory of the explorer") - @Sql(scripts = { ProjectWithLibraryDependencyContainingCommentAndLibraryPackageTestProjectData.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)) + @GivenSysONServer({ ProjectWithLibraryDependencyContainingCommentAndLibraryPackageTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentWithImportedLibraryContainingCommentAndLibraryPackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -713,9 +697,7 @@ public void getExplorerContentWithImportedLibraryContainingCommentAndLibraryPack } @DisplayName("GIVEN a SysML library containing a LibraryPackage, WHEN the explorer is displayed on the library's semantic data, THEN the library model is visible at the root of the explorer") - @Sql(scripts = { ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData.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)) + @GivenSysONServer({ ProjectWithLibraryDependencyContainingLibraryPackageTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentOnLibrarySemanticDataWithLibraryPackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -742,9 +724,7 @@ public void getExplorerContentOnLibrarySemanticDataWithLibraryPackage() { } @DisplayName("GIVEN a SysML library containing a Package and a LibraryPackage, WHEN the explorer is displayed on the library's semantic data, THEN the library model is visible at the root of the explorer") - @Sql(scripts = { ProjectWithLibraryDependencyContainingPackageAndLibraryPackageTestProjectData.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)) + @GivenSysONServer({ ProjectWithLibraryDependencyContainingPackageAndLibraryPackageTestProjectData.SCRIPT_PATH }) @Test public void getExplorerContentOnLibrarySemanticDataWithPackage() { List filters = List.of(SysONTreeFilterConstants.HIDE_MEMBERSHIPS_TREE_ITEM_FILTER_ID); @@ -771,8 +751,7 @@ public void getExplorerContentOnLibrarySemanticDataWithPackage() { } @DisplayName("GIVEN the SysON Explorer, WHEN tree item context menu is requested, THEN the returned tree items are the appropriate one.") - @Sql(scripts = { GeneralViewEmptyTestProjectData.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)) + @GivenSysONServer({ GeneralViewEmptyTestProjectData.SCRIPT_PATH }) @Test public void sysONExplorerTreeItemContextMenuEntriesTest() { var expandedItemIds = List.of( @@ -871,4 +850,69 @@ public void sysONExplorerTreeItemContextMenuEntriesTest() { .verify(Duration.ofSeconds(10)); } + + @DisplayName("GIVEN the SysON Explorer, WHEN displaying an Expression item, THEN the item's label shows the textual representation of the expression") + @GivenSysONServer({ ActionTransitionUsagesProjectData.SCRIPT_PATH }) + @Test + public void sysONExplorerTreeExpressionLabelTest() { + + var optionalEditingContext = this.editingContextSearchService.findById(ActionTransitionUsagesProjectData.EDITING_CONTEXT_ID); + TreeDescription treeDescription = optionalEditingContext + .flatMap(editingContext -> this.representationDescriptionSearchService.findById(editingContext, this.sysONExplorerTreeDescriptionId)) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast) + .orElse(null); + List defaultFilters = this.sysonTreeFilterProvider.get(null, treeDescription).stream() + .filter(TreeFilter::defaultState) + .map(TreeFilter::id) + .toList(); + + var expandedItemIds = List.of( + ActionTransitionUsagesProjectData.SemanticIds.DOCUMENT_ID, + ActionTransitionUsagesProjectData.SemanticIds.PACKAGE_1_ID, + ActionTransitionUsagesProjectData.SemanticIds.A0_ID, + ActionTransitionUsagesProjectData.SemanticIds.S1_ID, + ActionTransitionUsagesProjectData.SemanticIds.S2_ID); + + var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONExplorerTreeDescriptionId, expandedItemIds, defaultFilters); + var input = new ExplorerEventInput(UUID.randomUUID(), ActionTransitionUsagesProjectData.EDITING_CONTEXT_ID, explorerRepresentationId); + var flux = this.explorerEventSubscriptionRunner.run(input).flux(); + TestTransaction.flagForCommit(); + TestTransaction.end(); + + var treeId = new AtomicReference(); + Consumer initialTreeContentConsumer = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + treeId.set(tree.getId()); + assertThat(tree.getChildren()).hasSize(2); + var documentItem = tree.getChildren().get(0); + assertThat(documentItem.getChildren()).hasSize(1); + assertThat(documentItem.getLabel().toString()).isEqualTo("ActionTransitionUsage.sysml"); + var packageItem = documentItem.getChildren().get(0); + assertThat(packageItem.getLabel().toString()).isEqualTo("Package 1"); + assertThat(packageItem.getChildren()).hasSize(3); + var a0Item = packageItem.getChildren().get(0); + assertThat(a0Item.getLabel().toString()).isEqualTo("a0"); + assertThat(a0Item.getChildren()).hasSize(7); + var s1Item = a0Item.getChildren().get(5); + assertThat(s1Item.getLabel().toString()).isEqualTo("S1"); + assertThat(s1Item.getChildren()).hasSize(3); + var expr1Item = s1Item.getChildren().get(0); + assertThat(expr1Item.getKind()).isEqualTo("siriusComponents://semantic?domain=sysml&entity=OperatorExpression"); + assertThat(expr1Item.getLabel().toString()).isEqualTo("attr1 < 1"); + + var s2Item = a0Item.getChildren().get(6); + assertThat(s2Item.getLabel().toString()).isEqualTo("S2"); + assertThat(s2Item.getChildren()).hasSize(3); + var expr2Item = s2Item.getChildren().get(0); + assertThat(expr2Item.getKind()).isEqualTo("siriusComponents://semantic?domain=sysml&entity=OperatorExpression"); + assertThat(expr2Item.getLabel().toString()).isEqualTo("attr1 < 0"); + + }); + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } } diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ActionTransitionUsagesProjectData.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ActionTransitionUsagesProjectData.java index 7b79a3338..ef794b9d4 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ActionTransitionUsagesProjectData.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ActionTransitionUsagesProjectData.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2025 Obeo. + * Copyright (c) 2025, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -42,6 +42,8 @@ public static final class GraphicalIds { */ public static final class SemanticIds { + public static final String DOCUMENT_ID = "26a78eef-bfa1-4de0-9d0a-c1f86a1b97d5"; + public static final String PACKAGE_1_ID = "2264f62c-b223-4b9b-ae41-96dc2ba0070e"; public static final String A0_ID = "82a2fa10-e736-4c3e-b27a-e94f76d7456d"; diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/EMFUtils.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/EMFUtils.java index 121a73629..0abfb9328 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/EMFUtils.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/EMFUtils.java @@ -282,7 +282,6 @@ public static List getAncestors(Class type, EObject ob */ public static Optional getFirstAncestor(Class type, EObject object, Predicate ancestorPredicate) { var current = object; - List results = new ArrayList<>(); while (current != null) { if (type.isInstance(current) && (ancestorPredicate == null || ancestorPredicate.test(current))) { return Optional.of((T) current); diff --git a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelQueryElementService.java b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelQueryElementService.java index 60ee50ff3..2f3bc0086 100644 --- a/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelQueryElementService.java +++ b/backend/services/syson-sysml-metamodel-services/src/main/java/org/eclipse/syson/sysml/metamodel/services/MetamodelQueryElementService.java @@ -28,6 +28,7 @@ import org.eclipse.syson.sysml.ReferenceUsage; import org.eclipse.syson.sysml.StakeholderMembership; import org.eclipse.syson.sysml.SubjectMembership; +import org.eclipse.syson.sysml.Usage; /** * Element-related services doing queries. This class should not depend on sirius-web services or other spring services. @@ -78,6 +79,19 @@ public boolean isStakeholder(Element element) { return element instanceof PartUsage && element.getOwningMembership() instanceof StakeholderMembership; } + /** + * Check if a given {@code element} is an {@link Expression} definition. We can not simply rely on whether the + * element is an instance of {@link Expression} as many types in SysMLv2 inherit from this type without being + * themselves an actual expressions. + * + * @param element + * the element to test. + * @return true if the element is an actual expression definition. + */ + public boolean isExpressionDefinition(Element element) { + return element instanceof Expression && !(element instanceof Usage); + } + /** * Get the source of a {@link Connector}. * @@ -144,7 +158,7 @@ public Optional getCommonOwnerAncestor(Element e1, Elemen * Gets the value expression of a feature (Value of the FeatureValue owned by this feature). * * @param feature - * a non null feature + * a non null feature * @return an optional expression */ public Optional getValueExpression(Feature feature) { diff --git a/backend/services/syson-tree-services/src/main/java/org/eclipse/syson/tree/explorer/services/SysONDefaultExplorerServices.java b/backend/services/syson-tree-services/src/main/java/org/eclipse/syson/tree/explorer/services/SysONDefaultExplorerServices.java index 5b9157880..906e39d7b 100644 --- a/backend/services/syson-tree-services/src/main/java/org/eclipse/syson/tree/explorer/services/SysONDefaultExplorerServices.java +++ b/backend/services/syson-tree-services/src/main/java/org/eclipse/syson/tree/explorer/services/SysONDefaultExplorerServices.java @@ -38,8 +38,13 @@ import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationMetadata; import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.services.api.IRepresentationMetadataSearchService; import org.eclipse.syson.sysml.Element; +import org.eclipse.syson.sysml.Expression; import org.eclipse.syson.sysml.Type; import org.eclipse.syson.sysml.ViewUsage; +import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService; +import org.eclipse.syson.sysml.textual.SysMLElementSerializer; +import org.eclipse.syson.sysml.textual.SysMLSerializingOptions; +import org.eclipse.syson.sysml.textual.utils.FileNameDeresolver; import org.eclipse.syson.sysml.util.ElementUtil; import org.eclipse.syson.tree.explorer.fragments.KerMLStandardLibraryDirectory; import org.eclipse.syson.tree.explorer.fragments.LibrariesDirectory; @@ -74,6 +79,8 @@ public class SysONDefaultExplorerServices implements ISysONDefaultExplorerServic private final IReadOnlyObjectPredicate readOnlyObjectPredicate; + private final MetamodelQueryElementService metamodelQueryElementService; + public SysONDefaultExplorerServices(IIdentityService identityService, IContentService contentService, IRepresentationMetadataSearchService representationMetadataSearchService, IExplorerServices explorerServices, ILabelService labelService, ISysONExplorerFilterService filterService, final IReadOnlyObjectPredicate readOnlyObjectPredicate) { this.identityService = Objects.requireNonNull(identityService); @@ -83,6 +90,7 @@ public SysONDefaultExplorerServices(IIdentityService identityService, IContentSe this.labelService = Objects.requireNonNull(labelService); this.filterService = Objects.requireNonNull(filterService); this.readOnlyObjectPredicate = Objects.requireNonNull(readOnlyObjectPredicate); + this.metamodelQueryElementService = new MetamodelQueryElementService(); } @Override @@ -148,6 +156,8 @@ public String getLabel(Object self) { String label = ""; if (self instanceof ISysONExplorerFragment fragment) { label = fragment.getLabel(); + } else if (self instanceof Expression expression && this.metamodelQueryElementService.isExpressionDefinition(expression)) { + label = this.getValueExpressionTextualRepresentation(expression); } else if (self instanceof Type type) { String name = type.getName(); if (name != null) { @@ -159,6 +169,25 @@ public String getLabel(Object self) { return label; } + private String getValueExpressionTextualRepresentation(Expression value) { + String result = ""; + if (value != null) { + SysMLSerializingOptions options = new SysMLSerializingOptions.Builder() + .lineSeparator("\n") + .nameDeresolver(new FileNameDeresolver()) + .indentation("\t") + .needEscapeCharacter(false) + .build(); + String textualFormat = new SysMLElementSerializer(options, s -> { + // Do nothing for now + }).doSwitch(value); + if (textualFormat != null) { + result = textualFormat; + } + } + return result; + } + private String getFallbackLabel(Object self) { StyledString styledLabel = this.labelService.getStyledLabel(self); if (styledLabel != null) { diff --git a/doc/content/modules/user-manual/assets/images/explorer-expression-text.png b/doc/content/modules/user-manual/assets/images/explorer-expression-text.png new file mode 100644 index 000000000..14e3c1ef5 Binary files /dev/null and b/doc/content/modules/user-manual/assets/images/explorer-expression-text.png differ diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.5.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.5.0.adoc index 40cf0b46b..33ea8e61a 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.5.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.5.0.adoc @@ -37,6 +37,12 @@ image::release-notes-stakeholder-node.png[Default representation of Stakeholder ** Improve the tool to create a `Subject` graphical node by making specialization selection optional. ** Improve the tool to create a `FlowUsage` from a `ConnectionUsage` by making the payload selection optional. +* In the _Explorer_ view: + +** `Expression` elements now display their full textual representation: ++ +image::explorer-expression-text.png[Expression textual representation] + == Technical details * For technical details on this {product} release (including breaking changes), please refer to https://github.com/eclipse-syson/syson/blob/main/CHANGELOG.adoc[changelog]. diff --git a/frontend/syson-components/src/extensions/InsertTextualSysMLv2Modal.tsx b/frontend/syson-components/src/extensions/InsertTextualSysMLv2Modal.tsx index 648c165c1..24d6638bc 100644 --- a/frontend/syson-components/src/extensions/InsertTextualSysMLv2Modal.tsx +++ b/frontend/syson-components/src/extensions/InsertTextualSysMLv2Modal.tsx @@ -22,7 +22,6 @@ import { Theme } from '@mui/material/styles'; import TextField from '@mui/material/TextField'; import { useEffect, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; - import { InsertTextualSysMLv2ModalProps, InsertTextualSysMLv2ModalState } from './InsertTextualSysMLv2Modal.types'; import { NewObjectAsTextReport } from './NewObjectAsTextDocumentReport'; import { useInsertTextualSysMLv2 } from './useInsertTextualSysMLv2'; @@ -106,7 +105,7 @@ export const InsertTextualSysMLv2Modal = ({ editingContextId, item, onClose }: I onClick={(event) => onInsertTextualSysMLv2(event)} startIcon={ state.insertInProgress ? ( - + ) : ( ) diff --git a/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.ts b/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.ts index 73393e3c0..9f8fcdc66 100644 --- a/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.ts +++ b/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2025 Obeo. + * Copyright (c) 2025, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -19,7 +19,7 @@ import { GQLInsertTextualSysMLv2MutationData, GQLInsertTextualSysMLv2Payload, UseInsertTextualSysMLv2Value, -} from './useInsertTextualSysML.v2types'; +} from './useInsertTextualSysMLv2.types'; const insertTextualSysMLv2Mutation = gql` mutation insertTextualSysMLv2($input: InsertTextualSysMLv2Input!) { diff --git a/frontend/syson-components/src/extensions/useInsertTextualSysML.v2types.ts b/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.types.ts similarity index 97% rename from frontend/syson-components/src/extensions/useInsertTextualSysML.v2types.ts rename to frontend/syson-components/src/extensions/useInsertTextualSysMLv2.types.ts index 0aa533c60..50dd6ad58 100644 --- a/frontend/syson-components/src/extensions/useInsertTextualSysML.v2types.ts +++ b/frontend/syson-components/src/extensions/useInsertTextualSysMLv2.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024, 2025 Obeo. + * Copyright (c) 2024, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at diff --git a/scripts/check-coverage.jsh b/scripts/check-coverage.jsh index f1003f2a3..5594a0f97 100755 --- a/scripts/check-coverage.jsh +++ b/scripts/check-coverage.jsh @@ -40,18 +40,18 @@ var moduleCoverageData = List.of( new ModuleCoverage("syson-form-services", 100.0), new ModuleCoverage("syson-model-services", 94.0), new ModuleCoverage("syson-representation-services", 100.0), - new ModuleCoverage("syson-services", 64.0), + new ModuleCoverage("syson-services", 65.0), new ModuleCoverage("syson-siriusweb-customnodes-metamodel", 41.0), new ModuleCoverage("syson-siriusweb-customnodes-metamodel-edit", 0.0), new ModuleCoverage("syson-standard-diagrams-view", 97.0), new ModuleCoverage("syson-sysml-export", 71.0), new ModuleCoverage("syson-sysml-import", 85.0), - new ModuleCoverage("syson-sysml-metamodel", 76.0), + new ModuleCoverage("syson-sysml-metamodel", 77.0), new ModuleCoverage("syson-sysml-metamodel-edit", 17.0), new ModuleCoverage("syson-sysml-metamodel-services", 92.0), new ModuleCoverage("syson-sysml-rest-api-services", 93.0), new ModuleCoverage("syson-sysml-validation", 97.0), - new ModuleCoverage("syson-table-requirements-view", 72.0), + new ModuleCoverage("syson-table-requirements-view", 73.0), new ModuleCoverage("syson-table-services", 100.0), new ModuleCoverage("syson-tree-explorer-view", 88.0), new ModuleCoverage("syson-tree-services", 80.0)