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 @@ -98,6 +98,7 @@ All existing SysON _DiagramDescriptions_ (i.g. _General View_, _Interconnection
- https://github.com/eclipse-syson/syson/issues/1310[#1310] [metamodel] Revert remove derived flag for `ViewUsage#exposedElement` feature.
- https://github.com/eclipse-syson/syson/issues/1359[#1359] [export] Implement textual export of `ViewUsage`.
- https://github.com/eclipse-syson/syson/issues/1350[#1350] [general-view] Improve _direct edit_ tool on `Feature` to be able to edit `FeatureValue` with basic expressions.
- https://github.com/eclipse-syson/syson/issues/1363[#1363] [general-view] Add a reveal only valued content action on the manage visibility node action that will hide empty graphical compartments and will reveal the others.

=== New features

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*******************************************************************************
* 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.controllers.diagrams.general.view;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import com.jayway.jsonpath.JsonPath;

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
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.collaborative.diagrams.dto.managevisibility.InvokeManageVisibilityActionInput;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.sirius.components.diagrams.ViewModifier;
import org.eclipse.sirius.components.diagrams.tests.graphql.GetManageVisibilityActionsQueryRunner;
import org.eclipse.sirius.components.diagrams.tests.graphql.InvokeManageVisibilityActionMutationRunner;
import org.eclipse.sirius.web.application.nodeaction.managevisibility.ManageVisibilityHideAllAction;
import org.eclipse.sirius.web.application.nodeaction.managevisibility.ManageVisibilityRevealAllAction;
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
import org.eclipse.syson.AbstractIntegrationTests;
import org.eclipse.syson.application.data.GeneralViewManageVisibilityTestsProjectData;
import org.eclipse.syson.diagram.general.view.services.nodeactions.managevisibility.GeneralViewManageVisibilityRevealValuedContentAction;
import org.eclipse.syson.services.diagrams.api.IGivenDiagramSubscription;
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;

/**
* Tests the manage visibility node action.
*
* @author mcharfadi
*/
@Transactional
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GVManageVisibilityTests extends AbstractIntegrationTests {

@Autowired
private IGivenInitialServerState givenInitialServerState;

@Autowired
private IGivenDiagramSubscription givenDiagramSubscription;

@Autowired
private GetManageVisibilityActionsQueryRunner getActionsQueryRunner;

@Autowired
private InvokeManageVisibilityActionMutationRunner invokeActionMutationRunner;

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

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

@Sql(scripts = { GeneralViewManageVisibilityTestsProjectData.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))
@DisplayName("GIVEN a graphical node with some children hidden and some revealed, WHEN invoking the show valued content only, THEN only the children that have children are visible")
@Test
public void invokeShowOnlyValuedContent() {
var flux = this.givenSubscriptionToGeneralViewDiagram();
var nodeId = new AtomicReference<String>();
Consumer<DiagramRefreshedEventPayload> initialDiagramContentConsumer = payload -> Optional.of(payload)
.ifPresentOrElse(diagramRefreshedEventPayload -> {
var diagram = diagramRefreshedEventPayload.diagram();
assertThat(diagram.getNodes()).hasSize(1);
nodeId.set(diagram.getNodes().get(0).getId());
assertThat(diagram.getNodes().get(0).getChildNodes()).hasSize(5);
var children = diagram.getNodes().get(0).getChildNodes();
assertThat(children.stream().filter(node -> node.getState().equals(ViewModifier.Hidden))).hasSize(5);
assertThat(children.stream().filter(node -> node.getState().equals(ViewModifier.Normal))).hasSize(0);
}, () -> fail("Missing diagram"));

Runnable getActions = () -> {
Map<String, Object> variables = Map.of(
"editingContextId", GeneralViewManageVisibilityTestsProjectData.EDITING_CONTEXT_ID,
"diagramId", GeneralViewManageVisibilityTestsProjectData.GraphicalIds.DIAGRAM_ID,
"diagramElementId", nodeId.get()
);
var result = this.getActionsQueryRunner.run(variables);
List<String> actionsIds = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.manageVisibilityActions[*].id");
List<String> actionsLabels = JsonPath.read(result, "$.data.viewer.editingContext.representation.description.manageVisibilityActions[*].label");

assertThat(actionsIds)
.isNotEmpty()
.contains(ManageVisibilityRevealAllAction.ACTION_ID)
.contains(ManageVisibilityHideAllAction.ACTION_ID)
.contains(GeneralViewManageVisibilityRevealValuedContentAction.ACTION_ID);

assertThat(actionsLabels)
.isNotEmpty()
.contains("Hide all")
.contains("Reveal all")
.contains("Reveal valued content only");
};

Runnable invokeRevealValuedContentAction = () -> {
var input = new InvokeManageVisibilityActionInput(UUID.randomUUID(), GeneralViewManageVisibilityTestsProjectData.EDITING_CONTEXT_ID, GeneralViewManageVisibilityTestsProjectData.GraphicalIds.DIAGRAM_ID, nodeId.get(), GeneralViewManageVisibilityRevealValuedContentAction.ACTION_ID);
var result = this.invokeActionMutationRunner.run(input);
String typename = JsonPath.read(result, "$.data.invokeManageVisibilityAction.__typename");
assertThat(typename).isEqualTo(SuccessPayload.class.getSimpleName());
};

Consumer<DiagramRefreshedEventPayload> updatedAfterRevealDiagramContentMatcher = payload -> Optional.of(payload)
.ifPresentOrElse(diagramRefreshedEventPayload -> {
var diagram = diagramRefreshedEventPayload.diagram();
assertThat(diagram.getNodes()).hasSize(1);
nodeId.set(diagram.getNodes().get(0).getId());
assertThat(diagram.getNodes().get(0).getChildNodes()).hasSize(5);
var children = diagram.getNodes().get(0).getChildNodes();
assertThat(children.stream().filter(node -> node.getState().equals(ViewModifier.Hidden))).hasSize(3);
assertThat(children.stream().filter(node -> node.getState().equals(ViewModifier.Normal))).hasSize(1);
assertThat(children.stream().filter(node -> node.getState().equals(ViewModifier.Faded))).hasSize(1);
}, () -> fail("Missing diagram"));

StepVerifier.create(flux)
.consumeNextWith(initialDiagramContentConsumer)
.then(getActions)
.then(invokeRevealValuedContentAction)
.consumeNextWith(updatedAfterRevealDiagramContentMatcher)
.thenCancel()
.verify(Duration.ofSeconds(10));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* 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.data;

/**
* Project data for the "GVManageVisibilityTests" project.
*
* @author mcharfadi
*/
public class GeneralViewManageVisibilityTestsProjectData {

public static final String SCRIPT_PATH = "/scripts/database-content/GeneralView-ManageVisibility.sql";

public static final String EDITING_CONTEXT_ID = "b01d9a82-7f04-46f9-9b49-d69b291ae105";

/**
* Ids of graphical elements.
*/
public static class GraphicalIds {

public static final String DIAGRAM_ID = "621aded7-5bd5-4966-9526-7ff0816dbb63";

}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.syson.diagram.general.view.services;
package org.eclipse.syson.diagram.general.view.services.nodeactions.managevisibility;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* 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.diagram.general.view.services.nodeactions.managevisibility;

import org.eclipse.sirius.components.collaborative.diagrams.api.nodeactions.IManageVisibilityMenuActionProvider;
import org.eclipse.sirius.components.collaborative.diagrams.dto.managevisibility.ManageVisibilityAction;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.diagrams.IDiagramElement;
import org.eclipse.sirius.components.diagrams.Node;
import org.eclipse.sirius.components.diagrams.description.DiagramDescription;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* Menu action on the manage visibility modal that will reveal children that also have children.
*
* @author mcharfadi
*/
@Service
public class GeneralViewManageVisibilityRevealValuedContentAction implements IManageVisibilityMenuActionProvider {

public static final String ACTION_ID = "manage_visibility_menu_reveal_valued_content_action";

@Override
public boolean canHandle(IEditingContext editingContext, DiagramDescription diagramDescription, IDiagramElement diagramElement) {
return diagramElement instanceof Node node && !node.getChildNodes().isEmpty();
}

@Override
public List<ManageVisibilityAction> handle(IEditingContext editingContext, DiagramDescription diagramDescription, IDiagramElement diagramElement) {
return List.of(new ManageVisibilityAction(ACTION_ID, "Reveal valued content only"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*******************************************************************************
* 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.diagram.general.view.services.nodeactions.managevisibility;

import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramContext;
import org.eclipse.sirius.components.collaborative.diagrams.api.IDiagramQueryService;
import org.eclipse.sirius.components.collaborative.diagrams.api.nodeactions.IManageVisibilityMenuActionHandler;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.diagrams.IDiagramElement;
import org.eclipse.sirius.components.diagrams.Node;
import org.eclipse.sirius.components.diagrams.events.HideDiagramElementEvent;
import org.eclipse.sirius.components.representations.IStatus;
import org.eclipse.sirius.components.representations.Success;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
* Handler for the menu action on the manage visibility modal that will reveal children that also have children.
*
* @author mcharfadi
*/
@Service
public class GeneralViewManageVisibilityRevealValuedContentHandler implements IManageVisibilityMenuActionHandler {

private final IDiagramQueryService diagramQueryService;

public GeneralViewManageVisibilityRevealValuedContentHandler(IDiagramQueryService diagramQueryService) {
this.diagramQueryService = Objects.requireNonNull(diagramQueryService);
}

@Override
public boolean canHandle(IEditingContext editingContext, IDiagramContext diagramContext, IDiagramElement diagramElement, String actionId) {
return actionId.equals(GeneralViewManageVisibilityRevealValuedContentAction.ACTION_ID);
}

@Override
public IStatus handle(IEditingContext editingContext, IDiagramContext diagramContext, IDiagramElement diagramElement, String actionId) {
Optional<Node> optionalNode = this.diagramQueryService.findNodeById(diagramContext.getDiagram(), diagramElement.getId());
Set<String> nodesToReveal = new HashSet<>();
Set<String> nodesToHide = new HashSet<>();
if (optionalNode.isPresent()) {
optionalNode.get().getChildNodes().forEach(node -> {
if (node.getChildNodes().isEmpty()) {
nodesToHide.add(node.getId());
} else {
nodesToReveal.add(node.getId());
}
});
diagramContext.getDiagramEvents().add(new HideDiagramElementEvent(nodesToReveal, false));
diagramContext.getDiagramEvents().add(new HideDiagramElementEvent(nodesToHide, true));
}
return new Success();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ image::view-usage-graphical-contents.png[ViewUsage graphical contents, width=65%

- `ManageVisibility` node action may now be displayed from the _General View_ on `Definition` and `Usage` graphical nodes.
This node action open a modal that can be used to reveal or hide the graphical node children's.
Menu actions can be used to `reveal all content`, `reveal valued content only` or `hide all content`.

image::release-notes-manage-visibility.png[Manage Visibility modal, width=65%,height=65%]

Expand Down
Loading