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
9 changes: 9 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,24 @@

=== Breaking changes

- https://github.com/eclipse-syson/syson/issues/893[#893] [explorer] Fix _Expand All_ tool in SysON _Explorer_ view
* `ISysONExplorerFragment` implementations now need to implement `getKind()` and `getParent()`.
* The constructors of `KerMLStandardLibraryDirectory`, `LibrariesDirectory`, `SysMLStandardLibraryDirectory`, and `UserLibrariesDirectory` now have a new `parent` parameter.
* `ISysONExplorerService` implementations now need to implement `canExpandAll(TreeItem, IEditingContext)`
* `ISysONExplorerServiceDelegate` implementations now need to implement `canExpandAll(TreeItem, IEditingContext)`

=== Dependency update

- [releng] Switch to https://github.com/spring-projects/spring-boot/releases/tag/v3.5.0[Spring Boot 3.5.0]
- [releng] Switch to https://github.com/eclipse-sirius/sirius-web[Sirius Web 2025.6.1]
- https://github.com/eclipse-syson/syson/issues/1385[#1385] [releng] Switch to SysIDE 0.9.0
- [releng] Switch to Sirius EMF-JSON 2.5.2
- [releng] Switch to Node 22.16.0

=== Bug fixes

- https://github.com/eclipse-syson/syson/issues/893[#893] [explorer] Fix _Expand All_ tool in SysON _Explorer_ view

=== Improvements

=== New features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2025 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.controller.explorer.testers;

import com.jayway.jsonpath.JsonPath;

import java.util.List;
import java.util.Map;

import org.eclipse.sirius.web.tests.graphql.TreeItemContextMenuQueryRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* Gets the context menu of a tree item in the explorer.
*
* @author gdaniel
*/
@Service
public class TreeItemContextMenuTester {

@Autowired
private TreeItemContextMenuQueryRunner treeItemContextMenuQueryRunner;

public List<String> getContextMenuEntries(String editingContextId, String representationId, String treeItemId) {
Map<String, Object> contextMenuVariables = Map.of(
"editingContextId", editingContextId,
"representationId", representationId,
"treeItemId", treeItemId);
String result = this.treeItemContextMenuQueryRunner.run(contextMenuVariables);
List<String> contextMenuIds = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.contextMenu[*].id");
return contextMenuIds;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -41,8 +42,10 @@
import org.eclipse.sirius.web.tests.services.representation.RepresentationIdBuilder;
import org.eclipse.syson.AbstractIntegrationTests;
import org.eclipse.syson.application.controller.explorer.testers.ExpandTreeItemTester;
import org.eclipse.syson.application.controller.explorer.testers.TreeItemContextMenuTester;
import org.eclipse.syson.application.data.GeneralViewEmptyTestProjectData;
import org.eclipse.syson.application.data.SysonStudioTestProjectData;
import org.eclipse.syson.tree.explorer.view.SysONExplorerTreeDescriptionProvider;
import org.eclipse.syson.tree.explorer.view.SysONTreeViewDescriptionProvider;
import org.eclipse.syson.tree.explorer.view.filters.SysONTreeFilterProvider;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -87,6 +90,9 @@ public class SysONExplorerTests extends AbstractIntegrationTests {
@Autowired
private ExpandTreeItemTester expandTreeItemTester;

@Autowired
private TreeItemContextMenuTester treeItemContextMenuTester;

@Autowired
private SysONTreeFilterProvider sysonTreeFilterProvider;

Expand Down Expand Up @@ -244,6 +250,66 @@ public void getRootContentWithHideMembershipsAndHideKerMLStandardLibraries() {
.verify(Duration.ofSeconds(10));
}

@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))
@Test
public void getContextMenuOfModelAndLibraryDirectories() {
// Expand the Libraries directory when building the explorer, we want to check the context menu of elements
// under it.
var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.treeDescriptionId,
List.of(UUID.nameUUIDFromBytes("SysON_Libraries_Directory".getBytes()).toString()), this.defaultFilters);
var input = new ExplorerEventInput(UUID.randomUUID(), GeneralViewEmptyTestProjectData.EDITING_CONTEXT, explorerRepresentationId);
var flux = this.explorerEventSubscriptionRunner.run(input);

AtomicReference<String> sysmlModelTreeItemId = new AtomicReference<>();
AtomicReference<String> librariesDirectoryTreeItemId = new AtomicReference<>();
AtomicReference<String> kermlDirectoryTreeItemId = new AtomicReference<>();
AtomicReference<String> sysmlDirectoryTreeItemId = new AtomicReference<>();

var initialExplorerContentConsumer = this.getTreeSubscriptionConsumer(tree -> {
assertThat(tree).isNotNull();
assertThat(tree.getChildren()).hasSize(2);
TreeItem sysmlv2Model = tree.getChildren().get(0);
this.assertThatTreeItemHasLabel(sysmlv2Model, "SysMLv2");
sysmlModelTreeItemId.set(sysmlv2Model.getId());
assertThat(sysmlv2Model.isHasChildren()).isTrue();
TreeItem librariesDirectory = tree.getChildren().get(1);
this.assertThatTreeItemHasLabel(librariesDirectory, "Libraries");
librariesDirectoryTreeItemId.set(librariesDirectory.getId());
assertThat(librariesDirectory.isHasChildren()).isTrue();
assertThat(librariesDirectory.getChildren()).hasSize(2);
TreeItem kermlDirectory = librariesDirectory.getChildren().get(0);
this.assertThatTreeItemHasLabel(kermlDirectory, "KerML");
kermlDirectoryTreeItemId.set(kermlDirectory.getId());
assertThat(kermlDirectory.isHasChildren()).isTrue();
TreeItem sysmlDirectory = librariesDirectory.getChildren().get(1);
this.assertThatTreeItemHasLabel(sysmlDirectory, "SysML");
sysmlDirectoryTreeItemId.set(sysmlDirectory.getId());
assertThat(sysmlDirectory.isHasChildren()).isTrue();
});

StepVerifier.create(flux)
.consumeNextWith(initialExplorerContentConsumer)
.thenCancel()
.verify(Duration.ofSeconds(10));

List<String> sysmlModelContextMenu = this.treeItemContextMenuTester.getContextMenuEntries(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, explorerRepresentationId,
sysmlModelTreeItemId.get());
// The expected size is 1: there is only one entry contributed from the backend, the other entries (new object,
// download, etc) are contributed from the frontend.
assertThat(sysmlModelContextMenu).hasSize(1).anyMatch(entry -> Objects.equals(entry, SysONExplorerTreeDescriptionProvider.EXPAND_ALL_MENU_ENTRY_CONTRIBUTION_ID));
List<String> librariesDirectoryContextMenu = this.treeItemContextMenuTester.getContextMenuEntries(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, explorerRepresentationId,
librariesDirectoryTreeItemId.get());
assertThat(librariesDirectoryContextMenu).isEmpty();
List<String> kermlDirectoryContextMenu = this.treeItemContextMenuTester.getContextMenuEntries(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, explorerRepresentationId,
kermlDirectoryTreeItemId.get());
assertThat(kermlDirectoryContextMenu).isEmpty();
List<String> sysmlDirectoryContextMenu = this.treeItemContextMenuTester.getContextMenuEntries(GeneralViewEmptyTestProjectData.EDITING_CONTEXT, explorerRepresentationId,
sysmlDirectoryTreeItemId.get());
assertThat(sysmlDirectoryContextMenu).isEmpty();
}

private void assertThatTreeItemHasLabel(TreeItem treeItem, String label) {
assertThat(treeItem.getLabel().styledStringFragments().stream().map(StyledStringFragment::text).collect(Collectors.joining())).isEqualTo(label);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
*******************************************************************************/
package org.eclipse.syson.tree.explorer.view;

import java.util.List;
import java.util.UUID;

import org.eclipse.sirius.components.emf.ResourceMetadataAdapter;
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.components.trees.TreeItem;
import org.eclipse.sirius.components.view.View;
import org.eclipse.sirius.components.view.builder.generated.tree.TreeBuilders;
import org.eclipse.sirius.components.view.builder.generated.tree.TreeDescriptionBuilder;
import org.eclipse.sirius.components.view.builder.generated.view.ViewBuilders;
import org.eclipse.sirius.components.view.tree.TreeDescription;
import org.eclipse.sirius.components.view.tree.TreeItemContextMenuEntry;
import org.eclipse.sirius.components.view.tree.TreeItemLabelDescription;
import org.eclipse.sirius.components.view.tree.TreeItemLabelFragmentDescription;
import org.eclipse.sirius.emfjson.resource.JsonResource;
Expand All @@ -34,6 +37,8 @@ public class SysONExplorerTreeDescriptionProvider {

public static final String SYSON_EXPLORER = "SysON Explorer";

public static final String EXPAND_ALL_MENU_ENTRY_CONTRIBUTION_ID = "expandAll";

public View createView() {

var sysonDefaultTreeView = new ViewBuilders()
Expand Down Expand Up @@ -70,6 +75,7 @@ private TreeDescription build() {
.treeItemIdExpression("aql:self.getTreeItemId()")
.treeItemObjectExpression("aql:id.getTreeItemObject(editingContext)")
.treeItemLabelDescriptions(this.createDefaultStyle())
.contextMenuEntries(this.getContextMenuEntries().toArray(TreeItemContextMenuEntry[]::new))
.build();
return description;
}
Expand All @@ -88,4 +94,12 @@ private TreeItemLabelFragmentDescription getDefaultLabelFragmentDescription() {
.labelExpression("aql:self.getLabel()")
.build();
}

private List<TreeItemContextMenuEntry> getContextMenuEntries() {
var expandAllMenuEntry = new TreeBuilders().newCustomTreeItemContextMenuEntry()
.contributionId(EXPAND_ALL_MENU_ENTRY_CONTRIBUTION_ID)
.preconditionExpression("aql:" + TreeItem.SELECTED_TREE_ITEM + ".canExpandAll(editingContext)")
.build();
return List.of(expandAllMenuEntry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.web.application.editingcontext.EditingContext;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationMetadata;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFragment;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFilterService;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFragment;

/**
* The <i>KerML</i> directory displayed in the explorer.
Expand All @@ -30,11 +30,14 @@
*/
public class KerMLStandardLibraryDirectory implements ISysONExplorerFragment {

private final String id = UUID.nameUUIDFromBytes("KERML".getBytes()).toString();
private final String id = UUID.nameUUIDFromBytes("SysON_KerML_Directory".getBytes()).toString();

private final Object parent;

private final ISysONExplorerFilterService filterService;

public KerMLStandardLibraryDirectory(ISysONExplorerFilterService filterService) {
public KerMLStandardLibraryDirectory(Object parent, ISysONExplorerFilterService filterService) {
this.parent = Objects.requireNonNull(parent);
this.filterService = Objects.requireNonNull(filterService);
}

Expand All @@ -48,6 +51,11 @@ public String getLabel() {
return "KerML";
}

@Override
public String getKind() {
return this.getClass().getSimpleName();
}

@Override
public List<String> getIconURL() {
return List.of("icons/LibraryResource.svg");
Expand All @@ -63,6 +71,11 @@ public boolean hasChildren(IEditingContext editingContext, List<RepresentationMe
return hasChildren;
}

@Override
public Object getParent() {
return this.parent;
}

@Override
public List<Object> getChildren(IEditingContext editingContext, List<RepresentationMetadata> existingRepresentations, List<String> expandedIds, List<String> activeFilterIds) {
List<Object> result = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ public class LibrariesDirectory implements ISysONExplorerFragment {

private final String id = UUID.nameUUIDFromBytes("SysON_Libraries_Directory".getBytes()).toString();

private final ISysONExplorerFilterService filterService;

private final String label;

public LibrariesDirectory(String label, ISysONExplorerFilterService filterService) {
private final Object parent;

private final ISysONExplorerFilterService filterService;

public LibrariesDirectory(String label, Object parent, ISysONExplorerFilterService filterService) {
this.label = Objects.requireNonNull(label);
this.parent = Objects.requireNonNull(parent);
this.filterService = Objects.requireNonNull(filterService);
}

Expand All @@ -51,6 +54,16 @@ public String getLabel() {
return this.label;
}

@Override
public String getKind() {
return this.getClass().getSimpleName();
}

@Override
public Object getParent() {
return this.parent;
}

@Override
public List<String> getIconURL() {
return List.of("icons/LibraryResource.svg");
Expand All @@ -63,7 +76,7 @@ public boolean hasChildren(IEditingContext editingContext, List<RepresentationMe
if (!result) {
// Check if the user libraries directory contains children, we don't want to display the libraries directory
// if it only contains empty directories.
UserLibrariesDirectory userLibrariesDirectory = new UserLibrariesDirectory("User Libraries", this.filterService);
UserLibrariesDirectory userLibrariesDirectory = new UserLibrariesDirectory("User Libraries", this, this.filterService);
result = !activeFilterIds.contains(SysONTreeFilterProvider.HIDE_USER_LIBRARIES_TREE_FILTER_ID)
&& userLibrariesDirectory.hasChildren(editingContext, existingRepresentations, expandedIds, activeFilterIds);
}
Expand All @@ -74,13 +87,13 @@ public boolean hasChildren(IEditingContext editingContext, List<RepresentationMe
public List<Object> getChildren(IEditingContext editingContext, List<RepresentationMetadata> existingRepresentations, List<String> expandedIds, List<String> activeFilterIds) {
List<Object> result = new ArrayList<>();
if (!activeFilterIds.contains(SysONTreeFilterProvider.HIDE_KERML_STANDARD_LIBRARIES_TREE_FILTER_ID)) {
result.add(new KerMLStandardLibraryDirectory(this.filterService));
result.add(new KerMLStandardLibraryDirectory(this, this.filterService));
}
if (!activeFilterIds.contains(SysONTreeFilterProvider.HIDE_SYSML_STANDARD_LIBRARIES_TREE_FILTER_ID)) {
result.add(new SysMLStandardLibraryDirectory(this.filterService));
result.add(new SysMLStandardLibraryDirectory(this, this.filterService));
}
if (!activeFilterIds.contains(SysONTreeFilterProvider.HIDE_USER_LIBRARIES_TREE_FILTER_ID)) {
UserLibrariesDirectory userLibrariesDirectory = new UserLibrariesDirectory("User libraries", this.filterService);
UserLibrariesDirectory userLibrariesDirectory = new UserLibrariesDirectory("User libraries", this, this.filterService);
if (userLibrariesDirectory.hasChildren(editingContext, existingRepresentations, expandedIds, activeFilterIds)) {
// Add the user libraries directory only if it contains children.
result.add(userLibrariesDirectory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.web.application.editingcontext.EditingContext;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationMetadata;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFragment;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFilterService;
import org.eclipse.syson.tree.explorer.view.services.api.ISysONExplorerFragment;

/**
* The <i>SysML</i> directory displayed in the explorer.
Expand All @@ -30,11 +30,14 @@
*/
public class SysMLStandardLibraryDirectory implements ISysONExplorerFragment {

private final String id = UUID.nameUUIDFromBytes("SYSML".getBytes()).toString();
private final String id = UUID.nameUUIDFromBytes("SysON_SysML_Directory".getBytes()).toString();

private final Object parent;

private final ISysONExplorerFilterService filterService;

public SysMLStandardLibraryDirectory(ISysONExplorerFilterService filterService) {
public SysMLStandardLibraryDirectory(Object parent, ISysONExplorerFilterService filterService) {
this.parent = Objects.requireNonNull(parent);
this.filterService = Objects.requireNonNull(filterService);
}

Expand All @@ -48,6 +51,16 @@ public String getLabel() {
return "SysML";
}

@Override
public String getKind() {
return this.getClass().getSimpleName();
}

@Override
public Object getParent() {
return this.parent;
}

@Override
public List<String> getIconURL() {
return List.of("icons/LibraryResource.svg");
Expand Down
Loading