From 15a641a509c033862100bee263de670861841c7c Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Fri, 15 Mar 2024 13:52:55 +0100 Subject: [PATCH] Infinite Scroll: wait for users to reach the top before triggering new requests (#84318) * Infinite Scroll: wait for users to reach the top before triggering new requests * Prettier * Infinite Scroll: control top scrolling via prop * Prettier --- .../features/logs/components/InfiniteScroll.test.tsx | 11 ++++++++++- .../app/features/logs/components/InfiniteScroll.tsx | 8 +++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/public/app/features/logs/components/InfiniteScroll.test.tsx b/public/app/features/logs/components/InfiniteScroll.test.tsx index a4078ea5ca3..47429764b3b 100644 --- a/public/app/features/logs/components/InfiniteScroll.test.tsx +++ b/public/app/features/logs/components/InfiniteScroll.test.tsx @@ -43,7 +43,7 @@ function ScrollWithWrapper({ children, ...props }: Props) { return (
{initialized && ( - + {children} )} @@ -60,8 +60,16 @@ function setup(loadMoreMock: () => void, startPosition: number, rows: LogRowMode act(() => { events['scroll'](new Event('scroll')); }); + + // When scrolling top, we wait for the user to reach the top, and then for a new scrolling event + // in the same direction before triggering a new query. + if (position === 0) { + wheel(-1); + } } function wheel(deltaY: number) { + element.scrollTop += deltaY; + act(() => { const event = new WheelEvent('wheel', { deltaY }); events['wheel'](event); @@ -75,6 +83,7 @@ function setup(loadMoreMock: () => void, startPosition: number, rows: LogRowMode rows={rows} scrollElement={element as unknown as HTMLDivElement} loadMoreLogs={loadMoreMock} + topScrollEnabled >
diff --git a/public/app/features/logs/components/InfiniteScroll.tsx b/public/app/features/logs/components/InfiniteScroll.tsx index 9cf97d4d3fd..744584735db 100644 --- a/public/app/features/logs/components/InfiniteScroll.tsx +++ b/public/app/features/logs/components/InfiniteScroll.tsx @@ -17,6 +17,7 @@ export type Props = { scrollElement?: HTMLDivElement; sortOrder: LogsSortOrder; timeZone: TimeZone; + topScrollEnabled?: boolean; }; export const InfiniteScroll = ({ @@ -28,6 +29,7 @@ export const InfiniteScroll = ({ scrollElement, sortOrder, timeZone, + topScrollEnabled = false, }: Props) => { const [upperOutOfRange, setUpperOutOfRange] = useState(false); const [lowerOutOfRange, setLowerOutOfRange] = useState(false); @@ -83,9 +85,9 @@ export const InfiniteScroll = ({ lastScroll.current = scrollElement.scrollTop; if (scrollDirection === ScrollDirection.NoScroll) { return; - } else if (scrollDirection === ScrollDirection.Top) { + } else if (scrollDirection === ScrollDirection.Top && topScrollEnabled) { scrollTop(); - } else { + } else if (scrollDirection === ScrollDirection.Bottom) { scrollBottom(); } } @@ -127,7 +129,7 @@ export const InfiniteScroll = ({ scrollElement.removeEventListener('scroll', handleScroll); scrollElement.removeEventListener('wheel', handleScroll); }; - }, [loadMoreLogs, loading, range, rows, scrollElement, sortOrder, timeZone]); + }, [loadMoreLogs, loading, range, rows, scrollElement, sortOrder, timeZone, topScrollEnabled]); // We allow "now" to move when using relative time, so we hide the message so it doesn't flash. const hideTopMessage = sortOrder === LogsSortOrder.Descending && isRelativeTime(range.raw.to);