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

[EuiBasicTable] Implement nameTooltip API in columns prop #8273

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

acstll
Copy link
Contributor

@acstll acstll commented Jan 14, 2025

Summary

This PR implements the feature request from #7963

It adds a nameTooltip prop for columns in the EuiBasicTable, in order to easily render a tooltip in a column header.

Regarding the actual API, I left a comment in the original issue with a question; and a comment in the source.

Before

Screenshot 2025-01-20 at 14 43 34

name: (
  <EuiToolTip content="Their mascot is the Octokitty">
    <>
      Github{' '}
      <EuiIcon
        size="s"
        color="subdued"
        type="questionInCircle"
        className="eui-alignTop"
      />
    </>
  </EuiToolTip>
),

After

a59e9d9f055b9fe2e617ce8479a9e273

name: 'GibHub',
nameTooltip: {
  content: 'Their mascot is the Octokitty',
},

QA

General checklist

  • Browser QA
    • Checked in both light and dark modes
    • Checked in mobile
    • Checked in Chrome, Safari, Edge, and Firefox
    • Checked for accessibility including keyboard-only and screenreader modes
  • Docs site QA
  • Code quality checklist
    • Added or updated jest and cypress tests
    • Updated visual regression tests (⚠️ there's the issue with the font rendering, so they might need an update once the issue is resolved)
  • Release checklist
    • A changelog entry exists and is marked appropriately.
    • If applicable, added the breaking change issue label (and filled out the breaking change checklist)
  • Designer checklist
    • If applicable, file an issue to update EUI's Figma library with any corresponding UI changes. (This is an internal repo, if you are external to Elastic, ask a maintainer to submit this request)

@acstll acstll force-pushed the basic-table-nametooltip-7963 branch from 1f08961 to dcf3d6f Compare January 20, 2025 14:07
@acstll acstll marked this pull request as ready for review January 20, 2025 14:14
@acstll acstll requested a review from a team as a code owner January 20, 2025 14:14
@@ -1280,6 +1282,9 @@ export class EuiBasicTable<T extends object = any> extends Component<
sortable,
footer,
mobileOptions,
// do not pass it down, we don't want it in the DOM
// (is this the right way to do this?)
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this is right. When spreading ...rest on a component or element we want to ensure unexpected props are excluded, so restructuring them as you did here ensures that 👍

</EuiTableHeaderCell>
);

expect(container.firstChild).toMatchSnapshot();
Copy link
Contributor

@mgadewoll mgadewoll Jan 21, 2025

Choose a reason for hiding this comment

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

I know this file had already a lot of snapshots, but generally it would be nicer to assert that the element is available instead of using a snapshot, imho.

Edit: Here also a recent conversation on this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah thanks for the link! will remove all the unnecessary snapshots then (you noticed I kinda added everything)

size="m"
color="subdued"
iconProps={tooltip.iconProps}
{...tooltip.tooltipProps}
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I'm not the biggest fan of having tooltip.tooltipProps, that seems convoluted 😅
If the prop on the header cell is tooltip and the main purpose is adding a tooltip I'd assume to have the props directly on the type (similar to EuiIconTip)

Otherwise I'd assume the prop to be called something else (like maybe iconTip 🤔) but that would not match the API in place for e.g. EuiIconTip so we should better align.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understand your point, I'll revise the API to try and polish it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mgadewoll what do you think about this:

  • we make the prop in EuiTableHeaderCell be iconTip, and it just spreads into EuiIconTip
    • the current test in EuiTableHeaderCell will check it renders correctly
  • we keep the API as it is, columns.nameTooltip for EuiBasicTable
    • we add a unit test for EuiBasicTable to check the API

and we do the "normalisation" in basic_table.tsx while rendering the header cells:

const { icon, tooltipProps, ...iconTipProps } = nameTooltip;

const sharedProps = {
    width,
    iconTip: {
        type: icon ?? 'questionInCircle',
        ...tooltipProps,
        ...iconTipProps,
    },
    description,
    mobileOptions,
    align: columnAlign,
    append: this.renderCopyChar(index),
};

yes or nah? 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

or we just make it columns.nameIconTip as well and no normalisation is needed, super easy and transparent… 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, yeah I think this might be a good idea.
My initial worry was that we generally call tooltips tooltip in the APIs and "tooltip" is generally a bit more understandable what's happening than "iconTip". But this is not actually a tooltip on the cell or even the cell name/content but it adds an actual EuiIconTip, so I think this does make sense 👍

On EuiTableHeaderCell it should be iconTipProps then considering our common usage of such an API for passing props to components.

size="m"
color="subdued"
iconProps={tooltip.iconProps}
{...{ position: 'top', ...tooltip.tooltipProps }}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Why combine the props as object on the fly? It's doing the same but - at least to me - this seems more clean since we're spreading props on the component anyway:

position="top"
{...tooltip.tooltipProps}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

much cleaner indeed, thank you

@@ -66,3 +66,14 @@ export const Playground: Story = {
onSort: false,
},
};

export const Tooltip: Story = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's have this open by default so VRT is more useful.

We can use play on the story object to define interactions, e.g. something like this:

play: async ({ step }) => {
    await step('show tooltip on hover', async () => {
      await waitFor(async () => {
        await fireEvent.mouseOver(document.querySelector('.euiToolTipAnchor')!);
      });
    });
  },

Additionally we'll need to change the selector in which the VRT image is taken to ensure the tooltip is included:

parameters: {
    loki: {
      chromeSelector: LOKI_SELECTORS.portal,
    },
  },

Screenshot 2025-01-21 at 10 52 26

Copy link
Contributor Author

Choose a reason for hiding this comment

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

lovely, I will include this (I was actually not sure because it seemed to me the important part was the icon position, and the tooltip is a different component — also I didn't know how to do this haha)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried with different logic (I found in other stories) in the play function but couldn't get it to work — I'll keep trying!

tooltip: {
content: 'tooltip content',
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

For stories showcasing specific behavior, we don't include all props but only relevant ones as all others are already shown by the "playground" story.

You can use parameters.controls.include to define props that should be included.

/**
* Allows adding an icon with a tooltip displayed next to the name
*/
nameTooltip?: EuiTableHeaderCellTooltip;
Copy link
Contributor

Choose a reason for hiding this comment

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

Considering we add this option, I'd vote for updating an EuiBasicTable story to include this prop for one column.

</EuiToolTip>
),
name: 'Date of Birth',
nameTooltip: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Considering that EuiInMemoryTable is a wrapper around EuiBasicTable, we should also include an example in docs/storybook. I think it's fine to just add it to one column in an existing example to showcase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do, nice!

@@ -0,0 +1 @@
- Updated `EuiBasicTable` to allow adding a tooltip to the header cells, with a new `nameTooltip` key in the `columns` prop
Copy link
Contributor

Choose a reason for hiding this comment

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

We updated EuiTableHeaderCell too 🙂

Suggestion:

- Updated table components to support adding tooltips to header cells
  - Added `tooltip` prop on `EuiTableHeaderCell`
  - Added `columns.nameTooltip` on `EuiBasicTable`

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's much better 👌

</EuiTableHeaderCell>
);

expect(container).toMatchSnapshot();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd think this snapshot is not needed?

</EuiTableHeaderCell>
);

expect(container.firstChild).toMatchSnapshot();
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could instead assert DOM order based on checking the nodes and their position? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will give it a try

expect(container.firstChild).toMatchSnapshot();
});

it('handles expected props', async () => {
Copy link
Contributor

@mgadewoll mgadewoll Jan 21, 2025

Choose a reason for hiding this comment

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

Imho, this is the more appropriate test: We assert that the props create an expected DOM output (based on icon and tooltip shown).

Maybe we can remove the first added test in favor of this one.

Edit: Maybe we can make the description a bit more precise though, something like renders an icon with tooltip

Copy link
Contributor Author

Choose a reason for hiding this comment

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

perfect, I agree — regarding the description I was trying to match the overall tone, I can definitely rephrase it

@JasonStoltz JasonStoltz assigned mgadewoll and acstll and unassigned mgadewoll Jan 21, 2025
@acstll acstll force-pushed the basic-table-nametooltip-7963 branch from 570bb48 to 0f096ad Compare January 22, 2025 18:14
@acstll acstll requested a review from mgadewoll January 22, 2025 18:19
@acstll acstll marked this pull request as draft January 23, 2025 08:19
@kibanamachine
Copy link

Preview staging links for this PR:

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @acstll

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

Successfully merging this pull request may close these issues.

4 participants