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

[EuiTablePagination] Adding a Show all option; Plus Pagination Guidelines #5547

Merged
merged 43 commits into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
756d2e4
Fix console error of Custom table example
Nov 1, 2021
86a36a1
[EuiPagination] Allowing `null` if `pageCount` is unknown
Nov 1, 2021
faf9b6d
[EuiPagination] Added tooltip around prev/next buttons and added `'ar…
Nov 1, 2021
ddf3940
[EuiIcon] Added `doubleArrowLeft` and `doubleArrowRight` while also u…
Nov 1, 2021
95875ef
Merge remote-tracking branch 'upstream/main' into feature/simple_pagi…
Nov 8, 2021
57ef10d
Added `first` and `last` buttons and refactored arrow button component
Nov 8, 2021
46476e3
Using negative index for `activePage` to indicate last page
Nov 8, 2021
cedef9c
Cleanup component
Nov 8, 2021
46bfd8d
Render first/last if `compressed` and remove clicks from numbers
Nov 8, 2021
c5d5ec3
Update examples and add one for `Indeterminate`
Nov 8, 2021
82fd090
Fix a11y
Nov 9, 2021
e7d23c6
Merge remote-tracking branch 'upstream/main' into feature/simple_pagi…
Nov 9, 2021
fc129ba
cl
Nov 9, 2021
ff3542f
Added `responsive` prop that renders the `compressed` display and is …
Nov 11, 2021
5227677
cl
Nov 11, 2021
8aa7e20
Merge remote-tracking branch 'upstream/main' into feature/simple_pagi…
Nov 11, 2021
02e59e1
Fix snippets
Nov 11, 2021
a020fe9
Initial text and images for Guidelines
Nov 10, 2021
f8fccde
Allowing `0` for pageCount and adding example of table saved state
Nov 11, 2021
479f27d
Updating copy from UX writer review
Nov 16, 2021
38c53d8
Converted EuiTablePagination to FunctionComponent
Nov 16, 2021
9144b37
[EuiTablePagination] Extending all EuiPagination props
Nov 16, 2021
7e106e5
Merge remote-tracking branch upstream/main into guidelines/pagination
Jan 19, 2022
aab8360
Update Guidelines per suggestions
Jan 19, 2022
06ec154
Fix snaps
Jan 19, 2022
63b5ff2
Cleanup
Jan 19, 2022
34a0d86
[EuiImage] Fix max-width
Jan 19, 2022
f8d9ec2
Merge remote-tracking branch 'upstream/main' into guidelines/pagination
Feb 7, 2022
fcb5618
Fix test & gif
Feb 7, 2022
6903978
Update EuiTablePagination to accept number | 'all' instead of 0 for all
cee-chen Feb 11, 2022
2a05385
Update documentation examples to use 'all'
cee-chen Feb 11, 2022
8efabe6
Update EuiBasicTable and EuiInMemoryTable props to accept 'all'
cee-chen Feb 11, 2022
c476dc8
Update EuiDataGrid pagination props to accept 'all'
cee-chen Feb 11, 2022
62ab0cc
[misc cleanup] Fix typo in pagination prop docs
cee-chen Feb 11, 2022
befab51
Last few fixes
Feb 15, 2022
9e35e86
Merge remote-tracking branch '2_upstream/main' into guidelines/pagina…
Feb 15, 2022
b3e2267
cl
Feb 15, 2022
57d9cfe
Merge branch 'main' into guidelines/pagination
cchaos Feb 15, 2022
c6d3c4d
[PR feedback] Performance optimization + fn naming suggestion
cee-chen Feb 17, 2022
a72972c
Update src/components/table/table_pagination/table_pagination.tsx
cchaos Feb 18, 2022
0fdfff1
snaps
Feb 18, 2022
7d0a43c
Merge branch 'main' into guidelines/pagination
cchaos Feb 18, 2022
c47e3b7
Append `rows` to option text
Feb 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added src-docs/src/images/pagination_filters.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src-docs/src/images/pagination_infinite_do.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src-docs/src/images/pagination_infinite_dont.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src-docs/src/views/datagrid/in_memory_pagination.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default () => {
sorting={{ columns: sortingColumns, onSort }}
pagination={{
...pagination,
pageSizeOptions: [10, 50, 100],
pageSizeOptions: [10, 50, 100, 'all'],
onChangeItemsPerPage: onChangeItemsPerPage,
onChangePage: onChangePage,
}}
Expand Down
384 changes: 384 additions & 0 deletions src-docs/src/views/pagination/guidelines.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,384 @@
import React from 'react';
import { Link } from 'react-router-dom';

import {
GuideRule,
GuideRuleExample,
GuideSectionTypes,
} from '../../components';

import {
EuiText,
EuiSpacer,
EuiPanel,
EuiImage,
EuiHorizontalRule,
EuiBasicTable,
EuiLink,
EuiCode,
EuiButtonEmpty,
EuiContextMenuPanel,
EuiContextMenuItem,
} from '../../../../src/components';

import animatedGif from '../../images/pagination_filters.gif';
import infiniteDo from '../../images/pagination_infinite_do.svg';
import infiniteDont from '../../images/pagination_infinite_dont.svg';

import Table from './paginated_table';
import { GuideSection } from '../../components/guide_section/guide_section';
const source = require('!!raw-loader!./paginated_table');

const items = [
<EuiContextMenuItem key="10 rows" icon={'check'}>
10 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="20 rows" icon={'empty'}>
20 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="50 rows" icon={'empty'}>
50 rows
</EuiContextMenuItem>,
];

const tooManyItems = [
<EuiContextMenuItem key="10 rows" icon={'check'}>
10 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="20 rows" icon={'empty'}>
15 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="20 rows" icon={'empty'}>
20 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="20 rows" icon={'empty'}>
30 rows
</EuiContextMenuItem>,
<EuiContextMenuItem key="50 rows" icon={'empty'}>
50 rows
</EuiContextMenuItem>,
];

export default () => (
<>
<EuiText grow={false}>
<h2>
Don’t rely on pagination for users to find what they’re looking for
</h2>
<p>
For any results-style table, always provide ways to filter, search, etc
for the thing that the user wants. Pagination is only helpful once the
user has reduced the 1000+ results to just 100 (for example).
</p>
</EuiText>

<EuiSpacer />

<EuiPanel
color="subdued"
paddingSize="l"
hasShadow={false}
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<EuiImage
alt="Using search, filters and pagination together"
url={animatedGif}
cchaos marked this conversation as resolved.
Show resolved Hide resolved
size="xl"
/>
<EuiSpacer />
<EuiLink href="https://www.figma.com/proto/RzfYLj2xmH9K7gQtbSKygn/Elastic-UI?page-id=15025%3A1&node-id=22522%3A276461&viewport=441%2C48%2C0.28&scaling=min-zoom&starting-point-node-id=22522%3A276461">
Full prototype
cchaos marked this conversation as resolved.
Show resolved Hide resolved
</EuiLink>
</EuiPanel>

<EuiSpacer size="xxl" />

<EuiText grow={false}>
<h2>Don’t rely on pagination to indicate total results</h2>
<p>
When possible, always present a clear indicator of how many (and if not
all results) have been returned. Just a simple count will do. Including
a detailed summary of results at the top of the table or list goes a
long way to signify what paging can’t.
</p>
<h3>Indicate indeterminate results</h3>
<p>
If you cannot provide a concrete number of results, you still have to
communicate what the current results showcase. For instance, say
&quot;Showing first 100 results&quot; or &quot;Search results maxed at
1000&quot; or &quot;Results fetched at runtime&quot;.
</p>
<p>
<em>
Remember that not all users understand how your data API works. They
just care about the data that&apos;s being shown to them.
</em>
</p>
</EuiText>

<EuiSpacer size="xl" />

<EuiHorizontalRule />

<EuiSpacer size="l" />

<EuiText grow={false}>
<h2>Give users control of pagination</h2>
<p>
Providing a{' '}
<Link to="/navigation/pagination#customizable-pagination">
“Rows per page” option
</Link>{' '}
is often helpful enough to provide users control over the amount of data
they see at once.
</p>
<p>
Keep the choices simple and only show “Rows per page” if there are more
rows than the smallest option. For example, if there are only 9 rows and
the smallest option is 10 rows per page, hide the selector.
</p>
</EuiText>

<GuideRule>
<GuideRuleExample
type="do"
text="For shorter sets of data, you may want to include an “Show all” option."
panelProps={{ paddingSize: 'l' }}
panelStyles={{ alignItems: 'flex-start' }}
minHeight={300}
>
<div>
<EuiButtonEmpty
size="xs"
color="text"
iconType="arrowDown"
iconSide="right"
>
Rows per page: 10
</EuiButtonEmpty>
<EuiSpacer size="s" />
<EuiPanel paddingSize="none" hasShadow>
<EuiContextMenuPanel items={items} />
</EuiPanel>
</div>
</GuideRuleExample>
<GuideRuleExample
type="dont"
text="Overload the user with choices, stick to only 2-3 options."
panelProps={{ paddingSize: 'l' }}
panelStyles={{ alignItems: 'flex-start' }}
minHeight={300}
>
<div>
<EuiButtonEmpty
size="xs"
color="text"
iconType="arrowDown"
iconSide="right"
>
Rows per page: 10
</EuiButtonEmpty>
<EuiSpacer size="s" />
<EuiPanel paddingSize="none" hasShadow>
<EuiContextMenuPanel items={tooManyItems} />
</EuiPanel>
</div>
</GuideRuleExample>
</GuideRule>

<EuiSpacer size="xxl" />

<EuiText grow={false}>
<h3>Optimize your defaults</h3>
<p>
Most users don’t customize the default view. Therefore, it’s vital that
you provide optimal defaults and reduce complexity as the number of
entries increase. This means choosing a default “Rows per page” that
best corresponds to the total results. For instance, 1000+ results
shouldn’t start with 10 rows per page, but rather 20 or 50.
</p>
<p>
Here are some <strong>samples</strong> of what controls to provide based
on the number of data entries.
</p>
</EuiText>

<EuiSpacer size="l" />

<EuiBasicTable
columns={[
{
field: 'entries',
name: 'Total entries',
valign: 'top',
},
{
field: 'rows',
name: 'Rows per page options',
render: (rows) => rows,
valign: 'top',
},
{
field: 'style',
name: 'Pagination style',
render: (style) => style,
valign: 'top',
},
]}
items={[
{
entries: '0',
rows: (
<span>
Use{' '}
<Link to="/display/empty-prompt">
<strong>EuiEmptyPrompt</strong>
</Link>{' '}
in place of table
</span>
),
style: 'N/A',
},
{
entries: 'Less than 50',
rows: 'Show 10, but allow All',
style: <Link to="/navigation/pagination#few-pages">Numbered</Link>,
},
{
entries: '51 - 100',
rows: '10, 20, All',
style: (
<Link to="/navigation/pagination#basic-usage-with-many-pages">
Numbered
</Link>
),
},
{
entries: '101 - 200',
rows: '10, 20, 50',
style: (
<span>
<Link to="/navigation/pagination#basic-usage-with-many-pages">
Numbered
</Link>{' '}
or{' '}
<Link to="/navigation/pagination#compressed-display">
Compressed
</Link>
</span>
),
},
{
entries: 'More than 200',
rows: '20, 50, 100',
style: (
<span>
<Link to="/navigation/pagination#basic-usage-with-many-pages">
Numbered
</Link>{' '}
or{' '}
<Link to="/navigation/pagination#indeterminate-page-count">
Indeterminate
</Link>
</span>
),
},
{
entries: 'Unknown',
rows: (
<span>
Depends on what you <em>expect</em> the total entries to be
</span>
),
style: (
<Link to="/navigation/pagination#indeterminate-page-count">
Indeterminate
</Link>
),
},
]}
/>

<EuiSpacer size="l" />

<EuiText grow={false}>
<p>
If the total results are unknown, you can make a best guess based on the
context of that specific table, whether there’s{' '}
<strong>most likely</strong> going to be tens or thousands of results.
From there you can decide to show 10 rows per page or 20 by default.
</p>
<p>
<strong>
The complexity of the data will also contribute to this equation,
which is why the table above is just a sample.
</strong>
</p>
</EuiText>

<EuiSpacer size="xl" />

<EuiHorizontalRule />

<EuiSpacer size="l" />

<EuiText grow={false}>
<h2>Preserve the user-customized state of pagination</h2>
<p>
When providing pagination, customizable display options, and data
filters, always save the user’s state in some form. This is especially
important if your data includes links that navigate a user away from the
current view. There’s nothing more frustrating for users than going back
to find their filters and pagination have been reset.
</p>
<p>
Below is a working example that utilizes <EuiCode>localStorage</EuiCode>{' '}
to save the table’s state.
</p>
</EuiText>

<EuiSpacer size="l" />

<GuideSection
demo={<Table />}
source={[
{
type: GuideSectionTypes.JS,
code: source,
},
]}
/>

<EuiSpacer size="l" />

<GuideRule
heading="Don’t use infinite scrolling"
description="Infinite scrolling, i.e. loading data as the user scrolls, is the exact
opposite of being able to save the user’s pagination state. As soon as
they navigate away from the page, their position in the list is lost.
It’s better to increase the quantities of rows per page or provide a
“Load more” action."
>
<GuideRuleExample
type="do"
text="Provide a direct action for users to initiate the loading of more data. "
panelProps={{ paddingSize: 'none' }}
panelStyles={{ justifyContent: 'flex-end' }}
>
<EuiImage alt="Provide a Show all" url={infiniteDo} />
</GuideRuleExample>
<GuideRuleExample
type="dont"
text="Use infinite scroll to automatically load more rows of data."
panelProps={{ paddingSize: 'none' }}
panelStyles={{ justifyContent: 'flex-end' }}
>
<EuiImage alt="Too many rows per page choices" url={infiniteDont} />
</GuideRuleExample>
</GuideRule>
</>
);
Loading