mirror of https://github.com/grafana/grafana
Alerting: Paginate result previews (#65257)
Co-authored-by: konrad147 <konradlalik@gmail.com> Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com>pull/65283/head
parent
382b24742a
commit
409bd33a8f
@ -0,0 +1,66 @@ |
||||
import { screen, render } from '@testing-library/react'; |
||||
import userEvent from '@testing-library/user-event'; |
||||
import { times } from 'lodash'; |
||||
import React from 'react'; |
||||
|
||||
import { DataFrame, toDataFrame } from '@grafana/data'; |
||||
|
||||
import { ExpressionResult } from './Expression'; |
||||
|
||||
describe('TestResult', () => { |
||||
it('should be able to render', () => { |
||||
expect(() => { |
||||
render(<ExpressionResult series={[]} />); |
||||
}).not.toThrow(); |
||||
}); |
||||
|
||||
it('should not paginate with less than PAGE_SIZE', () => { |
||||
const series: DataFrame[] = [ |
||||
toDataFrame({ |
||||
fields: [ |
||||
{ |
||||
name: 'temp', |
||||
values: [23, 11, 10], |
||||
}, |
||||
], |
||||
}), |
||||
]; |
||||
|
||||
render(<ExpressionResult series={series} />); |
||||
expect(screen.queryByTestId('paginate-expression')).not.toBeInTheDocument(); |
||||
}); |
||||
|
||||
it('should paginate with greater than PAGE_SIZE', async () => { |
||||
const series: DataFrame[] = makeSeries(50); |
||||
|
||||
render(<ExpressionResult series={series} />); |
||||
expect(screen.getByTestId('paginate-expression')).toBeInTheDocument(); |
||||
expect(screen.getByText(`1 - 20 of ${50}`)).toBeInTheDocument(); |
||||
|
||||
// click previous page
|
||||
await userEvent.click(screen.getByLabelText('previous-page')); |
||||
expect(screen.getByText(`1 - 20 of ${50}`)).toBeInTheDocument(); |
||||
|
||||
// keep clicking next page, should clamp
|
||||
await userEvent.click(screen.getByLabelText('next-page')); |
||||
expect(screen.getByText(`21 - 40 of ${50}`)).toBeInTheDocument(); |
||||
await userEvent.click(screen.getByLabelText('next-page')); |
||||
expect(screen.getByText(`41 - 50 of ${50}`)).toBeInTheDocument(); |
||||
// click one more time, should still be on the last page
|
||||
await userEvent.click(screen.getByLabelText('next-page')); |
||||
expect(screen.getByText(`41 - 50 of ${50}`)).toBeInTheDocument(); |
||||
}); |
||||
}); |
||||
|
||||
function makeSeries(n: number) { |
||||
return times(n, () => |
||||
toDataFrame({ |
||||
fields: [ |
||||
{ |
||||
name: 'temp', |
||||
values: [1], |
||||
}, |
||||
], |
||||
}) |
||||
); |
||||
} |
@ -0,0 +1,67 @@ |
||||
import { act, renderHook } from '@testing-library/react-hooks'; |
||||
|
||||
import { usePagination } from './usePagination'; |
||||
|
||||
describe('usePagination()', () => { |
||||
it('should work with no items', () => { |
||||
const { result } = renderHook(() => { |
||||
return usePagination([], 1, 20); |
||||
}); |
||||
|
||||
const { pageItems, numberOfPages, page, pageStart, pageEnd } = result.current; |
||||
|
||||
expect(pageItems).toStrictEqual([]); |
||||
expect(numberOfPages).toStrictEqual(0); |
||||
expect(page).toStrictEqual(1); |
||||
expect(pageStart).toStrictEqual(1); |
||||
expect(pageEnd).toStrictEqual(0); |
||||
}); |
||||
|
||||
it('should work with items < page size', () => { |
||||
const { result } = renderHook(() => { |
||||
return usePagination([1, 2, 3], 1, 10); |
||||
}); |
||||
|
||||
const { pageItems, numberOfPages, page, pageStart, pageEnd } = result.current; |
||||
|
||||
expect(pageItems).toStrictEqual([1, 2, 3]); |
||||
expect(numberOfPages).toStrictEqual(1); |
||||
expect(page).toStrictEqual(1); |
||||
expect(pageStart).toStrictEqual(1); |
||||
expect(pageEnd).toStrictEqual(3); |
||||
}); |
||||
|
||||
it('should work with items > page size', () => { |
||||
const { result } = renderHook(() => { |
||||
return usePagination([1, 2, 3], 1, 1); |
||||
}); |
||||
|
||||
const { pageItems, numberOfPages, page, pageStart, pageEnd } = result.current; |
||||
|
||||
expect(pageItems).toStrictEqual([1]); |
||||
expect(numberOfPages).toStrictEqual(3); |
||||
expect(page).toStrictEqual(1); |
||||
expect(pageStart).toStrictEqual(1); |
||||
expect(pageEnd).toStrictEqual(1); |
||||
}); |
||||
|
||||
it('should clamp pages', () => { |
||||
const { result } = renderHook(() => { |
||||
return usePagination([1, 2, 3], 1, 1); |
||||
}); |
||||
|
||||
expect(result.current.pageItems).toStrictEqual([1]); |
||||
|
||||
act(() => result.current.previousPage()); |
||||
expect(result.current.pageItems).toStrictEqual([1]); |
||||
|
||||
act(() => result.current.nextPage()); |
||||
expect(result.current.pageItems).toStrictEqual([2]); |
||||
|
||||
act(() => result.current.nextPage()); |
||||
expect(result.current.pageItems).toStrictEqual([3]); |
||||
|
||||
act(() => result.current.nextPage()); |
||||
expect(result.current.pageItems).toStrictEqual([3]); |
||||
}); |
||||
}); |
@ -1,25 +1,29 @@ |
||||
import { useCallback, useEffect, useMemo, useState } from 'react'; |
||||
import { chunk, clamp } from 'lodash'; |
||||
import { useCallback, useEffect, useState, useMemo } from 'react'; |
||||
|
||||
export function usePagination<T>(items: T[], initialPage: number, itemsPerPage: number) { |
||||
export function usePagination<T>(items: T[], initialPage = 1, itemsPerPage: number) { |
||||
const [page, setPage] = useState(initialPage); |
||||
|
||||
const numberOfPages = Math.ceil(items.length / itemsPerPage); |
||||
const firstItemOnPageIndex = itemsPerPage * (page - 1); |
||||
const pages = useMemo(() => chunk(items, itemsPerPage), [items, itemsPerPage]); |
||||
|
||||
const pageItems = useMemo( |
||||
() => items.slice(firstItemOnPageIndex, firstItemOnPageIndex + itemsPerPage), |
||||
[items, firstItemOnPageIndex, itemsPerPage] |
||||
); |
||||
const numberOfPages = pages.length; |
||||
const pageItems = pages[page - 1] ?? []; |
||||
|
||||
const pageStart = (page - 1) * itemsPerPage + 1; |
||||
const pageEnd = clamp(page * itemsPerPage, items.length); |
||||
|
||||
const onPageChange = useCallback( |
||||
(newPage: number) => { |
||||
setPage(newPage); |
||||
setPage(clamp(newPage, 1, pages.length)); |
||||
}, |
||||
[setPage] |
||||
[setPage, pages] |
||||
); |
||||
|
||||
const nextPage = useCallback(() => onPageChange(page + 1), [page, onPageChange]); |
||||
const previousPage = useCallback(() => onPageChange(page - 1), [page, onPageChange]); |
||||
|
||||
// Reset the current page when number of pages has been changed
|
||||
useEffect(() => setPage(1), [numberOfPages]); |
||||
|
||||
return { page, onPageChange, numberOfPages, pageItems }; |
||||
return { page, onPageChange, numberOfPages, pageItems, pageStart, pageEnd, nextPage, previousPage }; |
||||
} |
||||
|
Loading…
Reference in new issue