-
Notifications
You must be signed in to change notification settings - Fork 50
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 support for styled labels in view model for trees #3989
base: master
Are you sure you want to change the base?
[doc] Add support for styled labels in view model for trees #3989
Conversation
b6df9a5
to
4cbaabd
Compare
doc/adrs/158_add_support_for_styled_labels_in_view_model_for_trees.adoc
Outdated
Show resolved
Hide resolved
doc/adrs/158_add_support_for_styled_labels_in_view_model_for_trees.adoc
Outdated
Show resolved
Hide resolved
doc/adrs/158_add_support_for_styled_labels_in_view_model_for_trees.adoc
Outdated
Show resolved
Hide resolved
The first additional owned property (``stylePalette``) holds all text styles that are defined in this tree specification. | ||
This is a sort of catalog of all defined style that could be used (or not) for a particular tree item label (or one of its part). | ||
We do prefer wrap all text styles in a dedicated property to avoid to mix them with other part of the tree specification (such as menu actions in a further work). | ||
A similar approach has been followed for storing colors in a palette inside diagrams specification. | ||
This property will be automatically created for each tree specification. | ||
|
||
The second owned property (``labelStyles``) is the actual set of styles that are used for displaying labels in this tree specification. | ||
|
||
``` | ||
StylePalette { | ||
textStyles : TextStyleDescription [0..*] | ||
} |
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.
My first gripe with this is that none of this is particularly relevant to sole the problem described. It does not matter at all to support styled labels. It may be useful but it's definitely not the heart of the issue nor required. This is completely optional, start the ADR by the core of the solution.
The first major problem is defining the solution not how to organize it.
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 what you mean?
For me the purpose of the "advanced" ADR was to agree on the technical stuff now, so afterward we could be autonomous with Florian?
|
||
=== Tree view DSL | ||
|
||
Currently, the tree view DSL, ``TreeDescription`` only has the ``treeItemLabelExpression`` that returns the string to display regarding the given ``self`` element. |
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 you really make that work while keeping a single treeItemLabelExpression
?
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.
The idea was that this expression would be used if ConditionalStyle predicate returns false.
I think in most use cases, users would not define style for their items and use the default style provided by the appplication (maybe I'm wrong). So by having this fallback mechanism it would reduce the complexity of defining a TreeDescription.
} | ||
|
||
StyledLabelFragment { | ||
labelExpression: InterpretedExpression<string> |
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.
Why is there another label expression here? I mean I understand this one, not the other one DiagramDescription#treeItemLabelExpression
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.
See above
The styles applied to labels (or portions of label) are named and conditional and they hold an ordered list of styled label fragments. | ||
In case the evaluation of its ``conditionExpression`` returns ``false`` no one of embedded fragments will be considered and an unstyled label will be used using the ``treeItemLabelExpression`` result. | ||
If ``conditionExpression`` returns ``true``, fragments are considered in the specified order. | ||
Each of them specifies the style of a sub-part of the label. | ||
The ``labelExpression`` of the fragment should return the string itself and the style to apply is given through the reference of an actual TextStyleDescription through the ``style`` property. |
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 don't think that it can realistically work for a couple of reason:
- I would need to both define a label and another version of the label in case I want to have some fragments
- This is not dynamic enough to be usable
- You can't just consider the order the fragment like that, it won't work, you can't really sort all. The potential use case of a metamodel using one list.
Consider some my current use cases with the Papaya metamodel. It's a bit like a metamodel of the Java language. How can I, with your API create a description to let me specific the color for those examples:
Method types
- I have some operations with parameters, there can be any number of parameters in the operations of my models from 0 to god knows how many.
- I want the type of each value and the return type of the method in blue
- I want to support displaying the parenthesis in grey
Keyword and generic types
- I have classes, interfaces and records which can have generic types
- They can have any number of generic type whatsoever
- I want to support displaying keywords in purple
- I want to support displaying generic types in light blue
- I want to support displaying
<
and>
in grey
And finally, I don't want to manually define all the potential combinations of all the potential use cases. So in the case of my operations, I don't want to create a fragment for all the potential number of parameters in an operations that can appear. Just try to order all the fragments to make it work, it's not viable.
Unless I missed something, and I would be happy to be proved wrong, this approach cannot possibly work beyond basic use cases. With this approach based on conditional style, you are taking an existing solution (a hammer) and you are looking for a nail but it won't work.
I think you need to start using complex examples as the target to reach and stay focused on how to express potential solutions. You can't assume that the specifier will know at build time the number of fragments that will be required, models expressed by end users are too complex for such assumptions. You may need to start taking inspiration from our work on dynamic mappings in the form DSL which encountered the same issue. You could end up with something like this:
- A new field
TreeDescription#labelDescriptions: LabelDescription[1..*]
TreeItemLabelDescription {
name: Identifier
preconditionExpression: InterpretedExpression<boolean>
children: TreeItemLabelElementDescription[1..*] // TreeItemLabelElementDescription is abstract
}
ForTreeItemLabelElementDescription extends TreeItemLabelElementDescription {
iterator: String
iterableExpression: InterpretedExpression<List<Object>>
children: TreeItemLabelElementDescription[1..*]
}
IfTreeItemLabelElementDescription extends TreeItemLabelElementDescription {
predicateExpression: InterpretedExpression<boolean>
children: TreeItemLabelElementDescription[1..*]
}
TreeItemLabelFragmentDescription extends TreeItemLabelElementDescription {
labelExpression: string
colorExpression: InterpretedExpression<string>
// All the other properties, it's not that relevant
}
With this, you could end up supporting the operation example like that:
TreeDescription {
labelDescriptions: [
LabelDescription {
name: "Operation"
preconditionExpression: "aql:self.eClass() = papaya::Operation"
children: [
TreeItemLabelFragmentDescription {
labelExpression: "aql:self.name"
colorExpression: "black"
},
TreeItemLabelFragmentDescription {
labelExpression: "("
colorExpression: "grey"
},
ForTreeItemLabelElementDescription {
iterator: "parameter"
iterableExpression: "aql:self.parameters"
children: [
TreeItemLabelFragmentDescription{
labelExpression: "aql:parameter.name",
colorExpression: "black"
},
TreeItemLabelFragmentDescription{
labelExpression: "aql:parameter.type.name",
colorExpression: "blue"
},
IfTreeItemLabelElementDescription{
predicateExpression: "aql:self.parameters.indexOf(parameter) <> (self.parameters.size() -1))
children: [
TreeItemLabelFragmentDescription{
labelExpression: ","
colorExpression: "black"
}
]
},
]
},
TreeItemLabelFragmentDescription {
labelExpression: ")"
colorExpression: "grey"
},
TreeItemLabelFragmentDescription {
labelExpression: ":"
colorExpression: "black"
},
TreeItemLabelFragmentDescription {
labelExpression: "aql:self.type.name"
colorExpression: "blue"
},
]
}
]
}
(I know, I'm not considering spaces but it's simple to add)
Now unless you can prove me that your solution can work to create the labels that I have given you as an example, prove me that my solution here cannot work even for my most complex examples. The first thing I care about is not creating a palette of TextStyle, it's completely optional, I want a solution which can work for complex use cases.
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 totally agree with you solution for complex labels. But initial the Form DSL dit not provide the dynamic mapping at the begining so this solution would have been a first step (and sufficient for our use case). Afteward, we could have added the dynamic item to express the if and loop feature.
I agree that the complex example should be taken in consideration now to avoid any API break in the future. So you examples are good to keep in mind but it was not our intention to handle them as a first step.
Do you think that a first stage that do not handle complexe example as your is acceptable, or should we implement it now? (I'm affraid for my budget)
As a first step, we could introduce an abstract class that would allow us to extend with dynamic concepts afterwards?
Moreover, in our solution we add the capacity to express a meaninfull style. For example, as a specifier I want to create a Read Only style that display a text in italic and grey (or any another combination). Then I want to be able to reuse that style in many different scenario. The fact to link the the precondition, labe expression and the definition of the style make them not really reusable. It would mean for the specifier to dupplicate many time the colorExpression, isItalicExpresion and so on.
For example, in your example the "Black" style is repeated a lot of time. With our solution we would have a TextStyleDescription name "Default Style" with difine this "Black Color". Then it would be referenced any time needed.
=== Backend | ||
|
||
As far as ``isBoldExpression`` and ``isItalicExpression`` expressions are concerned, we need to add two boolean flags in the class ``StyledStringFragmentStyle`` to handle those style features. | ||
``org.eclipse.sirius.components.emf.services.StyledStringConverter`` should also be updated to set those flags to ``false`` as the default value since this features are not present in EMF edit styles. | ||
|
||
The graphQL type ``StyledStringFragmentStyle`` in trees/tree.graphqls should be updated with new flags to be able to retrieve those style features in the frontend code. | ||
|
||
``ViewTreeDescriptionConverter`` should be updated to take into account the ``treeItemStyledLabel`` property from the view description. | ||
The function passed to the ``treeItemLabelProvider`` of the tree description should be changed to return the correct ``StyledString`` according to the evaluation of the ``conditionExpression`` of the ``treeItemStyledLabel``. | ||
If the condition is not valid, we need to build the StyledString from the ``treeItemLabelExpression`` evaluation, otherwise it is built using contained fragments. | ||
|
||
=== Frontend | ||
|
||
The type ``GQLStyledStringFragmentStyle`` should be updated to reflect the change in the graphQL type in the backend code. | ||
The StyledLabel react component should be updated to handle new bold and italic style contained in the fragments. | ||
|
||
== Status | ||
|
||
Work in progress | ||
|
||
== Consequences | ||
|
||
The ``org.eclipse.sirius.components.emf.services.StyledStringConverter`` class which is in charge of converting an EMF style into a Sirius web one might have to be updated in the future. | ||
We suspect that the URI of the font may contain flags for expressing the bold or italic style. | ||
If this is verified, extraction of that information from the URI to the new flags should have to be made. |
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.
All this is fine and nice but completely secondary to bring support for existing styled labels in the tree DSL. That's about improving what exists today, ok. It's an entirely different matter.
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.
Yes we could have created a second ADR for those but we wanted you to give us all your feedback in one time to reduce the loop cost.
This is something that we have solved already with the reusability of NodeDescription as children. For example for a component diagram where components can be children of themselves. But there is one critical difference in our case, we need to control the order which is not the case in a diagram (nobody cares about the order of both NodeDescription#childrenDescriptions and NodeDescription#reusedChildNodeDescriptions). So the solution needs to be different, something like this maybe:
to let us create something like that:
This would work. Since it should allow us to reuse pretty much anything, I don't think we even need a palette for styles at all. |
With this latest solution, I can:
Is there any use case that I'm missing? |
No I think you got it all, but do you think that we could split this development effort in several steps? |
We are going to rewrite this ADR taking your remarks in consideration but I need to understand if you are expecting us to implements all those features or if we could split the effort to stop when we have everthing we need; or you want all those feature in one PR? |
4cbaabd
to
44c7544
Compare
I rewrote the ADR to fit with the comments:
|
|
||
TreeItemLabelFragmentDescription extends TreeItemLabelElementDescription { | ||
labelExpression: String | ||
style: TextStyleDescription [0..1] |
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.
Please specifiy it is non containment reference
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.
Done
|
||
=== Usage example | ||
|
||
The following style description handles the operation with argument' and returned types in blue. |
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.
typo after argument
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.
Done
children: [ | ||
TreeItemLabelFragmentDescription { | ||
labelExpression: "aql:self.name" | ||
style: TextStyleDescription { |
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 guess here it would be more a reference to a BackLabelStyle TextStyleDescription
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.
Done
44c7544
to
8168a8c
Compare
468303e
to
87af093
Compare
Signed-off-by: Jerome Gout <[email protected]>
87af093
to
b8320a3
Compare
Pull request template
General purpose
What is the main goal of this pull request?
Project management
priority:
andpr:
labels been added to the pull request? (In case of doubt, start with the labelspriority: low
andpr: to review later
)area:
,difficulty:
,type:
)CHANGELOG.adoc
been updated to reference the relevant issues?CHANGELOG.adoc
? (Including changes in the GraphQL API)CHANGELOG.adoc
? For example indoc/screenshots/2022.5.0-my-new-feature.png
Architectural decision records (ADR)
[doc]
?CHANGELOG.adoc
?Dependencies
CHANGELOG.adoc
?CHANGELOG.adoc
?Frontend
This section is not relevant if your contribution does not come with changes to the frontend.
General purpose
Typing
We need to improve the typing of our code, as such, we require every contribution to come with proper TypeScript typing for both changes contributing new files and those modifying existing files.
Please ensure that the following statements are true for each file created or modified (this may require you to improve code outside of your contribution).
useMutation<DATA_TYPE, VARIABLE_TYPE>(…)
useQuery<DATA_TYPE, VARIABLE_TYPE>(…)
useSubscription<DATA_TYPE, VARIABLE_TYPE>(…)
useMachine<CONTEXT_TYPE, EVENTS_TYPE>(…)
useState<STATE_TYPE>(…)
?.
(if the GraphQL API specifies that a field cannot benull
, do not treat it has potentiallynull
for example)let diagram: Diagram | null = null;
)Backend
This section is not relevant if your contribution does not come with changes to the backend.
General purpose
Architecture
Review
How to test this PR?
Please describe here the various use cases to test this pull request