-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[1141] Add support for a new 'Related Elements' view
Bug: #1141 Signed-off-by: Pierre-Charles David <[email protected]>
- Loading branch information
1 parent
a871ddc
commit f5219c6
Showing
16 changed files
with
402 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
...g/eclipse/sirius/components/collaborative/forms/RelatedElementsEventProcessorFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 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.forms; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
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.forms.api.FormCreationParameters; | ||
import org.eclipse.sirius.components.collaborative.forms.api.IFormEventHandler; | ||
import org.eclipse.sirius.components.collaborative.forms.api.IFormEventProcessor; | ||
import org.eclipse.sirius.components.collaborative.forms.api.IRelatedElementsDescriptionProvider; | ||
import org.eclipse.sirius.components.collaborative.forms.api.IWidgetSubscriptionManagerFactory; | ||
import org.eclipse.sirius.components.collaborative.forms.api.RelatedElementsConfiguration; | ||
import org.eclipse.sirius.components.core.api.IEditingContext; | ||
import org.eclipse.sirius.components.core.api.IObjectService; | ||
import org.eclipse.sirius.components.forms.description.FormDescription; | ||
import org.springframework.stereotype.Service; | ||
|
||
/** | ||
* Used to create the related elements event processors. | ||
* | ||
* @author pcdavid | ||
*/ | ||
@Service | ||
public class RelatedElementsEventProcessorFactory implements IRepresentationEventProcessorFactory { | ||
|
||
private final IRelatedElementsDescriptionProvider relatedElementsDescriptionProvider; | ||
|
||
private final IObjectService objectService; | ||
|
||
private final List<IFormEventHandler> formEventHandlers; | ||
|
||
private final ISubscriptionManagerFactory subscriptionManagerFactory; | ||
|
||
private final IWidgetSubscriptionManagerFactory widgetSubscriptionManagerFactory; | ||
|
||
private final IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry; | ||
|
||
public RelatedElementsEventProcessorFactory(IRelatedElementsDescriptionProvider relatedElementsDescriptionProvider, IObjectService objectService, List<IFormEventHandler> formEventHandlers, | ||
ISubscriptionManagerFactory subscriptionManagerFactory, IWidgetSubscriptionManagerFactory widgetSubscriptionManagerFactory, | ||
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry) { | ||
this.relatedElementsDescriptionProvider = Objects.requireNonNull(relatedElementsDescriptionProvider); | ||
this.objectService = Objects.requireNonNull(objectService); | ||
this.formEventHandlers = Objects.requireNonNull(formEventHandlers); | ||
this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory); | ||
this.widgetSubscriptionManagerFactory = Objects.requireNonNull(widgetSubscriptionManagerFactory); | ||
this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry); | ||
} | ||
|
||
@Override | ||
public <T extends IRepresentationEventProcessor> boolean canHandle(Class<T> representationEventProcessorClass, IRepresentationConfiguration configuration) { | ||
return IFormEventProcessor.class.isAssignableFrom(representationEventProcessorClass) && configuration instanceof RelatedElementsConfiguration; | ||
} | ||
|
||
@Override | ||
public <T extends IRepresentationEventProcessor> Optional<T> createRepresentationEventProcessor(Class<T> representationEventProcessorClass, IRepresentationConfiguration configuration, | ||
IEditingContext editingContext) { | ||
if (IFormEventProcessor.class.isAssignableFrom(representationEventProcessorClass) && configuration instanceof RelatedElementsConfiguration) { | ||
RelatedElementsConfiguration relatedElementsConfiguration = (RelatedElementsConfiguration) configuration; | ||
|
||
// @formatter:off | ||
var objects = relatedElementsConfiguration.getObjectIds().stream() | ||
.map(objectId -> this.objectService.getObject(editingContext, objectId)) | ||
.flatMap(Optional::stream) | ||
.collect(Collectors.toList()); | ||
// @formatter:on | ||
if (!objects.isEmpty()) { | ||
FormDescription formDescription = this.relatedElementsDescriptionProvider.getFormDescription(); | ||
// @formatter:off | ||
FormCreationParameters formCreationParameters = FormCreationParameters.newFormCreationParameters(relatedElementsConfiguration.getId()) | ||
.editingContext(editingContext) | ||
.formDescription(formDescription) | ||
.objects(objects) | ||
.build(); | ||
// @formatter:on | ||
|
||
IRepresentationEventProcessor formEventProcessor = new FormEventProcessor(formCreationParameters, this.formEventHandlers, this.subscriptionManagerFactory.create(), | ||
this.widgetSubscriptionManagerFactory.create(), this.representationRefreshPolicyRegistry); | ||
|
||
// @formatter:off | ||
return Optional.of(formEventProcessor) | ||
.filter(representationEventProcessorClass::isInstance) | ||
.map(representationEventProcessorClass::cast); | ||
// @formatter:on | ||
} | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
...clipse/sirius/components/collaborative/forms/api/IRelatedElementsDescriptionProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 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.forms.api; | ||
|
||
import org.eclipse.sirius.components.forms.description.FormDescription; | ||
|
||
/** | ||
* Interface used to contribute the form to display for the "Related Elements" view. | ||
* | ||
* @author pcdavid | ||
*/ | ||
public interface IRelatedElementsDescriptionProvider { | ||
FormDescription getFormDescription(); | ||
} |
47 changes: 47 additions & 0 deletions
47
...a/org/eclipse/sirius/components/collaborative/forms/api/RelatedElementsConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 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.forms.api; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.UUID; | ||
|
||
import org.eclipse.sirius.components.collaborative.api.IRepresentationConfiguration; | ||
|
||
/** | ||
* The configuration used to create a related elements event processor. | ||
* | ||
* @author pcdavid | ||
*/ | ||
public class RelatedElementsConfiguration implements IRepresentationConfiguration { | ||
|
||
private static final String RELATED_PREFIX = "related:"; //$NON-NLS-1$ | ||
|
||
private final String formId; | ||
|
||
private final List<String> objectIds; | ||
|
||
public RelatedElementsConfiguration(List<String> objectIds) { | ||
this.objectIds = Objects.requireNonNull(objectIds); | ||
this.formId = UUID.nameUUIDFromBytes((RELATED_PREFIX + objectIds).getBytes()).toString(); | ||
} | ||
|
||
@Override | ||
public String getId() { | ||
return this.formId; | ||
} | ||
|
||
public List<String> getObjectIds() { | ||
return this.objectIds; | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
backend/sirius-components-collaborative-forms/src/main/resources/schema/form.graphqls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
= ADR-066 - Add a new "Related Elements" view | ||
|
||
== Context | ||
|
||
Capella provides a very useful __Semantic Browser_ view which gives end-users contextual informations about the currently selected element. | ||
When an element is selected this view displays 3 tree widgets: | ||
|
||
- _Referencing_: shows elements of interest that refer to the current selecion. | ||
- _Current_: shows elements directly associated to the current selection. | ||
- _Referenced_: shows elements of interest that the current selecion refers to. | ||
|
||
We want a similar view in Sirius Components that applications (like Sirius Web) can decide to intergrate (or not) in their workbench. | ||
It should be extensible so that the actual information displayed can be customized/extended for specific applications or domains. | ||
It should provide a default generic implementation that provides useful information for an arbirtary semantic element. | ||
|
||
== Decision | ||
|
||
We will provide a new _Related Elements_ view component that can be integrated into a workbench using a `WorkbenchViewContribution`: | ||
|
||
``` | ||
<WorkbenchViewContribution | ||
side="right" | ||
title="Related Elements" | ||
icon={<LinkIcon />} | ||
component={RelatedElementsView} | ||
/> | ||
``` | ||
|
||
This new view will behave almost exactly like the _Details_ view, in that it will display an arbitrary _Form_, synchronized with the (possibly multiple) selection. | ||
The only difference with the _Details_ view is that it will connect to a different (new) GraphQL subscription: | ||
|
||
``` | ||
// In form.graphqls | ||
extend type Subscription { | ||
propertiesEvent(input: PropertiesEventInput!): PropertiesEventPayload! // existing | ||
relatedElementsEvent(input: PropertiesEventInput!): PropertiesEventPayload! // added | ||
} | ||
``` | ||
|
||
=== Generic PropertiesWebSocketContainer | ||
|
||
To avoid duplicating too much frontend code, the existing `PropertiesWebSocketContainer` will be made more generic and take the name of the GraphQL subscription to use as an argument. | ||
|
||
The two concrete views (_Details_ and _Related Elements_) will use this new generic component like this: | ||
|
||
``` | ||
// Replaces the old, hard-coded PropertiesWebSocketContainer | ||
export const DetailsView = (props: WorkbenchViewComponentProps) => ( | ||
<PropertiesWebSocketContainer {...props} subscriptionName={'propertiesEvent'} /> | ||
); | ||
|
||
export const RelatedElementsView = (props: WorkbenchViewComponentProps) => ( | ||
<PropertiesWebSocketContainer {...props} subscriptionName={'relatedElementsEvent'} /> | ||
); | ||
``` | ||
|
||
Applications which used to include the `PropertiesWebSocketContainer` component will need to be updated to use the new `DetailsView` component instead. | ||
|
||
NOTE: The `PropertiesWebSocketContainer` could be renamed with a more generic name, like `FormWebSocketContainer`, or more simply `FormBasedView` to reflect its more generic nature, but this is defered for later to reduce the impacts of this new feature. | ||
|
||
This change requires modifications in the `GQL*` types used by `PropertiesWebSocketContainer` as they currently hard-code in their structure the fact that the form data is inside a `propertiesEvent` subscription. | ||
Because the now generic/configurable name can not be encoded in the static type structure, the corresponding state machine must be modified so that `HandleSubscriptionResultEvent` takes the `GQLPropertiesEventPayload` directly as a `result`, instead of a `SubscriptionResult<GQLPropertiesEventSubscription>` where `GQLPropertiesEventSubscription` hard-code the `propertiesEvent` name. | ||
|
||
The GraphQL subscription used to be static (known at compile-time), and use the `gql` template literal tag from `'graphql-tag'` to parse it. | ||
Because the text of the subscription is now parameterized by a string, we must use the `gql` _function_ instead (as already done in `ExplorerWebSocketContainer` with `getTreeEventSubscription`). | ||
|
||
The `RepresentationsWebSocketContainer` is also impacted by this change, as it uses the GraphQL fragments defined in `FormEventFragments.ts`. | ||
|
||
=== IRelatedElementsDescriptionProvider | ||
|
||
On the backend, a new `RelatedElementsEventProcessorFactory` (which implements `IRepresentationEventProcessorFactory`) will be added. | ||
To keep things simple in the first version of this feature, we will assume there is a single, system-wide `IRelatedElementsDescriptionProvider` bean which provides the `FormDescription` to use for this view: | ||
|
||
``` | ||
public interface IRelatedElementsDescriptionProvider { | ||
FormDescription getFormDescription(); | ||
} | ||
``` | ||
|
||
Future versions may provide some ways to customize and/or extend the content of the new view for different semantic elements. | ||
|
||
Applications that want to use the new view will need to provide a single bean implementing this interface. | ||
|
||
=== Default implementation | ||
|
||
Sirius Web will provide a default implementation named `DefaultRelatedElementsDescriptionProvider`. | ||
|
||
It will display 3 _Tree_ widgets inside a single Group configured using the new `displayMode = TOGGLEABLE_AREAS`. | ||
|
||
* A tree named "Incoming", which displays all the elements that reference the current element. | ||
These referecing elements are organized into folders/categories that correspond to the (EMF) reference through which they reference the element. | ||
It is possible for a referencing element to appear in multiple categories if it references the current element multiple times. | ||
* A tree named "Current" with the following folders/categories: | ||
|
||
- "Parent", with a single node for the parent of the current element | ||
- One folder per containment reference (named after the reference) with all the direct children of the current element owned through that reference | ||
|
||
* A tree name "Outgoing", which displays all the elements referenced by the current element (exluding its children). | ||
As for the "Incoming" tree, the elements are organized into categories that correspond to the EMF reference. | ||
|
||
== Status | ||
|
||
Accepted. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 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 { FormBasedView } from 'properties/FormBasedView'; | ||
import React from 'react'; | ||
import { WorkbenchViewComponentProps } from 'workbench/Workbench.types'; | ||
|
||
export const DetailsView = (props: WorkbenchViewComponentProps) => ( | ||
<FormBasedView {...props} subscriptionName="propertiesEvent" /> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.