Skip to content
Snippets Groups Projects
Unverified Commit 7c636450 authored by Oisin Coveney's avatar Oisin Coveney Committed by GitHub
Browse files

Convert Pagination Controls to TS (#43586)

parent b561b011
No related branches found
No related tags found
No related merge requests found
Showing
with 99 additions and 17 deletions
......@@ -7,7 +7,7 @@ import { connect } from "react-redux";
import { push } from "react-router-redux";
import _ from "underscore";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import CS from "metabase/css/core/index.css";
import { usePagination } from "metabase/hooks/use-pagination";
import { getMetadata } from "metabase/selectors/metadata";
......
......@@ -5,7 +5,7 @@ import { t } from "ttag";
import { useListApiKeysQuery } from "metabase/api";
import AdminContentTable from "metabase/components/AdminContentTable";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import Link from "metabase/core/components/Link";
import CS from "metabase/css/core/index.css";
import Users from "metabase/entities/users";
......
......@@ -6,7 +6,7 @@ import { usePrevious } from "react-use";
import { t, ngettext, msgid } from "ttag";
import _ from "underscore";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import AdminS from "metabase/css/admin.module.css";
import CS from "metabase/css/core/index.css";
import Group from "metabase/entities/groups";
......
......@@ -7,7 +7,7 @@ import { t } from "ttag";
import NoResults from "assets/img/no_results.svg";
import DateTime from "metabase/components/DateTime";
import EmptyState from "metabase/components/EmptyState";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import Link from "metabase/core/components/Link";
import Tooltip from "metabase/core/components/Tooltip";
import AdminS from "metabase/css/admin.module.css";
......
......@@ -7,7 +7,7 @@ import _ from "underscore";
import { useListTasksQuery, useListDatabasesQuery } from "metabase/api";
import AdminHeader from "metabase/components/AdminHeader";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper/LoadingAndErrorWrapper";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import Link from "metabase/core/components/Link";
import AdminS from "metabase/css/admin.module.css";
import CS from "metabase/css/core/index.css";
......
......@@ -27,7 +27,7 @@ import {
import { ItemsTable } from "metabase/components/ItemsTable";
import type { SortingOptions } from "metabase/components/ItemsTable/BaseItemsTable";
import { SortDirection } from "metabase/components/ItemsTable/Columns";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import ItemsDragLayer from "metabase/containers/dnd/ItemsDragLayer";
import CS from "metabase/css/core/index.css";
import Collections from "metabase/entities/collections";
......
import cx from "classnames";
import PropTypes from "prop-types";
import { Fragment } from "react";
import { t } from "ttag";
import { c, t } from "ttag";
import Button from "metabase/core/components/Button";
import CS from "metabase/css/core/index.css";
import { Group, Text } from "metabase/ui";
export default function PaginationControls({
const isLastPage = (pageIndex: number, pageSize: number, total: number) =>
pageIndex === Math.ceil(total / pageSize) - 1;
export type PaginationControlsProps = {
page: number;
pageSize: number;
itemsLength: number;
total?: number;
showTotal?: boolean;
onNextPage?: (() => void) | null;
onPreviousPage?: (() => void) | null;
};
export const PaginationControls = ({
page,
pageSize,
itemsLength,
total,
showTotal,
showTotal = false,
onNextPage,
onPreviousPage,
}) {
}: PaginationControlsProps) => {
const isSinglePage = total !== undefined && total <= pageSize;
if (isSinglePage) {
return null;
}
const isLastPage = (pageIndex, pageSize, total) =>
pageIndex === Math.ceil(total / pageSize) - 1;
const isPreviousDisabled = page === 0;
const isNextDisabled =
total != null ? isLastPage(page, pageSize, total) : !onNextPage;
return (
<div
className={cx(CS.flex, CS.alignCenter, CS.textBold)}
aria-label="pagination"
>
<span className={CS.mr1}>
<Group align="center" fw="bold" aria-label="pagination" role="navigation">
<Text span mr="sm">
{page * pageSize + 1} - {page * pageSize + itemsLength}
{showTotal && (
<Fragment>
<span className={CS.textLight}>&nbsp;{t`of`}&nbsp;</span>
<span data-testid="pagination-total">{total}</span>
</Fragment>
<>
<Text span c="text-light">
&nbsp;
{c(
"Appears in phrases like '1-10 of 100', referring to a page of results",
).t`of`}
&nbsp;
</Text>
<Text span data-testid="pagination-total">
{total}
</Text>
</>
)}
</span>
</Text>
<Button
onlyIcon
icon="chevronleft"
onClick={onPreviousPage}
onClick={onPreviousPage ?? undefined}
disabled={isPreviousDisabled}
data-testid="previous-page-btn"
aria-label={t`Previous page`}
......@@ -54,25 +66,11 @@ export default function PaginationControls({
<Button
onlyIcon
icon="chevronright"
onClick={onNextPage}
onClick={onNextPage ?? undefined}
disabled={isNextDisabled}
data-testid="next-page-btn"
aria-label={t`Next page`}
/>
</div>
</Group>
);
}
PaginationControls.propTypes = {
page: PropTypes.number.isRequired,
pageSize: PropTypes.number.isRequired,
itemsLength: PropTypes.number.isRequired,
total: PropTypes.number,
showTotal: PropTypes.bool,
onNextPage: PropTypes.func,
onPreviousPage: PropTypes.func,
};
PaginationControls.defaultProps = {
showTotal: false,
};
import { render, fireEvent, screen } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import PaginationControls from "metabase/components/PaginationControls";
import type { PaginationControlsProps } from "./PaginationControls";
import { PaginationControls } from "./PaginationControls";
const DEFAULT_PROPS = {
const DEFAULT_PROPS: PaginationControlsProps = {
page: 0,
pageSize: 50,
itemsLength: 25,
......@@ -10,7 +12,7 @@ const DEFAULT_PROPS = {
onPreviousPage: null,
};
const setup = props => {
const setup = (props: Partial<PaginationControlsProps> = {}) => {
const { container } = render(
<PaginationControls {...DEFAULT_PROPS} {...props} />,
);
......@@ -70,7 +72,7 @@ describe("PaginationControls", () => {
expect(container).toBeEmpty();
});
it("should call pagination callbacks when buttons clicked", () => {
it("should call pagination callbacks when buttons clicked", async () => {
const onNextPageSpy = jest.fn();
const onPreviousPageSpy = jest.fn();
......@@ -80,10 +82,14 @@ describe("PaginationControls", () => {
onPreviousPage: onPreviousPageSpy,
});
fireEvent.click(nextPageButton);
if (nextPageButton) {
await userEvent.click(nextPageButton);
}
expect(onNextPageSpy).toHaveBeenCalledTimes(1);
fireEvent.click(previousPageButton);
if (previousPageButton) {
await userEvent.click(previousPageButton);
}
expect(onPreviousPageSpy).toHaveBeenCalledTimes(1);
});
......
export { default } from "./PaginationControls";
export { PaginationControls } from "./PaginationControls";
......@@ -2,7 +2,7 @@ import { useUserListQuery } from "metabase/common/hooks";
import { BrowserCrumbs } from "metabase/components/BrowserCrumbs";
import Card from "metabase/components/Card";
import { Grid } from "metabase/components/Grid";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import Link from "metabase/core/components/Link";
import CS from "metabase/css/core/index.css";
import {
......
......@@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { t } from "ttag";
import EmptyState from "metabase/components/EmptyState";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import SelectList from "metabase/components/SelectList";
import type { BaseSelectListItemProps } from "metabase/components/SelectList/BaseSelectListItem";
import Search from "metabase/entities/search";
......
......@@ -5,7 +5,7 @@ import { jt, t } from "ttag";
import _ from "underscore";
import EmptyState from "metabase/components/EmptyState";
import PaginationControls from "metabase/components/PaginationControls";
import { PaginationControls } from "metabase/components/PaginationControls";
import { NoObjectError } from "metabase/components/errors/NoObjectError";
import Search from "metabase/entities/search";
import { usePagination } from "metabase/hooks/use-pagination";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment