Skip to content

Commit 6d293b8

Browse files
committed
feat: move to infiniteQuery
1 parent 020b2c2 commit 6d293b8

File tree

6 files changed

+173
-193
lines changed

6 files changed

+173
-193
lines changed

package-lock.json

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@gravity-ui/websql-autocomplete": "^13.7.0",
3030
"@hookform/resolvers": "^3.10.0",
3131
"@mjackson/multipart-parser": "^0.8.2",
32-
"@reduxjs/toolkit": "^2.5.0",
32+
"@reduxjs/toolkit": "^2.8.2",
3333
"@tanstack/react-table": "^8.20.6",
3434
"@ydb-platform/monaco-ghost": "^0.6.1",
3535
"axios": "^1.8.4",

src/containers/Operations/Operations.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {getColumns} from './columns';
1313
import {OPERATIONS_SELECTED_COLUMNS_KEY} from './constants';
1414
import i18n from './i18n';
1515
import {b} from './shared';
16-
import {useInfiniteOperations} from './useInfiniteOperations';
16+
import {useOperationsInfiniteQuery} from './useOperationsInfiniteQuery';
1717
import {useOperationsQueryParams} from './useOperationsQueryParams';
1818

1919
interface OperationsProps {
@@ -26,7 +26,7 @@ export function Operations({database, scrollContainerRef}: OperationsProps) {
2626
useOperationsQueryParams();
2727

2828
const {operations, isLoading, isLoadingMore, error, refreshTable, totalCount} =
29-
useInfiniteOperations({
29+
useOperationsInfiniteQuery({
3030
database,
3131
kind,
3232
pageSize,

src/containers/Operations/useInfiniteOperations.ts

Lines changed: 0 additions & 186 deletions
This file was deleted.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import React from 'react';
2+
3+
import {throttle} from 'lodash';
4+
5+
import {operationsApi} from '../../store/reducers/operations';
6+
import type {OperationKind} from '../../types/api/operations';
7+
8+
interface UseOperationsInfiniteQueryProps {
9+
database: string;
10+
kind: OperationKind;
11+
pageSize?: number;
12+
searchValue: string;
13+
scrollContainerRef?: React.RefObject<HTMLElement>;
14+
}
15+
16+
const DEFAULT_SCROLL_MARGIN = 100;
17+
18+
export function useOperationsInfiniteQuery({
19+
database,
20+
kind,
21+
pageSize = 10,
22+
searchValue,
23+
scrollContainerRef,
24+
}: UseOperationsInfiniteQueryProps) {
25+
const {data, error, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, refetch} =
26+
operationsApi.useGetOperationListInfiniteInfiniteQuery({
27+
database,
28+
kind,
29+
page_size: pageSize,
30+
});
31+
32+
// Flatten all pages into a single array of operations
33+
const allOperations = React.useMemo(() => {
34+
if (!data?.pages) {
35+
return [];
36+
}
37+
// Each page is a TOperationList, so we need to extract operations from each
38+
return data.pages.flatMap((page) => page.operations || []);
39+
}, [data]);
40+
41+
const filteredOperations = React.useMemo(() => {
42+
if (!searchValue) {
43+
return allOperations;
44+
}
45+
return allOperations.filter((op) =>
46+
op.id?.toLowerCase().includes(searchValue.toLowerCase()),
47+
);
48+
}, [allOperations, searchValue]);
49+
50+
// Auto-load more pages to fill viewport
51+
const checkAndLoadMorePages = React.useCallback(async () => {
52+
const scrollContainer = scrollContainerRef?.current;
53+
if (!scrollContainer || !hasNextPage || isFetchingNextPage) {
54+
return;
55+
}
56+
57+
const {scrollHeight, clientHeight} = scrollContainer;
58+
if (scrollHeight <= clientHeight) {
59+
await fetchNextPage();
60+
}
61+
}, [scrollContainerRef, hasNextPage, isFetchingNextPage, fetchNextPage]);
62+
63+
// Check after data updates
64+
React.useLayoutEffect(() => {
65+
if (!isFetchingNextPage) {
66+
checkAndLoadMorePages();
67+
}
68+
}, [data, isFetchingNextPage, checkAndLoadMorePages]);
69+
70+
// Scroll handler for infinite scrolling
71+
React.useEffect(() => {
72+
const scrollContainer = scrollContainerRef?.current;
73+
if (!scrollContainer) {
74+
return undefined;
75+
}
76+
77+
const handleScroll = () => {
78+
const {scrollTop, scrollHeight, clientHeight} = scrollContainer;
79+
80+
if (
81+
scrollHeight - scrollTop - clientHeight < DEFAULT_SCROLL_MARGIN &&
82+
hasNextPage &&
83+
!isFetchingNextPage
84+
) {
85+
fetchNextPage();
86+
}
87+
};
88+
89+
scrollContainer.addEventListener('scroll', handleScroll);
90+
return () => scrollContainer.removeEventListener('scroll', handleScroll);
91+
}, [scrollContainerRef, hasNextPage, isFetchingNextPage, fetchNextPage]);
92+
93+
// Resize handler to check if more content is needed when viewport changes
94+
React.useEffect(() => {
95+
const throttledHandleResize = throttle(checkAndLoadMorePages, 200, {
96+
trailing: true,
97+
leading: true,
98+
});
99+
100+
window.addEventListener('resize', throttledHandleResize);
101+
return () => window.removeEventListener('resize', throttledHandleResize);
102+
}, [checkAndLoadMorePages]);
103+
104+
// Listen for diagnostics refresh events
105+
React.useEffect(() => {
106+
const handleRefresh = () => refetch();
107+
document.addEventListener('diagnosticsRefresh', handleRefresh);
108+
return () => document.removeEventListener('diagnosticsRefresh', handleRefresh);
109+
}, [refetch]);
110+
111+
return {
112+
operations: filteredOperations,
113+
isLoading,
114+
isLoadingMore: isFetchingNextPage,
115+
error,
116+
refreshTable: refetch,
117+
totalCount: allOperations.length,
118+
};
119+
}

0 commit comments

Comments
 (0)