-
Notifications
You must be signed in to change notification settings - Fork 841
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
[EuiDataGrid] Use integer values for dimensions derived from integers #6895
[EuiDataGrid] Use integer values for dimensions derived from integers #6895
Conversation
Preview documentation changes for this PR: https://eui.elastic.co/pr_6895/ |
@kqualters-elastic Apologies for totally missing this PR until now - I literally just didn't see the GH notification go by 🤦
I did a bit of logging and unfortunately |
@kqualters-elastic So unfortunately I'm testing https://eui.elastic.co/pr_6895/#/tabular-content/data-grid on Edge/Safari/etc at non-100% zoom and heights are still off/incorrect for me compared to 100% zoom. I think I have a fix locally after some playing around with behavior - let me push up what I have and get your thoughts on it. |
- this appears to be causing at least 50% of the problem / making height recalculate when only width should update, and vice versa
- from my zoom testing, *both* can have annoying decimal behavior, and rounding both solves the issue
Preview documentation changes for this PR: https://eui.elastic.co/pr_6895/ |
tested locally in kibana, everything lgtm from the ways I was previously able to reproduce it 👍 Couple thoughts: can easily write unit tests for all these looks by mocking the refs/getBoundingClientRect calls. Also think long term it would be a good idea to rework making all of these calculations in a series of useEffect/useState -> set a prop on a ref that causes the ref to resize, triggering the whole process over again. Same calculations could be done in fewer steps I think, because there are quite a few custom hooks that return a referentially different value every render, inline functions or variables defined in the render that change every time, etc etc that should either be memoized more aggressively, or the parent components that they are used in not forcing rerenders so casually. |
I'm slightly marginal on writing unit tests for a browser-level bug/edge case; I'd personally rather know that the bug we're attempting to resolve is solved, and mocking That being said if you feel strongly about adding a test to this PR before merge definitely let me know, otherwise I think the lengthy dev comment (hopefully) suffices in terms of future devs not accidentally regressing the check or behavior.
Totally agreed - EuiDataGrid is complex at best and a nightmareish behemoth at worst 😅 Just to add some context around the custom hooks, they were added in #5506 because literally everything was being handled all in 1-2 files and it was frankly super hard to read/grok, let alone write unit tests for (and back then, unit tests were even more missing than they are today). It's definitely still not perfect, but at least concerns are separated by file which should hopefully make it easier to isolate problem areas. I'd be super happy to take PRs on any perf improvements or memoization cleanups you'd like to see happen - feel free to assign any datagrid PRs to me! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to shout if you think this fix needs a test written for it, otherwise I think we can merge this in and get it into Kibana next week 🤞
was thinking about a test that mimics how this bug comes about, where the first few updates to the hook contain a ref with the same dimensions as useUnconstrainedHeight, and then on the fourth or fifth update have the hook mocked as an integer and the ref being slightly smaller, but agree that's not testing much. merge it imo |
## Summary `eui@84.0.0` ⏩ `eui@85.0.1` ## [`85.0.1`](https://github.com/elastic/eui/tree/v85.0.1) **Bug fixes** - Fixed `EuiFilterGroup`'s responsive styles ([#6983](elastic/eui#6983)) ## [`85.0.0`](https://github.com/elastic/eui/tree/v85.0.0) - Updated `EuiThemeProvider` to set an Emotion theme context that returns the values of `useEuiTheme()` ([#6913](elastic/eui#6913)) - Added `size` prop to `EuiStepsHorizontal`, defaulting to the previous size of `m` ([#6928](elastic/eui#6928)) - Added new `s` sizing to `EuiStepsHorizontal` ([#6928](elastic/eui#6928)) - Added `at` and `key` icon glyphs. ([#6934](elastic/eui#6934)) - Added a new `cloneElementWithCss` Emotion utility ([#6939](elastic/eui#6939)) - Updated `EuiPopover` to allow consumer control of all `focusTrapProps` ([#6955](elastic/eui#6955)) **Bug fixes** - Fixed `EuiDataGrid` height calculation bug when browser zoom levels are not 100% ([#6895](elastic/eui#6895)) - Fixed `EuiTab` not correctly passing selection color state to `prepend` and `append` children ([#6938](elastic/eui#6938)) - Fixed `EuiInputPopover` to allow consumer control of its focus trap via `focusTrapProps` ([#6955](elastic/eui#6955)) **Breaking changes** - `EuiProvider` will no longer render multiple or duplicate nested instances of itself. If a nested `EuiProvider` is detected, that instance will return early without further processing, and will warn if configured to do so via `setEuiDevProviderWarning`. For nested theming, use `EuiThemeProvider` instead. ([#6949](elastic/eui#6949)) - Removed `onTrapDeactivation` prop from `EuiPopover`. Use `focusTrapProps.onDeactivation` instead ([#6955](elastic/eui#6955)) **CSS-in-JS conversions** - Converted `EuiFilterGroup` and `EuiFilterButton` to Emotion; Removed styles attached to `.euiFilterGroup__popoverPanel` ([#6957](elastic/eui#6957)) --------- Co-authored-by: Cee Chen <constance.chen@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
## Summary `eui@84.0.0` ⏩ `eui@85.0.1` ## [`85.0.1`](https://github.com/elastic/eui/tree/v85.0.1) **Bug fixes** - Fixed `EuiFilterGroup`'s responsive styles ([elastic#6983](elastic/eui#6983)) ## [`85.0.0`](https://github.com/elastic/eui/tree/v85.0.0) - Updated `EuiThemeProvider` to set an Emotion theme context that returns the values of `useEuiTheme()` ([elastic#6913](elastic/eui#6913)) - Added `size` prop to `EuiStepsHorizontal`, defaulting to the previous size of `m` ([elastic#6928](elastic/eui#6928)) - Added new `s` sizing to `EuiStepsHorizontal` ([elastic#6928](elastic/eui#6928)) - Added `at` and `key` icon glyphs. ([elastic#6934](elastic/eui#6934)) - Added a new `cloneElementWithCss` Emotion utility ([elastic#6939](elastic/eui#6939)) - Updated `EuiPopover` to allow consumer control of all `focusTrapProps` ([elastic#6955](elastic/eui#6955)) **Bug fixes** - Fixed `EuiDataGrid` height calculation bug when browser zoom levels are not 100% ([elastic#6895](elastic/eui#6895)) - Fixed `EuiTab` not correctly passing selection color state to `prepend` and `append` children ([elastic#6938](elastic/eui#6938)) - Fixed `EuiInputPopover` to allow consumer control of its focus trap via `focusTrapProps` ([elastic#6955](elastic/eui#6955)) **Breaking changes** - `EuiProvider` will no longer render multiple or duplicate nested instances of itself. If a nested `EuiProvider` is detected, that instance will return early without further processing, and will warn if configured to do so via `setEuiDevProviderWarning`. For nested theming, use `EuiThemeProvider` instead. ([elastic#6949](elastic/eui#6949)) - Removed `onTrapDeactivation` prop from `EuiPopover`. Use `focusTrapProps.onDeactivation` instead ([elastic#6955](elastic/eui#6955)) **CSS-in-JS conversions** - Converted `EuiFilterGroup` and `EuiFilterButton` to Emotion; Removed styles attached to `.euiFilterGroup__popoverPanel` ([elastic#6957](elastic/eui#6957)) --------- Co-authored-by: Cee Chen <constance.chen@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Bug repro steps
Rows per page
in the bottom left corner of the grid, and select 50Issues affected by this bug
Summary of problem
Under certain circumstances, such as when zoom is not 100%, OS level font/zoom levels are not default, child components having a transform actively applied, browser extensions, and probably a whole lot of other scenarios,
getBoundingClientRect().height/width
will return a decimal number. When these close but not exactly the same values are compared with a value derived from a static number in javascript, like with row height from https://github.com/elastic/eui/blob/main/src/components/datagrid/utils/row_heights.ts#L40, pixel math will break. I believe what's happening is this:useFinalGridDimensions
will calculate a height/width and apply it to the Grid component, this calculation is done by storing a height/width in hook state, and setting it to agetBoundingClientRect().height/width
if those measured values do not match the value fromuseUnconstrainedHeight
. This normally works, asuseUnconstrainedHeight
is first static 34 when row heights are default, and no scrollbar/header row/footer row has been rendered yet, state is set to 34, and both the EUI components and the grid rerender, and the process happens again. This time with the static 34, and a scrollbar of 16, then once more with a static 34 + 16 + 30 from the header, etc. With integer pixel values, everything is good.Two things ultimately make the bug happen: the first is the pixel math and
getBoundingClientRect
resulting in decimal values, and the second is that the useEffect that updates the state will run on either height or width changing, and potentially update them both. Sometimes they both are updated, in other cases just the height or width, and when the bug triggers, the effect will typically only update the width, theunconstrainedHeight
has a value of 50, but for some reason the container is measured as 49.9999997 or something, and so the container height is set to this lower value. From here, no matter what you do, add more rows, change the page etc, the Grid will keep the 49.9997 value as it's height, making the table not usable.QA
Rows per page
in the bottom left corner of the grid, and select 50General checklist
[ ] Added or updated jest and cypress tests