Skip to content
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

LPS-128506 - Make sure taglibs using react and clay are using proper tooltip #855

Closed

Conversation

bryceosterhaus
Copy link
Collaborator

@bryceosterhaus bryceosterhaus commented Mar 2, 2021

This addresses https://issues.liferay.com/browse/LPS-128506

The main change here is that we wrap out render with a ClayTooltipProvider similar to how we provide a ClayIconContext so that devs don't have to provide it themselves(unless they want to override the styles).

This means that everything render through react:component, ReactRenderer or import {render} from 'frontend-js-react-web' automatically provides default tooltip support simplifying the setup for applications down the line.

Because removing the provider in the modules changes basically all the indentation of the files, it can easily cause conflicts.

/cc @liferay-echo, @liferay-tango, @liferay-lima, @liferay-commerce, @liferay-headless, @liferay-app-builder, @liferay-data-engine, @liferay-forms, @liferay-workflow, @liferay-search... and maybe others 🙈

@liferay-continuous-integration
Copy link
Collaborator

CI is automatically triggering the following test suites:

  •     ci:test:relevant
  •     ci:test:sf

@liferay-continuous-integration
Copy link
Collaborator

✔️ ci:test:sf - 1 out of 1 jobs passed in 4 minutes

Click here for more details.

Base Branch:

Branch Name: master
Branch GIT ID: d157dfa16ee97ddd0425114fbc41f621b01cea40

Sender Branch:

Branch Name: LPS-128506
Branch GIT ID: 019589abe2ff541acb4e16a484b6fbdc9b1be9cd

1 out of 1jobs PASSED
1 Successful Jobs:
For more details click here.

@bryceosterhaus
Copy link
Collaborator Author

I added an additional commit removing uses of ClayTooltipProvider. I haven't fully tested all of these instances yet

@liferay-continuous-integration
Copy link
Collaborator

@@ -38,6 +38,8 @@ const ALIGN_POSITIONS = [

const SELECTOR_TOOLTIP = '.tooltip[role="tooltip"]';
const SELECTOR_TRIGGER = `
.taglib-clay-tag [title],
.taglib-clay-tag [data-restore-title],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe we finally want to be more aggressive and just do [title], [data-title] as a trigger selector and clean up all the specific exceptions we've been adding over time instead of adding a new one.

I don't think the [data-restore-title] selector should really be used even though it appears in other entries below. It basically signals an intermediate step where we usually move the title attribute to data-restore-title so we can leave html the same way we found it before showing a tooltip and avoiding a double tooltip triggered by the default behaviour of a title attribute.

Copy link
Collaborator Author

@bryceosterhaus bryceosterhaus Mar 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[date-restore-title] was necessary for the mouseout event and removing the tooltip, we use the same selector list for both enabling and disabling the tooltip. But I think you are right, we should just do all [title] and [data-title] and then we can add an explicit opt-out such as :not([data-disable-tooltip])

<ClayIconSpriteContext.Provider value={spritemap}>
{Component ? <Component {...renderData} /> : renderable}
</ClayIconSpriteContext.Provider>,
<ClayTooltipProvider>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I was just wondering if @matuzalemsteles or @wincent can think of a reason we decided not to do this yet. Maybe it just didn't come up.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, as far as I know, we never even discussed this possibility, but it seems fine to do it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I think the initial idea of this was to be the Provider of the application but probably people were always adding above the component with Title for some reason... I remember we had an issue open in Clay where we would centralize all Providers, something like ClayManager to probably add to the render. This would contain:

  • ClayModalProvider
  • ClayIconSpriteContext
  • ClayTooltipProvider

I think we didn't get to prioritize that because we haven’t seen a great need at the moment. This could alleviate forgetting to add any Provider.

Perhaps another reason was that Tooltip was also always controlled by singleton on the Portal and we had been working on his evolution to use React, maybe that discouraged us from using Provider since it only works on the React tree.

@@ -15,7 +15,6 @@
import {ClayButtonWithIcon} from '@clayui/button';
import ClayForm, {ClayRadio, ClayRadioGroup, ClayToggle} from '@clayui/form';
import ClayPopover from '@clayui/popover';
import {ClayTooltipProvider} from '@clayui/tooltip';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect at least some removals in package.json dependencies of @clayui/tooltip that are surely unnecessary after this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very true, didn't think about that. I'll update

@liferay-continuous-integration
Copy link
Collaborator

❌ ci:test:stable - 8 out of 9 jobs passed

❌ ci:test:relevant - 17 out of 23 jobs passed in 3 hours 31 minutes

Click here for more details.

Base Branch:

Branch Name: master
Branch GIT ID: d157dfa16ee97ddd0425114fbc41f621b01cea40

Upstream Comparison:

Branch GIT ID: d157dfa16ee97ddd0425114fbc41f621b01cea40
Jenkins Build URL: Acceptance Upstream DXP (master) #1598

ci:test:stable - 8 out of 9 jobs PASSED
8 Successful Jobs:
ci:test:relevant - 17 out of 23 jobs PASSED
17 Successful Jobs:
For more details click here.

Failures unique to this pull:

  1. test-portal-acceptance-pullrequest-batch(master)/functional-smoke-tomcat90-mysql57-jdk11_open/0
    Job Results:

    5 Tests Passed.
    3 Tests Failed.

    1. AXIS_VARIABLE=0,label_exp=!master #2764
      1. PortalLogAssertorTest.testScanXMLLog
        junit.framework.AssertionFailedError: 
        java.lang.RuntimeException: org.elasticsearch.ElasticsearchStatusException: [liferay-35736-workflow-metrics-sla-instance-results/VVylYJwJRIaBFKNTplw97g] ElasticsearchStatusException[Elasticsearch exception [type=resource_already_exists_exception, reason=index [liferay-35736-workflow-metrics-sla-instance-results/VVylYJwJRIaBFKNTplw97g] already exists]]
        java.lang.RuntimeException: org.elasticsearch.ElasticsearchStatusException: [liferay-35736-workflow-metrics-sla-instance-results/VVylYJwJRIaBFKNTplw97g] ElasticsearchStatusException[Elasticsearch exception [type=resource_already_exists_exception, reason=index [liferay-35736-workflow-metrics-sla-instance-results/VVylYJwJRIaBFKNTplw97g] already exists]]
        	at org.elasticsearch.rest.BytesRestResponse.errorFromXContent(BytesRestResponse.java:187)
        	at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:1892)
        	at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:1869)
        	at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1626)
        	at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1583)
        	at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1553)
        	at org.elasticsearch.client.IndicesClient.create(IndicesClient.java:316)
        	at com.liferay.portal.search.elasticsearch7.internal.search.engine.adapter.index.C...
  2. test-portal-acceptance-pullrequest-batch(master)/functional-tomcat90-mysql57-jdk8/0
    Job Results:

    46 Tests Passed.
    8 Tests Failed.

    1. ...
    Click here for more failures.

Failures in common with acceptance upstream results at d157dfa:
  1. test-portal-acceptance-pullrequest-batch(master)/modules-semantic-versioning-jdk8/0
    Job Results:

    0 Tests Passed.
    1 Test Failed.

    1. AXIS_VARIABLE=0,label_exp=!master #465100

      Please fix semantic versioning on bryceosterhaus/LPS-128506

           [exec] Note: Some input files use unchecked or unsafe operations.
           [exec] Note: Recompile with -Xlint:unchecked for details.
           [exec] 
           [exec] > Task :apps:configuration-admin:configuration-admin-web:compileJSP
           [exec] 
           [exec] > Task :apps:configuration-admin:configuration-admin-web:jar
           [exec] > Task :apps:configuration-admin:configuration-admin-web:autoUpdateXml SKIPPED
           [exec] Note: /opt/dev/projects/github/liferay-portal/modules/apps/frontend-js/frontend-js-portlet-extender/src/main/java/com/liferay/frontend/js/portlet/extender/internal/portlet/action/PortletExtenderConfigurationAction.java uses or overrides a deprecated API.
           [exec] Note: Recompile with -Xlint:deprecation for details.
           [exec] Note: /opt/dev/projects/github/liferay-portal/modules/apps/frontend-js/frontend-js-portlet-extender/src/main/java/com/liferay/frontend/js/portlet/extender/internal/portlet/JSPortlet.java uses unchecked or unsafe operations.
           [exec] Note: Recompile with -Xlint:unchecked for details.
           [exec] 
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:compileJava
           [exec] 
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:copyLibs SKIPPED
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:classes
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:jar
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:autoUpdateXml SKIPPED
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:baseline SKIPPED
           [exec] > Task :apps:frontend-js:frontend-js-portlet-extender:syncVersions
           [exec] Gradle build finished at 2021-03-03 00:53:44.325.
           [exec] 
           [exec] 
           [exec] FAILURE: Build completed with 2 failures.
           [exec] 
           [exec] 1: Task failed with an exception.
           [exec] -----------
           [exec] * What went wrong:
           [exec] Execution failed for task ':apps:frontend-taglib:frontend-taglib-react:baseline'.
           [exec] > A failure occurred while executing com.liferay.gradle.plugins.baseline.internal.work.BaselineWorkAction
           [exec]    > org.gradle.api.GradleException: Semantic versioning is incorrect while checking /opt/dev/projects/github/liferay-portal/tools/sdk/dist/com.liferay.frontend.taglib.react-5.0.0.jar against /opt/dev/projects/github/liferay-portal/.gradle/caches/modules-2/files-2.1/com.liferay/com.liferay.frontend.taglib.react/4.1.2/ec050fd1c3aa0f51ab209177255ba6f126eabeef/com.liferay.frontend.taglib.react-4.1.2.jar

  2. ...

@liferay-continuous-integration
Copy link
Collaborator

@jbalsas jbalsas marked this pull request as ready for review March 5, 2021 10:24
@jbalsas
Copy link

jbalsas commented Mar 5, 2021

Taking this out of draft and building as we speak to test. I removed the initial commit so we can work on figuring out applying this to the more global [title], [data-title] trigger in a followup PR so we focus here on the infra improvements.

@jbalsas
Copy link

jbalsas commented Mar 5, 2021

As much as I like this PR, I'm not confident this works as intended

<ClayTooltipProvider>
    <ClayMultiSelect />
</ClayTooltipProvider>

This apparently only works for the main input element but not for the rest of buttons or components. I assume because @bryceosterhaus also tweaked the tags to work with our global tooltip provider that he saw it working, but I think that's a false positive since this should work out of the box and it does not.

<ClayTooltipProvider>
    <div>
        <ClayMultiSelect />
    </div>
</ClayTooltipProvider>

This will actually also make the tooltip over the button show up. I've created this codesandbox where this behaviour can be seen. Note that even though the "Clear All" button is not visible, it's there and hovering over it shows or not the tooltip while hovering over the input always shows the tooltip.

I'm going to open an issue in Clay now and return this back to Draft status with a heavy heart.

/cc @matuzalemsteles, @wincent

@jbalsas jbalsas marked this pull request as draft March 5, 2021 13:16
@matuzalemsteles
Copy link

@jbalsas I think this probably won't work for this case because it will depend on children, TooltipProvider will add two events in the child element to be able to visualize the mouse and create the interactions. In the case of MultiSelect this does not work because his otherProps will go to the input element and we are based on the premise that TooltipProvider needs to add these events to a root element so that it can view in-depth.

Maybe we can make this wrapper in TooltipProvider or add it to the render?

@jbalsas
Copy link

jbalsas commented Mar 9, 2021

@jbalsas I think this probably won't work for this case because it will depend on children, TooltipProvider will add two events in the child element to be able to visualize the mouse and create the interactions. In the case of MultiSelect this does not work because his otherProps will go to the input element and we are based on the premise that TooltipProvider needs to add these events to a root element so that it can view in-depth.

Hmmm... I see, the thing is we even wrap that further but apparently following the same approach in our DXP Multiselect component wrapper

What would be your proposal to address this? :D

Maybe we can make this wrapper in TooltipProvider or add it to the render?

I'm worried about adding unnecessary wrappers since that can easily break layouts, so we should find a way to easily target only the needed components.

One thing I'm also worried about now that I'm seeing the code is this:

<ClayTooltipProvider>
    <ClayButton 
          title="hey!"
          onMouseOver={() => {alert('foo');}}
          onMouseOut={() => {alert('bar');}}
    >
        Button with tooltip but not mouse events
    </ClayButton>
</ClayTooltipProvider>

I've updated the codesandbox sample to show this in 2 different buttons, so TooltipProvider might be actually being destructive.

How do you think we should proceed updating either TooltipProvider and/or our components to work with it?

/cc @wincent

@matuzalemsteles
Copy link

I'm worried about adding unnecessary wrappers since that can easily break layouts, so we should find a way to easily target only the needed components.

Yeah, I totally agree I also don't like adding divs to handle this, it creates a mess in the markup and will eventually break the layout.

One thing I'm also worried about now that I'm seeing the code is this [...] so TooltipProvider might be actually being destructive.

Yeah, that can be fixed to still allow the developer to hear those events and Clay too.

How do you think we should proceed updating either TooltipProvider and/or our components to work with it?

Well, the TooltipProvider needs some root element to support it, I see some people now but we will have some trade-off to choose from.

  • Using synthetic events in the React component is healthier for us to take advantage of the React life cycle and not deal with the DOM directly, to maintain this we would still have to have a root element of the application, add an extra div.
  • A second option would be to not use synthetic React events and add the event manually to the componentId element.
  • In the implementation of TooltipProvider we can partially opt for both, keep the listeners of the synthetic event in the children component of React and add a new property so that the component can alternate between adding the listener in children and adding the event in the element via DOM.

As render has no view of its children elements and there is no way to infer, we can continue with the idea of adding the event to the root element and we leave the synthetic event available only for use cases outside of render where the developer has that choice control and knows its root component.

@jbalsas jbalsas marked this pull request as ready for review March 11, 2021 13:21
@jbalsas
Copy link

jbalsas commented Mar 11, 2021

Hey @matuzalemsteles, I just thought that since this was already being done like that, we could simply add an additional ClayTooltipProvider to our MultiSelect component in DXP

This obviously doesn't fix any of the issues we've discussed, but maybe it's a simpler pattern. If the tooltip provider doesn't work because of the implementation of your component, you have to either provide a wrapper or another TooltipProvider in a place you know props won't be displaced?

I think this at least allows us to unblock this and provide tooltips by default in react in an easier way for the rest of components.

Thoughts on this anyone?

bryceosterhaus and others added 2 commits March 11, 2021 21:21
In this case, this is necessary because of how the component is passing
`otherProps` to a specific element within the element hierarchy and
not directly to a container. This makes the mouse listeners to be added
to the wrong element and not triggered in other parts of the component.

To solve this in this case we can simply add one additional TooltipProvider
which targets an ancestor wrapper and can handle the mouse interactions
properly
@jbalsas
Copy link

jbalsas commented Mar 11, 2021

ci:forward

@liferay-continuous-integration
Copy link
Collaborator

CI is automatically triggering the following test suites:

  •     ci:test:relevant
  •     ci:test:sf

The pull request will automatically be forwarded to the user brianchandotcom if the following test suites pass:

  •     ci:test:relevant
  •     ci:test:sf
  •     ci:test:stable

@liferay-continuous-integration
Copy link
Collaborator

✔️ ci:test:sf - 1 out of 1 jobs passed in 3 minutes

Click here for more details.

Base Branch:

Branch Name: master
Branch GIT ID: ea0cfa42daaf4aaf805bd985cd2450156086ebb8

Sender Branch:

Branch Name: LPS-128506
Branch GIT ID: 441d8d1c9338a67a0536f59007611c0003d19d00

1 out of 1jobs PASSED
1 Successful Jobs:
For more details click here.

@liferay-continuous-integration
Copy link
Collaborator

@john-co
Copy link

john-co commented Mar 11, 2021

Reviewed. Test failures are unrelated. ✔️

[Unrelated]

@rodrigocunhaa
Copy link

Hi @john-co , this test is actually related to my team. I'll take a look. Thanks!

@liferay-continuous-integration
Copy link
Collaborator

✔️ ci:test:stable - 9 out of 9 jobs passed

❌ ci:test:relevant - 21 out of 33 jobs passed in 3 hours

Click here for more details.

This pull is eligible for reevaluation. When this upstream build has completed, using the following CI command will compare this pull request result against a more recent upstream result:

ci:reevaluate:1087401_7024

Base Branch:

Branch Name: master
Branch GIT ID: ea0cfa42daaf4aaf805bd985cd2450156086ebb8

Upstream Comparison:

Branch GIT ID: 66cbe2581c65f56da46e90a7c5c290b022bfd4fb
Jenkins Build URL: Acceptance Upstream DXP (master) #1630

ci:test:stable - 9 out of 9 jobs PASSED
9 Successful Jobs:
ci:test:relevant - 21 out of 33 jobs PASSED

12 Failed Jobs:

21 Successful Jobs:
For more details click here.

Failures unique to this pull:

  1. test-portal-acceptance-pullrequest-batch(master)/modules-integration-mysql57-jdk8/0
    Job Results:

    6453 Tests Passed.
    1 Test Failed.

    1. AXIS_VARIABLE=17,label_exp=!master #456838
      1. SearchRequestBuilderTest.testAddRescore
        org.junit.ComparisonFailure: {"from":0,"size":10000,"query":{"bool":{"must":[{"bool":{"must":[{"bool":{"should":[{"bool":{"must":[{"match":{"comments":{"query":"delta"}}}],"should":[{"match_phrase":{"comments":{"query":"delta","slop":50}}},{"match_phrase":{"comments":{"query":"delta","boost":2.0}}}]}},{"bool":{"must":[{"match":{"content":{"query":"delta"}}}],"should":[{"match_phrase":{"content":{"query":"delta","slop":50}}},{"match_phrase":{"content":{"query":"delta","boost":2.0}}}]}},{"bool":{"must":[{"match":{"description":{"query":"delta"}}}],"should":[{"match_phrase":{"description":{"query":"delta","slop":50}}},{"match_phrase":{"description":{"query":"delta","boost":2.0}}}]}},{"bool":{"should":[{"wildcard":{"properties":{"wildcard":"*delta*"}}}]}},{"bool":{"must":[{"bool":{"should":[{"match":{"title":{"query":"delta"}}},{"match_phrase_prefix":{"title":{"query":"delta"}}}]}}],"should":[{"match_phrase":{"title":{"query":"delta","boost":2.0}}}]}},{"bool":{"should":[{"match_phrase":{"url":{"query":"delta"}}},{"bool":{"should":[{"wildcard":{"url":{"wildcard":"*delta*"}}}]}},{"match_phrase_prefix":{"url":{"query":"delta","max_expansions":300}}}]}},{"bool":{"should":[{"wildcard":{"userName":{"wildcard":"*delta*"}}}]}},{"bool":{"must":[{"match":{"assetCategoryTitles_en_US":{"query":"delta"}}}],"should":[{"match_phrase":{"assetCategoryTitles_en_US":{"query":"delta","slop":50}}},{"match_phrase":{"assetCategoryTitles_en_US":{"query":"delta","boost":2.0}}}]}},{"bool":{"must":[{"bo...

Failures in common with acceptance upstream results at 66cbe25:
  1. ...
Test bundle downloads:

@john-co
Copy link

john-co commented Mar 12, 2021

I'd also consider the last run unique test failure on modules-integration-mysql57-jdk8/0 as unrelated. Will manually forward.

@john-co
Copy link

john-co commented Mar 12, 2021

forwarded to brianchandotcom#99837

@liferay-continuous-integration
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants