-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[doc] Add initial ADR for the selection dialog as a tree #3723
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
= [ADR-155] Make it possible to display the semantic elements as a tree in the Selection Dialog | ||
|
||
== Context | ||
|
||
We have restored the previous deactivated Selection Dialog in the context of the ADR: _[ADR-153] Restore the Selection Dialog support in diagrams | ||
_. | ||
|
||
We want now to improve this Selection Dialog. | ||
|
||
The Selection dialog displayed the candidates elements (returned by the `candidatesExpression` in the `SelectionDialogDescription`) as a flat list without any information about the hierarchical structure. | ||
|
||
Since the selection dialog is intended to be used to select semantic elements, it will be necessary to have the ability to display them as they are in their structure (as a tree). | ||
|
||
image:images/155/currentSelectionDialog.png[Current Selection Dialog, 50%] | ||
|
||
=== Current behavior | ||
|
||
The Selection dialog opens a subscription to the selection representation. The `SelectionRefreshedEventPayload` returns the Selection that only owns a list of objects to display. | ||
|
||
Here is the current GraphQL API: | ||
|
||
|
||
``` | ||
type SelectionRefreshedEventPayload { | ||
id: ID! | ||
selection: Selection! | ||
} | ||
|
||
type Selection implements Representation { | ||
id: ID! | ||
metadata: RepresentationMetadata! | ||
targetObjectId: String! | ||
message: String | ||
objects: [SelectionObject!]! | ||
} | ||
|
||
type SelectionObject { | ||
id: ID! | ||
label: String! | ||
iconURL: [String!]! | ||
} | ||
``` | ||
|
||
== Decision | ||
|
||
=== Preferred option | ||
|
||
==== View model | ||
|
||
The specifier will choose whether the objects returned by the candidates expression will be displayed as a tree or as a flat list. | ||
|
||
The `SelectionDialogDescription` from the Diagram View model will have an additional boolean attributes: | ||
|
||
* `displayedAsTree`: to indicate whether the dialog layout should be a tree. | ||
|
||
|
||
==== Backend and GraphQL API | ||
|
||
If the displayedAsTree is true, we will rely on the TreeRepresentation instead of the current SelectionRepresentation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How will the specifier be able to configure that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For me, the specifier will only indicate by a boolean (a checkbox in the studio) in the SelectionDescription whether he want to display the selectable element as a list or as a tree. |
||
|
||
We will need to contribute a new `IEditingContextRepresentationDescriptionProvider` as the `ModelBrowsersDescriptionProvider` for the Reference widget. | ||
|
||
This `DescriptionProvider` will rely on the `SelectionDialogDescription` to compute the `TreeDescription`. | ||
|
||
The GraphQL API will evolve to handle the layout information: | ||
|
||
``` | ||
type Selection implements Representation { | ||
id: ID! | ||
metadata: RepresentationMetadata! | ||
targetObjectId: String! | ||
message: String | ||
displayedAsTree: Boolean! | ||
objects: [SelectionObject!]! | ||
Comment on lines
+73
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to reuse a tree subscription instead of the raw selection subscription with its list of objects. I don't understand why this needs to be modified and why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok with that but I still have a problem with the "message" I agree to avoid opening a subscription toward the SelectionRepresentation if the SelectionDialog is intended to represent selectable elements as a tree (in this case we will rely on the TreeView). The message specified by the specifier is for now not interpreted but the SelectionDescription java pojo code relies on a messageProvider (Function<VariableManager, String>) so it could be interpreted in the future. So in this case, I'm not sure what I should do to compute the dialog message which is common for both flat and tree representations. Should I provide the displayAsTree and the message statically by passing them in the graphQL API : instead of :
We will have :
|
||
} | ||
``` | ||
|
||
|
||
==== Tree computation Algorithm | ||
|
||
Starting from objects returned by the candidates expression, we will compute all the ancestors hierarchy until we reach the root document. | ||
|
||
Comment on lines
+79
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will use the tree subscription which let the specifier define how the tree structure is organized. We won't define any magic algorithm to create a tree, it's the plain old tree representation which can be organized any way we want. It may not follow EMF's EObject#eContents topological structure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea is to describe how we will represent selectable elements. |
||
For example, supposing we have the following semantic model: | ||
|
||
``` | ||
Root | ||
|_ A | ||
|_ D | ||
|_ H | ||
|_ E | ||
|_ B | ||
|_ F | ||
|_ C | ||
|_ G | ||
``` | ||
|
||
If the candidates expression return three elements: D,H and F, then We will display these elements as follow: | ||
|
||
``` | ||
Root | ||
|_ A | ||
|_ (D) | ||
|_ (H) | ||
|_ B | ||
|_ (F) | ||
``` | ||
|
||
==== Frontend | ||
|
||
Elements that are not selectable (out of the computed candidates set) will by faded in the same way than the reference widget semantic browser do: | ||
|
||
image:images/155/referenceWidgetSemanticBrowser.png[Reference Widget Semantic Browser, 50%] | ||
|
||
The frontend `SelectionDialog` component will be modified to handle both flat and tree layouts. | ||
|
||
If the value of `displayedAsTree` is false, then we keep the current behavior. | ||
|
||
If the value of `displayedAsTree` is true, then we will use the `TreeView` component to display the content. We will have something similar to the following code: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, and if it's not true, we will fallback on the existing selection subscription which means that this displayedAsTree boolean cannot be part of the selection subscription in the first place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #3723 (comment) |
||
|
||
``` | ||
<SelectionContext.Provider | ||
value={{ | ||
selection: [], | ||
setSelection: setDialogSelection, | ||
}}> | ||
<TreeView | ||
editingContextId={editingContextId} | ||
readOnly={true} | ||
treeId={`selectionDialog://?targetObjectId=${encodeURIComponent(targetObjectId}&descriptionId=${encodeURIComponent(descriptionId)}`} | ||
enableMultiSelection={enableMultiSelection} | ||
synchronizedWithSelection={true} | ||
activeFilterIds={[]} | ||
/> | ||
</SelectionContext.Provider> | ||
``` | ||
|
||
We need to provide a `SelectionContext` to capture the selection from the `TreeView`. | ||
|
||
We need the layout information (tree or flat) and the message in both case. In the case of the tree layout, we will have two subscriptions: | ||
* The one two retrieve the SelectionDialog (to have the message) | ||
* The one for the Tree representation. | ||
|
||
Note that for now, the message is not interpreted but the `SelectionDescription#messageProvider` is already returning a function taking the variableManager as parameter. | ||
That why we can't provide the message directly from the graphQL query (by modifying the `SingleClickOnDiagramElementTool` GraphQL API for instance) | ||
|
||
=== Second option | ||
|
||
The second option would consist in changing the current Selection Dialog representation to handle both flat and tree layout. | ||
|
||
That would mean computing the tree structure in the backend and providing it to the frontend with the containment information. | ||
|
||
The frontend would handle both the flat and tree layout. | ||
|
||
The option has finally not been retained to reuse the existing `TreeView`. | ||
|
||
|
||
== Status | ||
|
||
Work in progress | ||
|
||
== Consequences | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
= [ADR-156] Make it possible to display the semantic elements as a tree in the Selection Dialog | ||
|
||
== Context | ||
|
||
We have restored the previous deactivated Selection Dialog in the context of the ADR: _[ADR-152] Reactivate the Selection Dialog Tool_. | ||
|
||
We want now to improve this Selection Dialog. | ||
|
||
The Selection dialog displayed the candidates elements (returned by the `candidatesExpression` in the `SelectionDialogDescription`) as a flat list without any information about the hierarchical structure. | ||
|
||
Since the selection dialog is intended to be used to select semantic elements, it will be necessary to have the ability to display them as they are in their structure (as a tree). | ||
|
||
image:images/153/currentSelectionDialog.png[Current Selection Dialog, 50%] | ||
|
||
=== Current behavior | ||
|
||
The Selection dialog opens a subscription to the selection representation. The `SelectionRefreshedEventPayload` returns the Selection that only owns a list of objects to display. | ||
|
||
Here is the current GraphQL API: | ||
|
||
|
||
``` | ||
type SelectionRefreshedEventPayload { | ||
id: ID! | ||
selection: Selection! | ||
} | ||
|
||
type Selection implements Representation { | ||
id: ID! | ||
metadata: RepresentationMetadata! | ||
targetObjectId: String! | ||
message: String | ||
objects: [SelectionObject!]! | ||
} | ||
|
||
type SelectionObject { | ||
id: ID! | ||
label: String! | ||
iconURL: [String!]! | ||
} | ||
``` | ||
|
||
== Decision | ||
|
||
=== Preferred option | ||
|
||
==== View model | ||
|
||
The specifier will choose whether the objects returned by the candidates expression will be displayed as a tree or as a flat list. | ||
|
||
The `SelectionDialogDescription` from the Diagram View model will have two additional boolean attributes: | ||
|
||
* `displayedAsTree`: to indicate whether the dialog layout should be a tree. | ||
* `expandedAtOpening`: to indicate if the tree should be expanded by default (that means all tree items are expanded at opening) | ||
|
||
==== Backend and GraphQL API | ||
|
||
In addition, the Selection computed by the `SelectionRender` by the server will now return the containment information. | ||
|
||
Since the tree depth is not known by the frontend beforehand, the backend needs to return the whole tree items in a flat way. | ||
|
||
The GraphQL subscription query will thus have a fixed depth. The containment information will be owned by a field called `parentId`. | ||
|
||
To do so, we will keep the same GraphQL structure but with the following changes: | ||
|
||
* A `SelectionObject` will have a `parentId` field (optional), that will be a reference to another `SelectionObject#id` field. | ||
* A `SelectionObject` will contain the information whether it can be selected or not in order to differentiate elements from the candidatesExpression to the hierarchical nodes. | ||
* The `Selection` will also contains the information whether the dialog should be displayed as a tree or not and if we should expand all nodes at opening. | ||
|
||
Thus, the GraphQL API will evolved as following: | ||
|
||
``` | ||
type Selection implements Representation { | ||
id: ID! | ||
metadata: RepresentationMetadata! | ||
targetObjectId: String! | ||
message: String | ||
objects: [SelectionObject!]! | ||
displayedAsTree: Boolean! | ||
expandedAtOpening: Boolean! | ||
} | ||
|
||
type SelectionObject { | ||
id: ID! | ||
label: String! | ||
iconURL: [String!]! | ||
parentId: String | ||
isSelectable: Boolean! | ||
} | ||
``` | ||
|
||
==== Tree computation Algorithm | ||
|
||
Starting from objects returned by the candidates expression, we will compute all the ancestors hierarchy until we reach the root document. | ||
|
||
For example, supposing we have the following semantic model: | ||
|
||
``` | ||
Root | ||
|_ A | ||
|_ D | ||
|_ H | ||
|_ E | ||
|_ B | ||
|_ F | ||
|_ C | ||
|_ G | ||
``` | ||
|
||
If the candidates expression return three elements: D,H and F, then We will display these elements as follow: | ||
|
||
``` | ||
Root | ||
|_ A | ||
|_ (D) | ||
|_ (H) | ||
|_ B | ||
|_ (F) | ||
``` | ||
|
||
==== Frontend | ||
|
||
Elements that are not selectable (out of the computed candidates set) will by faded in the same way than the reference widget semantic browser do: | ||
|
||
image:images/153/referenceWidgetSemanticBrowser.png[Reference Widget Semantic Browser, 50%] | ||
|
||
The frontend `SelectionDialog` component will be modified to handle both flat and tree layouts. | ||
|
||
If the value of `displayedAsTree` is false, then we keep the current behavior. | ||
|
||
If the value of `displayedAsTree` is true, then we will represent the structure returned by the backend in a similar way than the `TreePropertySection` component. | ||
|
||
We will rely on the MaterialUI `TreeItem` and `TreeView` in the same way than the internal `TreeItem` component from the `TreePropertySection`: | ||
|
||
``` | ||
const childNodes = nodes.filter((childNode) => childNode.parentId === node.id); | ||
return ( | ||
<MuiTreeItem nodeId={node.id} label={label}> | ||
{childNodes.map((childNode) => ( | ||
<TreeItem | ||
node={childNode} | ||
nodes={nodes} | ||
key={childNode.id} | ||
readOnly={readOnly} | ||
aria-role="treeitem" | ||
editingContextId={editingContextId} | ||
formId={formId} | ||
widgetId={widgetId} | ||
/> | ||
))} | ||
</MuiTreeItem> | ||
); | ||
``` | ||
|
||
If the Selection is refreshed by the backend, following a semantic change from another client for instance, a new Selection from the subscription will be received by the SelectionDialog and trigger the component rerendering. | ||
|
||
If the end-user has changed the expanded state, we want to keep them expanded in that situation. | ||
|
||
To do so, We will modify the SelectionDialog state machine as follow: | ||
|
||
* A new `expandedSelectionObjectIds : string[]` will be added in the `SelectionDialogContext`. | ||
* A new event `HandleExpandUpdatedEvent` = { type: 'HANDLE_EXPAND_UPDATED'; expandedObjectId: string }; This event will add or remove the expandedObjectId from the expandedSelectionObjectIds array. | ||
|
||
A TreeItem will be expanded if: | ||
|
||
* The expandedAtOpening is activated: in that case, the `expandedSelectionObjectIds` will be initialized with all selectedObject ids. | ||
* The user expanded the item manually. | ||
|
||
=== Second option | ||
|
||
The second option but not the preferred one, consists in relying on the TreeRepresentation. | ||
|
||
With this option, we would need to contribute a new `IEditingContextRepresentationDescriptionProvider` as the `ModelBrowsersDescriptionProvider` for the Reference widget. | ||
|
||
This DescriptionProvider would rely on the SelectionDialogDescription to compute the TreeDescription. | ||
|
||
This option appears to be more complicated to implement. In addition, the first option seems to be a good answer to the Selection dialog need. | ||
|
||
|
||
== Status | ||
|
||
Work in progress | ||
|
||
== Consequences | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be enough? How can you figure out how to display a simple list as a tree? We should probably hardcore a TreeDescription in the view converter for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure to understand. For me, we will have an hard-coded TreeDescription but provider by an IEditingContextRepresentationDescriptionProvider ?