diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.tsx index d98c6aa582b..a40c49e669d 100644 --- a/packages/grafana-ui/src/components/Pagination/Pagination.tsx +++ b/packages/grafana-ui/src/components/Pagination/Pagination.tsx @@ -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 = ({ 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') => ( +
  • + +
  • + ); + + const pageButtons = pages.reduce((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( +
  • + +
  • + ); + } + } else { + pagesToRender.push(getListItem(page, variant)); + } + return pagesToRender; + }, []); + return (
      - {pages.map((pageIndex) => { - const page = pageIndex + 1; - const variant: ButtonVariant = page === currentPage ? 'primary' : 'secondary'; - - return ( -
    1. - -
    2. - ); - })} +
    3. + +
    4. + {pageButtons} +
    5. + +
    ); @@ -46,5 +112,8 @@ const getStyles = stylesFactory(() => { padding-left: 10px; margin-bottom: 5px; `, + ellipsis: css` + transform: rotate(90deg); + `, }; });