From 76ccd1f59925315258814d2c4bd5cf1a53f55598 Mon Sep 17 00:00:00 2001 From: Pierre-Charles David Date: Wed, 31 May 2023 09:19:05 +0200 Subject: [PATCH] [1988] Add support for optional help text on widgets Bug: https://github.com/eclipse-sirius/sirius-components/issues/1988 Signed-off-by: Pierre-Charles David --- CHANGELOG.adoc | 26 + doc/adrs/103_help_expressions.adoc | 112 +++++ doc/images/Widget_Help_Tooltip.png | Bin 0 -> 12530 bytes ...wFormDescriptionEditorConverterSwitch.java | 158 +++--- .../src/BarChartWidget.tsx | 19 +- .../src/ButtonWidget.tsx | 19 +- .../src/CheckboxWidget.tsx | 17 +- .../src/CustomWidget.tsx | 15 +- .../src/FlexboxContainerWidget.tsx | 41 +- .../src/ImageWidget.tsx | 19 +- .../src/LabelWidget.tsx | 17 +- .../src/LinkWidget.tsx | 41 +- .../src/ListWidget.tsx | 17 +- .../src/MultiSelectWidget.tsx | 17 +- .../src/PieChartWidget.tsx | 20 +- .../src/RadioWidget.tsx | 17 +- .../src/RichTextWidget.tsx | 19 +- .../src/SelectWidget.tsx | 17 +- .../src/TextAreaWidget.tsx | 17 +- .../src/TextfieldWidget.tsx | 17 +- .../forms/dto/HelpTextRequestInput.java | 25 + .../forms/dto/HelpTextSuccessPayload.java | 25 + .../handlers/HelpTextRequestEventHandler.java | 92 ++++ .../src/main/resources/schema/form.graphqls | 55 ++- .../FormDescriptionHelpTextDataFetcher.java | 74 +++ .../form/WidgetHasHelpTextDataFetcher.java | 79 +++ .../form/WidgetIconURLDataFetcher.java | 52 +- .../components/forms/AbstractWidget.java | 9 +- .../sirius/components/forms/Button.java | 10 +- .../sirius/components/forms/ChartWidget.java | 13 +- .../sirius/components/forms/Checkbox.java | 13 +- .../components/forms/FlexboxContainer.java | 20 +- .../sirius/components/forms/Image.java | 13 +- .../sirius/components/forms/LabelWidget.java | 11 +- .../eclipse/sirius/components/forms/Link.java | 11 +- .../eclipse/sirius/components/forms/List.java | 13 +- .../sirius/components/forms/MultiSelect.java | 13 +- .../sirius/components/forms/Radio.java | 13 +- .../sirius/components/forms/RichText.java | 13 +- .../sirius/components/forms/Select.java | 16 +- .../sirius/components/forms/Textarea.java | 13 +- .../sirius/components/forms/Textfield.java | 13 +- .../components/forms/ToolbarAction.java | 14 +- .../sirius/components/forms/TreeWidget.java | 13 +- .../forms/components/ButtonComponent.java | 5 +- .../components/ChartWidgetComponent.java | 5 +- .../forms/components/CheckboxComponent.java | 5 +- .../forms/components/ImageComponent.java | 5 +- .../components/LabelWidgetComponent.java | 5 +- .../forms/components/LinkComponent.java | 5 +- .../forms/components/ListComponent.java | 6 +- .../components/MultiSelectComponent.java | 5 +- .../forms/components/RadioComponent.java | 5 +- .../forms/components/RichTextComponent.java | 3 + .../forms/components/SelectComponent.java | 5 +- .../forms/components/TextareaComponent.java | 5 +- .../forms/components/TextfieldComponent.java | 5 +- .../components/ToolbarActionComponent.java | 5 +- .../forms/components/TreeComponent.java | 15 +- .../AbstractWidgetDescription.java | 8 +- .../forms/description/ButtonDescription.java | 10 +- .../description/ChartWidgetDescription.java | 10 +- .../description/CheckboxDescription.java | 10 +- .../FlexboxContainerDescription.java | 10 +- .../forms/description/ImageDescription.java | 10 +- .../forms/description/LabelDescription.java | 10 +- .../forms/description/LinkDescription.java | 10 +- .../forms/description/ListDescription.java | 10 +- .../description/MultiSelectDescription.java | 10 +- .../forms/description/RadioDescription.java | 10 +- .../description/RichTextDescription.java | 10 +- .../forms/description/SelectDescription.java | 10 +- .../description/TextareaDescription.java | 10 +- .../description/TextfieldDescription.java | 10 +- .../forms/description/TreeDescription.java | 10 +- .../forms/elements/ButtonElementProps.java | 16 +- .../elements/ChartWidgetElementProps.java | 17 +- .../forms/elements/CheckboxElementProps.java | 17 +- .../FlexboxContainerElementProps.java | 17 +- .../forms/elements/ImageElementProps.java | 17 +- .../elements/LabelWidgetElementProps.java | 17 +- .../forms/elements/LinkElementProps.java | 17 +- .../forms/elements/ListElementProps.java | 17 +- .../elements/MultiSelectElementProps.java | 17 +- .../forms/elements/RadioElementProps.java | 17 +- .../forms/elements/RichTextElementProps.java | 17 +- .../forms/elements/SelectElementProps.java | 17 +- .../forms/elements/TextareaElementProps.java | 17 +- .../forms/elements/TextfieldElementProps.java | 17 +- .../elements/ToolbarActionElementProps.java | 16 +- .../forms/elements/TreeElementProps.java | 17 +- .../forms/renderer/FormElementFactory.java | 81 +++- .../src/form/FormEventFragments.ts | 1 + .../src/form/FormEventFragments.types.ts | 1 + .../ButtonPropertySection.tsx | 12 +- .../ChartWidgetPropertySection.tsx | 18 +- .../ChartWidgetPropertySection.types.ts | 6 +- .../CheckboxPropertySection.tsx | 9 +- .../FlexboxContainerPropertySection.tsx | 4 +- .../src/propertysections/HelpTooltip.tsx | 96 ++++ .../src/propertysections/HelpTooltip.types.ts | 37 ++ .../propertysections/ImagePropertySection.tsx | 6 +- .../ImagePropertySection.types.ts | 4 +- .../LabelWidgetPropertySection.tsx | 16 +- .../LabelWidgetPropertySection.types.ts | 4 +- .../propertysections/LinkPropertySection.tsx | 15 +- .../LinkPropertySection.types.ts | 4 +- .../propertysections/ListPropertySection.tsx | 11 +- .../MultiSelectPropertySection.tsx | 11 +- .../src/propertysections/PropertySection.tsx | 37 +- .../propertysections/PropertySectionLabel.tsx | 12 +- .../PropertySectionLabel.types.ts | 8 +- .../propertysections/RadioPropertySection.tsx | 11 +- .../RichTextPropertySection.tsx | 7 +- .../SelectPropertySection.tsx | 11 +- .../TextfieldPropertySection.tsx | 11 +- .../propertysections/TreePropertySection.tsx | 19 +- .../TreePropertySection.types.ts | 4 +- .../__tests__/ButtonPropertySection.test.tsx | 34 +- .../ChartWidgetPropertySection.test.tsx | 29 ++ .../CheckboxPropertySection.test.tsx | 18 + .../__tests__/ImagePropertySection.test.tsx | 14 + .../__tests__/LabelPropertySection.test.tsx | 11 + .../__tests__/LinkPropertySection.test.tsx | 11 + .../__tests__/ListPropertySection.test.tsx | 21 +- .../MultiSelectPropertySection.test.tsx | 18 + .../__tests__/RadioPropertySection.test.tsx | 20 +- .../__tests__/SelectPropertySection.test.tsx | 18 + .../TextfieldPropertySection.test.tsx | 20 +- .../__tests__/TreePropertySection.test.tsx | 30 ++ .../ButtonPropertySection.test.tsx.snap | 48 ++ .../ChartWidgetPropertySection.test.tsx.snap | 458 ++++++++++++++++++ .../CheckboxPropertySection.test.tsx.snap | 69 +++ .../ImagePropertySection.test.tsx.snap | 40 ++ .../LabelPropertySection.test.tsx.snap | 36 ++ .../LinkPropertySection.test.tsx.snap | 42 +- .../ListPropertySection.test.tsx.snap | 161 ++++++ .../MultiSelectPropertySection.test.tsx.snap | 69 +++ .../RadioPropertySection.test.tsx.snap | 157 ++++++ .../SelectPropertySection.test.tsx.snap | 69 +++ .../TextfieldPropertySection.test.tsx.snap | 49 ++ .../TreePropertySection.test.tsx.snap | 70 +++ .../web/sample/slider/SliderDescription.java | 13 +- .../SliderDescriptionConverterSwitch.java | 11 +- ...erDescriptionPreviewConverterProvider.java | 19 +- .../src/main/resources/schema/slider.graphqls | 1 + .../sirius-web/src/widgets/SliderPreview.tsx | 15 +- .../src/widgets/SliderPropertySection.tsx | 8 +- .../generated/BarChartDescriptionBuilder.java | 10 + .../generated/ButtonDescriptionBuilder.java | 10 + .../generated/CheckboxDescriptionBuilder.java | 10 + .../FlexboxContainerDescriptionBuilder.java | 10 + .../generated/ImageDescriptionBuilder.java | 10 + .../generated/LabelDescriptionBuilder.java | 10 + .../generated/LinkDescriptionBuilder.java | 10 + .../generated/ListDescriptionBuilder.java | 10 + .../MultiSelectDescriptionBuilder.java | 10 + .../generated/PieChartDescriptionBuilder.java | 10 + .../generated/RadioDescriptionBuilder.java | 10 + .../generated/RichTextDescriptionBuilder.java | 10 + .../generated/SelectDescriptionBuilder.java | 10 + .../generated/TextAreaDescriptionBuilder.java | 10 + .../TextfieldDescriptionBuilder.java | 10 + .../generated/WidgetDescriptionBuilder.java | 10 + .../DiagramDescriptionItemProvider.java | 1 - .../provider/EdgeDescriptionItemProvider.java | 4 +- .../view/provider/FixedColorItemProvider.java | 4 +- .../WidgetDescriptionItemProvider.java | 14 + .../src/main/resources/plugin.properties | 1 + .../ViewFormDescriptionConverterSwitch.java | 182 ++++--- .../view/ButtonDescriptionStyle.java | 5 +- .../components/view/FormDescription.java | 2 +- .../view/MultiSelectDescriptionStyle.java | 5 +- .../components/view/NodeStyleDescription.java | 5 +- .../components/view/PageDescription.java | 14 +- .../view/SelectDescriptionStyle.java | 10 +- .../eclipse/sirius/components/view/Style.java | 3 +- .../view/TextareaDescriptionStyle.java | 5 +- .../view/TextfieldDescriptionStyle.java | 5 +- .../sirius/components/view/ViewPackage.java | 150 +++++- .../components/view/WidgetDescription.java | 23 + .../view/impl/BarChartDescriptionImpl.java | 3 +- .../view/impl/CheckboxDescriptionImpl.java | 3 +- .../view/impl/FormDescriptionImpl.java | 2 +- .../view/impl/MultiSelectDescriptionImpl.java | 3 +- .../view/impl/PieChartDescriptionImpl.java | 3 +- .../view/impl/TextAreaDescriptionImpl.java | 3 +- .../view/impl/TextfieldDescriptionImpl.java | 3 +- .../components/view/impl/ViewPackageImpl.java | 13 + .../view/impl/WidgetDescriptionImpl.java | 55 +++ .../src/main/resources/model/view.ecore | 1 + .../src/main/resources/model/view.genmodel | 1 + 192 files changed, 3948 insertions(+), 530 deletions(-) create mode 100644 doc/adrs/103_help_expressions.adoc create mode 100644 doc/images/Widget_Help_Tooltip.png create mode 100644 packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/dto/HelpTextRequestInput.java create mode 100644 packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/dto/HelpTextSuccessPayload.java create mode 100644 packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/handlers/HelpTextRequestEventHandler.java create mode 100644 packages/forms/backend/sirius-components-forms-graphql/src/main/java/org/eclipse/sirius/components/forms/graphql/datafetchers/form/FormDescriptionHelpTextDataFetcher.java create mode 100644 packages/forms/backend/sirius-components-forms-graphql/src/main/java/org/eclipse/sirius/components/forms/graphql/datafetchers/form/WidgetHasHelpTextDataFetcher.java create mode 100644 packages/forms/frontend/sirius-components-forms/src/propertysections/HelpTooltip.tsx create mode 100644 packages/forms/frontend/sirius-components-forms/src/propertysections/HelpTooltip.types.ts diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5bc73bfc0c..2643f31bdb 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,31 @@ = Changelog +== v2023.8.0 (unreleased) + +=== Shapes + +- Add support for Help Expressions in Form widgets + +=== Architectural decision records + +- [ADR-103] Add support for Help Expressions in Form widgets + +=== Breaking changes + +=== Dependency update + +=== Bug fixes + +=== New Features + +=== Improvements + +- https://github.com/eclipse-sirius/sirius-components/issues/1988[#1988] All Form widgets can now define (if relevant) a dynamically computed "help text". +Widgets which define such a help text have a new "?" icon next to their labels; the actual help text is accessible as a tooltip on this icon. +For View-based widgets, this materializes as an AQL `helpExpression`. +The help text can include multiple lines (separated by `\n`), but no text formatting. +:image:doc/images/Widget_Help_Tooltip.png[Example of a help tooltip on a widget] + == v2023.6.0 (unreleased) === Shapes diff --git a/doc/adrs/103_help_expressions.adoc b/doc/adrs/103_help_expressions.adoc new file mode 100644 index 0000000000..ed22118806 --- /dev/null +++ b/doc/adrs/103_help_expressions.adoc @@ -0,0 +1,112 @@ += ADR-103 - Add support for Help Expressions in Form widgets + +== Context + +In the desktop version of EEF-based properties views, widgets support an optional "Help" text which is exposed as a tooltip on widgets which define one. +This is helpful to add user-oriented documentation on the property represented by the widget. +It is not currently supported in the Sirius Components' _Form_ representation. + +== Decision + +All widget descriptions in the _Form_ representation (including the View-based Forms) will have an optional "help text provider". +If defined, the corresponding widget instances will have a visible "?" icon which, when hovered, will display the corresponding help text to the end-user. +The help content will be a plain text (no formatting). +It will be computed in the context of the semantic element of the widget so that the text can be adapted to the current state of the element. + +== Solution + +=== Backend + +The overall design of the solution will follow the same approach as for completion support. + +We will add a new (optional) field `Function helpTextProvider` to the core `AbstractWidgetDescription` class: + +```java +public abstract class AbstractWidgetDescription extends AbstractControlDescription { + // Added: + protected Function helpTextProvider; + + public Function getHelpTextProvider() { + return this.helpTextProvider; + } +} +``` + +When a widget is rendered, this `Function` is specialized into a plain, parameter-less `Supplier` in the widget instance, with the `VariableManager` used for the rendering captured: + +```java +public class CheckboxComponent implements IComponent { + + @Override + public Element render() { + // ... + if (checkboxDescription.getHelpTextProvider() != null) { + checkboxElementPropsBuilder.helpTextProvider(() -> checkboxDescription.getHelpTextProvider().apply(variableManager)); + } + ... + } +} +``` + +This means the value of the help expression will *not* be evaluated as part of the widget's rendering. +In the vast majority of form renders, no help text will need to be displayed for any widget. +Computing them eagerly would incur both an additional runtime cost to each render of each form _and_ a network transfer cost for text values which will never be visible. + +Instead, the evaluation of a "help expression" will be done on-demand through a new GraphQL Query: + +``` +type FormDescription implements RepresentationDescription { + helpText(widgetId: ID!): String +} +``` + +The event handler for this query will simply need to find the proper widget, and if it has a non-null `Supplier getHelpTextProvider()`, invoke it. + +Although the actual help expression is not evaluated at render-time, we will provide a `hasHelpText: Boolean` field for each widget in the GraphQL Schema. +This GraphQL field will be computed using a custom datafetcher: + +```java +@QueryDataFetcher(type = "Widget", field = "hasHelpText") +public class WidgetHasHelpTextDataFetcher implements IDataFetcherWithFieldCoordinates { + @Override + public Boolean get(DataFetchingEnvironment environment) throws Exception { + AbstractWidget item = environment.getSource(); + return item.getHelpTextProvider() != null; + } +} +``` + +This attribute will be used by the frontend to know if it should display a visual hint/icon to indicate that a help text is available for the widget. + +There will be no caching of the help expression's value. +Each GraphQL Query invocation will trigger the evaluation of the expression. + +=== View + +In the View DSL, we will add a `helpExpression : IntepretedExpression` attribute the `WidgetDescription` _EClass_. +During the View conversion, we will create a non-null `helpTextProvider` only if the WidgetDescription has a non-null and non-blank `helpExpression`: + +```java +if (viewWidgetDescription.getHelpExpression() != null && !viewWidgetDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(this.getStringValueProvider(viewWidgetDescription.getHelpExpression())); +} +``` + +This will allow users to clear the `helpExpression` field of a widget definition to mean "no help text". + +=== Frontend + +On the frontend, the Form representation will fetch the `hasHelpText` for all widgets, and use that to know if some help text is available on a given widget. +When help text is available, a "?" icon (`HelpOutlineOutlined`) will be added to the right of the widget's label text. +If the user hovers the mouse on the icon, the frontend will issue the GraphQL Query mentioned above to retrieve the proper help text, and display it inside a tooltip. + +The "preview" version of all widgets displaed inside a _FormDescriptionEditor_ will also show the "?" icon if (and only if) the widget defines a non-empty help expression. +This icon will not show any toolip, it will just be a visual indication that the widget has/will have a help text at runtime. + +== Status + +Accepted. + +== Consequences + +A similar feature could be added to all our representations (diagram elements, tree items...), but this is out of scope for the moment. diff --git a/doc/images/Widget_Help_Tooltip.png b/doc/images/Widget_Help_Tooltip.png new file mode 100644 index 0000000000000000000000000000000000000000..c758bef89590a17ce9569e19b8949419db62b993 GIT binary patch literal 12530 zcmeHuWl$Ykv?dS;!3k~&!GjaHxFrxmIJmn9cXxLW4#5KlcXtRH+#$HTTX2}oef4T) zYNl%5kE!`JsUq}gn(n>VUZ1Shn-Cc(Q8Z*CWEdD2G_kLr4hg_Z3c3pWod8xJdop(C;d49q(i zvCp3roKp`Mo!lj_NPACbBrP2&9lPIt>cVrI&ev@6gbd+99ciiPsK)n%N{DbpWSb_9 z0}6B0)QKs+Vqzg7&3^Op^2%wz68p;adF|YtZ#cW*D*e1=+3x7_=*n}1d%0}5RY*Gk zQ|Q$Y!KNdEKPGuwv<|M&s|c}jWHSFAN)_-UeXL@kS6LsBl*s%?li-Umg^VS96#w@Y_5VC=r$E+cCRiCcEsZkh$xn_`CS5eV-$g@GHq?EAx zcAx@V=-U@73yZXQhu>@rgA<5FB)nvw4JlRZ+B^Em7xlRvg@OlnN{WkZo6ubXZzvd* z{^N|Kq@>;RnWZkS|Ga2uaPZ%YLd0(0#p~1f{|?tGo7r}JbB3zFe$fkwOv5B+bJf>h zrzxX?VPPGIx-s-hy^1DmiH=@ykJseUyw#`r_k`HX|Gvs)6T9in2{0>T`tiq+njKV+ zN0sR(bZN#-^|aK1_(G>|?-^lNYfLIjI1w_OhneEek39z>f_tj}OcI)L_g+n|W$QIG z9=%7;p67Gq&wvKybCuKPA`EKF40Wx44O486Ta!BM%$|~vx_4Gifx~7xb-GKw=ea@c z8>y5+4=C2?SW3`dbvoUJG=sY+bCRrG3|gp`+ReGpKY!S3%$8P{{5LPP^uRM@)-HMA zpFF82toaX{<5xP3Xir_!XlhNn!zcvDyW~T+w)z*Zj~WO42=p09%vP^uX|(9gVr-_m z_EQh;__J!+-&^9gr=hG8;Fo-C_|Q@?KF-m(cjbAX-j=BO;@!7d_rFh5H*KXMpUL^q zZ65EiKQBqO|0yNk{Nk7g5m#UH@Z27e4U%De6fK%%m*IR|JJxk;IQ|ooo2|$7_wn^w z49fP=axEB$$A96@>)p1{D!^IJta!m2yxa>vcq?={fGtNw~)rsY|cI9-_v3_lJ_HVl- z?K^2cYSWOh@myH&AlA>buxYcrRp&e;XYURjuq}aSI0;Phs9#%2=i|jK88v^4ffyIpe?pvm(0&nn#>~?yW$k5 z+uN7RFG6)Rn$iD0@%HrL!czWGfc|y+J8~V%5dC!-^J`?MQ!{a^$#Rtr0h0I7z7)<< zGukrkIZ~mb&zfYR{85Ra3Z65pa`;AFk=)s9B&BHCPrML^{Inz6qH?r0Tju+=pr?n0 zI^(Hiq85nYf)s`lZWZTRA_PLI`YG}!8KJ$wo}8KOi}BVlu@Jq$&~8!c@8P~VTx+Bo zIVTL1u&%rZf`<^Y{h*pDRopHd7CObCzFK zJ|NtqbZwK&qnNz+0vf7o`O*eu`l|8cX`yyj1Fs*6 zNJaVr0~);6;GIh6WWCm5Lg)C@r25w>m$Or?#d4gJ369JKMPo#$AT`x}7hHSDKXkvr zzkZ8Y|7|e|ve+-%sBHl!z#Vo~U$d|;gQq!)3y1MV=I?+F7gzUs+l3Q(jJVu-HY~xR zMn{|Aap%=HgF>!kxLg8t;qh*L=Q5bPEQj*Jlf#jEspz*u@2lN-VYSOBS8W-KUu{h@ z<9|5h_ciPk*C!$FDj6~g4h_$d;1?&yfdBqY0kde_HBN2^MJ+SNuc6}Ci|ivb+GUn? zMNDa1>M(3YRZYfswi%~`$!waoO;{s-a{c9$G&IDIcMM_65$*Py3CxOX$ph{M30*Rl zmiLK&I&f)cvT%4h&Bhj%TvC7kS&KW+#FcL^EPb&>7v4m}WV?NA)|DI&y+=%=HL-%& z+WzC@_=bkO76G!X?U zhAB-F?0IXIv6SgXndrUB3X;aMUcnj@E0Z-@;!R6tyg0mnjS72!!7J9(_Tw|BeB5I+!; z-)0T|d~0ZZG)tJzIa4Gk1(P{2AOOK)u3C5ePY6x}rgRO)oWNf^(+23}X3ViKJG(*@ zsi0I4`kUa0h@nF|q|?d4p`n}08Eun4_!s^@ z*VEUxv9qK2@Zp0dzK?UmW)Ys5sTn&52OcjkFQ5YEq?8nF9320KhK6dj^I-QWy?{7t zNeCoH2KNSlhe1qCY+P+f_)N20NT3-N(tNhTn^w2cq!Z7a`MYeRDa{ES50$3zI^{M| zUyeaNA8x}5*$4?e2?uYCToMM+1x_fL-t>0g-N2T() zV0pjgcU{@o=xTO34~~p{`HqE!g|p~tyrQnoXm=cXeSKZ-eq-zF=f_sOzPkG9;r5bN zg@xF!u=z6Mwy34D$Od+qdAa3mW%r5G&Do}nt*zcKUxehBf!?N5g}UFq zbs1%N^xR(V+cohBHBV~ImU^ceFEw*N-JfGbM@O5_RwB^T(|4LJHac|9&!_C{7)OF& z4z*o}8TA+RiRpu}CRZ&?`MDiGYufue_>?&3t`lCpahw5yV8J)je4@`-?$C z6j;E)AM9b?-Y{?ZoZEl-A==p6!|QbTBOT1upm;m%Pp_`8$LijloLJA*T7;F9SOjJ~ zMe%xa7wCuKF>*N`5P-W~-`sp~JWzp|t2XhI3vIC5CYoNXGQvPYLc(FvAdr`r$79m? zYHiH|hIoHAz^qWL63yeVml@ab=TFknVpD9=wRPN4uSe;xU%yDWti7j-lpCcVRmYU9#YJ#5#+@A;|9qZ-gcCtE%4CIM99^YZc_U%$$rqoX6sq;OcsL1-N= zc4RjX4vLvH8*}31_P|8?r=}DenwsdLacY&{Lf{ml$wej)=j*062NI_?`eLVQE#~9o zARwlU6Z$J#Te)#^rk#Okraj?=bd;2z7n@z=Rn^stAn|ksBLa64;Ni;J9#9bW6x}=U zkbJMl8`18ru6&TU`5gf$f~VJ;Igz!swRGg~;H7<{rwJl~VMQEW4S4WHS6%`d= zDoREp>5AU0Y;5viq4w&QJ>|V`FD9fFZEY)me9#YceR{Z3R8dLd@wlz7tf^7tcfF7S z(A)b{p&xkVF}_ViLQ)Kdx!x0DI-JT)$I2?#-P1!SC@9G8acl2zeWDAEle22MRElg3 zic%L65>k+m2oDVl8@Ti`s^oKVF=&FbU2C~o(jQ6ZS5Z^Ldhw8m0Bm(Y9TSF;%W@L^#qdxih?}yWPdn4cQs??ej4i68*RGZC2x?b+Vve@s)gyJ(x zfq-y39g)y06=$ke8KS=B`!jkgVPI(3118Gte$Dc5cZIkDROeu}DhPm}>RTTcxZBJ2 zzE~P==M$a4hdGeY*fdf(8V$Aw3k_`Qz05QY#WGoN92^_~DPd^D9OXtMZ>7?BM4X+u zKm^T~Thjo-WE<^G3Kfe2p-`&%S}1Csa+9M4IR%AkxehE?kA-HJSR!^)%r|c=xIzeV zaK1T@9JrU}NoQ;w)-Aux{OAK0PAZrlO(D9ry8266@WH>VjQMhJN_=MXf&ty$zI*UD zJVl!9a8LP=NLq`AT@!M{7hiT_fPa{JuO|V3k-&^&hrP)x=hL-?mK4v>t+UMmBh~2^ zw<{RulNDHSfr`5Ni^z^`O&!-0`7-1Q~u--Rq2h(GKzbHf_S&W8B8XXV&A0O^Oq|s)| zv=McH-h>mehk`YduQ64OiH)7D&_{%MUJUs>sq4GDDywAy&&M01*4sV$m>5=4N_O51 zv$;%2fvsXY8xWMv$w?dx3=DzW9f|~I?crswr!=O_%6%|>82771 zCy5k}2zIk+n9Lc$$0rZf2MYBHJp?i`vSO7AUv9fC7Pr6V&CSh8d@i!H|9FG7rVu(Re?=T$CZwUbLPjwGBTJ5$T%zKBZ9q4OOGM@+c}XyJDQ&!?}{~> z5&(&%AYoI(SpPjx?c_<}wCWigM1{s>5yQwe^0YquRnL`3?r8UUVFGm4$H&J%Fpy|( zvD!pFH7yNHN&2AyvJ#?jdq1fm{l=S$>8KmE-FD;m>m}EHMi3Bd2L~z^mhZIkxjFkq zgQZaM#I==`k06rPK-nMfZw6C1qmXgm3X;1kJtZA4HuVx)HUHvVcJBlP9}*Ix3z%{+ zLr`$ya(g%}tf7HhI0zjo8ugZh*D>5?z2`L+R?MNt_3eI{$#@P@wrG?gpfza?K^g}> zyDe0Y+Y8;l2eZ$ySXt2lgHfq5jn{o6EiDb0_2lwW(#fy4>9}G!e*9LAm|EZT^kepY>Pl@k-Y$28grDRAQ1p#o+DRVPRr=Cnn;5 zx6N=-P{4V^>*&5^TT)UY3n8?0@rWKjniv>fT6zn`DJ?BK8g(GQ;*$?kR7;<=dwTRJ z)ox3-gwMOrbvfU1c6DX7S^Eqo{(XMxHMuf>;=YQLxnM`%I)3uq&F^hl_jJ3*dl%E` z;^g@$%!aN%f4BxJv_&3sT$I}*4@HwsPmvuDPQLY2Z>r&EQ1uob%Pi`?t0~0Dm3??U zJC_Sw<+IQrV!Xv9AP6ohGHbjm55gdg1T+kSpUP#^!BVYlc>DJ-3|LJdG5UZEl7QjT z+MlbThtPIjr>hSAf?ru#@s=S^&xpII0td>U?{ox3lwwH?ROzmWwn0PqS#hkW?V5l&0C9?a{tOSy7=vmhJPHa*=dJV){C&VJ8#CHo zRIIG5>YE|=!V@}@Xo{Wd_#~y=x@KkrAV1!#R#NKsMjAXlJ`5&(@N-)B!2e44WCy6_ z9!N_#!3Q{C1p&b0Eh}3UfG67SCH3n1{X1AB3~zO3=j-WOca{4wA)6r!@RE3pYF*VP z6UNiUgkUm~by9%v0UB^K+|Q5zXAD+K*8qR}Y~>f~ZTx`H0%Uann{8ul{j4@Hfv{;Q z|CsoKl+x|TGBPp(Gk=bxw)-hU1QEL)p!ps9Mv}t`K>f)A9y~Bb%4J)z(gL6ICMwKk zn81n-fZ_K7qd~}`10x7*W3B-Xt(^Ze=~WsGu$oOXG`F;eFxUa`M#&l8CLrvK)AyTNu7`RM2fmFS;fuvBRvLbAYbzyP|A1YiU7$*kFE|7&4^ zPgoW3l1SMM8_+UzQi1S-f?a*llo3<(-0JL0X7$=|D)9su8Q@)dB8Wwyka*Sw#Had( zN-)&!02KV4aVQElwFFBl9}q8M*Ov4UY??|y8i04l+pKjV1!9m&+1vjE$cKiGE)>{9o3jlu;Tw}Y#gOpuec!Jvfwi-KkTiN8Qw7FygAK_0%w z#QX?y-?e3lrFRk_2niV(;LDHS?eA!%fp`LwWz$vZJ(J*1YkYiFKffX!qOuM5p)o&HJ|luY2jBa zRLBC5N#%8l6i;N5ZFP4+#--~@v1%0qtSBoh8)zdlkjR{|?%}Gi_mou08>KXNQ}*-c z&*0$Tm6{nXar|JwGWT)?=MdotX?-Pvpnfi0q%xMmR{Qm9L@*-z1V*2n*lb&{aB%?^7Oz}9*;ez zgM}OO#D_RW^#ov&^(`%>fHNtO&qIHx)v9&CK<$s0(gdIGCq^5k)A0Al^b>FCDe?e)Z6^D&H)WZs zX!}`Dkt@Iwaax80iyns0yak>HkBFFuQu>pGHXfXNu?10lLUAeDw)DT*xv|n z=GyXBR8;gG6-*V+*b7=amKuwBJdoFWGi4(H?7IsMc8$LpgrnA+4&9B_w?*+4R9?b2S)-hL|e`oa(*A! z`Q*L!^3sNLfaHDLIyZ)6J^r-7ewMD}8$& z(cBys2}!CYdhR6NDOiM%sHon_$v86Mz!RVoE8E+Nx;zKfb_QvDE-|O;y)SmR`{$Zn z*qE4@Kr>@j<_T2vK-YSKqTYbw=}(grGjJ6-KpEob6zO{JaBy(ob2PFr@$dqhns|YT z_sq@`g4PSL>V$%xd|vmbL0M)LC15ZtCgYS!#VVgbp(P9XV7b86`gm)$HJBWGiFlI% zWUI<#f*RyzFX#*quo(_w*Kxa?Q7$$)Z5Nfbb}THUu670yYoVZ_K|$qhzdIfP%&(4# zi5Rd3vki7M-&vPcK`-s(kK_RKbHp$A!YCJUHksoS=GgQ z8{y|7-O9>p3S!xoy&l!B&6AS&Tc7{zj(PhgQs zfga`oMwkROuwsc?4NfKr2?^*~SS+_{K0I74?}77spg1aYzd1ve0SgU&f4W#T8^%CS z?`Hy|dMp=a>oU^xe{{H^?!1p~*X||0?JF61L9e z_=WNK$d6@J6_u5PgTZp$PA<@&@h`+={+f=WEO<>~3zL7tY1ib`Otrcm&<^n_0QSSfg^Pa4_#V{T5|?M*hO zi|U?}s+8L1n;Rw-vQ3mfpn_N^4aEFmyii}^Z~8X&*jF)cLf71UFkdzswayngS~>a0 z4_4F3_W(Ln8t32L35$UR$dybv11?X#Op6~$C3-vQ#}7Gh_zayN92RslWm_M9EWJBn zm4QU3rb@WGH|r9B;{7Q4`*)rCj0ckkH`<4m+nPcp*W9zS(BrnJbg;x*#wl7Yu4AAb zvaOJP&*-2L2vk(QLQe!}q<=vHEofb0mAZUx1rZ@A1yxR0cee>vA&eJ^V9JqAQJ_P5 z!(j7Tc9ekL!|j3Q<>_h==^6ME*e2SvDp)l&Gz`=#OOzSXzxcOIcW`Es^Hs>2?2JxK zXV+ky2#S+yv&!%6R!(y7Jm9t^|C=TX!}c; zlBrtMqxAd3S8`>(Kq;Pkzo7HO>fr&n<41(mySFhiLvCjdti}%k?$yo8rzmaqyK>&B zt2}mF5{AR6$;66SYtY!^Qe@1LWl&U4L>w?@(S3HkY3!y;&zMXoN=r)v84&ed2UnVr zT_XT!Sw2{UhH)DI-OVs9UfD_R&7j)GR0AqG#WCBrOnM*KECw~!=-R{7@fOd~ zb)1PjrtLKmujyjDo}M1oL{qxYN3nSOD7GfO)U_Ir;X_ltnvv~NDwcO~FWQ(hEqG}X z80MtbZz+s5yx_(0Eb_n^^!rxtc5fMhj3$n{BKpszF*+Ww5(9}jsYfr1ww|O^658&u zPiCvqUoVQv)lJL%aIjykO5+USY(D6ud4o7^oX;C3_(LqrRk&c;6>s^VrROwad93J? zrEum=C(O3+g2Y#KOL$QwhM&s&x|2n`zD&mr>o)vMqL)_Js>Rc#h8z#ckeX_U(q=Yu`v5J|!Rg>|;UGf;}_?^nn zqVgqXLU>wzFmjK!T|@9B9yS=4oEeiGs#*;?12#mb@51D%YY15C$qe+$&K@Rb-A{xm zhwdELOB%nV&Q?Zl-jTNUCL5d+wvDFvGA@5R`27W^-Zr=o+i@-N#2Bs8@&1p>gx;slPK56)&NM|5AiJ&8_H&~1EDtg~upIB}_h|mVAt4pw-Iq9SpEY>FVosUbvnfx>W_pAA4R@*ss zUl`ihGh5g?(!CEl?t>@Jqu(P2;)y8nqGq+Wsjh{Bjs7Iq!OLFm={P z{OU9mJkkf!HXHSrqN!5jN(`HTJU)1URqn>Euko0*=k0WJRE3R!Fzo|QVN%O9owsn!8HwOg?CQ;%`6wOb%J-J%OVU^OLn&m{ChAYg zg-oBds6C3AV_H!=scW;GyBOUqbF4n33%Vq~$98+!JRdiw2+=hD3(&|w&`n*@oxQNmpN@0RbpN+XoATf-9lX~yA@gYrSR9Pn-BL?n(WAB)7&yV}Z~aMq@%0fDzyTFcTYF(7^H4n5X;z0&Ki>4i1g#tDVK zru*DV@$0rDS*GI5jPlVn(G4kdJeTKanX5;rZs^|q;B5$k__)bR=7lB#oi9ZZ-UqV@ zLf!W+@x0p=s}r}^O(W~s4xDKFMX$6U>y>a5H%p7{O+NoQI<}rAfIqoD zlr%lLY26$=HWD5~7v^?6$X=K;Ak(4+IjC|{usFDk`FV&*GXEP~o#*_>rzzjv2{rjD z4V%L1gT7)6Ive+FM1fN}1B!h$iQ620w8Hp~0)4^Uzs!Bf526hv>CG*}gIM4ln!T(1 z;Gl%9({_Nf2zVpmgmlmE#WQ8rDt!6lc+_yzQeiu~9*q{o`?&ifL(!c4(3-B1*({IZ zdpuW^pVRNHs6L+862|nR@Qmt_#vC z%C(#qQF^G2q5=rEKKSRvMTOqW1Ot)+J zcjXQ)=L-fx$cbI8G7x$NDr!vZt8%_J6rZF7CI}(6W^FCLP_xSI#wa2%Ey|E?0jmkK zc@4Zq?QRbtDoCxBXjpuh^<5?FaA)Dq^E;H8r@=g#d?U|M?Agjt5Xi|qW%-Vm4Y^b>{akjB8{Qq_)9 zE>r0;+U5ZFJmCU+cn&$$E|(5@Y+wSrxxPk!$T056`q>h-B_(c-OWBppt~MMDMGB3T zc9lAf>7jOSl9RC3^&|2r-FWv>=yx`fS^JamhW~{5*#${aYiEEsc*jm8v|%>h`#(0K zTlI2?KLX?XFM1Nzby^&Glg#S07rr|Qy^5aMc&}2nh;Fz(GCzB9j*g^E=Ks4x-T~qL z1~MZ!ghX0m=AWn`X<04xpVT=ww+y9$cWgqz8sD@3y-%l>SEg`~W;8igDY#ikUL#bo z5w0??D$xue_Ej`W4*kdHU9p<5&%0$C=$=0$te1M%HC?gZGXfKyO_I?Z^AT4lxHq-} z&j0_kuXchMx8^t4D*7hTwh2xsxcQ^ne{~mbI1G3J|NHs1$-KjBp-T@2$T{Ty-d~f z!Mv*+VgEkkAfe#IaDh7d@7Q!bK~~hI-yW8)Sn6J8?>X2uK|qv0rJGh1*25!D?e<@} z;j^__RcxQVWlizLTvOeJjS=!t`P&_3E`aqh+~yOJ<8jbH*Oz9)m`b_Pu{VPcu7aXv zJ@UVQgb7uaElecbGoFHdtXML3loxcpn1VBUVFRZwd_wP zId?iXDDY3Mc;ERQXJo~w1)Csglc?UW7<(eF;D2e?Z{sU-VBNgGL0-ScC0Ce*l@W(T zVPE+etpiVqn8ph^jm!B z(#`i0Ud^Np`=ByvtCi1jLftpzI{niAlb%76ciUAL4>2USdasw$f)U!Sig?+a_6cfr z(C<8ngsbX>-LLzs{As^NUTjUg9^k%H!&f>=?G2RPUq2Rzike<@S83{c_1L23Z-ZiV zI@Qj~yx|SrEo&JnfRSN)+`CA7KIY+2)LmtY5mIC_GR0c4c6Vm*7BckCJO!3M+`0d$ zLeBjdP~pK{>GZlSjmTfVMF#FzO|HtsqA-CqXvr_h=#l0_E$vVruMb&LqSdFATPSS~ z{m`{)HmwUew8nM6?tw&s@!C_(%v5bBQ$yO&!`kQRVZ}$fjZ6V{bbj3IV%|RA>b?X0 zHz@MPcJ0H7IgbKb@-WH0#+KV`!gx70^Y7<6m#4eu&~+u%KO(Fx@`i z!!jl%ii(cF_PZt3*~{rmHIvQ2lQf%v%Bvp~%k>v7?@O9KZ4IX^K0ytNc&e?I{p;ND zU#?_?`KTyaNU(hI!M4AD)QhKY^9V&Jy`z= z7ee^jnj+QLAWXJVqhGH0^QTai-LLhI;UeOXl>Mbdi-D~}GiG^g id) .labelProvider(vm -> this.getWidgetLabel(viewTextfieldDescription, "Textfield")) .valueProvider(vm -> "") @@ -112,9 +111,11 @@ public AbstractWidgetDescription caseTextfieldDescription(org.eclipse.sirius.com .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewTextfieldDescription.getHelpExpression() != null && !viewTextfieldDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewTextfieldDescription)); + } + return builder.build(); } @Override @@ -131,8 +132,7 @@ public AbstractWidgetDescription caseCheckboxDescription(org.eclipse.sirius.comp return new CheckboxStyleProvider(style).build(); }; - // @formatter:off - return CheckboxDescription.newCheckboxDescription(UUID.randomUUID().toString()) + CheckboxDescription.Builder builder = CheckboxDescription.newCheckboxDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewCheckboxDescription, "Checkbox")) .valueProvider(vm -> true) @@ -140,9 +140,11 @@ public AbstractWidgetDescription caseCheckboxDescription(org.eclipse.sirius.comp .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewCheckboxDescription.getHelpExpression() != null && !viewCheckboxDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewCheckboxDescription)); + } + return builder.build(); } @Override @@ -159,8 +161,7 @@ public AbstractWidgetDescription caseSelectDescription(org.eclipse.sirius.compon return new SelectStyleProvider(style).build(); }; - // @formatter:off - return SelectDescription.newSelectDescription(UUID.randomUUID().toString()) + SelectDescription.Builder builder = SelectDescription.newSelectDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewSelectDescription, "Select")) .valueProvider(vm -> "") @@ -171,9 +172,11 @@ public AbstractWidgetDescription caseSelectDescription(org.eclipse.sirius.compon .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewSelectDescription.getHelpExpression() != null && !viewSelectDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewSelectDescription)); + } + return builder.build(); } @Override @@ -190,8 +193,7 @@ public AbstractWidgetDescription caseTextAreaDescription(org.eclipse.sirius.comp return new TextareaStyleProvider(style).build(); }; - // @formatter:off - return TextareaDescription.newTextareaDescription(UUID.randomUUID().toString()) + TextareaDescription.Builder builder = TextareaDescription.newTextareaDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewTextareaDescription, "Textarea")) .valueProvider(vm -> "") @@ -199,9 +201,11 @@ public AbstractWidgetDescription caseTextAreaDescription(org.eclipse.sirius.comp .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewTextareaDescription.getHelpExpression() != null && !viewTextareaDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewTextareaDescription)); + } + return builder.build(); } @Override @@ -218,8 +222,7 @@ public AbstractWidgetDescription caseMultiSelectDescription(org.eclipse.sirius.c return new MultiSelectStyleProvider(style).build(); }; - // @formatter:off - return MultiSelectDescription.newMultiSelectDescription(UUID.randomUUID().toString()) + MultiSelectDescription.Builder builder = MultiSelectDescription.newMultiSelectDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewMultiSelectDescription, "MultiSelect")) .valuesProvider(vm -> List.of()) @@ -230,9 +233,11 @@ public AbstractWidgetDescription caseMultiSelectDescription(org.eclipse.sirius.c .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewMultiSelectDescription.getHelpExpression() != null && !viewMultiSelectDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewMultiSelectDescription)); + } + return builder.build(); } @Override @@ -249,8 +254,7 @@ public AbstractWidgetDescription caseRadioDescription(org.eclipse.sirius.compone return new RadioStyleProvider(style).build(); }; - // @formatter:off - return RadioDescription.newRadioDescription(UUID.randomUUID().toString()) + RadioDescription.Builder builder = RadioDescription.newRadioDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewRadioDescription, "Radio")) .optionIdProvider(vm -> "") @@ -261,9 +265,11 @@ public AbstractWidgetDescription caseRadioDescription(org.eclipse.sirius.compone .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewRadioDescription.getHelpExpression() != null && !viewRadioDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewRadioDescription)); + } + return builder.build(); } @@ -280,17 +286,18 @@ public AbstractWidgetDescription caseFlexboxContainerDescription(org.eclipse.sir }); - // @formatter:off - return FlexboxContainerDescription.newFlexboxContainerDescription(UUID.randomUUID().toString()) + FlexboxContainerDescription.Builder builder = FlexboxContainerDescription.newFlexboxContainerDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewFlexboxContainerDescription, "FlexboxContainer")) .flexDirection(flexDirection) .children(children) .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") - .messageProvider(object -> "") - .build(); - // @formatter:on + .messageProvider(object -> ""); + if (viewFlexboxContainerDescription.getHelpExpression() != null && !viewFlexboxContainerDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewFlexboxContainerDescription)); + } + return builder.build(); } @Override @@ -307,8 +314,7 @@ public AbstractWidgetDescription caseButtonDescription(org.eclipse.sirius.compon return new ButtonStyleProvider(style).build(); }; - // @formatter:off - return ButtonDescription.newButtonDescription(UUID.randomUUID().toString()) + ButtonDescription.Builder builder = ButtonDescription.newButtonDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewButtonDescription, "Button")) .buttonLabelProvider(vm -> viewButtonDescription.getButtonLabelExpression()) @@ -317,9 +323,11 @@ public AbstractWidgetDescription caseButtonDescription(org.eclipse.sirius.compon .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewButtonDescription.getHelpExpression() != null && !viewButtonDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewButtonDescription)); + } + return builder.build(); } @Override @@ -336,17 +344,18 @@ public AbstractWidgetDescription caseLabelDescription(org.eclipse.sirius.compone return new LabelStyleProvider(style).build(); }; - // @formatter:off - return LabelDescription.newLabelDescription(UUID.randomUUID().toString()) + LabelDescription.Builder builder = LabelDescription.newLabelDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewLabelDescription, "Label")) .valueProvider(vm -> "") .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewLabelDescription.getHelpExpression() != null && !viewLabelDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewLabelDescription)); + } + return builder.build(); } @Override @@ -363,17 +372,18 @@ public AbstractWidgetDescription caseLinkDescription(org.eclipse.sirius.componen return new LinkStyleProvider(style).build(); }; - // @formatter:off - return LinkDescription.newLinkDescription(UUID.randomUUID().toString()) + LinkDescription.Builder builder = LinkDescription.newLinkDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewLinkDescription, "Link")) .urlProvider(vm -> "") .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") .messageProvider(object -> "") - .styleProvider(styleProvider) - .build(); - // @formatter:on + .styleProvider(styleProvider); + if (viewLinkDescription.getHelpExpression() != null && !viewLinkDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewLinkDescription)); + } + return builder.build(); } @Override @@ -390,7 +400,6 @@ public AbstractWidgetDescription caseListDescription(org.eclipse.sirius.componen return new ListStyleProvider(style).build(); }; - // @formatter:off ListDescription.Builder builder = ListDescription.newListDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewListDescription, "List")) @@ -406,8 +415,9 @@ public AbstractWidgetDescription caseListDescription(org.eclipse.sirius.componen .kindProvider(object -> "") .messageProvider(object -> "") .styleProvider(styleProvider); - // @formatter:on - + if (viewListDescription.getHelpExpression() != null && !viewListDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewListDescription)); + } return builder.build(); } @@ -417,16 +427,17 @@ public AbstractWidgetDescription caseImageDescription(org.eclipse.sirius.compone childVariableManager.put(VariableManager.SELF, viewImageDescription); String id = this.formDescriptionEditorDescription.getTargetObjectIdProvider().apply(childVariableManager); - // @formatter:off - return ImageDescription.newImageDescription(UUID.randomUUID().toString()) + ImageDescription.Builder builder = ImageDescription.newImageDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewImageDescription, "Image")) .urlProvider(vm -> Optional.ofNullable(viewImageDescription.getUrlExpression()).orElse("")) .maxWidthProvider(vm -> viewImageDescription.getMaxWidthExpression()) .diagnosticsProvider(vm -> List.of()).kindProvider(object -> "") - .messageProvider(object -> "") - .build(); - // @formatter:on + .messageProvider(object -> ""); + if (viewImageDescription.getHelpExpression() != null && !viewImageDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewImageDescription)); + } + return builder.build(); } @Override @@ -435,17 +446,18 @@ public AbstractWidgetDescription caseRichTextDescription(org.eclipse.sirius.comp childVariableManager.put(VariableManager.SELF, viewRichTextDescription); String id = this.formDescriptionEditorDescription.getTargetObjectIdProvider().apply(childVariableManager); - // @formatter:off - return RichTextDescription.newRichTextDescription(UUID.randomUUID().toString()) + RichTextDescription.Builder builder = RichTextDescription.newRichTextDescription(UUID.randomUUID().toString()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(viewRichTextDescription, "RichText")) .valueProvider(vm -> "") .newValueHandler((vm, value) -> new Success()) .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") - .messageProvider(object -> "") - .build(); - // @formatter:on + .messageProvider(object -> ""); + if (viewRichTextDescription.getHelpExpression() != null && !viewRichTextDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(viewRichTextDescription)); + } + return builder.build(); } @Override @@ -498,16 +510,17 @@ private AbstractWidgetDescription createChartWidgetDescription(org.eclipse.siriu childVariableManager.put(VariableManager.SELF, widgetDescription); String id = this.formDescriptionEditorDescription.getTargetObjectIdProvider().apply(childVariableManager); - // @formatter:off - return ChartWidgetDescription.newChartWidgetDescription(chartDescription.getId()) + ChartWidgetDescription.Builder builder = ChartWidgetDescription.newChartWidgetDescription(chartDescription.getId()) .idProvider(vm -> id) .labelProvider(vm -> this.getWidgetLabel(widgetDescription, "Chart")) .chartDescription(chartDescription) .diagnosticsProvider(vm -> List.of()) .kindProvider(object -> "") - .messageProvider(object -> "") - .build(); - // @formatter:on + .messageProvider(object -> ""); + if (widgetDescription.getHelpExpression() != null && !widgetDescription.getHelpExpression().isBlank()) { + builder.helpTextProvider(vm -> this.getWidgetHelpText(widgetDescription)); + } + return builder.build(); } @Override @@ -525,6 +538,15 @@ public String getWidgetLabel(org.eclipse.sirius.components.view.WidgetDescriptio widgetLabel = name; } return widgetLabel; + } + public String getWidgetHelpText(org.eclipse.sirius.components.view.WidgetDescription widgetDescription) { + String helpText = "Help"; + String helpExpression = widgetDescription.getHelpExpression(); + if (helpExpression != null && !helpExpression.isBlank() && !helpExpression.startsWith(AQL_PREFIX)) { + helpText = helpExpression; + } + return helpText; } + } diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/BarChartWidget.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/BarChartWidget.tsx index d2c38bbcd4..9e4fdfbeaf 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/BarChartWidget.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/BarChartWidget.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -12,8 +12,9 @@ *******************************************************************************/ import { BarChart, BarChartRepresentation } from '@eclipse-sirius/sirius-components-charts'; import { GQLBarChart } from '@eclipse-sirius/sirius-components-forms'; -import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; +import { Theme, makeStyles } from '@material-ui/core/styles'; +import HelpOutlineOutlined from '@material-ui/icons/HelpOutlineOutlined'; import { useEffect, useRef, useState } from 'react'; import { BarChartWidgetProps } from './WidgetEntry.types'; @@ -24,6 +25,11 @@ const useStyles = makeStyles((theme) => ({ chart: { overflowX: 'auto', }, + propertySectionLabel: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, })); export const BarChartWidget = ({ widget, selection }: BarChartWidgetProps) => { @@ -84,9 +90,12 @@ export const BarChartWidget = ({ widget, selection }: BarChartWidgetProps) => { onBlur={() => setSelected(false)} ref={ref} tabIndex={0}> - - {barChartWidget.label} - +
+ + {widget.label} + + {widget.hasHelpText ? : null} +
diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ButtonWidget.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ButtonWidget.tsx index 16d7de23f6..f17c468729 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ButtonWidget.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ButtonWidget.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -13,8 +13,9 @@ import { ServerContext, ServerContextValue } from '@eclipse-sirius/sirius-components-core'; import { ButtonStyleProps, getTextDecorationLineValue } from '@eclipse-sirius/sirius-components-forms'; import Button from '@material-ui/core/Button'; -import { makeStyles, Theme } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; +import { Theme, makeStyles } from '@material-ui/core/styles'; +import HelpOutlineOutlined from '@material-ui/icons/HelpOutlineOutlined'; import { useContext, useEffect, useRef, useState } from 'react'; import { ButtonWidgetState } from './ButtonWidget.types'; import { ButtonWidgetProps } from './WidgetEntry.types'; @@ -42,6 +43,11 @@ const useStyles = makeStyles((theme) => ({ selected: { color: theme.palette.primary.main, }, + propertySectionLabel: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, })); export const ButtonWidget = ({ widget, selection }: ButtonWidgetProps) => { @@ -131,9 +137,12 @@ export const ButtonWidget = ({ widget, selection }: ButtonWidgetProps) => { return (
- - {widget.label} - +
+ + {widget.label} + + {widget.hasHelpText ? : null} +