Skip to content
Draft
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 @@ -45,6 +45,7 @@ This fix ensure that imported models containing, for example, a top-level `Libra
A new compartment named _satisfy requirements_ has also been added to `PartDefinition` and `PartUsage` graphical nodes in diagrams.
- https://github.com/eclipse-syson/syson/issues/1762[#1762] [diagrams] Increase the default size of nodes.
- https://github.com/eclipse-syson/syson/issues/1752[#1752] [diagrams] In diagrams, hide the node displayed on the top of the diagram if the candidate compartment is not hidden.
- https://github.com/eclipse-syson/syson/issues/1778[#1778] [diagrams] Add new `ReferenceSubsetting` tool to create `ReferenceSubsetting` relationships between `Usage` elements in diagrams.

=== New features

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023, 2025 Obeo.
* Copyright (c) 2023, 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
Expand Down Expand Up @@ -83,6 +83,8 @@ public class SysMLv2PropertiesConfigurer implements IPropertiesDescriptionRegist

private static final String ADVANCED_PROPERTIES = "Advanced Properties";

private static final String REFERENCE_SUBSETTING_PROPERTIES = "Reference Subsetting Properties";

private static final String REDEFINITION_PROPERTIES = "Redefinition Properties";

private static final String SUBCLASSIFICATION_PROPERTIES = "Subclassification Properties";
Expand Down Expand Up @@ -176,6 +178,7 @@ private FormDescription createDetailsViewForElement() {
pageCore.setLabelExpression("Core");
pageCore.getGroups().add(this.createCorePropertiesGroup());
pageCore.getGroups().add(this.createVisibilityPropertyGroup());
pageCore.getGroups().add(this.createExtraReferenceSubsettingPropertiesGroup());
pageCore.getGroups().add(this.createExtraRedefinitionPropertiesGroup());
pageCore.getGroups().add(this.createExtraStatesubactionMembershipKindPropertiesGroup());
pageCore.getGroups().add(this.createExtraSubclassificationPropertiesGroup());
Expand Down Expand Up @@ -273,6 +276,31 @@ private GroupDescription createExtraRedefinitionPropertiesGroup() {
return group;
}

// should handle multiple ReferenceSubsetting
private GroupDescription createExtraReferenceSubsettingPropertiesGroup() {
GroupDescription group = FormFactory.eINSTANCE.createGroupDescription();
group.setDisplayMode(GroupDisplayMode.LIST);
group.setName(REFERENCE_SUBSETTING_PROPERTIES);
group.setLabelExpression("");
group.setSemanticCandidatesExpression("aql:self.ownedRelationship->filter(sysml::ReferenceSubsetting)");

ReferenceWidgetDescription refWidget = ReferenceFactory.eINSTANCE.createReferenceWidgetDescription();
refWidget.setName("ExtraReferenceWidget");
refWidget.setLabelExpression("References");
refWidget.setReferenceNameExpression(SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName());
refWidget.setReferenceOwnerExpression(AQLConstants.AQL_SELF);
refWidget.setIsEnabledExpression(AQL_NOT_SELF_IS_READ_ONLY);
ChangeContext setRefWidget = ViewFactory.eINSTANCE.createChangeContext();
setRefWidget
.setExpression("aql:self.handleReferenceWidgetNewValue('" + SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().getName() + "', " + ViewFormDescriptionConverter.NEW_VALUE
+ LabelConstants.CLOSE_PARENTHESIS);
refWidget.getBody().add(setRefWidget);

group.getChildren().add(refWidget);

return group;
}

private GroupDescription createExtraStatesubactionMembershipKindPropertiesGroup() {
GroupDescription group = FormFactory.eINSTANCE.createGroupDescription();
group.setDisplayMode(GroupDisplayMode.LIST);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023, 2025 Obeo.
* Copyright (c) 2023, 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
Expand Down Expand Up @@ -36,8 +36,8 @@
import org.eclipse.sirius.components.core.api.IReadOnlyObjectPredicate;
import org.eclipse.sirius.components.representations.Message;
import org.eclipse.sirius.components.representations.MessageLevel;
import org.eclipse.syson.form.services.api.IDetailsViewHelpTextProvider;
import org.eclipse.syson.application.configuration.SysMLv2PropertiesConfigurer;
import org.eclipse.syson.form.services.api.IDetailsViewHelpTextProvider;
import org.eclipse.syson.services.ElementInitializerSwitch;
import org.eclipse.syson.services.ImportService;
import org.eclipse.syson.services.UtilService;
Expand Down Expand Up @@ -670,6 +670,8 @@ private void handleImplied(Element element, EStructuralFeature eStructuralFeatur
if (element instanceof Relationship relationship) {
if (SysmlPackage.eINSTANCE.getRedefinition_RedefinedFeature().equals(eStructuralFeature)) {
relationship.setIsImplied(false);
} else if (SysmlPackage.eINSTANCE.getReferenceSubsetting_ReferencedFeature().equals(eStructuralFeature)) {
relationship.setIsImplied(false);
} else if (SysmlPackage.eINSTANCE.getSubsetting_SubsettedFeature().equals(eStructuralFeature)) {
relationship.setIsImplied(false);
} else if (SysmlPackage.eINSTANCE.getSubclassification_Superclassifier().equals(eStructuralFeature)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -242,6 +242,7 @@ public List<EClass> caseUsage(Usage object) {
childrenCandidates.add(SysmlPackage.eINSTANCE.getFeatureTyping());
childrenCandidates.add(SysmlPackage.eINSTANCE.getSubsetting());
childrenCandidates.add(SysmlPackage.eINSTANCE.getRedefinition());
childrenCandidates.add(SysmlPackage.eINSTANCE.getReferenceSubsetting());
childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralBoolean());
childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralInfinity());
childrenCandidates.add(SysmlPackage.eINSTANCE.getLiteralInteger());
Expand Down
13 changes: 9 additions & 4 deletions backend/application/syson-application/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

## Developer testing environment

SysON contains tests that can be executed out of the box. The instructions below detail how to configure your development environment to contribute/modify tests and their baseline models.
SysON contains tests that can be executed out of the box.
The instructions below detail how to configure your development environment to contribute/modify tests and their baseline models.

### Prerequisites

The scripts used in the instructions below rely on the `pg_dump` and `psql` executables. We recommand to install [pgAdmin](https://www.pgadmin.org/download/) to get them as well as additional tools to manipulate Postgres databases.
The scripts used in the instructions below rely on the `pg_dump` and `psql` executables.
We recommand to install [pgAdmin](https://www.pgadmin.org/download/) to get them as well as additional tools to manipulate Postgres databases.

The scripts below have been tested with Git Bash on Windows. They rely on `winpty` to communicate with Windows console programs. Please adapt the scripts if you are using a different shell/operating system.
The scripts below must be adapted when using Git Bash on Windows.
In this case they rely on `winpty` to communicate with Windows console programs.
Please adapt the scripts if you are using Git Bash on Windows (just comment/uncomment appropriate line in the scripts).

### Setup the testing environment

Expand All @@ -33,7 +37,8 @@ docker run -p 5433:5432 --name syson-test-postgres \

2. Start SysON backend & frontend

This creates the database tables required by the tests. The SysON frontend can be used later to update the test models.
This creates the database tables required by the tests.
The SysON frontend can be used later to update the test models.

3. Run the initialization script

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (c) 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
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.syson.application.controllers.diagrams.general.view;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.sirius.components.diagrams.tests.DiagramEventPayloadConsumer.assertRefreshedDiagramThat;

import java.time.Duration;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramEventInput;
import org.eclipse.sirius.components.collaborative.diagrams.dto.DiagramRefreshedEventPayload;
import org.eclipse.sirius.components.diagrams.Diagram;
import org.eclipse.sirius.components.diagrams.tests.navigation.DiagramNavigator;
import org.eclipse.sirius.components.view.emf.diagram.IDiagramIdProvider;
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
import org.eclipse.syson.AbstractIntegrationTests;
import org.eclipse.syson.application.controllers.diagrams.testers.EdgeCreationTester;
import org.eclipse.syson.application.data.GeneralViewWithTopNodesTestProjectData;
import org.eclipse.syson.services.diagrams.DiagramDescriptionIdProvider;
import org.eclipse.syson.services.diagrams.api.IGivenDiagramDescription;
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
import org.eclipse.syson.standard.diagrams.view.SDVDescriptionNameGenerator;
import org.eclipse.syson.sysml.SysmlPackage;
import org.eclipse.syson.util.IDescriptionNameGenerator;
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
import org.junit.jupiter.api.BeforeEach;
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.core.publisher.Flux;
import reactor.test.StepVerifier;

/**
* ReferenceSubsetting-Edge related tests the in the General View diagram.
*
* @author arichard
*/
@Transactional
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GVEdgeReferenceSubsettingTest extends AbstractIntegrationTests {

@Autowired
private IGivenInitialServerState givenInitialServerState;

@Autowired
private IGivenDiagramSubscription givenDiagramSubscription;

@Autowired
private IGivenDiagramDescription givenDiagramDescription;

@Autowired
private IDiagramIdProvider diagramIdProvider;

@Autowired
private EdgeCreationTester edgeTester;

private final IDescriptionNameGenerator descriptionNameGenerator = new SDVDescriptionNameGenerator();

private Flux<DiagramRefreshedEventPayload> givenSubscriptionToDiagram() {
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
GeneralViewWithTopNodesTestProjectData.GraphicalIds.DIAGRAM_ID);
var flux = this.givenDiagramSubscription.subscribe(diagramEventInput);
return flux;
}

@BeforeEach
public void beforeEach() {
this.givenInitialServerState.initialize();
}

@DisplayName("GIVEN a diagram with two Usage nodes, WHEN a ReferenceSubsetting edge is created between them, THEN the edge is visisble on the diagram")
@Sql(scripts = { GeneralViewWithTopNodesTestProjectData.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))
@Test
public void testCreateReferenceSubsettingEdge() {
var flux = this.givenSubscriptionToDiagram();

var diagramDescription = this.givenDiagramDescription.getDiagramDescription(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID,
SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID);
var diagramDescriptionIdProvider = new DiagramDescriptionIdProvider(diagramDescription, this.diagramIdProvider);

var newReferenceSubsettingToolId = diagramDescriptionIdProvider.getEdgeCreationToolId(this.descriptionNameGenerator.getNodeName(SysmlPackage.eINSTANCE.getActionUsage()),
"New Reference Subsetting");
assertThat(newReferenceSubsettingToolId).as("The tool 'New Reference Subsetting' should exist on the ActionUsage").isNotNull();

var diagram = new AtomicReference<Diagram>();

Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diag -> {
diagram.set(diag);
assertThat(new DiagramNavigator(diag).findDiagramEdgeCount()).isEqualTo(3);
});

Runnable newReferenceSubsettingTool = () -> this.edgeTester.createEdgeUsingNodeId(GeneralViewWithTopNodesTestProjectData.EDITING_CONTEXT_ID, diagram,
GeneralViewWithTopNodesTestProjectData.GraphicalIds.ACTION_USAGE_ID, GeneralViewWithTopNodesTestProjectData.GraphicalIds.STATE_USAGE_ID, newReferenceSubsettingToolId);

Consumer<Object> updatedDiagramContentConsumer = assertRefreshedDiagramThat(diag -> {
var diagramNavigator = new DiagramNavigator(diag);
assertThat(diagramNavigator.findDiagramEdgeCount()).isEqualTo(4);
var edgeDescriptionId = diagramDescriptionIdProvider.getEdgeDescriptionId(this.descriptionNameGenerator.getEdgeName(SysmlPackage.eINSTANCE.getReferenceSubsetting()));
var referenceSubsettingEdge = diagramNavigator.edgeWithEdgeDescriptionId(edgeDescriptionId).getEdge();
assertThat(referenceSubsettingEdge).isNotNull();
assertThat(referenceSubsettingEdge.getSourceId()).isEqualTo(GeneralViewWithTopNodesTestProjectData.GraphicalIds.ACTION_USAGE_ID);
assertThat(referenceSubsettingEdge.getTargetId()).isEqualTo(GeneralViewWithTopNodesTestProjectData.GraphicalIds.STATE_USAGE_ID);
});

StepVerifier.create(flux)
.consumeNextWith(initialDiagramContentConsumer)
.then(newReferenceSubsettingTool)
.consumeNextWith(updatedDiagramContentConsumer)
.thenCancel()
.verify(Duration.ofSeconds(10));
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -245,7 +245,7 @@ public void setUp() {
public void tearDown() {
if (this.verifier != null) {
this.verifier.thenCancel()
.verify(Duration.ofSeconds(10));
.verify(Duration.ofSeconds(1000));
}
}

Expand Down Expand Up @@ -561,11 +561,10 @@ public void createReferencingPerformActionUsageInActionUsage() {
this.creationTestsService.createNode(this.verifier, this.diagramDescriptionIdProvider, this.diagram, parentEClass, parentLabel, creationToolName, variables);

IDiagramChecker diagramChecker = (initialDiagram, newDiagram) -> {
int createdNodesExpectedCount = 14;
new CheckDiagramElementCount(this.diagramComparator)
.hasNewNodeCount(createdNodesExpectedCount)
.hasNewEdgeCount(1)
.check(initialDiagram, newDiagram);
.hasNewNodeCount(1) // 1 visible new PerformActionUsage node
.hasNewEdgeCount(2) // 1 visible composition edge and 1 visible ReferenceSubsetting edge
.check(initialDiagram, newDiagram, true);
String listNodeDescription = this.descriptionNameGenerator.getCompartmentItemName(parentEClass, containmentReference);
new CheckNodeInCompartment(this.diagramDescriptionIdProvider, this.diagramComparator)
.withParentLabel(parentLabel)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -35,6 +35,10 @@ public static class GraphicalIds {
public static final String PART_DEFINITION_ID = "fa617798-658e-3812-92f2-52e2fc39f851";

public static final String PART_DEFINITION_TEXTUAL_REP_ID = "3a992e49-95fa-384a-bb54-47284825bf17";

public static final String ACTION_USAGE_ID = "61aaf64a-4fbc-356e-ba73-4bd47b386989";

public static final String STATE_USAGE_ID = "1541c013-2cc7-3dd7-a39f-6e33d07b411e";
}

/**
Expand Down
Loading
Loading