diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/PageSizeDropdown.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/PageSizeDropdown.tsx
index efcff73423d..5fb01cd0da4 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/PageSizeDropdown.tsx
+++ b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/components/PageSizeDropdown.tsx
@@ -1,7 +1,12 @@
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 = ({
@@ -9,6 +14,8 @@ export const PageSizeDropdown = ({
pageSize,
decrementPage,
incrementPage,
+ goToFirstPage,
+ goToLastPage,
setPageSize,
dataSize,
totalPages,
@@ -17,6 +24,11 @@ export const PageSizeDropdown = ({
Page {pageNumber} of {totalPages}
+ }
+ onClick={goToFirstPage}
+ disabled={pageNumber === 1}
+ />
}
onClick={decrementPage}
@@ -40,5 +52,10 @@ export const PageSizeDropdown = ({
onClick={incrementPage}
disabled={pageNumber >= dataSize / pageSize}
/>
+ }
+ onClick={goToLastPage}
+ disabled={pageNumber >= dataSize / pageSize}
+ />
);
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.test.ts b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.test.ts
new file mode 100644
index 00000000000..bb9aff50855
--- /dev/null
+++ b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.test.ts
@@ -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);
+ });
+});
diff --git a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.tsx b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.tsx
index 35f7aef6d6a..11157332982 100644
--- a/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.tsx
+++ b/frontend/libs/console/legacy-ce/src/lib/features/Data/TrackResources/hooks/usePaginatedSearchableList.tsx
@@ -37,10 +37,10 @@ export function usePaginatedSearchableList({
[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 =>
@@ -54,6 +54,14 @@ export function usePaginatedSearchableList({
);
}, []);
+ const goToFirstPage = React.useCallback(() => {
+ setPageNumber(() => 1);
+ }, []);
+
+ const goToLastPage = React.useCallback(() => {
+ setPageNumber(() => totalPages);
+ }, [totalPages]);
+
return {
pageNumber,
setPageNumber,
@@ -61,6 +69,8 @@ export function usePaginatedSearchableList({
setPageSize,
incrementPage,
decrementPage,
+ goToFirstPage,
+ goToLastPage,
totalPages,
searchIsActive,
handleSearch,
@@ -68,7 +78,7 @@ export function usePaginatedSearchableList({
filteredData,
paginatedData,
getCheckedItems,
- dataSize: data.length,
+ dataSize: filteredData.length,
};
}