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 @@ -49,6 +49,7 @@ Now, the choice is restricted to the _timeslice/snapshot_ type that match the gr
Users should use the dedicated tools to edit expressions instead, as they ensure only valid expressions (with all names resolving) are accepted.
- https://github.com/eclipse-syson/syson/issues/2287[#2287] [details] Use a label instead of a text field to display Expressions in the Details view.
- https://github.com/eclipse-syson/syson/issues/2290[#2290] [details] When the selected element can have an expression (but does not), display a widget to indicate it and to allow to create one.
- https://github.com/eclipse-syson/syson/issues/2301[#2301] [diagram] Constraint nodes now display their corresponding expression directly in their label if it is set.

=== New features

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.syson.application.controllers.expressions;

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

import com.jayway.jsonpath.JsonPath;
Expand All @@ -27,28 +28,34 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput;
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IIdentityService;
import org.eclipse.sirius.components.core.api.IInput;
import org.eclipse.sirius.components.core.api.IObjectSearchService;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.sirius.components.diagrams.Diagram;
import org.eclipse.sirius.components.graphql.tests.ExecuteEditingContextFunctionInput;
import org.eclipse.sirius.components.graphql.tests.ExecuteEditingContextFunctionSuccessPayload;
import org.eclipse.sirius.components.graphql.tests.api.IExecuteEditingContextFunctionRunner;
import org.eclipse.sirius.web.application.views.explorer.ExplorerEventInput;
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.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.controllers.diagrams.checkers.CheckDiagramElementCount;
import org.eclipse.syson.application.controllers.diagrams.testers.DropFromExplorerTester;
import org.eclipse.syson.application.controllers.expressions.graphql.CreateExpressionMutationRunner;
import org.eclipse.syson.application.controllers.expressions.graphql.DeleteExpressionMutationRunner;
import org.eclipse.syson.application.controllers.expressions.graphql.EditExpressionMutationRunner;
import org.eclipse.syson.application.controllers.expressions.graphql.ExpressionTextualRepresentationQueryRunner;
import org.eclipse.syson.application.data.ExpressionSamplesProjectData;
import org.eclipse.syson.application.expressions.dto.DeleteExpressionInput;
import org.eclipse.syson.services.diagrams.DiagramComparator;
import org.eclipse.syson.services.explorer.api.IExplorerDefaultFiltersSearchService;
import org.eclipse.syson.sysml.AttributeUsage;
import org.eclipse.syson.sysml.ConstraintUsage;
Expand All @@ -62,6 +69,7 @@
import org.eclipse.syson.sysml.dto.EditExpressionSuccessPayload;
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
import org.eclipse.syson.tree.explorer.view.SysONTreeViewDescriptionProvider;
import org.eclipse.syson.util.SysONRepresentationDescriptionIdentifiers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -70,6 +78,7 @@
import org.springframework.test.context.transaction.TestTransaction;
import org.springframework.transaction.annotation.Transactional;

import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;

/**
Expand All @@ -84,6 +93,9 @@ public class ExpressionsControllersIntegrationTests extends AbstractIntegrationT
@Autowired
private IGivenInitialServerState givenInitialServerState;

@Autowired
private DropFromExplorerTester dropFromExplorerTester;

@Autowired
private ExplorerEventSubscriptionRunner explorerEventSubscriptionRunner;

Expand Down Expand Up @@ -117,6 +129,12 @@ public class ExpressionsControllersIntegrationTests extends AbstractIntegrationT
@Autowired
private DeleteExpressionMutationRunner deleteExpressionMutationRunner;

@Autowired
private IGivenCreatedDiagramSubscription givenCreatedDiagramSubscription;

@Autowired
private DiagramComparator diagramComparator;

private String sysONExplorerTreeDescriptionId;

private MetamodelQueryElementService metamodelQueryElementService;
Expand Down Expand Up @@ -585,6 +603,52 @@ public void topLevelExpressionTextualRepresentation() {
.verify(Duration.ofSeconds(10));
}

private Flux<Object> givenSubscriptionToNewDiagram() {
var input = new CreateRepresentationInput(
UUID.randomUUID(),
ExpressionSamplesProjectData.EDITING_CONTEXT_ID,
SysONRepresentationDescriptionIdentifiers.GENERAL_VIEW_DIAGRAM_DESCRIPTION_ID,
ExpressionSamplesProjectData.SemanticIds.EXPRESSIONS_PACKAGE_ID,
"Diagram");
return this.givenCreatedDiagramSubscription.createAndSubscribe(input).flux();
}


@DisplayName("GIVEN a SysML model with expressions, WHEN dropping a contraint with an associated expression on an empty diagram, THEN the node showing the constraint includes the text of the exression in its label")
@GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH })
@Test
public void topLevelConstraintNodeLabelIncludesExpressionInLabel() {
var flux = this.givenSubscriptionToNewDiagram();

AtomicReference<Diagram> diagram = new AtomicReference<>();
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram::set);

Runnable dropFromExplorerRunnable = () -> {
assertThat(diagram.get().getNodes()).hasSize(0);
var background = diagram.get().getStyle().getBackground();
assertThat(background).isNotEqualTo("white");
this.dropFromExplorerTester.dropFromExplorerOnDiagram(ExpressionSamplesProjectData.EDITING_CONTEXT_ID, diagram, ExpressionSamplesProjectData.SemanticIds.TANK_PRESSURE_LIMIT_CONSTRAINT_ID);
};

Consumer<Object> updatedDiagramConsumer = assertRefreshedDiagramThat(newDiagram -> {
new CheckDiagramElementCount(this.diagramComparator)
.hasNewEdgeCount(0)
// 1 node for the ConstraintUsage, 4 for its compartments (doc, attributes, constraints, ports)
.hasNewNodeCount(5)
.check(diagram.get(), newDiagram);

String nodeLabel = newDiagram.getNodes().get(0).getInsideLabel().getText();
assertThat(nodeLabel).isEqualTo("«constraint»\npressureLimit\n{ pressure <= maxPressure }");
});

StepVerifier.create(flux)
.consumeNextWith(initialDiagramContentConsumer)
.then(dropFromExplorerRunnable)
.consumeNextWith(updatedDiagramConsumer)
.thenCancel()
.verify(Duration.ofSeconds(10));

}

/**
* Executes a function in the editing context with the specified id (which is assumed to be loaded). The function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.eclipse.syson.sysml.Redefinition;
import org.eclipse.syson.sysml.ReferenceSubsetting;
import org.eclipse.syson.sysml.RequirementConstraintMembership;
import org.eclipse.syson.sysml.ResultExpressionMembership;
import org.eclipse.syson.sysml.SatisfyRequirementUsage;
import org.eclipse.syson.sysml.StateSubactionMembership;
import org.eclipse.syson.sysml.Subclassification;
Expand Down Expand Up @@ -355,12 +356,15 @@ public String getDefaultInitialDirectEditLabel(Element element) {
* @return the label of the value part of the given {@link Usage} if there is one, an empty string otherwise.
*/
private String getValueStringRepresentation(Usage usage, boolean directEditInput) {
if (directEditInput) {
return "";
}
StringBuilder label = new StringBuilder();
var featureValue = usage.getOwnedRelationship().stream()
.filter(FeatureValue.class::isInstance)
.map(FeatureValue.class::cast)
.findFirst();
if (featureValue.isPresent() && !directEditInput) {
if (featureValue.isPresent()) {
var expression = featureValue.get().getValue();
String valueAsString = null;
if (expression != null) {
Expand All @@ -377,6 +381,12 @@ private String getValueStringRepresentation(Usage usage, boolean directEditInput
.append(this.getFeatureValueRelationshipSymbol(featureValue.get()))
.append(LabelConstants.SPACE)
.append(valueAsString);
} else if (usage instanceof ConstraintUsage constraintUsage) {
String expressionPart = this.getConstraintExpression(constraintUsage);
if (!expressionPart.isEmpty()) {
label.append(LabelConstants.CR);
label.append(expressionPart);
}
}
return label.toString();
}
Expand Down Expand Up @@ -574,7 +584,7 @@ public String getDependencyLabel(Dependency dependency) {
* Returns the label for the given {@link SatisfyRequirementUsage}.
*
* @param satisfyRequirementUsage
* The given {@link SatisfyRequirementUsage}
* The given {@link SatisfyRequirementUsage}
* @return the label for the given {@link SatisfyRequirementUsage}
*/
public String getSatisfyLabel(SatisfyRequirementUsage satisfyRequirementUsage) {
Expand Down Expand Up @@ -607,19 +617,35 @@ private String getCompartmentItemLabel(ConstraintUsage constraintUsage, boolean
label.append(this.getIdentificationLabel(constraintUsage));
label.append(this.getReferenceSubsettingLabel(constraintUsage));
}

if (!directEditInput && !constraintUsage.getOwnedMember().isEmpty() && constraintUsage.getOwnedMember().get(0) instanceof Expression expression) {
if (!label.isEmpty()) {
label.append(LabelConstants.SPACE);
}
label.append(LabelConstants.OPEN_BRACE).append(LabelConstants.SPACE);
label.append(this.getSysmlTextualRepresentation(expression, directEditInput));
label.append(LabelConstants.SPACE).append(LabelConstants.CLOSE_BRACE);
String expressionPart = this.getConstraintExpression(constraintUsage);
if (!expressionPart.isEmpty()) {
label.append(LabelConstants.SPACE);
label.append(expressionPart);
}
}
return label.toString();
}

/**
* Returns the string representation of the {@link Expression} associated with a {@link ConstraintUsage} using the
* proper syntax (between braces=.
*
* @param constraintUsage
* a {@link ConstraintUsage}
* @param label
* the string representation of the corresponding expression if it is set, or an empty string if there is
* no associated expression.
*/
private String getConstraintExpression(ConstraintUsage constraintUsage) {
StringBuilder label = new StringBuilder();
if (this.metamodelQueryElementService.getResultExpressionMembership(constraintUsage) instanceof ResultExpressionMembership rem && rem.getOwnedResultExpression() != null) {
label.append(LabelConstants.OPEN_BRACE).append(LabelConstants.SPACE);
label.append(this.metamodelQueryElementService.getExpressionTextualRepresentation(rem.getOwnedResultExpression()));
label.append(LabelConstants.SPACE).append(LabelConstants.CLOSE_BRACE);
}
return label.toString();
}

/**
* Return the label for the given {@link Documentation} when displayed as a compartment item.
*
Expand Down
Loading