mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
grafana/ui: Update pagination component for large number of pages (#30151)
This commit is contained in:
parent
4ed283e7bf
commit
9b4d4915b0
@ -2,6 +2,9 @@ import React from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { stylesFactory } from '../../themes';
|
||||
import { Button, ButtonVariant } from '../Button';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
|
||||
const PAGE_LENGTH_TO_CONDENSE = 8;
|
||||
|
||||
interface Props {
|
||||
/** The current page index being shown. */
|
||||
@ -16,21 +19,84 @@ export const Pagination: React.FC<Props> = ({ currentPage, numberOfPages, onNavi
|
||||
const styles = getStyles();
|
||||
const pages = [...new Array(numberOfPages).keys()];
|
||||
|
||||
const condensePages = numberOfPages > PAGE_LENGTH_TO_CONDENSE;
|
||||
const getListItem = (page: number, variant: 'primary' | 'secondary') => (
|
||||
<li key={page} className={styles.item}>
|
||||
<Button size="sm" variant={variant} onClick={() => onNavigate(page)}>
|
||||
{page}
|
||||
</Button>
|
||||
</li>
|
||||
);
|
||||
|
||||
const pageButtons = pages.reduce<JSX.Element[]>((pagesToRender, pageIndex) => {
|
||||
const page = pageIndex + 1;
|
||||
const variant: ButtonVariant = page === currentPage ? 'primary' : 'secondary';
|
||||
|
||||
// The indexes at which to start and stop condensing pages
|
||||
const lowerBoundIndex = PAGE_LENGTH_TO_CONDENSE;
|
||||
const upperBoundIndex = numberOfPages - PAGE_LENGTH_TO_CONDENSE + 1;
|
||||
// When the indexes overlap one another this number is negative
|
||||
const differenceOfBounds = upperBoundIndex - lowerBoundIndex;
|
||||
|
||||
const isFirstOrLastPage = page === 1 || page === numberOfPages;
|
||||
// This handles when the lowerBoundIndex < currentPage < upperBoundIndex
|
||||
const currentPageIsBetweenBounds =
|
||||
differenceOfBounds > -1 && currentPage >= lowerBoundIndex && currentPage <= upperBoundIndex;
|
||||
|
||||
if (condensePages) {
|
||||
if (
|
||||
isFirstOrLastPage ||
|
||||
(currentPage < lowerBoundIndex && page < lowerBoundIndex) ||
|
||||
(differenceOfBounds >= 0 && currentPage > upperBoundIndex && page > upperBoundIndex) ||
|
||||
(differenceOfBounds < 0 && currentPage >= lowerBoundIndex && page > upperBoundIndex) ||
|
||||
(currentPageIsBetweenBounds && page >= currentPage - 2 && page <= currentPage + 2)
|
||||
) {
|
||||
// Renders a button for the page
|
||||
pagesToRender.push(getListItem(page, variant));
|
||||
} else if (
|
||||
(page === lowerBoundIndex && currentPage < lowerBoundIndex) ||
|
||||
(page === upperBoundIndex && currentPage > upperBoundIndex) ||
|
||||
(currentPageIsBetweenBounds && (page === currentPage - 3 || page === currentPage + 3))
|
||||
) {
|
||||
// Renders and ellipsis to represent condensed pages
|
||||
pagesToRender.push(
|
||||
<li key={page} className={styles.item}>
|
||||
<Icon className={styles.ellipsis} name="ellipsis-v" />
|
||||
</li>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
pagesToRender.push(getListItem(page, variant));
|
||||
}
|
||||
return pagesToRender;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<ol>
|
||||
{pages.map((pageIndex) => {
|
||||
const page = pageIndex + 1;
|
||||
const variant: ButtonVariant = page === currentPage ? 'primary' : 'secondary';
|
||||
|
||||
return (
|
||||
<li key={page} className={styles.item}>
|
||||
<Button size="sm" variant={variant} onClick={() => onNavigate(page)}>
|
||||
{page}
|
||||
</Button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
<li className={styles.item}>
|
||||
<Button
|
||||
aria-label="previous"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => onNavigate(currentPage - 1)}
|
||||
disabled={currentPage === 1}
|
||||
>
|
||||
<Icon name="angle-left" />
|
||||
</Button>
|
||||
</li>
|
||||
{pageButtons}
|
||||
<li className={styles.item}>
|
||||
<Button
|
||||
aria-label="next"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => onNavigate(currentPage + 1)}
|
||||
disabled={currentPage === numberOfPages}
|
||||
>
|
||||
<Icon name="angle-right" />
|
||||
</Button>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
);
|
||||
@ -46,5 +112,8 @@ const getStyles = stylesFactory(() => {
|
||||
padding-left: 10px;
|
||||
margin-bottom: 5px;
|
||||
`,
|
||||
ellipsis: css`
|
||||
transform: rotate(90deg);
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user