diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 455387a7ce4..b1fb6ef8c81 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -110,6 +110,7 @@ A migration participant has been added to automatically keep compatible all diag - https://github.com/eclipse-sirius/sirius-web/issues/3392[#3392] [diagram] Prevent edge from passing through another node - https://github.com/eclipse-sirius/sirius-web/issues/3763[#3763] [diagram] Split the SelectionDialogDescription to prepare the Tree support - https://github.com/eclipse-sirius/sirius-web/issues/3875[#3875] [sirius-web] Move explorer related code from components-trees to sirius-web-application +- https://github.com/eclipse-sirius/sirius-web/issues/3882[#3882] [sirius-web] Add a new tree event to handle tree description which are not explorer-related == v2024.7.0 diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerConfiguration.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerConfiguration.java index 750005e96d1..05562e50a53 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerConfiguration.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerConfiguration.java @@ -57,10 +57,12 @@ public String getId() { return this.treeId; } + @Override public List getActiveFilterIds() { return this.activeFilterIds; } + @Override public List getExpanded() { return this.expanded; } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerEventProcessorFactory.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerEventProcessorFactory.java index 10131037d8f..886c5500c6f 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerEventProcessorFactory.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/ExplorerEventProcessorFactory.java @@ -23,6 +23,7 @@ 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.ITreeConfiguration; 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; @@ -91,9 +92,9 @@ public Optional createRepresentationEventProcesso return Optional.empty(); } - private Optional findTreeDescription(IEditingContext editingContext, ExplorerConfiguration treeConfiguration) { + private Optional findTreeDescription(IEditingContext editingContext, ITreeConfiguration treeConfiguration) { VariableManager variableManager = new VariableManager(); - variableManager.put(ExplorerConfiguration.TREE_ID, treeConfiguration.getId()); + variableManager.put(ITreeConfiguration.TREE_ID, treeConfiguration.getId()); return this.representationDescriptionSearchService .findAll(editingContext).values().stream() .filter(TreeDescription.class::isInstance) diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/SubscriptionExplorerEventDataFetcher.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/SubscriptionExplorerEventDataFetcher.java index c8b8fc28448..349bde5573a 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/SubscriptionExplorerEventDataFetcher.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/SubscriptionExplorerEventDataFetcher.java @@ -19,6 +19,7 @@ import java.util.Objects; import org.eclipse.sirius.components.annotations.spring.graphql.SubscriptionDataFetcher; +import org.eclipse.sirius.components.collaborative.trees.api.ITreeConfiguration; import org.eclipse.sirius.components.core.api.IPayload; import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; import org.eclipse.sirius.components.graphql.api.IEventProcessorSubscriptionProvider; @@ -56,7 +57,7 @@ public SubscriptionExplorerEventDataFetcher(ObjectMapper objectMapper, IExceptio public Publisher> get(DataFetchingEnvironment environment) throws Exception { Object argument = environment.getArgument(INPUT_ARGUMENT); var input = this.objectMapper.convertValue(argument, ExplorerEventInput.class); - var treeConfiguration = new ExplorerConfiguration(input.editingContextId(), input.treeId(), input.expanded(), input.activeFilterIds()); + ITreeConfiguration treeConfiguration = new ExplorerConfiguration(input.editingContextId(), input.treeId(), input.expanded(), input.activeFilterIds()); Map localContext = new HashMap<>(); localContext.put(LocalContextConstants.EDITING_CONTEXT_ID, input.editingContextId()); diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java index 23759845211..ddff00f0c6f 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExpandAllTreePathProvider.java @@ -27,7 +27,6 @@ import org.eclipse.sirius.components.core.api.IIdentityService; import org.eclipse.sirius.components.core.api.IPayload; import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; -import org.eclipse.sirius.components.domain.Entity; import org.eclipse.sirius.components.representations.VariableManager; import org.eclipse.sirius.components.trees.Tree; import org.eclipse.sirius.components.trees.description.TreeDescription; @@ -99,17 +98,6 @@ private int addAllContents(IEditingContext editingContext, String treeItemId, in var object = this.getTreeItemObject(editingContext, treeItemId, tree); if (object instanceof EObject eObject) { - if (object instanceof Entity entity) { - // an Entity has a virtual node for its super types, this node should be a child of the Entity - var id = ExplorerDescriptionProvider.SETTING + this.identityService.getId(entity) + ExplorerDescriptionProvider.SETTING_ID_SEPARATOR + "superTypes"; - treeItemIdsToExpand.add(id); - var superTypes = entity.getSuperTypes(); - if (superTypes.size() > 0) { - depthConsidered = Math.max(depthConsidered, depth + 2); - } else { - depthConsidered = Math.max(depthConsidered, depth + 1); - } - } var contents = this.contentService.getContents(eObject); if (!contents.isEmpty()) { treeItemIdsToExpand.add(treeItemId); diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java index 82dcccd813a..7fe5d6a9371 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerChildrenProvider.java @@ -13,20 +13,16 @@ package org.eclipse.sirius.web.application.views.explorer.services; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Objects; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; -import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.sirius.components.core.RepresentationMetadata; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.core.api.IRepresentationMetadataSearchService; -import org.eclipse.sirius.components.domain.Entity; import org.eclipse.sirius.components.representations.VariableManager; import org.eclipse.sirius.components.trees.renderer.TreeRenderer; import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerChildrenProvider; @@ -71,15 +67,6 @@ public boolean hasChildren(VariableManager variableManager) { String id = this.objectService.getId(eObject); hasChildren = this.representationDataSearchService.existAnyRepresentationForTargetObjectId(id); } - - if (!hasChildren && self instanceof Entity) { - hasChildren = true; - } - } else if (self instanceof Setting setting) { - var value = setting.get(true); - if (value instanceof Collection collection) { - hasChildren = !collection.isEmpty(); - } } return hasChildren; } @@ -130,17 +117,8 @@ private List getDefaultChildren(VariableManager variableManager) { representationMetadata.sort(Comparator.comparing(RepresentationMetadata::getLabel)); result.addAll(representationMetadata); List contents = this.objectService.getContents(self); - if (self instanceof Entity entity) { - result.add(((InternalEObject) entity).eSetting(entity.eClass().getEStructuralFeature("superTypes"))); - } result.addAll(contents); - } else if (self instanceof Setting setting) { - var value = setting.get(true); - if (value instanceof Collection collection) { - result.addAll(collection); - } } - } } return result; @@ -167,8 +145,6 @@ private String getTreeItemId(VariableManager variableManager) { id = resource.getURI().path().substring(1); } else if (self instanceof EObject) { id = this.objectService.getId(self); - } else if (self instanceof Setting setting) { - id = ExplorerDescriptionProvider.SETTING + this.objectService.getId(setting.getEObject()) + ExplorerDescriptionProvider.SETTING_ID_SEPARATOR + setting.getEStructuralFeature().getName(); } return id; } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java index 11618c4dff4..950004f9178 100644 --- a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/explorer/services/ExplorerDescriptionProvider.java @@ -21,8 +21,6 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EStructuralFeature.Setting; -import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.sirius.components.collaborative.api.IRepresentationImageProvider; @@ -67,10 +65,6 @@ public class ExplorerDescriptionProvider implements IEditingContextRepresentatio public static final String REPRESENTATION_NAME = "Explorer"; - public static final String SETTING = "setting:"; - - public static final String SETTING_ID_SEPARATOR = "::"; - private final IObjectService objectService; private final IURLParser urlParser; @@ -155,8 +149,6 @@ private String getTreeItemId(VariableManager variableManager) { id = resource.getURI().path().substring(1); } else if (self instanceof EObject) { id = this.objectService.getId(self); - } else if (self instanceof Setting setting) { - id = SETTING + this.objectService.getId(setting.getEObject()) + SETTING_ID_SEPARATOR + setting.getEStructuralFeature().getName(); } return id; } @@ -168,8 +160,6 @@ private String getKind(VariableManager variableManager) { kind = representationMetadata.getKind(); } else if (self instanceof Resource) { kind = DOCUMENT_KIND; - } else if (self instanceof Setting) { - kind = "setting"; } else { kind = this.objectService.getKind(self); } @@ -192,8 +182,6 @@ private StyledString getLabel(VariableManager variableManager) { var kind = this.objectService.getKind(self); label = this.urlParser.getParameterValues(kind).get(SemanticKindConstants.ENTITY_ARGUMENT).get(0); } - } else if (self instanceof Setting setting) { - label = setting.getEStructuralFeature().getName(); } return StyledString.of(label); } @@ -297,36 +285,24 @@ private Object getTreeItemObject(VariableManager variableManager) { if (optionalEditingContext.isPresent() && optionalTreeItemId.isPresent()) { var treeItemId = optionalTreeItemId.get(); var editingContext = optionalEditingContext.get(); - - if (treeItemId.startsWith(SETTING)) { - // the tree item is a setting, get the object and then the structural feature associated - var objectId = treeItemId.substring(SETTING.length(), treeItemId.indexOf(SETTING_ID_SEPARATOR)); - var featureName = treeItemId.substring(treeItemId.indexOf(SETTING_ID_SEPARATOR) + SETTING_ID_SEPARATOR.length()); - var optObject = this.objectService.getObject(editingContext, objectId); - if (optObject.isPresent()) { - InternalEObject internalObject = (InternalEObject) optObject.get(); - result = internalObject.eSetting(internalObject.eClass().getEStructuralFeature(featureName)); - } + var optionalObject = this.objectService.getObject(editingContext, treeItemId); + if (optionalObject.isPresent()) { + result = optionalObject.get(); } else { - var optionalObject = this.objectService.getObject(editingContext, treeItemId); - if (optionalObject.isPresent()) { - result = optionalObject.get(); - } else { - var optionalEditingDomain = Optional.of(editingContext) - .filter(IEMFEditingContext.class::isInstance) - .map(IEMFEditingContext.class::cast) - .map(IEMFEditingContext::getDomain); - - if (optionalEditingDomain.isPresent()) { - var editingDomain = optionalEditingDomain.get(); - ResourceSet resourceSet = editingDomain.getResourceSet(); - URI uri = new JSONResourceFactory().createResourceURI(treeItemId); - - result = resourceSet.getResources().stream() - .filter(resource -> resource.getURI().equals(uri)) - .findFirst() - .orElse(null); - } + var optionalEditingDomain = Optional.of(editingContext) + .filter(IEMFEditingContext.class::isInstance) + .map(IEMFEditingContext.class::cast) + .map(IEMFEditingContext::getDomain); + + if (optionalEditingDomain.isPresent()) { + var editingDomain = optionalEditingDomain.get(); + ResourceSet resourceSet = editingDomain.getResourceSet(); + URI uri = new JSONResourceFactory().createResourceURI(treeItemId); + + result = resourceSet.getResources().stream() + .filter(resource -> resource.getURI().equals(uri)) + .findFirst() + .orElse(null); } } } diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeDescriptionProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeDescriptionProvider.java new file mode 100644 index 00000000000..bfa8c9b7160 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeDescriptionProvider.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * 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.web.application.views.tree; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature.Setting; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.sirius.components.collaborative.api.IRepresentationImageProvider; +import org.eclipse.sirius.components.core.CoreImageConstants; +import org.eclipse.sirius.components.core.RepresentationMetadata; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IEditingContextRepresentationDescriptionProvider; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IRepresentationMetadataSearchService; +import org.eclipse.sirius.components.core.api.IURLParser; +import org.eclipse.sirius.components.core.api.SemanticKindConstants; +import org.eclipse.sirius.components.core.api.labels.StyledString; +import org.eclipse.sirius.components.domain.Domain; +import org.eclipse.sirius.components.domain.Entity; +import org.eclipse.sirius.components.representations.GetOrCreateRandomIdProvider; +import org.eclipse.sirius.components.representations.IRepresentationDescription; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.description.TreeDescription; +import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.services.api.IRepresentationDataSearchService; +import org.springframework.stereotype.Service; + +/** + * This class is used to provide the description of a tree on Domain element.
+ * This is an example to demonstrate how to use a tree description which is not a tree explorer. + * + * @author Jerome Gout + */ +@Service +public class DomainTreeDescriptionProvider implements IEditingContextRepresentationDescriptionProvider { + + public static final String DESCRIPTION_ID = "domain_tree_description"; + + public static final String SETTING = "setting:"; + + public static final String SETTING_ID_SEPARATOR = "::"; + + private final IObjectService objectService; + + private final IURLParser urlParser; + + private final List representationImageProviders; + + private final IRepresentationMetadataSearchService representationMetadataSearchService; + + private final IRepresentationDataSearchService representationDataSearchService; + + public DomainTreeDescriptionProvider(IObjectService objectService, IURLParser urlParser, List representationImageProviders, IRepresentationDataSearchService representationDataSearchService, IRepresentationMetadataSearchService representationMetadataSearchService) { + this.objectService = Objects.requireNonNull(objectService); + this.urlParser = Objects.requireNonNull(urlParser); + this.representationImageProviders = Objects.requireNonNull(representationImageProviders); + this.representationMetadataSearchService = Objects.requireNonNull(representationMetadataSearchService); + this.representationDataSearchService = Objects.requireNonNull(representationDataSearchService); + } + + @Override + public List getRepresentationDescriptions(IEditingContext editingContext) { + + var treeDescription = TreeDescription.newTreeDescription(DESCRIPTION_ID) + .label("Domain Tree") + .idProvider(new GetOrCreateRandomIdProvider()) + .canCreatePredicate(this::canCreate) + .treeItemIdProvider(this::getTreeItemId) + .kindProvider(this::getKind) + .labelProvider(this::getLabel) + .targetObjectIdProvider(variableManager -> variableManager.get(VariableManager.SELF, Object.class).map(this.objectService::getId).orElse(null)) + .iconURLProvider(this::getImageURL) + .editableProvider(variableManager -> false) + .deletableProvider(variableManager -> false) + .selectableProvider(variableManager -> true) + .elementsProvider(this::getElements) + .hasChildrenProvider(this::hasChildren) + .childrenProvider(this::getChildren) + .deleteHandler(variableManager -> new Success()) + .renameHandler((variableManager, newName) -> new Success()) + .treeItemObjectProvider(this::getTreeItemObject) + .build(); + return List.of(treeDescription); + + } + + private boolean canCreate(VariableManager variableManager) { + Object self = variableManager.getVariables().get(VariableManager.SELF); + return self instanceof Domain; + } + + private String getTreeItemId(VariableManager variableManager) { + Object self = variableManager.getVariables().get(VariableManager.SELF); + + String id = null; + if (self instanceof RepresentationMetadata representationMetadata) { + id = representationMetadata.getId(); + } else if (self instanceof EObject) { + id = this.objectService.getId(self); + } else if (self instanceof Setting setting) { + id = SETTING + this.objectService.getId(setting.getEObject()) + SETTING_ID_SEPARATOR + setting.getEStructuralFeature().getName(); + } + return id; + } + + private String getKind(VariableManager variableManager) { + String kind = ""; + Object self = variableManager.getVariables().get(VariableManager.SELF); + if (self instanceof RepresentationMetadata representationMetadata) { + kind = representationMetadata.getKind(); + } else if (self instanceof Setting) { + kind = "setting"; + } else { + kind = this.objectService.getKind(self); + } + return kind; + } + + private StyledString getLabel(VariableManager variableManager) { + Object self = variableManager.getVariables().get(VariableManager.SELF); + + String label = ""; + if (self instanceof RepresentationMetadata representationMetadata) { + label = representationMetadata.getLabel(); + } else if (self instanceof EObject) { + label = this.objectService.getLabel(self); + if (label.isBlank()) { + var kind = this.objectService.getKind(self); + label = this.urlParser.getParameterValues(kind).get(SemanticKindConstants.ENTITY_ARGUMENT).get(0); + } + } else if (self instanceof Setting setting) { + label = setting.getEStructuralFeature().getName(); + } + return StyledString.of(label); + } + + private List getImageURL(VariableManager variableManager) { + Object self = variableManager.getVariables().get(VariableManager.SELF); + + List imageURL = List.of(CoreImageConstants.DEFAULT_SVG); + if (self instanceof EObject) { + imageURL = this.objectService.getImagePath(self); + } else if (self instanceof RepresentationMetadata representationMetadata) { + imageURL = this.representationImageProviders.stream() + .map(representationImageProvider -> representationImageProvider.getImageURL(representationMetadata.getKind())) + .flatMap(Optional::stream) + .toList(); + } else if (self instanceof Resource) { + imageURL = List.of("/explorer/Resource.svg"); + } + return imageURL; + } + + private List getElements(VariableManager variableManager) { + List elements = new ArrayList<>(); + Object self = variableManager.getVariables().get(VariableManager.SELF); + if (self instanceof Domain domain) { + elements.add(domain); + } + return elements; + } + + private boolean hasChildren(VariableManager variableManager) { + Object self = variableManager.getVariables().get(VariableManager.SELF); + + boolean hasChildren = false; + if (self instanceof EObject eObject) { + hasChildren = !eObject.eContents().isEmpty(); + + if (!hasChildren) { + String id = this.objectService.getId(eObject); + hasChildren = this.representationDataSearchService.existAnyRepresentationForTargetObjectId(id); + } + + if (!hasChildren && self instanceof Entity) { + hasChildren = true; + } + } else if (self instanceof Setting setting) { + var value = setting.get(true); + if (value instanceof Collection collection) { + hasChildren = !collection.isEmpty(); + } + } + return hasChildren; + } + + public List getChildren(VariableManager variableManager) { + List children = new ArrayList<>(); + Object self = variableManager.getVariables().get(VariableManager.SELF); + if (self != null) { + children = this.getDefaultChildren(variableManager); + } + return children; + } + + private List getDefaultChildren(VariableManager variableManager) { + List result = new ArrayList<>(); + var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); + Object self = variableManager.getVariables().get(VariableManager.SELF); + + if (optionalEditingContext.isPresent()) { + IEditingContext editingContext = optionalEditingContext.get(); + String id = this.getTreeItemId(variableManager); + if (self instanceof EObject) { + var representationMetadata = new ArrayList<>(this.representationMetadataSearchService.findAllByTargetObjectId(editingContext, id)); + representationMetadata.sort(Comparator.comparing(RepresentationMetadata::getLabel)); + result.addAll(representationMetadata); + List contents = this.objectService.getContents(self); + if (self instanceof Entity entity) { + result.add(((InternalEObject) entity).eSetting(entity.eClass().getEStructuralFeature("superTypes"))); + } + result.addAll(contents); + } else if (self instanceof Setting setting) { + var value = setting.get(true); + if (value instanceof Collection collection) { + result.addAll(collection); + } + } + } + return result; + } + + private Object getTreeItemObject(VariableManager variableManager) { + Object result = null; + var optionalTreeItemId = variableManager.get(TreeDescription.ID, String.class); + var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); + + if (optionalEditingContext.isPresent() && optionalTreeItemId.isPresent()) { + var treeItemId = optionalTreeItemId.get(); + var editingContext = optionalEditingContext.get(); + + if (treeItemId.startsWith(SETTING)) { + // the tree item is a setting, get the object and then the structural feature associated + var objectId = treeItemId.substring(SETTING.length(), treeItemId.indexOf(SETTING_ID_SEPARATOR)); + var featureName = treeItemId.substring(treeItemId.indexOf(SETTING_ID_SEPARATOR) + SETTING_ID_SEPARATOR.length()); + var optObject = this.objectService.getObject(editingContext, objectId); + if (optObject.isPresent()) { + InternalEObject internalObject = (InternalEObject) optObject.get(); + result = internalObject.eSetting(internalObject.eClass().getEStructuralFeature(featureName)); + } + } else { + var optionalObject = this.objectService.getObject(editingContext, treeItemId); + if (optionalObject.isPresent()) { + result = optionalObject.get(); + } + } + } + + return result; + } +} diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreePathProvider.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreePathProvider.java new file mode 100644 index 00000000000..556d9655d00 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreePathProvider.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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.web.application.views.tree; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.sirius.components.collaborative.trees.api.ITreePathProvider; +import org.eclipse.sirius.components.collaborative.trees.dto.TreePath; +import org.eclipse.sirius.components.collaborative.trees.dto.TreePathInput; +import org.eclipse.sirius.components.collaborative.trees.dto.TreePathSuccessPayload; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerNavigationService; +import org.springframework.stereotype.Service; + +/** + * Implementation of {@link ITreePathProvider} for the example Domain tree. + * + * @author Jerome Gout + */ +@Service +public class DomainTreePathProvider implements ITreePathProvider { + + // At the moment, the navigation service is still explorer-related, + // but once he issue https://github.com/eclipse-sirius/sirius-web/issues/3793 will be merged + // it won't no longer be dependent of the explorer logic. + // It will be based upon what is described in the TreeDescription (through treeItemObjectProvider and parentObjectProvider). + // This way it would be possible to define a tree navigation service fully agnostic and thus reusable for all Tree description. + private final IExplorerNavigationService explorerNavigationService; + + public DomainTreePathProvider(IExplorerNavigationService explorerNavigationService) { + this.explorerNavigationService = Objects.requireNonNull(explorerNavigationService); + } + + @Override + public boolean canHandle(Tree tree) { + return tree.getDescriptionId().equals(DomainTreeDescriptionProvider.DESCRIPTION_ID); + } + + @Override + public IPayload handle(IEditingContext editingContext, Tree tree, TreePathInput input) { + int maxDepth = 0; + Set allAncestors = new LinkedHashSet<>(); + for (String selectionEntryId : input.selectionEntryIds()) { + List itemAncestors = this.explorerNavigationService.getAncestors(editingContext, selectionEntryId, tree); + allAncestors.addAll(itemAncestors); + maxDepth = Math.max(maxDepth, itemAncestors.size()); + } + return new TreePathSuccessPayload(input.id(), new TreePath(allAncestors.stream().toList(), maxDepth)); + } +} diff --git a/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeRepresentationDescription.java b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeRepresentationDescription.java new file mode 100644 index 00000000000..18bc0f13656 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-application/src/main/java/org/eclipse/sirius/web/application/views/tree/DomainTreeRepresentationDescription.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.web.application.views.tree; + +import java.util.List; + +import org.eclipse.sirius.components.collaborative.api.IRepresentationDescriptionsProvider; +import org.eclipse.sirius.components.collaborative.api.RepresentationDescriptionMetadata; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.representations.IRepresentationDescription; +import org.springframework.stereotype.Service; + +/** + * Used to make the example Domain tree description work. + * + * @author Jerome Gout + */ +@Service +public class DomainTreeRepresentationDescription implements IRepresentationDescriptionsProvider { + + @Override + public boolean canHandle(IRepresentationDescription representationDescription) { + return representationDescription.getId().equals(DomainTreeDescriptionProvider.DESCRIPTION_ID); + } + + @Override + public List handle(IEditingContext editingContext, Object object, IRepresentationDescription representationDescription) { + return List.of(new RepresentationDescriptionMetadata(representationDescription.getId(), representationDescription.getLabel(), representationDescription.getLabel())); + } + +} diff --git a/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/api/IGivenCreatedTreeSubscription.java b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/api/IGivenCreatedTreeSubscription.java new file mode 100644 index 00000000000..3f6fa7b0d5e --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/api/IGivenCreatedTreeSubscription.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.web.tests.services.api; + +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; +import org.eclipse.sirius.components.collaborative.trees.dto.TreeRefreshedEventPayload; + +import reactor.core.publisher.Flux; + +/** + * Used to create a tree and subscribe to it. + * + * @author Jerome Gout + */ +public interface IGivenCreatedTreeSubscription { + Flux createAndSubscribe(CreateRepresentationInput input); +} diff --git a/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/GivenCreatedTreeSubscription.java b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/GivenCreatedTreeSubscription.java new file mode 100644 index 00000000000..c34133a1efc --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/GivenCreatedTreeSubscription.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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.web.tests.services.tree; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; +import org.eclipse.sirius.components.collaborative.trees.dto.TreeEventInput; +import org.eclipse.sirius.components.collaborative.trees.dto.TreeRefreshedEventPayload; +import org.eclipse.sirius.web.tests.services.api.IGivenCommittedTransaction; +import org.eclipse.sirius.web.tests.services.api.IGivenCreatedRepresentation; +import org.eclipse.sirius.web.tests.services.api.IGivenCreatedTreeSubscription; +import org.springframework.stereotype.Service; +import org.springframework.test.context.transaction.TestTransaction; + +import graphql.execution.DataFetcherResult; +import reactor.core.publisher.Flux; + +/** + * Used to create a tree and subscribe to it. + * + * @author Jerome Gout + */ +@Service +public class GivenCreatedTreeSubscription implements IGivenCreatedTreeSubscription { + + private final IGivenCommittedTransaction givenCommittedTransaction; + + private final IGivenCreatedRepresentation givenCreatedRepresentation; + + private final TreeEventSubscriptionRunner treeEventSubscriptionRunner; + + public GivenCreatedTreeSubscription(IGivenCommittedTransaction givenCommittedTransaction, IGivenCreatedRepresentation givenCreatedRepresentation, TreeEventSubscriptionRunner treeEventSubscriptionRunner) { + this.givenCommittedTransaction = Objects.requireNonNull(givenCommittedTransaction); + this.givenCreatedRepresentation = Objects.requireNonNull(givenCreatedRepresentation); + this.treeEventSubscriptionRunner = Objects.requireNonNull(treeEventSubscriptionRunner); + } + + @Override + public Flux createAndSubscribe(CreateRepresentationInput input) { + this.givenCommittedTransaction.commit(); + + String representationId = this.givenCreatedRepresentation.createRepresentation(input); + + var treeEventInput = new TreeEventInput(UUID.randomUUID(), input.editingContextId(), representationId, List.of(), List.of()); + var flux = this.treeEventSubscriptionRunner.run(treeEventInput); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + TestTransaction.start(); + + return flux.filter(DataFetcherResult.class::isInstance) + .map(DataFetcherResult.class::cast) + .map(DataFetcherResult::getData) + .filter(TreeRefreshedEventPayload.class::isInstance) + .map(TreeRefreshedEventPayload.class::cast); + } +} diff --git a/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/TreeEventSubscriptionRunner.java b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/TreeEventSubscriptionRunner.java new file mode 100644 index 00000000000..e559e8c11b4 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-tests/src/main/java/org/eclipse/sirius/web/tests/services/tree/TreeEventSubscriptionRunner.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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.web.tests.services.tree; + +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.trees.dto.TreeEventInput; +import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor; +import org.eclipse.sirius.components.graphql.tests.api.ISubscriptionRunner; +import org.springframework.stereotype.Service; + +import reactor.core.publisher.Flux; + +/** + * Used to get the tree event subscription with the GraphQL API. + * + * @author Jerome Gout + */ +@Service +public class TreeEventSubscriptionRunner implements ISubscriptionRunner { + + private static final String TREE_EVENT_SUBSCRIPTION = """ + subscription treeEvent($input: TreeEventInput!) { + treeEvent(input: $input) { + __typename + } + } + """; + + private final IGraphQLRequestor graphQLRequestor; + + public TreeEventSubscriptionRunner(IGraphQLRequestor graphQLRequestor) { + this.graphQLRequestor = Objects.requireNonNull(graphQLRequestor); + } + + @Override + public Flux run(TreeEventInput input) { + return this.graphQLRequestor.subscribe(TREE_EVENT_SUBSCRIPTION, input); + } +} diff --git a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java index ca7a5d5b1ff..728608cf33a 100644 --- a/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java +++ b/packages/sirius-web/backend/sirius-web/src/test/java/org/eclipse/sirius/web/application/controllers/trees/ExplorerNonSemanticElementControllerTests.java @@ -15,26 +15,18 @@ 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.dto.CreateRepresentationInput; import org.eclipse.sirius.components.collaborative.trees.dto.TreeRefreshedEventPayload; -import org.eclipse.sirius.components.trees.Tree; -import org.eclipse.sirius.components.trees.TreeItem; -import org.eclipse.sirius.components.trees.tests.graphql.ExpandAllTreePathQueryRunner; import org.eclipse.sirius.web.AbstractIntegrationTests; -import org.eclipse.sirius.web.application.views.explorer.ExplorerEventInput; -import org.eclipse.sirius.web.application.views.explorer.services.ExplorerDescriptionProvider; +import org.eclipse.sirius.web.application.views.tree.DomainTreeDescriptionProvider; import org.eclipse.sirius.web.data.StudioIdentifiers; +import org.eclipse.sirius.web.tests.services.api.IGivenCreatedTreeSubscription; import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState; -import org.eclipse.sirius.web.tests.services.explorer.ExplorerEventSubscriptionRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -44,7 +36,7 @@ import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.transaction.annotation.Transactional; -import graphql.execution.DataFetcherResult; +import reactor.core.publisher.Flux; import reactor.test.StepVerifier; /** @@ -61,97 +53,45 @@ public class ExplorerNonSemanticElementControllerTests extends AbstractIntegrati private IGivenInitialServerState givenInitialServerState; @Autowired - private ExplorerEventSubscriptionRunner treeEventSubscriptionRunner; - - @Autowired - private ExpandAllTreePathQueryRunner expandAllTreePathQueryRunner; + private IGivenCreatedTreeSubscription givenCreatedTreeSubscription; @BeforeEach public void beforeEach() { this.givenInitialServerState.initialize(); } + + private Flux givenSubscriptionToTree() { + var input = new CreateRepresentationInput( + UUID.randomUUID(), + StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), + DomainTreeDescriptionProvider.DESCRIPTION_ID, + StudioIdentifiers.DOMAIN_OBJECT.toString(), + "Tree" + ); + return this.givenCreatedTreeSubscription.createAndSubscribe(input); + } + @Test - @DisplayName("Given a sample studio, when we expand all the domain elements, then underneath entities have a superTypes child") + @DisplayName("Given a domain tree representation, when we subscribe to its event, then the representation data contains a superTypes node") @Sql(scripts = {"/scripts/studio.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = {"/scripts/cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED)) - public void givenStudioWhenWeAskForTheTreePathOfPapayaViewObjectThenItsPathInTheExplorerIsReturned() { - var input = new ExplorerEventInput(UUID.randomUUID(), StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), ExplorerDescriptionProvider.PREFIX, List.of(), List.of()); - var flux = this.treeEventSubscriptionRunner.run(input); - - var treeId = new AtomicReference(); - var domainDocumentId = new AtomicReference(); - - Consumer initialTreeContentConsumer = this.getTreeSubscriptionConsumer(tree -> { - assertThat(tree).isNotNull(); - assertThat(tree.getChildren()).hasSize(5); - assertThat(tree.getChildren()).allSatisfy(treeItem -> assertThat(treeItem.getChildren()).isEmpty()); - - treeId.set(tree.getId()); - domainDocumentId.set(tree.getChildren().get(1).getId()); // Domain document is the second child of the tree - }); - - // Expand the part of the tree corresponding to the Domain document - var treeItemIds = new AtomicReference>(); + public void givenADomainTreeRepresentationWhenWeSubscribeToItsEventThenTheRepresentationDataContainsASuperTypesNode() { + var flux = this.givenSubscriptionToTree(); - Runnable getTreePath = () -> { - Map variables = Map.of( - "editingContextId", StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), - "treeId", treeId.get(), - "treeItemId", domainDocumentId.get() - ); - var result = this.expandAllTreePathQueryRunner.run(variables); - List treeItemIdsToExpand = JsonPath.read(result, "$.data.viewer.editingContext.expandAllTreePath.treeItemIdsToExpand"); - assertThat(treeItemIdsToExpand).isNotEmpty(); - // there are 3 entities in the Domain document, so should get 3 superType treeItems - assertThat(treeItemIdsToExpand.stream() - .filter(id -> id.startsWith(ExplorerDescriptionProvider.SETTING)) - .toList() - ).hasSize(3); - treeItemIds.set(treeItemIdsToExpand); - }; + Consumer initialTreeContentConsumer = payload -> Optional.of(payload) + .map(TreeRefreshedEventPayload::tree) + .ifPresentOrElse(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getChildren()).hasSize(1); + assertThat(tree.getChildren().get(0).getChildren()).hasSize(4); + assertThat(tree.getChildren().get(0).getChildren().get(1).getChildren()).hasSize(3); + assertThat(tree.getChildren().get(0).getChildren().get(1).getChildren().get(0).getId()).startsWith(DomainTreeDescriptionProvider.SETTING); + }, () -> fail("Missing tree")); StepVerifier.create(flux) .consumeNextWith(initialTreeContentConsumer) - .then(getTreePath) - .thenCancel() - .verify(Duration.ofSeconds(10)); - - - var expandedTreeInput = new ExplorerEventInput(UUID.randomUUID(), StudioIdentifiers.SAMPLE_STUDIO_PROJECT.toString(), ExplorerDescriptionProvider.PREFIX, treeItemIds.get(), List.of()); - var expandedTreeFlux = this.treeEventSubscriptionRunner.run(expandedTreeInput); - - Consumer initialExpandedTreeContentConsumer = this.getTreeSubscriptionConsumer(tree -> { - assertThat(tree).isNotNull(); - assertThat(tree.getChildren()).isNotEmpty(); - assertThat(tree.getChildren()).hasSize(5); - var domainDocument = tree.getChildren().get(1); - assertThat(domainDocument).isNotNull(); - assertThat(domainDocument.getChildren()).isNotEmpty(); - assertThat(domainDocument.getChildren()).hasSize(1); - assertThat(domainDocument.getChildren().get(0)).isNotNull(); - List domainElements = domainDocument.getChildren().get(0).getChildren(); - assertThat(domainElements).hasSize(3); - assertThat(domainElements.get(0).getLabel().toString()).isEqualTo("Root"); - assertThat(domainElements.get(0).getChildren()).isNotEmpty(); - assertThat(domainElements.get(0).getChildren()).hasSize(3); - assertThat(domainElements.get(0).getChildren().get(0).getLabel().toString()).isEqualTo("superTypes"); - }); - - StepVerifier.create(expandedTreeFlux) - .consumeNextWith(initialExpandedTreeContentConsumer) .thenCancel() .verify(Duration.ofSeconds(10)); } - - private Consumer getTreeSubscriptionConsumer(Consumer treeConsumer) { - return object -> Optional.of(object) - .filter(DataFetcherResult.class::isInstance) - .map(DataFetcherResult.class::cast) - .map(DataFetcherResult::getData) - .filter(TreeRefreshedEventPayload.class::isInstance) - .map(TreeRefreshedEventPayload.class::cast) - .map(TreeRefreshedEventPayload::tree) - .ifPresentOrElse(treeConsumer, () -> fail("Missing tree")); - } } diff --git a/packages/sirius-web/frontend/sirius-web-application/src/extension/DefaultExtensionRegistry.tsx b/packages/sirius-web/frontend/sirius-web-application/src/extension/DefaultExtensionRegistry.tsx index 8f21737f8d7..7fd30516f5b 100644 --- a/packages/sirius-web/frontend/sirius-web-application/src/extension/DefaultExtensionRegistry.tsx +++ b/packages/sirius-web/frontend/sirius-web-application/src/extension/DefaultExtensionRegistry.tsx @@ -35,7 +35,11 @@ import { } from '@eclipse-sirius/sirius-components-forms'; import { GanttRepresentation } from '@eclipse-sirius/sirius-components-gantt'; import { PortalRepresentation } from '@eclipse-sirius/sirius-components-portals'; -import { ExplorerView, treeItemContextMenuEntryExtensionPoint } from '@eclipse-sirius/sirius-components-trees'; +import { + ExplorerView, + TreeRepresentation, + treeItemContextMenuEntryExtensionPoint, +} from '@eclipse-sirius/sirius-components-trees'; import { ValidationView } from '@eclipse-sirius/sirius-components-validation'; import { GQLReferenceWidget, @@ -151,6 +155,7 @@ const representationFactories: RepresentationComponentFactory[] = [ (representationMetadata) => (getType(representationMetadata) === 'Gantt' ? GanttRepresentation : null), (representationMetadata) => (getType(representationMetadata) === 'Deck' ? DeckRepresentation : null), (representationMetadata) => (getType(representationMetadata) === 'Portal' ? PortalRepresentation : null), + (representationMetadata) => (getType(representationMetadata) === 'Tree' ? TreeRepresentation : null), ]; defaultExtensionRegistry.putData(representationFactoryExtensionPoint, { diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeEventProcessorFactory.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeEventProcessorFactory.java new file mode 100644 index 00000000000..506cf39f045 --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeEventProcessorFactory.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * 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.trees; + +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.IRepresentationSearchService; +import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory; +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.TreeConfiguration; +import org.eclipse.sirius.components.collaborative.trees.api.TreeCreationParameters; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.trees.Tree; +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. + * + * @author Jerome Gout + */ +@Service +public class TreeEventProcessorFactory implements IRepresentationEventProcessorFactory { + + private final IRepresentationSearchService representationSearchService; + + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + private final IObjectService objectService; + + private final ITreeService treeService; + + private final List treeEventHandlers; + + private final ISubscriptionManagerFactory subscriptionManagerFactory; + + private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry; + + public TreeEventProcessorFactory(IRepresentationSearchService representationSearchService, IRepresentationDescriptionSearchService representationDescriptionSearchService, IObjectService objectService, ITreeService treeService, List treeEventHandlers, IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, ISubscriptionManagerFactory subscriptionManagerFactory) { + this.representationSearchService = Objects.requireNonNull(representationSearchService); + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); + this.objectService = Objects.requireNonNull(objectService); + 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 TreeConfiguration; + } + + @Override + public Optional createRepresentationEventProcessor(IRepresentationConfiguration configuration, IEditingContext editingContext) { + if (configuration instanceof TreeConfiguration treeConfiguration) { + + Optional optionalTree = this.representationSearchService.findById(editingContext, treeConfiguration.getId(), Tree.class); + if (optionalTree.isPresent()) { + Tree tree = optionalTree.get(); + Optional optionalTreeDescription = this.representationDescriptionSearchService.findById(editingContext, tree.getDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + Optional optionalObject = this.objectService.getObject(editingContext, tree.getTargetObjectId()); + if (optionalTreeDescription.isPresent() && optionalObject.isPresent()) { + TreeDescription treeDescription = optionalTreeDescription.get(); + Object object = optionalObject.get(); + + TreeCreationParameters treeCreationParameters = TreeCreationParameters.newTreeCreationParameters(treeConfiguration.getId()) + .treeDescription(treeDescription) + .activeFilterIds(treeConfiguration.getActiveFilterIds()) + .expanded(treeConfiguration.getExpanded()) + .editingContext(editingContext) + .object(object) + .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(); + } + +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeService.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeService.java index 25ba1f6d6c9..0688961d503 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeService.java +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/TreeService.java @@ -36,6 +36,7 @@ public Tree create(TreeCreationParameters treeCreationParameters) { variableManager.put(GetOrCreateRandomIdProvider.PREVIOUS_REPRESENTATION_ID, treeCreationParameters.getId()); variableManager.put(ITreeConfiguration.TREE_ID, treeCreationParameters.getId()); variableManager.put(IEditingContext.EDITING_CONTEXT, treeCreationParameters.getEditingContext()); + variableManager.put(VariableManager.SELF, treeCreationParameters.getObject()); variableManager.put(TreeRenderer.EXPANDED, treeCreationParameters.getExpanded()); variableManager.put(TreeRenderer.ACTIVE_FILTER_IDS, treeCreationParameters.getActiveFilterIds()); diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/ITreeConfiguration.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/ITreeConfiguration.java index 097288244e4..570b4f6baac 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/ITreeConfiguration.java +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/ITreeConfiguration.java @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.sirius.components.collaborative.trees.api; +import java.util.List; + import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration; /** @@ -22,4 +24,8 @@ public interface ITreeConfiguration extends IRepresentationConfiguration { String TREE_ID = "treeId"; + + List getExpanded(); + + List getActiveFilterIds(); } diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeConfiguration.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeConfiguration.java new file mode 100644 index 00000000000..b8c10031bcc --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeConfiguration.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.trees.api; + +import java.util.List; + +/** + * The configuration used to create a tree event processor. + * + * @author Jerome Gout + */ +public class TreeConfiguration implements ITreeConfiguration { + + private final String treeId; + + public TreeConfiguration(String treeId) { + this.treeId = treeId; + } + + @Override + public String getId() { + return this.treeId; + } + + @Override + public List getExpanded() { + return List.of(); + } + + @Override + public List getActiveFilterIds() { + return List.of(); + } + +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeCreationParameters.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeCreationParameters.java index 98b043316e3..4990408aeb9 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeCreationParameters.java +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/api/TreeCreationParameters.java @@ -37,6 +37,8 @@ public final class TreeCreationParameters { private IEditingContext editingContext; + private Object object; + private TreeCreationParameters() { // Prevent instantiation } @@ -61,6 +63,10 @@ public IEditingContext getEditingContext() { return this.editingContext; } + public Object getObject() { + return this.object; + } + public static Builder newTreeCreationParameters(String id) { return new Builder(id); } @@ -88,6 +94,8 @@ public static final class Builder { private IEditingContext editingContext; + private Object object; + private Builder(String id) { this.id = id; } @@ -112,6 +120,11 @@ public Builder editingContext(IEditingContext editingContext) { return this; } + public Builder object(Object object) { + this.object = object; + return this; + } + public TreeCreationParameters build() { TreeCreationParameters treeCreationParameters = new TreeCreationParameters(); treeCreationParameters.id = Objects.requireNonNull(this.id); @@ -119,6 +132,7 @@ public TreeCreationParameters build() { treeCreationParameters.activeFilterIds = Objects.requireNonNull(this.activeFilterIds); treeCreationParameters.expanded = Objects.requireNonNull(this.expanded); treeCreationParameters.editingContext = Objects.requireNonNull(this.editingContext); + treeCreationParameters.object = this.object; // can be null; return treeCreationParameters; } } diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/dto/TreeEventInput.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/dto/TreeEventInput.java new file mode 100644 index 00000000000..ba3e4703c34 --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/dto/TreeEventInput.java @@ -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.trees.dto; + +import java.util.List; +import java.util.UUID; + +import org.eclipse.sirius.components.core.api.IInput; + +/** + * The input of the tree event subscription. + * + * @author Jerome Gout + */ +public record TreeEventInput(UUID id, String editingContextId, String treeId, List expanded, List activeFilterIds) implements IInput { +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/CreateTreeEventHandler.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/CreateTreeEventHandler.java new file mode 100644 index 00000000000..e3525052e6b --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/handlers/CreateTreeEventHandler.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * 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.trees.handlers; + +import java.util.Objects; +import java.util.Optional; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler; +import org.eclipse.sirius.components.collaborative.api.IRepresentationPersistenceService; +import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationSuccessPayload; +import org.eclipse.sirius.components.collaborative.messages.ICollaborativeMessageService; +import org.eclipse.sirius.components.collaborative.trees.services.TreeCreationService; +import org.eclipse.sirius.components.core.RepresentationMetadata; +import org.eclipse.sirius.components.core.api.ErrorPayload; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IInput; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.IRepresentationDescriptionSearchService; +import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.components.trees.description.TreeDescription; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import reactor.core.publisher.Sinks.Many; +import reactor.core.publisher.Sinks.One; + +/** + * Handler used to create a new Tree representation. + * + * @author Jerome Gout + */ +@Service +public class CreateTreeEventHandler implements IEditingContextEventHandler { + + private final IRepresentationDescriptionSearchService representationDescriptionSearchService; + + private final IRepresentationPersistenceService representationPersistenceService; + + private final TreeCreationService treeCreationService; + + private final IObjectService objectService; + + private final ICollaborativeMessageService messageService; + + private final Counter counter; + + public CreateTreeEventHandler(IRepresentationDescriptionSearchService representationDescriptionSearchService, IRepresentationPersistenceService representationPersistenceService, + TreeCreationService treeCreationService, IObjectService objectService, ICollaborativeMessageService messageService, MeterRegistry meterRegistry) { + this.representationDescriptionSearchService = Objects.requireNonNull(representationDescriptionSearchService); + this.representationPersistenceService = Objects.requireNonNull(representationPersistenceService); + this.treeCreationService = Objects.requireNonNull(treeCreationService); + this.objectService = Objects.requireNonNull(objectService); + this.messageService = Objects.requireNonNull(messageService); + + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(IEditingContext editingContext, IInput input) { + if (input instanceof CreateRepresentationInput createRepresentationInput) { + return this.representationDescriptionSearchService.findById(editingContext, createRepresentationInput.representationDescriptionId()) + .filter(TreeDescription.class::isInstance) + .isPresent(); + } + return false; + } + + @Override + public void handle(One payloadSink, Many changeDescriptionSink, IEditingContext editingContext, IInput input) { + this.counter.increment(); + + String message = this.messageService.invalidInput(input.getClass().getSimpleName(), CreateRepresentationInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(input.id(), message); + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, editingContext.getId(), input); + + if (input instanceof CreateRepresentationInput createRepresentationInput) { + Optional optionalDeckDescription = this.representationDescriptionSearchService.findById(editingContext, createRepresentationInput.representationDescriptionId()) + .filter(TreeDescription.class::isInstance) + .map(TreeDescription.class::cast); + Optional optionalObject = this.objectService.getObject(editingContext, createRepresentationInput.objectId()); + + if (optionalDeckDescription.isPresent() && optionalObject.isPresent()) { + TreeDescription deckDescription = optionalDeckDescription.get(); + Object object = optionalObject.get(); + + Tree tree = this.treeCreationService.create(createRepresentationInput.representationName(), object, deckDescription, editingContext); + + this.representationPersistenceService.save(editingContext, tree); + + var representationMetadata = new RepresentationMetadata(tree.getId(), tree.getKind(), tree.getLabel(), tree.getDescriptionId()); + payload = new CreateRepresentationSuccessPayload(input.id(), representationMetadata); + changeDescription = new ChangeDescription(ChangeKind.REPRESENTATION_CREATION, editingContext.getId(), input); + } + } + + payloadSink.tryEmitValue(payload); + changeDescriptionSink.tryEmitNext(changeDescription); + } +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeCreationService.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeCreationService.java new file mode 100644 index 00000000000..d580d178653 --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeCreationService.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * 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.trees.services; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.trees.Tree; +import org.eclipse.sirius.components.trees.description.TreeDescription; +import org.eclipse.sirius.components.trees.renderer.TreeRenderer; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Timer; + +/** + * Service used to create tree representations. + * + * @author Jerome Gout + */ +@Service +public class TreeCreationService { + + private final Timer timer; + + public TreeCreationService(MeterRegistry meterRegistry) { + this.timer = Timer.builder(Monitoring.REPRESENTATION_EVENT_PROCESSOR_REFRESH).tag(Monitoring.NAME, "tree").register(meterRegistry); + } + + public Tree create(String label, Object targetObject, TreeDescription treeDescription, IEditingContext editingContext) { + return this.doRender(label, targetObject, editingContext, treeDescription); + } + + private Tree doRender(String label, Object targetObject, IEditingContext editingContext, TreeDescription treeDescription) { + long start = System.currentTimeMillis(); + + VariableManager variableManager = new VariableManager(); + variableManager.put(VariableManager.SELF, targetObject); + variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext); + + Tree newTree = new TreeRenderer(variableManager, treeDescription).render(); + + long end = System.currentTimeMillis(); + this.timer.record(end - start, TimeUnit.MILLISECONDS); + return newTree; + } + +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeDeserializer.java b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeDeserializer.java new file mode 100644 index 00000000000..9bee7236930 --- /dev/null +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/java/org/eclipse/sirius/components/collaborative/trees/services/TreeDeserializer.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.trees.services; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.util.Optional; + +import org.eclipse.sirius.components.collaborative.api.IRepresentationDeserializer; +import org.eclipse.sirius.components.representations.IRepresentation; +import org.eclipse.sirius.components.trees.Tree; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +/** + * Used to deserialize a tree representation. + * + * @author Jerome Gout + */ +@Service +public class TreeDeserializer implements IRepresentationDeserializer { + + private final Logger logger = LoggerFactory.getLogger(TreeDeserializer.class); + + @Override + public boolean canHandle(ObjectNode root) { + return Optional.ofNullable(root.get("kind")) + .map(JsonNode::asText) + .filter(Tree.KIND::equals) + .isPresent(); + } + + @Override + public Optional handle(ObjectMapper mapper, ObjectNode root) { + try { + return Optional.of(mapper.readValue(root.toString(), Tree.class)); + } catch (JsonProcessingException exception) { + this.logger.warn(exception.getMessage(), exception); + } + + return Optional.empty(); + } +} diff --git a/packages/trees/backend/sirius-components-collaborative-trees/src/main/resources/schema/tree.graphqls b/packages/trees/backend/sirius-components-collaborative-trees/src/main/resources/schema/tree.graphqls index d231858d23a..b931c3ad62a 100644 --- a/packages/trees/backend/sirius-components-collaborative-trees/src/main/resources/schema/tree.graphqls +++ b/packages/trees/backend/sirius-components-collaborative-trees/src/main/resources/schema/tree.graphqls @@ -1,3 +1,15 @@ +extend type Subscription { + treeEvent(input: TreeEventInput!): TreeEventPayload! +} + +input TreeEventInput { + id: ID! + treeId: String! + editingContextId: ID! + expanded: [String!]! + activeFilterIds: [String!]! +} + extend type EditingContext { treePath(treeId: ID!, selectionEntryIds: [ID!]!): TreePath! expandAllTreePath(treeId: ID!, treeItemId: ID!): TreePath! diff --git a/packages/trees/backend/sirius-components-trees-graphql/src/main/java/org/eclipse/sirius/components/trees/graphql/datafetchers/subscription/SubscriptionTreeEventDataFetcher.java b/packages/trees/backend/sirius-components-trees-graphql/src/main/java/org/eclipse/sirius/components/trees/graphql/datafetchers/subscription/SubscriptionTreeEventDataFetcher.java new file mode 100644 index 00000000000..4b7f99587f2 --- /dev/null +++ b/packages/trees/backend/sirius-components-trees-graphql/src/main/java/org/eclipse/sirius/components/trees/graphql/datafetchers/subscription/SubscriptionTreeEventDataFetcher.java @@ -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.trees.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.trees.api.TreeConfiguration; +import org.eclipse.sirius.components.collaborative.trees.dto.TreeEventInput; +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 subscription. + * + * @author Jerome Gout + */ +@SubscriptionDataFetcher(type = "Subscription", field = "treeEvent") +public class SubscriptionTreeEventDataFetcher implements IDataFetcherWithFieldCoordinates>> { + + private static final String INPUT_ARGUMENT = "input"; + + private final ObjectMapper objectMapper; + + private final IExceptionWrapper exceptionWrapper; + + private final IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider; + + public SubscriptionTreeEventDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider) { + this.objectMapper = Objects.requireNonNull(objectMapper); + this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper); + this.eventProcessorSubscriptionProvider = Objects.requireNonNull(eventProcessorSubscriptionProvider); + } + + @Override + public Publisher> get(DataFetchingEnvironment environment) throws Exception { + Object argument = environment.getArgument(INPUT_ARGUMENT); + var input = this.objectMapper.convertValue(argument, TreeEventInput.class); + var treeConfiguration = new TreeConfiguration(input.treeId()); + + Map localContext = new HashMap<>(); + localContext.put(LocalContextConstants.EDITING_CONTEXT_ID, input.editingContextId()); + localContext.put(LocalContextConstants.REPRESENTATION_ID, treeConfiguration.getId()); + + return this.exceptionWrapper.wrapFlux(() -> this.eventProcessorSubscriptionProvider.getSubscription(input.editingContextId(), treeConfiguration, input), input) + .map(payload -> DataFetcherResult.newResult() + .data(payload) + .localContext(localContext) + .build()); + } +} diff --git a/packages/trees/frontend/sirius-components-trees/src/index.ts b/packages/trees/frontend/sirius-components-trees/src/index.ts index 89bc33b5751..d6d0831c846 100644 --- a/packages/trees/frontend/sirius-components-trees/src/index.ts +++ b/packages/trees/frontend/sirius-components-trees/src/index.ts @@ -14,12 +14,13 @@ export * from './toolbar/TreeToolBarContext'; export * from './toolbar/TreeToolBarContext.types'; export * from './toolbar/TreeToolBarContribution'; export * from './toolbar/TreeToolBarContribution.types'; +export * from './treeitems/filterTreeItem'; export * from './treeitems/TreeItemAction.types'; export * from './treeitems/TreeItemContextMenu'; export * from './treeitems/TreeItemContextMenu.types'; export * from './treeitems/TreeItemContextMenuEntry.types'; export * from './treeitems/TreeItemContextMenuEntryExtensionPoints'; -export * from './treeitems/filterTreeItem'; +export * from './trees/TreeRepresentation'; export * from './views/ExplorerView'; export * from './views/TreeView'; export * from './views/TreeView.types'; diff --git a/packages/trees/frontend/sirius-components-trees/src/trees/TreeRepresentation.tsx b/packages/trees/frontend/sirius-components-trees/src/trees/TreeRepresentation.tsx new file mode 100644 index 00000000000..249e2c15168 --- /dev/null +++ b/packages/trees/frontend/sirius-components-trees/src/trees/TreeRepresentation.tsx @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +import { RepresentationComponentProps } from '@eclipse-sirius/sirius-components-core'; +import { TreeView } from '../views/TreeView'; + +export const TreeRepresentation = ({ editingContextId, representationId }: RepresentationComponentProps) => { + return ( +
+ +
+ ); +};