Skip to content

Commit

Permalink
Fix and improvement on the pagination for tracked table in the new UI
Browse files Browse the repository at this point in the history
PR-URL: hasura/graphql-engine-mono#9890
GitOrigin-RevId: ff1bb64321721718378de6447be9c9cc98e34c32
  • Loading branch information
nicoinch authored and hasura-bot committed Jul 25, 2023
1 parent 78323ed commit 82011af
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from 'react';
import { Button } from '../../../../new-components/Button';
import { DEFAULT_PAGE_SIZES } from '../constants';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import {
FaAngleDoubleLeft,
FaAngleDoubleRight,
FaAngleLeft,
FaAngleRight,
} from 'react-icons/fa';
import { PaginatedSearchableListProps } from '../hooks/usePaginatedSearchableList';

export const PageSizeDropdown = ({
pageNumber,
pageSize,
decrementPage,
incrementPage,
goToFirstPage,
goToLastPage,
setPageSize,
dataSize,
totalPages,
Expand All @@ -17,6 +24,11 @@ export const PageSizeDropdown = ({
<span className="whitespace-nowrap mr-2">
Page {pageNumber} of {totalPages}
</span>
<Button
icon={<FaAngleDoubleLeft />}
onClick={goToFirstPage}
disabled={pageNumber === 1}
/>
<Button
icon={<FaAngleLeft />}
onClick={decrementPage}
Expand All @@ -40,5 +52,10 @@ export const PageSizeDropdown = ({
onClick={incrementPage}
disabled={pageNumber >= dataSize / pageSize}
/>
<Button
icon={<FaAngleDoubleRight />}
onClick={goToLastPage}
disabled={pageNumber >= dataSize / pageSize}
/>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { usePaginatedSearchableList } from './usePaginatedSearchableList';

const mockData = [
{ id: '1', name: 'John' },
{ id: '2', name: 'Jane' },
{ id: '3', name: 'Bob' },
{ id: '4', name: 'Alice' },
{ id: '5', name: 'Eve' },
{ id: '6', name: 'Carol' },
{ id: '7', name: 'Dave' },
{ id: '8', name: 'Frank' },
{ id: '9', name: 'Grace' },
{ id: '10', name: 'Heidi' },
{ id: '11', name: 'Ivan' },
{ id: '12', name: 'Mallory' },
{ id: '13', name: 'Oscar' },
{ id: '14', name: 'Peggy' },
{ id: '15', name: 'Trent' },
];

describe('usePaginatedSearchableList', () => {
it('should return the correct initial state', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

expect(result.current.pageNumber).toBe(1);
expect(result.current.pageSize).toBe(10);
expect(result.current.searchIsActive).toBe(false);
expect(result.current.filteredData).toEqual(mockData);
expect(result.current.paginatedData).toEqual(mockData.slice(0, 10));
expect(result.current.totalPages).toBe(2);
expect(result.current.checkData.checkedIds).toEqual([]);
expect(result.current.getCheckedItems()).toEqual([]);
expect(result.current.dataSize).toBe(mockData.length);
});

it('should go to page 2 and display page 2 data when navigating page', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

act(() => {
result.current.incrementPage();
});

expect(result.current.pageNumber).toBe(2);
expect(result.current.filteredData).toEqual(mockData);
expect(result.current.paginatedData).toEqual(mockData.slice(10, 15));
expect(result.current.totalPages).toBe(2);
expect(result.current.dataSize).toBe(mockData.length);
});

it('should update the filtered data when search text changes', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

act(() => {
result.current.incrementPage();
result.current.handleSearch('o');
});

expect(result.current.searchIsActive).toBe(true);
expect(result.current.pageNumber).toBe(1);
expect(result.current.totalPages).toBe(1);
expect(result.current.dataSize).toBe(4);
});

it('should go to page 1 when data are filtered on page 2 and filtered data length < page size', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

act(() => {
result.current.handleSearch('o');
});

expect(result.current.searchIsActive).toBe(true);
expect(result.current.filteredData).toEqual([
{ id: '1', name: 'John' },
{ id: '3', name: 'Bob' },
{ id: '6', name: 'Carol' },
{ id: '12', name: 'Mallory' },
]);
expect(result.current.paginatedData).toEqual([
{ id: '1', name: 'John' },
{ id: '3', name: 'Bob' },
{ id: '6', name: 'Carol' },
{ id: '12', name: 'Mallory' },
]);
expect(result.current.pageNumber).toBe(1);
expect(result.current.totalPages).toBe(1);
expect(result.current.dataSize).toBe(4);
});

it('should update the paginated data when page number changes', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

act(() => {
result.current.setPageNumber(2);
});

expect(result.current.pageNumber).toBe(2);
expect(result.current.paginatedData).toEqual([
{ id: '11', name: 'Ivan' },
{ id: '12', name: 'Mallory' },
{ id: '13', name: 'Oscar' },
{ id: '14', name: 'Peggy' },
{ id: '15', name: 'Trent' },
]);
expect(result.current.totalPages).toBe(2);
expect(result.current.dataSize).toBe(mockData.length);
});

it('should update the checked items when rows are checked', () => {
const { result } = renderHook(() =>
usePaginatedSearchableList({
data: mockData,
filterFn: (searchText, item) => item.name.includes(searchText),
})
);

act(() => {
result.current.checkData.onCheck('1');
});

expect(result.current.checkData.checkedIds).toEqual(['1']);
expect(result.current.getCheckedItems()).toEqual([
{ id: '1', name: 'John' },
]);
expect(result.current.dataSize).toBe(mockData.length);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export function usePaginatedSearchableList<TData extends { id: string }>({
[checkData.checkedIds, data]
);

const handleSearch = React.useCallback(
(searchQuery: string) => setSearchText(searchQuery),
[]
);
const handleSearch = React.useCallback((searchQuery: string) => {
setPageNumber(DEFAULT_PAGE_NUMBER);
setSearchText(searchQuery);
}, []);

const incrementPage = React.useCallback(() => {
setPageNumber(currentPage =>
Expand All @@ -54,21 +54,31 @@ export function usePaginatedSearchableList<TData extends { id: string }>({
);
}, []);

const goToFirstPage = React.useCallback(() => {
setPageNumber(() => 1);
}, []);

const goToLastPage = React.useCallback(() => {
setPageNumber(() => totalPages);
}, [totalPages]);

return {
pageNumber,
setPageNumber,
pageSize,
setPageSize,
incrementPage,
decrementPage,
goToFirstPage,
goToLastPage,
totalPages,
searchIsActive,
handleSearch,
checkData,
filteredData,
paginatedData,
getCheckedItems,
dataSize: data.length,
dataSize: filteredData.length,
};
}

Expand Down

0 comments on commit 82011af

Please sign in to comment.