-
Notifications
You must be signed in to change notification settings - Fork 840
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] Virtualization #4170
Merged
chandlerprall
merged 70 commits into
elastic:master
from
chandlerprall:feature/virtualized-datagrid
Jan 28, 2021
Merged
Changes from 68 commits
Commits
Show all changes
70 commits
Select commit
Hold shift + click to select a range
b0d616f
in-progress virtualization
chandlerprall 8125fe2
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 3795c28
Fix leading/trailing column focus management
chandlerprall d4060e5
Re-enabled datagrid header focus
chandlerprall 37c6146
Fix cell tabIndex enable/disabling
chandlerprall 70cec09
Re-enabled initial grid focus when tabbing into it
chandlerprall 3d2ac34
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 89ee454
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 639f3bb
removed outdated code
chandlerprall 653a313
restructure cell focus update calls to avoid render side effect
chandlerprall 3889cc7
respond to changes in cell height
chandlerprall d574ee3
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 9571bc0
Add optional height&width props to EuiDataGrid
chandlerprall f588432
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall e81c56d
Respect height/width props and DOM constraints
chandlerprall b61114a
updated snapshots
chandlerprall bef5073
grid cells styling fixes
snide 1c2a571
Merge remote-tracking branch 'upstream/master' into feature/virtualiz…
snide 1449d02
fix borders and stripes
snide 300801e
remove data_row, since it's no longer in use
snide 8656fc8
fix prop and type for style
snide 83254c1
remove console log
snide 87c97ac
Merge remote-tracking branch 'upstream/master' into feature/virtualiz…
snide 6281a5c
let popover in header act as a toggle
snide 0ca6b5a
Merge remote-tracking branch 'upstream/master' into feature/virtualiz…
snide c4790bc
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 00ed696
recompute grid height when rowCount changes
chandlerprall 8b4ed63
Dynamically detect header row height
chandlerprall 99e5346
Make useMutationObserver actually function
chandlerprall 5328347
fix double-clicky and getting-stuck header cell popovers
chandlerprall 1179b6f
small header height refactor
chandlerprall 52798b3
fix grid height detection to wait until header height is known
chandlerprall 458d25f
Fix footer column widths
chandlerprall 037c979
Down to 2 failing unit tests
chandlerprall adeb437
Fix unit tests
chandlerprall 42a0bb1
Quick react hook dependency cleanup
chandlerprall 33176bc
only show buttons and popover if necessary
flash1293 1f3ba20
improve
flash1293 3c47649
make sure buttons and popover are only rendered if necessary
flash1293 f45009e
Refactor grid container height/width detection, ignore datagrid pages…
chandlerprall 4e5111b
Fix datagrid setCellProps with a style object
chandlerprall 1b2788b
remove an inaccurate comment
chandlerprall b54b4d7
Merge branch 'feature/virtualized-datagrid' into flash1293/datagrid-n…
flash1293 c05d493
clean up
flash1293 5dadd41
reduce rerenders
flash1293 c0d6c4e
remove console logs
flash1293 d205559
fix tests
flash1293 0d91454
convert to single mutation observer
flash1293 ba3eed5
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall c75f81a
Small PR feedback cleanup
chandlerprall b1b9ae2
Fix fullscreen experience; revert change to default example which dup…
chandlerprall 3f14321
Merge remote-tracking branch 'chandlerprall/feature/virtualized-datag…
flash1293 dfe0a90
reduce number of wrapper elements if not necessary
flash1293 43712b9
fix some bugs
flash1293 b7e1685
resolve some issues
flash1293 39816b5
resolve some issues
flash1293 8e3f6e1
resolve some issues
flash1293 10e2ac4
fix leftover problems
flash1293 60f9bd1
fix prettier / ts issues
snide 5286e1f
Merge pull request #1 from snide/cleanup/less-wrappers
flash1293 2b99526
remove unnecessary checks
flash1293 b30faf1
remove unnecessary parameter
flash1293 624446f
Move datagrid's InnerElement to a stand alone component
chandlerprall bd0e2c6
Removed devDep on @types/resize-observer-browser in anticipation of T…
chandlerprall 0f532df
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall 80915fd
Merge pull request #18 from flash1293/flash1293/less-wrappers
chandlerprall fa04eb1
Documentation
chandlerprall 1e345a1
Fix a unit test setup
chandlerprall ca01966
chanagelog
chandlerprall d02a6b3
Merge branch 'master' into feature/virtualized-datagrid
chandlerprall File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src-docs/src/views/datagrid/datagrid_virtualization_example.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import React, { Fragment } from 'react'; | ||
|
||
import { renderToHtml } from '../../services'; | ||
import { EuiCallOut, EuiCode } from '../../../../src/components'; | ||
import { GuideSectionTypes } from '../../components'; | ||
|
||
import DataGridVirtualization from './virtualization'; | ||
const dataGridVirtualizationSource = require('!!raw-loader!./virtualization'); | ||
const dataGridVirtualizationHtml = renderToHtml(DataGridVirtualization); | ||
|
||
import DataGridVirtualizationConstrained from './virtualization_constrained'; | ||
const dataGridVirtualizationConstrainedSource = require('!!raw-loader!./virtualization_constrained'); | ||
const dataGridVirtualizationConstrainedHtml = renderToHtml( | ||
DataGridVirtualizationConstrained | ||
); | ||
|
||
export const DataGridVirtualizationExample = { | ||
title: 'Data grid virtualization', | ||
sections: [ | ||
{ | ||
source: [ | ||
{ | ||
type: GuideSectionTypes.JS, | ||
code: dataGridVirtualizationSource, | ||
}, | ||
{ | ||
type: GuideSectionTypes.HTML, | ||
code: dataGridVirtualizationHtml, | ||
}, | ||
], | ||
text: ( | ||
<Fragment> | ||
<p> | ||
Creating a lot of DOM nodes is computationally expensive, and{' '} | ||
<strong>EuiDataGrid</strong> uses a couple wrapping divs to build | ||
each cell. To help offset the cost of larger tables, cell | ||
virtualization can be opted into by constraining the grid's | ||
height and/or width. There are two ways to enable this | ||
functionality. First, <EuiCode>height</EuiCode> and/or{' '} | ||
<EuiCode>width</EuiCode> can be passed as props, which are applied | ||
to the grid's container style. Alternatively, if{' '} | ||
<strong>EuiDataGrid</strong> is unable to render at the full | ||
dimensions it needs due to screen real estate or other DOM | ||
constraints, it will overflow within a scrollable container and only | ||
render the visible cells. | ||
</p> | ||
|
||
<EuiCallOut | ||
title={ | ||
<> | ||
Never toggle the height between a value and{' '} | ||
<EuiCode>undefined</EuiCode>. | ||
</> | ||
} | ||
color="warning"> | ||
<p> | ||
Similar to React's rule of not switching between a controlled | ||
and uncontrolled input, <EuiCode>EuiDataGrid</EuiCode> does not | ||
accommodate for its height switching to or from{' '} | ||
<EuiCode>undefined</EuiCode>. For demonstration purposes, the | ||
example below uses a <EuiCode>key</EuiCode> to force{' '} | ||
<strong>EuiDataGrid</strong> to completely remount when its height | ||
changes between constrained & constrained heights. | ||
</p> | ||
</EuiCallOut> | ||
</Fragment> | ||
), | ||
components: { DataGridVirtualization }, | ||
demo: <DataGridVirtualization />, | ||
}, | ||
{ | ||
title: 'Constrained by DOM', | ||
source: [ | ||
{ | ||
type: GuideSectionTypes.JS, | ||
code: dataGridVirtualizationConstrainedSource, | ||
}, | ||
{ | ||
type: GuideSectionTypes.HTML, | ||
code: dataGridVirtualizationConstrainedHtml, | ||
}, | ||
], | ||
demo: <DataGridVirtualizationConstrained />, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
import React, { | ||
Fragment, | ||
useCallback, | ||
useState, | ||
createContext, | ||
useContext, | ||
useMemo, | ||
useEffect, | ||
} from 'react'; | ||
import { fake } from 'faker'; | ||
|
||
import { | ||
EuiDataGrid, | ||
EuiLink, | ||
EuiText, | ||
EuiSpacer, | ||
EuiButtonGroup, | ||
} from '../../../../src/components/'; | ||
import { EuiFormRow } from '../../../../src/components/form/form_row'; | ||
|
||
const DataContext = createContext(); | ||
|
||
const raw_data = []; | ||
|
||
for (let i = 1; i < 10000; i++) { | ||
const email = fake('{{internet.email}}'); | ||
const name = fake('{{name.lastName}}, {{name.firstName}}'); | ||
const suffix = fake('{{name.suffix}}'); | ||
raw_data.push({ | ||
name: `${name} ${suffix}`, | ||
email: <EuiLink href="">{email}</EuiLink>, | ||
location: ( | ||
<Fragment> | ||
{`${fake('{{address.city}}')}, `} | ||
<EuiLink href="https://google.com"> | ||
{fake('{{address.country}}')} | ||
</EuiLink> | ||
</Fragment> | ||
), | ||
date: fake('{{date.past}}'), | ||
account: fake('{{finance.account}}'), | ||
amount: fake('${{commerce.price}}'), | ||
phone: fake('{{phone.phoneNumber}}'), | ||
version: fake('{{system.semver}}'), | ||
}); | ||
} | ||
|
||
const columns = [ | ||
{ | ||
id: 'name', | ||
displayAsText: 'Name', | ||
defaultSortDirection: 'asc', | ||
}, | ||
{ | ||
id: 'email', | ||
}, | ||
{ | ||
id: 'location', | ||
}, | ||
{ | ||
id: 'account', | ||
}, | ||
{ | ||
id: 'date', | ||
defaultSortDirection: 'desc', | ||
}, | ||
{ | ||
id: 'amount', | ||
}, | ||
{ | ||
id: 'phone', | ||
isSortable: false, | ||
}, | ||
{ | ||
id: 'version', | ||
defaultSortDirection: 'desc', | ||
initialWidth: 65, | ||
isResizable: false, | ||
}, | ||
]; | ||
|
||
function RenderCellValue({ rowIndex, columnId }) { | ||
const { data, adjustMountedCellCount } = useContext(DataContext); | ||
|
||
useEffect(() => { | ||
adjustMountedCellCount(1); | ||
return () => adjustMountedCellCount(-1); | ||
}, [adjustMountedCellCount]); | ||
|
||
return data.hasOwnProperty(rowIndex) ? data[rowIndex][columnId] : null; | ||
} | ||
|
||
const dimensionSizes = { | ||
'height-300px': 300, | ||
'height-600px': 600, | ||
|
||
'width-200px': 200, | ||
'width-50%': '50%', | ||
'width-unconstrained': undefined, | ||
}; | ||
|
||
export default () => { | ||
// ** Pagination config | ||
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 50 }); | ||
const onChangeItemsPerPage = useCallback( | ||
(pageSize) => | ||
setPagination((pagination) => ({ | ||
...pagination, | ||
pageSize, | ||
pageIndex: 0, | ||
})), | ||
[setPagination] | ||
); | ||
const onChangePage = useCallback( | ||
(pageIndex) => | ||
setPagination((pagination) => ({ ...pagination, pageIndex })), | ||
[setPagination] | ||
); | ||
|
||
// Column visibility | ||
const [visibleColumns, setVisibleColumns] = useState(() => | ||
columns.map(({ id }) => id) | ||
); // initialize to the full set of columns | ||
|
||
const [mountedCellCount, setMountedCellCount] = useState(0); | ||
|
||
const dataContext = useMemo( | ||
() => ({ | ||
data: raw_data, | ||
adjustMountedCellCount: (adjustment) => | ||
setMountedCellCount( | ||
(mountedCellCount) => mountedCellCount + adjustment | ||
), | ||
}), | ||
[] | ||
); | ||
|
||
const [height, setHeight] = useState('height-300px'); | ||
const [width, setWidth] = useState('width-50%'); | ||
|
||
return ( | ||
<> | ||
<EuiFormRow label="Height"> | ||
<EuiButtonGroup | ||
legend="Set a height for the following grid" | ||
options={[ | ||
{ id: 'height-300px', label: '300px' }, | ||
{ id: 'height-600px', label: '600px' }, | ||
{ id: 'height-unconstrained', label: 'Unconstrained' }, | ||
]} | ||
idSelected={height} | ||
onChange={setHeight} | ||
/> | ||
</EuiFormRow> | ||
|
||
<EuiFormRow label="Width"> | ||
<EuiButtonGroup | ||
legend="Set a width for the following grid" | ||
options={[ | ||
{ id: 'width-200px', label: '200px' }, | ||
{ id: 'width-50%', label: '50%' }, | ||
{ id: 'width-unconstrained', label: 'Unconstrained' }, | ||
]} | ||
idSelected={width} | ||
onChange={setWidth} | ||
/> | ||
</EuiFormRow> | ||
|
||
<EuiSpacer /> | ||
|
||
<EuiText> | ||
<p>There are {mountedCellCount} rendered cells</p> | ||
</EuiText> | ||
|
||
<DataContext.Provider value={dataContext}> | ||
<EuiDataGrid | ||
// completely reset the grid when switching between controlled & uncontrolled heights | ||
// otherwise, going from constrained->unconstrained is ignored. | ||
// this is for example only, don't switch between controlled & uncontrolled heights | ||
key={ | ||
height === 'height-unconstrained' ? 'unconstrained' : 'constrained' | ||
} | ||
aria-label="Virtualized data grid demo" | ||
height={dimensionSizes[height]} | ||
width={dimensionSizes[width]} | ||
columns={columns} | ||
columnVisibility={{ visibleColumns, setVisibleColumns }} | ||
rowCount={raw_data.length} | ||
renderCellValue={RenderCellValue} | ||
pagination={{ | ||
...pagination, | ||
pageSizeOptions: [50, 250, 1000], | ||
onChangeItemsPerPage: onChangeItemsPerPage, | ||
onChangePage: onChangePage, | ||
}} | ||
/> | ||
</DataContext.Provider> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This has been bugging me a bunch in our docs. Why do we have a button (icon) within a
<button>
instead of just using a context menu?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.
There's also a whole bunch of console error because of the nested
<button>
s.