diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx index 30ed5965a63..8cb4fde02c1 100644 --- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx +++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx @@ -22,9 +22,10 @@ import { AnnotationsPlugin2 } from '../timeseries/plugins/AnnotationsPlugin2'; import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; import { getTimezones } from '../timeseries/utils'; -import { StateTimelineTooltip2 } from './StateTimelineTooltip2'; +import { StateTimelineTooltip } from './StateTimelineTooltip'; +import { usePagination } from './hooks'; import { Options } from './panelcfg.gen'; -import { containerStyles, usePagination } from './utils'; +import { containerStyles } from './styles'; interface TimelinePanelProps extends PanelProps {} @@ -78,7 +79,7 @@ export const StateTimelinePanel = ({ const enableAnnotationCreation = Boolean(canAddAnnotations && canAddAnnotations()); return ( -
+
{ +}: StateTimelineTooltipProps) => { const xField = series.fields[0]; const dataIdx = seriesIdx != null ? dataIdxs[seriesIdx] : dataIdxs.find((idx) => idx != null); diff --git a/public/app/plugins/panel/state-timeline/hooks.test.tsx b/public/app/plugins/panel/state-timeline/hooks.test.tsx new file mode 100644 index 00000000000..228cb206291 --- /dev/null +++ b/public/app/plugins/panel/state-timeline/hooks.test.tsx @@ -0,0 +1,62 @@ +import { render, renderHook, screen } from '@testing-library/react'; + +import { createDataFrame, FieldType } from '@grafana/data'; + +import { usePagination } from './hooks'; + +describe('StateTimelinePanel hooks', () => { + describe('usePagination', () => { + describe('empty value', () => { + it('returns the empty value if perPage is not set', () => { + const { result } = renderHook(() => usePagination([])); + expect(result.current).toEqual({ + paginatedFrames: [], + paginationRev: 'disabled', + paginationElement: undefined, + paginationHeight: 0, + }); + }); + + it('returns the empty value if frames are not set', () => { + const { result } = renderHook(() => usePagination(undefined, 5)); + expect(result.current).toEqual({ + paginatedFrames: undefined, + paginationRev: 'disabled', + paginationElement: undefined, + paginationHeight: 0, + }); + }); + }); + + it('returns the React element to be rendered for pagination', () => { + const frames = createDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [100, 200, 300] }, + { name: 'value-A', type: FieldType.number, values: [4, 5, 6] }, + { name: 'value-B', type: FieldType.number, values: [4, 5, 6] }, + { name: 'value-C', type: FieldType.number, values: [4, 5, 6] }, + ], + }); + + const { result } = renderHook(() => usePagination([frames], 2)); + + expect(result.current.paginatedFrames?.length).toBe(2); + }); + + const frame = createDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] }, + { name: 'value-A', type: FieldType.number, values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }, + { name: 'value-B', type: FieldType.number, values: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] }, + { name: 'value-C', type: FieldType.number, values: [21, 22, 23, 24, 25, 26, 27, 28, 29, 30] }, + ], + }); + const { result } = renderHook(() => usePagination([frame], 2)); + + render(result.current.paginationElement); + + expect(screen.getByText('1')).toBeInTheDocument(); // current page + expect(screen.getByText('2')).toBeInTheDocument(); // last page + expect(screen.getByLabelText('next page')).not.toBeDisabled(); + }); +}); diff --git a/public/app/plugins/panel/state-timeline/utils.tsx b/public/app/plugins/panel/state-timeline/hooks.tsx similarity index 85% rename from public/app/plugins/panel/state-timeline/utils.tsx rename to public/app/plugins/panel/state-timeline/hooks.tsx index 188625534c7..9d23d2cf21e 100644 --- a/public/app/plugins/panel/state-timeline/utils.tsx +++ b/public/app/plugins/panel/state-timeline/hooks.tsx @@ -6,16 +6,7 @@ import { DataFrame } from '@grafana/data'; import { Pagination } from '@grafana/ui'; import { makeFramePerSeries } from 'app/core/components/TimelineChart/utils'; -import { defaultOptions } from './panelcfg.gen'; - -export const containerStyles = { - container: css({ - display: 'flex', - flexDirection: 'column', - }), -}; - -const styles = { +const paginationStyles = { paginationContainer: css({ display: 'flex', justifyContent: 'center', @@ -45,8 +36,6 @@ export function usePagination(frames?: DataFrame[], perPage?: number) { }; } - perPage ||= defaultOptions.perPage!; - const numberOfPages = Math.ceil(pagedFrames.length / perPage); // `perPage` changing might lead to temporarily too large values of `currentPage`. const currentPageCapped = Math.min(currentPage, numberOfPages); @@ -60,9 +49,9 @@ export function usePagination(frames?: DataFrame[], perPage?: number) { const showSmallVersion = paginationWidth < 550; const paginationElement = ( -
+
+