Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3875] Refactor the tree event classes related to the explorer #3876

Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
=== Breaking changes

- https://github.com/eclipse-sirius/sirius-web/issues/3846[#3846] [core] Migrate frontend to React 18, you now need React 18 to import sirius web modules.

- https://github.com/eclipse-sirius/sirius-web/issues/3875[#3875] [sirius-web] The `ExplorerView` component has been moved from `sirius-components-trees` to `sirius-web-application` module

=== Dependency update

Expand All @@ -39,6 +39,7 @@
- https://github.com/eclipse-sirius/sirius-web/issues/2604[#2604] [diagram] Expand a tool section when the mouse is over it
- https://github.com/eclipse-sirius/sirius-web/issues/3887[#3887] [diagram] Memoize diagram representation (improve performance when selecting an element on large diagram)
- https://github.com/eclipse-sirius/sirius-web/issues/3987[#3987] [sirius-web] Transform `widgetFields` fragment to retrieve custom widget fields
- https://github.com/eclipse-sirius/sirius-web/issues/3875[#3875] [sirius-web] Move explorer related code from `sirius-components-trees` to `sirius-web-application`


== v2024.9.0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (c) 2024 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.sirius.components.collaborative.widget.reference.browser;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessor;
import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorFactory;
import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry;
import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory;
import org.eclipse.sirius.components.collaborative.trees.TreeEventProcessor;
import org.eclipse.sirius.components.collaborative.trees.api.ITreeEventHandler;
import org.eclipse.sirius.components.collaborative.trees.api.ITreeService;
import org.eclipse.sirius.components.collaborative.trees.api.TreeCreationParameters;
import org.eclipse.sirius.components.collaborative.widget.reference.configurations.ModelBrowserConfiguration;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService;
import org.eclipse.sirius.components.trees.description.TreeDescription;
import org.springframework.stereotype.Service;

import io.micrometer.core.instrument.simple.SimpleMeterRegistry;

/**
* Used to create the tree event processors in the context of model browser.
*
* @author Jerome Gout
*/
@Service
public class ModelBrowserEventProcessorFactory implements IRepresentationEventProcessorFactory {

private final IRepresentationDescriptionSearchService representationDescriptionSearchService;

private final ITreeService treeService;

private final List<ITreeEventHandler> treeEventHandlers;

private final ISubscriptionManagerFactory subscriptionManagerFactory;

private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry;

public ModelBrowserEventProcessorFactory(IRepresentationDescriptionSearchService representationDescriptionSearchService, List<ITreeEventHandler> treeEventHandlers, ITreeService treeService, IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, ISubscriptionManagerFactory subscriptionManagerFactory) {
this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService);
this.treeService = Objects.requireNonNull(treeService);
this.treeEventHandlers = Objects.requireNonNull(treeEventHandlers);
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory);
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry);
}

@Override
public boolean canHandle(IRepresentationConfiguration configuration) {
return configuration instanceof ModelBrowserConfiguration;
}

@Override
public Optional<IRepresentationEventProcessor> createRepresentationEventProcessor(IRepresentationConfiguration configuration, IEditingContext editingContext) {
if (configuration instanceof ModelBrowserConfiguration modelBrowserConfiguration) {

String descriptionId;
if (modelBrowserConfiguration.getId().startsWith(ModelBrowsersDescriptionProvider.MODEL_BROWSER_CONTAINER_PREFIX)) {
descriptionId = ModelBrowsersDescriptionProvider.CONTAINER_DESCRIPTION_ID;
} else {
descriptionId = ModelBrowsersDescriptionProvider.REFERENCE_DESCRIPTION_ID;
}

Optional<TreeDescription> optionalTreeDescription = this.representationDescriptionSearchService
.findById(editingContext, descriptionId)
.filter(TreeDescription.class::isInstance)
.map(TreeDescription.class::cast);
if (optionalTreeDescription.isPresent()) {
var treeDescription = optionalTreeDescription.get();

TreeCreationParameters treeCreationParameters = TreeCreationParameters.newTreeCreationParameters(modelBrowserConfiguration.getId())
.treeDescription(treeDescription)
.activeFilterIds(List.of())
.expanded(modelBrowserConfiguration.getExpanded())
.editingContext(editingContext)
.build();

IRepresentationEventProcessor treeEventProcessor = new TreeEventProcessor(editingContext, this.treeService, treeCreationParameters, this.treeEventHandlers,
this.subscriptionManagerFactory.create(), new SimpleMeterRegistry(), this.representationRefreshPolicyRegistry);
return Optional.of(treeEventProcessor);
}
}
return Optional.empty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
Expand All @@ -34,7 +33,6 @@
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.sirius.components.collaborative.trees.api.TreeConfiguration;
import org.eclipse.sirius.components.collaborative.widget.reference.api.IReferenceWidgetRootCandidateSearchProvider;
import org.eclipse.sirius.components.core.CoreImageConstants;
import org.eclipse.sirius.components.core.URLParser;
Expand Down Expand Up @@ -99,34 +97,28 @@ public ModelBrowsersDescriptionProvider(IObjectService objectService, IURLParser

@Override
public List<IRepresentationDescription> getRepresentationDescriptions(IEditingContext editingContext) {
Predicate<VariableManager> containerDescriptionCanCreatePredicate = variableManager -> variableManager.get(TreeConfiguration.TREE_ID, String.class)
.map(treeId -> treeId.startsWith(MODEL_BROWSER_CONTAINER_PREFIX))
.orElse(false);
Function<VariableManager, Boolean> containerDescriptionIsSelectableProvider = variableManager -> {
EClass referenceKind = this.resolveReferenceEClass(variableManager).orElse(null);
return this.isContainerSelectable(variableManager, referenceKind);
};
var containerDescription = this.getModelBrowserDescription(CONTAINER_DESCRIPTION_ID, containerDescriptionCanCreatePredicate, containerDescriptionIsSelectableProvider, this::getCreationScopeElements);
var containerDescription = this.getModelBrowserDescription(CONTAINER_DESCRIPTION_ID, containerDescriptionIsSelectableProvider, this::getCreationScopeElements, MODEL_BROWSER_CONTAINER_PREFIX);

Predicate<VariableManager> referenceDescriptionCanCreatePredicate = variableManager -> variableManager.get(TreeConfiguration.TREE_ID, String.class)
.map(treeId -> treeId.startsWith(MODEL_BROWSER_REFERENCE_PREFIX))
.orElse(false);
Function<VariableManager, Boolean> referenceDescriptionIsSelectableProvider = variableManager -> {
EClass targetType = this.resolveTargetType(variableManager).orElse(null);
boolean isContainment = this.resolveIsContainment(variableManager);
return this.isTypeSelectable(variableManager, targetType, isContainment);
};
var referenceDescription = this.getModelBrowserDescription(REFERENCE_DESCRIPTION_ID, referenceDescriptionCanCreatePredicate, referenceDescriptionIsSelectableProvider, this::getSearchScopeElements);
var referenceDescription = this.getModelBrowserDescription(REFERENCE_DESCRIPTION_ID, referenceDescriptionIsSelectableProvider, this::getSearchScopeElements, MODEL_BROWSER_REFERENCE_PREFIX);

return List.of(containerDescription, referenceDescription);
}

private TreeDescription getModelBrowserDescription(String descriptionId, Predicate<VariableManager> canCreatePredicate, Function<VariableManager, Boolean> isSelectableProvider,
Function<VariableManager, List<?>> elementsProvider) {
private TreeDescription getModelBrowserDescription(String descriptionId, Function<VariableManager, Boolean> isSelectableProvider,
Function<VariableManager, List<?>> elementsProvider, String treeId) {

return TreeDescription.newTreeDescription(descriptionId)
.label(REPRESENTATION_NAME)
.idProvider(variableManager -> variableManager.get(TreeConfiguration.TREE_ID, String.class).orElse(null))
.idProvider(variableManager -> variableManager.get(GetOrCreateRandomIdProvider.PREVIOUS_REPRESENTATION_ID, String.class).orElse(treeId))
.treeItemIdProvider(this::getTreeItemId)
.kindProvider(this::getKind)
.labelProvider(this::getLabel)
Expand All @@ -140,7 +132,7 @@ private TreeDescription getModelBrowserDescription(String descriptionId, Predica
.childrenProvider(variableManager -> this.getChildren(variableManager, isSelectableProvider))
// This predicate will NOT be used while creating the model browser, but we don't want to see the description of the
// model browser in the list of representations that can be created. Thus, we will return false all the time.
.canCreatePredicate(canCreatePredicate)
.canCreatePredicate(variableManager -> false)
.deleteHandler(this::getDeleteHandler)
.renameHandler(this::getRenameHandler)
.treeItemObjectProvider(this::getTreeItemObject)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2024 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.sirius.components.collaborative.widget.reference.configurations;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration;
import org.eclipse.sirius.components.collaborative.widget.reference.browser.ModelBrowsersDescriptionProvider;

/**
* The configuration of the model browser event processor.
*
* @author Jerome Gout
*/
public class ModelBrowserConfiguration implements IRepresentationConfiguration {

private final String treeId;

private final List<String> expanded;

public ModelBrowserConfiguration(String editingContextId, String treeId, List<String> expanded) {
this.expanded = Objects.requireNonNull(expanded);

StringBuilder idBuilder = new StringBuilder(treeId);
if (treeId.endsWith(ModelBrowsersDescriptionProvider.MODEL_BROWSER_CONTAINER_PREFIX) || treeId.endsWith(ModelBrowsersDescriptionProvider.MODEL_BROWSER_REFERENCE_PREFIX)) {
idBuilder.append("?");
} else {
idBuilder.append("&");
}

List<String> expandedObjectIds = expanded.stream().map(id -> URLEncoder.encode(id, StandardCharsets.UTF_8)).toList();
idBuilder.append("expandedIds=[").append(String.join(",", expandedObjectIds)).append("]");

this.treeId = idBuilder.toString();
}

@Override
public String getId() {
return this.treeId;
}

public List<String> getExpanded() {
return this.expanded;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2024 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.sirius.components.collaborative.widget.reference.dto;

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

import org.eclipse.sirius.components.core.api.IInput;

/**
* The input of the model browser event subscription.
*
* @author Jerome Gout
*/
public record ModelBrowserEventInput(UUID id, String editingContextId, String treeId, List<String> expanded) implements IInput {
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import java.util.List;

import org.eclipse.sirius.components.collaborative.trees.api.TreeConfiguration;
import org.eclipse.sirius.components.collaborative.widget.reference.browser.ModelBrowsersDescriptionProvider;
import org.eclipse.sirius.components.core.URLParser;
import org.eclipse.sirius.components.core.api.IEditingContext;
Expand Down Expand Up @@ -55,15 +54,13 @@ public void testModelBrowserDescriptionProvider() {
variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext);

var referenceTreeId = "modelBrowser://reference";
variableManager.put(TreeConfiguration.TREE_ID, referenceTreeId);
var tree = new TreeRenderer(variableManager, referenceBrowserDescription.get()).render();
assertThat(tree).isNotNull();
assertThat(tree.getId()).isEqualTo(referenceTreeId);
assertThat(tree.getDescriptionId()).isEqualTo(ModelBrowsersDescriptionProvider.REFERENCE_DESCRIPTION_ID);
assertThat(tree.getKind()).isEqualTo(Tree.KIND);

var containerTreeId = "modelBrowser://container";
variableManager.put(TreeConfiguration.TREE_ID, containerTreeId);
tree = new TreeRenderer(variableManager, containerBrowserDescription.get()).render();
assertThat(tree).isNotNull();
assertThat(tree.getId()).isEqualTo(containerTreeId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (c) 2024 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.sirius.components.widget.reference.graphql.datafetchers.subscription;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.eclipse.sirius.components.annotations.spring.graphql.SubscriptionDataFetcher;
import org.eclipse.sirius.components.collaborative.widget.reference.configurations.ModelBrowserConfiguration;
import org.eclipse.sirius.components.collaborative.widget.reference.dto.ModelBrowserEventInput;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEventProcessorSubscriptionProvider;
import org.eclipse.sirius.components.graphql.api.IExceptionWrapper;
import org.eclipse.sirius.components.graphql.api.LocalContextConstants;
import org.reactivestreams.Publisher;

import graphql.execution.DataFetcherResult;
import graphql.schema.DataFetchingEnvironment;

/**
* The data fetcher used to send the refreshed tree to a model browser subscription .
*
* @author Jerome Gout
*/
@SubscriptionDataFetcher(type = "Subscription", field = "modelBrowserEvent")
public class SubscriptionModelBrowserEventDataFetcher implements IDataFetcherWithFieldCoordinates<Publisher<DataFetcherResult<IPayload>>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IExceptionWrapper exceptionWrapper;

private final IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider;

public SubscriptionModelBrowserEventDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider) {
this.objectMapper = Objects.requireNonNull(objectMapper);
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
this.eventProcessorSubscriptionProvider = Objects.requireNonNull(eventProcessorSubscriptionProvider);
}

@Override
public Publisher<DataFetcherResult<IPayload>> get(DataFetchingEnvironment environment) throws Exception {
Object argument = environment.getArgument(INPUT_ARGUMENT);
var input = this.objectMapper.convertValue(argument, ModelBrowserEventInput.class);
var modelBrowserConfiguration = new ModelBrowserConfiguration(input.editingContextId(), input.treeId(), input.expanded());

Map<String, Object> localContext = new HashMap<>();
localContext.put(LocalContextConstants.EDITING_CONTEXT_ID, input.editingContextId());
localContext.put(LocalContextConstants.REPRESENTATION_ID, modelBrowserConfiguration.getId());

return this.exceptionWrapper.wrapFlux(() -> this.eventProcessorSubscriptionProvider.getSubscription(input.editingContextId(), modelBrowserConfiguration, input), input)
.map(payload -> DataFetcherResult.<IPayload>newResult()
.data(payload)
.localContext(localContext)
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extend type Subscription {
modelBrowserEvent(input: ModelBrowserEventInput!): TreeEventPayload!
}

input ModelBrowserEventInput {
id: ID!
treeId: String!
editingContextId: ID!
expanded: [String!]!
}
Loading
Loading