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

[Emotion] Convert EuiBasicTable #6539

Merged
merged 13 commits into from
Jan 23, 2023
Merged

Conversation

cee-chen
Copy link
Contributor

@cee-chen cee-chen commented Jan 20, 2023

Summary

Me: Oh basic_table.scss is pretty small, I should just super quickly go in and convert this component!
Also me: Oh yeah this is going to need a new theme helper. Also I'm going to rewrite literally all the unit tests.

I strongly recommend following along by commit, and also taking a shot when you get to the unit tests commit 🤪

QA

General checklist

  • Checked in both light and dark modes
  • Checked in mobile
  • Checked in Chrome, Safari, Edge, and Firefox
  • Added or updated jest and cypress tests
  • A changelog entry exists and is marked appropriately

Emotion conversion checklist

  • Does it work?
  • Output CSS matches the previous CSS / as expected in browsers
  • Rendered className reads as expected in snapshots and in browsers
    - [ ] Checked component playground (class components wrapped in withEuiTheme need to pass true as the second argument to its propUtilityForPlayground in src-docs/src/views/{component}/playground.js)
     
  • Unit tests
  • shouldRenderCustomStyles() test was added and passes with parent component and any nested childProps (e.g. tooltipProps)
  • Removed any mount()ed snapshots in favor of render() or a more specific assertion
     
  • Sass/Emotion conversion process
  • Removed component from src/components/index.scss
    - [ ] Converted all global Sass vars/mixins to JS (e.g. $euiSize to euiTheme.size.base)
    - [ ] Removed or converted component-specific Sass vars/mixins to exported JS versions, listed removals in changelog, and manually updated our theme JSON files
    - [ ] Simplified calc() to mathWithUnits if possible (if mixing different unit types, this may not be possible)
    - [ ] Added an @warn deprecation message within the global_styling/mixins/{component}.scss file
    - [ ] Deleted any src/amsterdam/overrides/{component}.scss files (styles within should have been converted to the baseline Emotion styles)
     
  • CSS tech debt
  • Reduced specificity where possible (usually by reducing nesting and class name chaining)
  • Wrapped all animations or transitions in euiCanAnimate
  • Converted side specific padding, margin, and position to -inline and -block logical properties (check inline styles as well as CSS)
    - [ ] Used gap property to add margin between items if using flex
     
  • DOM cleanup
  • Did not remove any block/element classNames (e.g. euiComponent, euiComponent__child)
  • Did not remove any modifier classes - I grepped through Kibana and there are too many instances of devs pointing at euiBasicTable-loading
     
  • Kibana due diligence
  • Pre-emptively check how your conversion will impact the next Kibana upgrade. This entails searching/grepping through Kibana (excluding **/target, **/*.snap, **/*.storyshot for less noise) for eui{Component} (case sensitive) to find:
  • Any test/query selectors that will need to be updated
  • Any Sass or CSS that will need to be updated, particularly if a component Sass var was deleted
  • Any direct className usages that will need to be refactored (e.g. someone calling the euiBadge class on a div instead of simply using the EuiBadge component)
  • No classNames were removed and no direct usages of people setting euiBasicTable on something, so we should be good
     
  • Extras/nice-to-have
  • Skipped - Elizabet is handling awesome docs refactor

- which is generally a nicer API than the one I yolo'd
- I opted not to create a top-level component for this due to the very limited styles being applied, and due to HOC/theme access shenanigans
- by only rendering one `<tbody>`, not multiple
+ switch `render` to RTL
- switch to RTL totally (shallow was not handling the new render prop well)
- DRY out various repeated props
- stop use snapshots for every single test - use specific assertions instead. For visual rendering for various prop combos, we should use Storybook
- leave snapshots in for two specific render tests - barebones & kitchen sink props
- this matches how EuiProgress behaves

+ clean up animation shorthand
Comment on lines +46 to +50
animation: ${tableLoadingLine} 1s linear infinite;

${euiCantAnimate} {
animation-duration: 2s;
}
Copy link
Contributor Author

@cee-chen cee-chen Jan 20, 2023

Choose a reason for hiding this comment

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

[not sure if this conversation belongs in this PR or as a separate/follow-up item]

@miukimiu I'm not sure if this needs to be DRY'd out with EuiProgress at all (including the animation)? The animation is remarkably similar (but not quite the same).

https://elastic.github.io/eui/#/display/progress

animation: ${euiIndeterminateAnimation} 1s
${euiTheme.animation.resistance} infinite;
${euiCantAnimate} {
animation-duration: 2s;
animation-timing-function: linear;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to work next on tables empty and loading states. So I think for now we can leave it as it is. Then according to the direction the design takes, I can refactor the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On second thought, I do still want to investigate this, but I'd prefer we address it in a follow-up PR rather than this PR. I'm hoping to get this in by tomorrow's release so we have an Emotion conversion in for the next Kibana upgrade

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds great, thanks @miukimiu!

- apparently `position: relative` on the parent and not on the `tbody` was a cross-browser fix :(
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6539/

@cee-chen cee-chen marked this pull request as ready for review January 20, 2023 05:19
Comment on lines +972 to +977
<EuiTableBody
bodyRef={this.setTbody}
css={loading && euiBasicTableBodyLoading(theme)}
>
{content}
</EuiTableBody>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This changes the error message & empty message to also set a body ref, but after investigating setTbody and what we're even using that for I have fairly strong feelings about getting rid of us blocking actions while loading is true (#5014), although I would prefer to remove all that in a separate PR.

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6539/

@elizabetdev elizabetdev self-requested a review January 23, 2023 15:41
Comment on lines +98 to +109
/**
* Render prop alternative for complex class components
* Most useful for scenarios where a HOC may interfere with typing
*/
export const RenderWithEuiTheme = <T extends {} = {}>({
children,
}: {
children: (theme: UseEuiTheme) => React.ReactElement;
}) => {
const theme = useEuiTheme<T>();
return children(theme);
};
Copy link
Contributor Author

@cee-chen cee-chen Jan 23, 2023

Choose a reason for hiding this comment

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

A quick explanation for why I added a new theme util for class components instead of simply attempting to use the existing withEuiTheme HOC:

Typescript lost its mind, especially typing around ref usage (used to access internal class methods). We've run into this in the past with EuiDualRange so I sorta knew this was coming:

// This super annoying type is now required to pass both the `ref` typing and account for instance methods
type EuiDualRangeRef = React.ComponentProps<typeof EuiDualRange> &
EuiDualRangeClass;
const ConsumerDualRange = ({ callResize }: { callResize?: boolean }) => {
const rangeRef = useRef<EuiDualRangeRef>(null);

Unfortunately, EuiBasicTable is worse than EuiDualRange because 1. it uses a typescript generic <T>, which the current withEuiTheme HOC appears to find impossible to understand (or I'm not using it correctly?), and 2. ref access to set internal selection state is a more common pattern with EuiBasicTable (we specifically document it in our table examples).

Since EuiBasicTable usage is generally higher across Kibana, I very specifically wanted to go out of my way to avoid type and snapshots headaches downstream in Kibana, by leaving its exported class component intact and grabbing the EUI theme via render prop instead. This was doable because styles on EuiBasicTable is actually very light and is limited to a conditional loading state.

Comment on lines +970 to +975
<RenderWithEuiTheme>
{(theme) => (
<EuiTableBody
bodyRef={this.setTbody}
css={loading && euiBasicTableBodyLoading(theme)}
>
Copy link
Contributor Author

@cee-chen cee-chen Jan 23, 2023

Choose a reason for hiding this comment

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

For context: The reason why I wrapped the loading styles around just the EuiTableBody and not the entire render()ed JSX was to reduce the previous .euiBasicTable-loading tbody {} CSS nesting to a single flat selector.

In general because the EuiBasicTable-specific styles are so light I think this worked fine. I didn't bother doing a traditional Emotion CSS-in-JS object with an euiBasicTable: css``, line because I didn't see it as necessary - we don't need to apply any styles to the actual wrapper and all the styles are conditional to the loading condition and could be represented by a simple &&.

{
'euiBasicTable-loading': loading,
},
{ 'euiBasicTable-loading': loading },
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately this modifier class has 48 usages in 21 files in Kibana so I left it alone / didn't bother converting it to a data attr since usage is so high.

Comment on lines +689 to +691
<tbody
class="css-0"
>
Copy link
Contributor Author

@cee-chen cee-chen Jan 23, 2023

Choose a reason for hiding this comment

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

(Follow up to #6539 (review))

Quick FYI as to where these classes are coming from - the conditional Emotion styles I added via loading && are working correctly, but for reasons (emotion-js/emotion#1529) Emotion still applies a blank/empty css-0 class when anything is passed to the css={} prop, even false or undefined, so this gets output.

This will probably end up looking less strange when we convert all our underlying table styles to Emotion (it will get the euiTable- prefix at that point).

Copy link
Contributor

@elizabetdev elizabetdev left a comment

Choose a reason for hiding this comment

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

Thanks, @cee-chen.

I tested in Chrome, Safari, and Firefox. I also looked at the code. LGTM! 👍🏽

Not sure if an engineer should also take a look.

Comment on lines +46 to +50
animation: ${tableLoadingLine} 1s linear infinite;

${euiCantAnimate} {
animation-duration: 2s;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to work next on tables empty and loading states. So I think for now we can leave it as it is. Then according to the direction the design takes, I can refactor the code.

@1Copenut 1Copenut self-requested a review January 23, 2023 19:13
Copy link
Contributor

@1Copenut 1Copenut left a comment

Choose a reason for hiding this comment

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

👍 LGTM! I took a couple of hours to really understand what was being added and how you're wrapping complicated class components. Your tests and comments were a big help explaining the HOC and render props. Much appreciated.

@cee-chen
Copy link
Contributor Author

Thanks y'all, much appreciated!

@cee-chen cee-chen merged commit be23158 into elastic:main Jan 23, 2023
@cee-chen cee-chen deleted the emotion/basic-table branch January 23, 2023 23:34
cee-chen added a commit that referenced this pull request Jan 24, 2023
* [EuiToolTip] Add `repositionOnScroll` prop (#6515)

* Add `repositionOnScroll` prop and event listener

* [Docs] Add fixed tooltip example

+ add auto-focus behavior for keyboard users

* changelog

* Updated changelog.

* 72.2.0

* Updated documentation.

* [EuiDataGrid] Fix nested interactive controls axe error (#6517)

* Fix nested interactive controls error in column visibility control

* Restore mouse experience by making switch "label" draggable

- this (almost) restores previous draggable functionality - the column name and handle are both mouse draggable, while the switch is not as it is its own interactive thing

* Fix nested interactive controls error in column sorting control

- the X button and sort button group should not be draggable as they are interactive

* Improve mouse experience by making column name draggable

- The x button and sort button group are interactive and cannot be draggable, but the column name/token can be

+ tweak padding to belong to the column name, for extra grabbable area

* [opinionated] Fix multiple CSS styles to actually work correctly

- whether or not these style changes are wanted will have to be approved by a designer

* changelog

* Improve Kibana upgrade docs (#6518)

- add table of contents

- order steps more generally in chronological order so it's easier to follow vs jumping around the page

- update recommendations and general context

* [Docs] Update `EuiConfirmModal` examples (#6519)

* [Docs] Update `EuiConfirmModal` examples

* Adding a width

* Update src-docs/src/views/modal/confirm_modal.tsx

Co-authored-by: florent-leborgne <[email protected]>

Co-authored-by: florent-leborgne <[email protected]>

* [EuiToolTip] Enforce only one visible tooltip at a time (#6520)

* [misc cleanup] Group relative imports by general concept

- keep parent services together, keep tooltip-specific imports together

* Add tooltip manager that hides all other tooltips when a new tooltip is shown

* Write Cypress E2E tests for multiple tooltip behavior

* Changelog

* Unit tests for control of internal tooltip visibility state via `ref` (#6522)

* [Docs] Fix code snippet (#6526)

* Added a11y specs for EuiNotificationEvent, EuiPageHeader, EuiPortal (#6524)

* Added a11y specs for EuiNotificationEvent, EuiPageHeader, EuiPortal

* Added a11y and keyboard specs for EuiNotificationEvent.
* Added page header a11y tests.
* Added a11y and keyboard specs for EuiPortal.

* Simplifying Portal test, adding breadcrumb and tabs to Page Header.

* Simplified two components, added a state check to EuiNotification.

* Further reducing the EuiPortal specs to test just that one component.

* update i18ntokens

* Updated changelog.

* 73.0.0

* Updated documentation.

* Check that the `upstream` remote is correctly set before proceeding in release script (#6528)

* [EuiModalHeaderTitle] Remove automatic detection of title contents in favor of always wrapping a `h1`, configurable via new `component` prop (#6530)

* Use a `component` prop for EuiModalHeaderTitle tag wrapper instead of trying to detect child types

- this is because Kibana's `<FormattedMessage>` component (which only outputs a string) is incorrectly not getting styles applied to it

* Add prop unit tests

+ convert tests to RTL while we're here

* Allow `EuiConfirmModal`s to override title component tag as well if necessary

* Changelog

* tweak changelog copy a bit more

* [Docs EuiTable] Replace all the demos using `data_store` with `faker-js` (#6521)

* Replacing `data_store` with `faker-js`

* Converted `actions.js` to `tsx`

* Converted `auto.js` to `.tsx`

* Converted `expanding_rows.js` to `*.tsx`

* Converted `footer.js` to `*.tsx`

* Converted `mobile.js` to `*.tsx`

* Converted `selection.js` to `*.tsx`

* Converted `sorting.js` to `*.tsx`

* Fix typing/`any` usages

- provide correct EuiBasicTable typescript usages/definitions

* Clean up divs and Fragments

* Simplify & clean up delete selected items code

+ remove it entirely from `footer` and `expanding_rows` examples - those demos really don't need that behavior at all

* Remove unnecessary `renderStatus` abstraction

- not being used in multiple places, so no need to DRY it out

* Fix incorrectly rendering mobile names

+ DRY out `renderStatus`
- not totally clear to me why those examples have such complex mobile examples

+ add a `mobileOptions.only` example in the `mobile` demo to make up for removed examples

* Remove unused `sortable`

- there's no sorting being passed to the table, so it does nothing

* Clean up table layout example

- remove need for randomly generated group IDs
- simplify var names
- use value passed directly from `onChange` instead of using a `.find()`
- use flex group for button toggles instead of `&emsp;`s

* Clean up emoji flag logic

- move `getEmojiFlag` util to bottom of the file - it's not relevant to anything table-related and shouldn't  be the first thing a dev has to read/parse

- remove unnecessary extra flag/countryCode() call

* Remove unnecessary data length abstraction/logic

- if `userLength` isn't being used anywhere else, just hard code it in - no need for a var

- remove unnecessary `filteredUsers` logic

+ remove unnecessary `RIGHT_ALIGNMENT` import

* Organize table/component logic by concept

- move `columns` out to static init where logical

- add headings to sort out manual pagination/sorting logic where it isn't necessarily relevant to the demo (but aids in visual output)

- add comment to `findUsers` to more clearly explain what it's doing

- remove unnecessary abstractions for longer files

* Removed `getEmojiFlag`

* Remove lodash `uniqBy` dependency

- replace one instance with a `Set` example for uniqueness

* Tweak new location column to truncate

- this column is now fairly long compared to before - let's restore the previous table visual apperances by truncating

* Standardize inconsistent link behavior

- it doesn't really make sense to have a last name be a link as opposed to a username - some demos were doing this, some weren't, so standardize the rendering

- remove actual external links to github - most of the newly random usernames aren't valid in any case

Co-authored-by: Constance Chen <[email protected]>

* Removed domain check from EuiLink (#6535)

This PR changes the behavior of the EUILink component to apply rel="noreferrer" universally for all external links, as it's considered a best practice.

Prior to this PR, there was an exception for elastic.co domains, added in #1565. As this behavior is no longer required, we're opting to remove the exception.

* [EuiBasicTable] Fix row heights jumping when actions are disabled (#6538)

* [EuiBasicTable] Fix row heights jumping when actions are disabled

* Update snapshots

* changelog

* Adding EuiModal callout for H1 rendering. (#6497)

* Adding EuiModal callout for H1 rendering.

* Updating text to be more concise and clear.

* Updating documentation for default H1 wrapper on EuiModalHeaderTitle.

* Removing example callout, added explanation to component type definition.

* Removed extra H1 tags from Docs examples.

* Removed H1 from EUIModal component and a11y specs.

* Update checklist template to recommend `@default` jsdoc usage (#6541)

* [Emotion] Convert EuiBasicTable (#6539)

* [tech debt] convert `useEuiTheme` tests to RTL `renderHook`

- which is generally a nicer API than the one I yolo'd

* [tech debt] Add more missing unit tests for `useEuiTheme`

* [tech debt] write basic unit test for `withEuiTheme`

* Add new `RenderWithEuiTheme` render prop util

* Convert `tbody` loading styles to Emotion

- I opted not to create a top-level component for this due to the very limited styles being applied, and due to HOC/theme access shenanigans

* Fix error/empty states not rendering loading styles

- by only rendering one `<tbody>`, not multiple

* Write basic `loading` test
+ switch `render` to RTL

* [extra] Massive clean up of EuiBasicTable unit tests

- switch to RTL totally (shallow was not handling the new render prop well)
- DRY out various repeated props
- stop use snapshots for every single test - use specific assertions instead. For visual rendering for various prop combos, we should use Storybook
- leave snapshots in for two specific render tests - barebones & kitchen sink props

* Delete scss files

* Add `shouldRenderCustomStyles` test

* changelog

* Add affordance for reduced motion media query

- this matches how EuiProgress behaves

+ clean up animation shorthand

* Add CSS workaround/fix for visual Safari bug

- apparently `position: relative` on the parent and not on the `tbody` was a cross-browser fix :(

* [EuiResizablePanel] Added tabindex prop to EuiResizablePanel for keyboard accessibility. (#6534)

* Added tabindex prop to EuiResizablePanel for keyboard accessibility.
* Added unit test and corrected tabIndex type.
* Renaming tabindex to tabIndex for consistency in docs.
* Renaming test description. Removing changelog.

Co-authored-by: Jason Stoltzfus <[email protected]>
Co-authored-by: Elizabet Oliveira <[email protected]>
Co-authored-by: florent-leborgne <[email protected]>
Co-authored-by: Trevor Pierce <[email protected]>
Co-authored-by: Bree Hall <[email protected]>
jbudz pushed a commit to elastic/kibana that referenced this pull request Jan 27, 2023
## Summary

`[email protected]` ⏩ `[email protected]`

---

## [`74.0.1`](https://github.com/elastic/eui/tree/v74.0.1)

**Bug fixes**

- Fixed `EuiModalHeaderTitle` type errors when passed `EuiTitle` props
([#6547](elastic/eui#6547))

## [`74.0.0`](https://github.com/elastic/eui/tree/v74.0.0)

- Added the `component` prop to `EuiModalHeaderTitle`, which allows
overriding the default `h1` tag
([#6530](elastic/eui#6530))
- Added the `titleProps` prop to `EuiConfirmModal`, which allows
overriding the default `h1` tag
([#6530](elastic/eui#6530))

**Bug fixes**

- Fixed slight row height jumping in `EuiBasicTable`s when actions with
tooltips became disabled
([#6538](elastic/eui#6538))

**Breaking changes**

- `EuiModalHeaderTitle` now **always** wraps its children in a `h1` tag
(previously attempted to conditionally detect whether its children were
raw strings or not). To change this tag type to, e.g. a more generic
`div`, use the new `component` prop.
([#6530](elastic/eui#6530))
- `EuiLink` now applies `rel="noreferrer"` to all domains, including
`elastic.co` ([#6535](elastic/eui#6535))
- `EuiBasicTable` no longer blocks mouse/keyboard interactions while
`loading` ([#6543](elastic/eui#6543))

**CSS-in-JS conversions**

- Converted `EuiBasicTable` to Emotion
([#6539](elastic/eui#6539))
- Added a new `RenderWithEuiTheme` render prop utility
([#6539](elastic/eui#6539))

---------

Co-authored-by: Kibana Machine <[email protected]>
kqualters-elastic pushed a commit to kqualters-elastic/kibana that referenced this pull request Feb 6, 2023
## Summary

`[email protected]` ⏩ `[email protected]`

---

## [`74.0.1`](https://github.com/elastic/eui/tree/v74.0.1)

**Bug fixes**

- Fixed `EuiModalHeaderTitle` type errors when passed `EuiTitle` props
([elastic#6547](elastic/eui#6547))

## [`74.0.0`](https://github.com/elastic/eui/tree/v74.0.0)

- Added the `component` prop to `EuiModalHeaderTitle`, which allows
overriding the default `h1` tag
([elastic#6530](elastic/eui#6530))
- Added the `titleProps` prop to `EuiConfirmModal`, which allows
overriding the default `h1` tag
([elastic#6530](elastic/eui#6530))

**Bug fixes**

- Fixed slight row height jumping in `EuiBasicTable`s when actions with
tooltips became disabled
([elastic#6538](elastic/eui#6538))

**Breaking changes**

- `EuiModalHeaderTitle` now **always** wraps its children in a `h1` tag
(previously attempted to conditionally detect whether its children were
raw strings or not). To change this tag type to, e.g. a more generic
`div`, use the new `component` prop.
([elastic#6530](elastic/eui#6530))
- `EuiLink` now applies `rel="noreferrer"` to all domains, including
`elastic.co` ([elastic#6535](elastic/eui#6535))
- `EuiBasicTable` no longer blocks mouse/keyboard interactions while
`loading` ([elastic#6543](elastic/eui#6543))

**CSS-in-JS conversions**

- Converted `EuiBasicTable` to Emotion
([elastic#6539](elastic/eui#6539))
- Added a new `RenderWithEuiTheme` render prop utility
([elastic#6539](elastic/eui#6539))

---------

Co-authored-by: Kibana Machine <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants