Skip to content

Commit 691508f

Browse files
gcoutableAxelRICHARD
authored andcommitted
[1978] Add support for PortionKind edition with direct-edit in diagrams
Bug: #1978 Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
1 parent 102ab46 commit 691508f

File tree

16 files changed

+1584
-1330
lines changed

16 files changed

+1584
-1330
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ This toggle is de-activated by default.
9191

9292
- https://github.com/eclipse-syson/syson/issues/1977[#1977] [diagram] Display the _timeslice_ and _snapshot_ prefixes in the label of `OccurrenceUsage` graphical nodes and some of the graphical nodes representing subclasses of `OccurrenceUsage`.
9393
- https://github.com/eclipse-syson/syson/issues/1977[#1977] [metamodel] Ensure a _timeSlice_ or a _snapshot_ `OccurrenceUsage` implicitly specializes `Occurrences::Occurrence::timeSlices` or `Occurrences::Occurrence::snapshots`, directly or indirectly.
94+
- https://github.com/eclipse-syson/syson/issues/1978[#1978] [diagram] Allow to edit the _timeslice_ and _snapshot_ properties of `OccurrenceUsage` graphical nodes (and all its subtypes such as `PartUsage`, `ItemUsage`, ...) with the direct edit.
9495

9596
== v2026.1.0
9697

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

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,13 @@
4141
import org.eclipse.syson.services.SemanticRunnableFactory;
4242
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
4343
import org.eclipse.syson.sysml.PartUsage;
44+
import org.eclipse.syson.sysml.PortionKind;
4445
import org.eclipse.syson.sysml.helper.LabelConstants;
4546
import org.junit.jupiter.api.BeforeEach;
4647
import org.junit.jupiter.api.DisplayName;
4748
import org.junit.jupiter.api.Test;
4849
import org.springframework.beans.factory.annotation.Autowired;
4950
import org.springframework.boot.test.context.SpringBootTest;
50-
import org.springframework.test.context.jdbc.Sql;
51-
import org.springframework.test.context.jdbc.SqlConfig;
5251
import org.springframework.transaction.annotation.Transactional;
5352

5453
import reactor.core.publisher.Flux;
@@ -92,9 +91,7 @@ public void beforeEach() {
9291
}
9392

9493
@DisplayName("GIVEN a diagram with a part and a part definition, WHEN the part is typed with direct edit, THEN the feature typing is created")
95-
@Sql(scripts = { GeneralViewDirectEditTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
96-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
97-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
94+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
9895
@Test
9996
public void directEditUsingName() {
10097
var flux = this.givenSubscriptionToDiagram();
@@ -144,10 +141,58 @@ public void directEditUsingName() {
144141
.verify(Duration.ofSeconds(10));
145142
}
146143

144+
@DisplayName("GIVEN a diagram with a part, WHEN the part portion kind is changed with direct edit, THEN the portion kind property is updated")
145+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
146+
@Test
147+
public void directEditUsingPortionKind() {
148+
var flux = this.givenSubscriptionToDiagram();
149+
150+
var diagramId = new AtomicReference<String>();
151+
var partNodeId = new AtomicReference<String>();
152+
var partNodeLabelId = new AtomicReference<String>();
153+
154+
Consumer<Object> initialDiagramContentConsumer = assertRefreshedDiagramThat(diagram -> {
155+
diagramId.set(diagram.getId());
156+
var partNode = new DiagramNavigator(diagram).nodeWithLabel(LabelConstants.OPEN_QUOTE + "part" + LabelConstants.CLOSE_QUOTE + "\npart1").getNode();
157+
partNodeId.set(partNode.getId());
158+
partNodeLabelId.set(partNode.getInsideLabel().getId());
159+
});
160+
161+
Runnable editLabel = () -> {
162+
var input = new EditLabelInput(UUID.randomUUID(), GeneralViewDirectEditTestProjectData.EDITING_CONTEXT_ID, diagramId.get(), partNodeLabelId.get(), "timeslice part1");
163+
var result = this.editLabelMutationRunner.run(input);
164+
165+
String typename = JsonPath.read(result.data(), "$.data.editLabel.__typename");
166+
assertThat(typename).isEqualTo(EditLabelSuccessPayload.class.getSimpleName());
167+
};
168+
169+
Consumer<Object> updatedDiagramContentMatcher = assertRefreshedDiagramThat(diagram -> {
170+
var node = new DiagramNavigator(diagram).nodeWithId(partNodeId.get()).getNode();
171+
DiagramAssertions.assertThat(node.getInsideLabel()).hasText(LabelConstants.OPEN_QUOTE + "timeslice" + LabelConstants.CLOSE_QUOTE + "\n" + LabelConstants.OPEN_QUOTE + "part" + LabelConstants.CLOSE_QUOTE + "\npart1");
172+
});
173+
174+
Runnable exposedElementsChecker = this.semanticRunnableFactory.createRunnable(GeneralViewDirectEditTestProjectData.EDITING_CONTEXT_ID,
175+
(editingContext, executeEditingContextFunctionInput) -> {
176+
PartUsage part = this.objectSearchService.getObject(editingContext, GeneralViewDirectEditTestProjectData.SemanticIds.PART_USAGE_ID)
177+
.filter(PartUsage.class::isInstance)
178+
.map(PartUsage.class::cast)
179+
.orElse(null);
180+
assertThat(part).isNotNull();
181+
assertThat(part.getPortionKind()).isEqualTo(PortionKind.TIMESLICE);
182+
return new ExecuteEditingContextFunctionSuccessPayload(executeEditingContextFunctionInput.id(), true);
183+
});
184+
185+
StepVerifier.create(flux)
186+
.consumeNextWith(initialDiagramContentConsumer)
187+
.then(editLabel)
188+
.consumeNextWith(updatedDiagramContentMatcher)
189+
.then(exposedElementsChecker)
190+
.thenCancel()
191+
.verify(Duration.ofSeconds(10));
192+
}
193+
147194
@DisplayName("GIVEN a diagram with a part and a part definition, WHEN the part is typed with direct edit using the qualified name, THEN the feature typing is created")
148-
@Sql(scripts = { GeneralViewDirectEditTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
149-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
150-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
195+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
151196
@Test
152197
public void directEditUsingWithQualifiedFullName() {
153198
var flux = this.givenSubscriptionToDiagram();
@@ -198,9 +243,7 @@ public void directEditUsingWithQualifiedFullName() {
198243
}
199244

200245
@DisplayName("GIVEN a diagram with a part and a part definition, WHEN the part is typed with direct edit using short name, THEN the feature typing is created")
201-
@Sql(scripts = { GeneralViewDirectEditTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
202-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
203-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
246+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
204247
@Test
205248
public void directEditUsingShortName() {
206249
var flux = this.givenSubscriptionToDiagram();
@@ -251,9 +294,7 @@ public void directEditUsingShortName() {
251294
}
252295

253296
@DisplayName("GIVEN a diagram with a part and a part definition, WHEN the part is typed with direct edit using the qualified short name, THEN the feature typing is created")
254-
@Sql(scripts = { GeneralViewDirectEditTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
255-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
256-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
297+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
257298
@Test
258299
public void directEditUsingQualifiedShortName() {
259300
var flux = this.givenSubscriptionToDiagram();
@@ -304,9 +345,7 @@ public void directEditUsingQualifiedShortName() {
304345
}
305346

306347
@DisplayName("GIVEN a diagram with a part and a part definition in the same scope, WHEN the part is typed with direct edit using short name, THEN the feature typing is created with the best candidat")
307-
@Sql(scripts = { GeneralViewDirectEditTestProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
308-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
309-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
348+
@GivenSysONServer({ GeneralViewDirectEditTestProjectData.SCRIPT_PATH })
310349
@Test
311350
public void directEditUsingShortNameAndScope() {
312351
var flux = this.givenSubscriptionToDiagram();
@@ -357,9 +396,7 @@ public void directEditUsingShortNameAndScope() {
357396
}
358397

359398
@DisplayName("GIVEN a diagram with an attribute, WHEN we direct edit with an operation using an unimported namespace, THEN the attribute is correctly set")
360-
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
361-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
362-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
399+
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
363400
@Test
364401
public void directEditOperationUsingUnImportedNameSpaceName() {
365402
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
@@ -403,9 +440,7 @@ public void directEditOperationUsingUnImportedNameSpaceName() {
403440
}
404441

405442
@DisplayName("GIVEN a diagram with a part, WHEN we direct edit with multiplicity and subsetting, THEN the part is correctly set")
406-
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
407-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
408-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
443+
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
409444
@Test
410445
public void directEditMultiplicityWithSubsetting() {
411446
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
@@ -466,9 +501,7 @@ public void directEditMultiplicityWithSubsetting() {
466501
}
467502

468503
@DisplayName("GIVEN a diagram with a part, WHEN we direct edit with multiplicity and redefinition, THEN the part is correctly set")
469-
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
470-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
471-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
504+
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
472505
@Test
473506
public void directEditMultiplicityWithRedefinition() {
474507
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
@@ -529,9 +562,7 @@ public void directEditMultiplicityWithRedefinition() {
529562
}
530563

531564
@DisplayName("GIVEN a diagram with a part, WHEN we direct edit with multiplicity and feature typing, THEN the part is correctly set")
532-
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
533-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
534-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
565+
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
535566
@Test
536567
public void directEditMultiplicityWithFeatureTyping() {
537568
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),
@@ -592,9 +623,7 @@ public void directEditMultiplicityWithFeatureTyping() {
592623
}
593624

594625
@DisplayName("GIVEN a diagram with a part, WHEN we direct edit with multiplicity and operation, THEN the part is correctly set only if the multiplicity is before the operation")
595-
@Sql(scripts = { GeneralViewItemAndAttributeProjectData.SCRIPT_PATH }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
596-
config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
597-
@Sql(scripts = { "/scripts/cleanup.sql" }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
626+
@GivenSysONServer({ GeneralViewItemAndAttributeProjectData.SCRIPT_PATH })
598627
@Test
599628
public void directEditMultiplicityWithOperation() {
600629
var diagramEventInput = new DiagramEventInput(UUID.randomUUID(),

backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/helper/LabelConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ public class LabelConstants {
8383

8484
public static final String SUBSETTING = SysMLv2Keywords.SPECIALIZES_OPERATOR;
8585

86+
public static final String TIMESLICE = SysMLv2Keywords.TIMESLICE;
87+
88+
public static final String SNAPSHOT = SysMLv2Keywords.SNAPSHOT;
89+
8690
public static final String VARIANT = SysMLv2Keywords.VARIANT;
8791

8892
public static final String VARIATION = SysMLv2Keywords.VARIATION;

backend/services/syson-diagram-services/src/main/java/org/eclipse/syson/diagram/services/DiagramQueryLabelService.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
import org.eclipse.syson.sysml.FeatureValue;
3939
import org.eclipse.syson.sysml.LiteralExpression;
4040
import org.eclipse.syson.sysml.MultiplicityRange;
41+
import org.eclipse.syson.sysml.OccurrenceUsage;
4142
import org.eclipse.syson.sysml.OwningMembership;
43+
import org.eclipse.syson.sysml.PortionKind;
4244
import org.eclipse.syson.sysml.Redefinition;
4345
import org.eclipse.syson.sysml.ReferenceSubsetting;
4446
import org.eclipse.syson.sysml.RequirementConstraintMembership;
@@ -366,14 +368,21 @@ private String getValueStringRepresentation(Usage usage, boolean directEditInput
366368
}
367369

368370
/**
369-
* Return the label of the prefix part of the given {@link Usage}.
371+
* Return the label of the prefix part of the given {@link Element}.
370372
*
371-
* @param usage
372-
* the given {@link Usage}.
373-
* @return the label of the prefix part of the given {@link Usage} if there is one, an empty string otherwise.
373+
* @param element
374+
* the given {@link Element}.
375+
* @return the label of the prefix part of the given {@link Element} if there is one, an empty string otherwise.
374376
*/
375377
private String getBasicNamePrefix(Element element) {
376378
StringBuilder label = new StringBuilder();
379+
if (element instanceof OccurrenceUsage occurrenceUsage && occurrenceUsage.isSetPortionKind()) {
380+
if (occurrenceUsage.getPortionKind().equals(PortionKind.TIMESLICE)) {
381+
label.append(LabelConstants.TIMESLICE + LabelConstants.SPACE);
382+
} else if (occurrenceUsage.getPortionKind().equals(PortionKind.SNAPSHOT)) {
383+
label.append(LabelConstants.SNAPSHOT + LabelConstants.SPACE);
384+
}
385+
}
377386
if (element instanceof Usage usage) {
378387
if (usage.isIsVariation()) {
379388
label.append(LabelConstants.VARIATION + LabelConstants.SPACE);

0 commit comments

Comments
 (0)