Skip to content

Commit b05361e

Browse files
Fixed record table fetch more scroll bug (#6790)
Fetch more on the record table was causing a strange bug where it was auto scrolling to the bottom of the newly loaded chunk of rows. This was confusing because we lost our previous position in the record table. With this fix the table doesn't scroll when more rows are loaded. The fetch more row has been moved in the same tbody as the rest of the rows. We now only hide it when there is no more record to fetch. --------- Co-authored-by: Charles Bochet <[email protected]>
1 parent cd06ae2 commit b05361e

File tree

6 files changed

+70
-44
lines changed

6 files changed

+70
-44
lines changed

packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
5353
totalCount,
5454
fetchMoreRecords,
5555
queryStateIdentifier,
56+
hasNextPage,
5657
} = useFindManyRecords({
5758
...params,
5859
recordGqlFields,
@@ -74,5 +75,6 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => {
7475
fetchMoreRecords,
7576
queryStateIdentifier,
7677
setRecordTableData,
78+
hasNextPage,
7779
};
7880
};
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
import { useRecoilValue } from 'recoil';
22

33
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
4+
import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader';
45
import { RecordTableRow } from '@/object-record/record-table/record-table-row/components/RecordTableRow';
56

67
export const RecordTableRows = () => {
78
const { tableRowIdsState } = useRecordTableStates();
89

910
const tableRowIds = useRecoilValue(tableRowIdsState);
1011

11-
return tableRowIds.map((recordId, rowIndex) => {
12-
return (
13-
<RecordTableRow key={recordId} recordId={recordId} rowIndex={rowIndex} />
14-
);
15-
});
12+
return (
13+
<>
14+
{tableRowIds.map((recordId, rowIndex) => {
15+
return (
16+
<RecordTableRow
17+
key={recordId}
18+
recordId={recordId}
19+
rowIndex={rowIndex}
20+
/>
21+
);
22+
})}
23+
<RecordTableBodyFetchMoreLoader />
24+
</>
25+
);
1626
};

packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBody.tsx

-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { useRecoilValue } from 'recoil';
22

33
import { RecordTableRows } from '@/object-record/record-table/components/RecordTableRows';
4-
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
54
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
65
import { RecordTableBodyDragDropContext } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContext';
76
import { RecordTableBodyDroppable } from '@/object-record/record-table/record-table-body/components/RecordTableBodyDroppable';
8-
import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader';
97
import { RecordTableBodyLoading } from '@/object-record/record-table/record-table-body/components/RecordTableBodyLoading';
108
import { RecordTablePendingRow } from '@/object-record/record-table/record-table-row/components/RecordTablePendingRow';
11-
import { useContext } from 'react';
129

1310
export const RecordTableBody = () => {
1411
const { tableRowIdsState, isRecordTableInitialLoadingState } =
1512
useRecordTableStates();
1613

17-
const { objectNameSingular } = useContext(RecordTableContext);
18-
1914
const tableRowIds = useRecoilValue(tableRowIdsState);
2015

2116
const isRecordTableInitialLoading = useRecoilValue(
@@ -32,7 +27,6 @@ export const RecordTableBody = () => {
3227
<RecordTablePendingRow />
3328
<RecordTableRows />
3429
</RecordTableBodyDroppable>
35-
<RecordTableBodyFetchMoreLoader objectNameSingular={objectNameSingular} />
3630
</RecordTableBodyDragDropContext>
3731
);
3832
};

packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyEffect.tsx

+22-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useL
77
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
88
import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext';
99
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
10+
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
1011
import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState';
1112
import { isRecordTableScrolledTopComponentState } from '@/object-record/record-table/states/isRecordTableScrolledTopComponentState';
1213
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
@@ -22,12 +23,13 @@ export const RecordTableBodyEffect = () => {
2223
const [hasInitializedScroll, setHasInitiazedScroll] = useState(false);
2324

2425
const {
25-
fetchMoreRecords: fetchMoreObjects,
26+
fetchMoreRecords,
2627
records,
2728
totalCount,
2829
setRecordTableData,
2930
loading,
3031
queryStateIdentifier,
32+
hasNextPage,
3133
} = useLoadRecordIndexTable(objectNameSingular);
3234

3335
const isFetchingMoreObjects = useRecoilValue(
@@ -43,6 +45,9 @@ export const RecordTableBodyEffect = () => {
4345
isRecordTableScrolledTopComponentState,
4446
);
4547

48+
const setHasRecordTableFetchedAllRecordsComponents =
49+
useSetRecoilComponentState(hasRecordTableFetchedAllRecordsComponentStateV2);
50+
4651
// TODO: move this outside because it might cause way too many re-renders for other hooks
4752
useEffect(() => {
4853
setIsRecordTableScrolledTop(scrollTop === 0);
@@ -108,9 +113,7 @@ export const RecordTableBodyEffect = () => {
108113
}
109114
}, [
110115
loading,
111-
isFetchingMoreObjects,
112116
lastShowPageRecordId,
113-
fetchMoreObjects,
114117
records,
115118
scrollToPosition,
116119
hasInitializedScroll,
@@ -125,14 +128,26 @@ export const RecordTableBodyEffect = () => {
125128

126129
const fetchMoreDebouncedIfRequested = useDebouncedCallback(async () => {
127130
// We are debouncing here to give the user some room to scroll if they want to within this throttle window
128-
await fetchMoreObjects();
131+
await fetchMoreRecords();
129132
}, 100);
130133

131134
useEffect(() => {
132-
if (!isFetchingMoreObjects && tableLastRowVisible) {
133-
fetchMoreDebouncedIfRequested();
134-
}
135+
const allRecordsHaveBeenFetched = !hasNextPage;
136+
137+
setHasRecordTableFetchedAllRecordsComponents(allRecordsHaveBeenFetched);
138+
}, [hasNextPage, setHasRecordTableFetchedAllRecordsComponents]);
139+
140+
useEffect(() => {
141+
(async () => {
142+
if (!isFetchingMoreObjects && tableLastRowVisible && hasNextPage) {
143+
await fetchMoreDebouncedIfRequested();
144+
}
145+
})();
135146
}, [
147+
hasNextPage,
148+
records,
149+
lastShowPageRecordId,
150+
scrollToPosition,
136151
fetchMoreDebouncedIfRequested,
137152
isFetchingMoreObjects,
138153
tableLastRowVisible,
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import styled from '@emotion/styled';
22
import { useContext } from 'react';
33
import { useInView } from 'react-intersection-observer';
4-
import { useRecoilCallback, useRecoilValue } from 'recoil';
4+
import { useRecoilCallback } from 'recoil';
55
import { GRAY_SCALE } from 'twenty-ui';
66

7-
import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable';
87
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
9-
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
8+
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
109
import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts';
11-
12-
type RecordTableBodyFetchMoreLoaderProps = {
13-
objectNameSingular: string;
14-
};
10+
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
1511

1612
const StyledText = styled.div`
1713
align-items: center;
@@ -23,16 +19,9 @@ const StyledText = styled.div`
2319
padding-left: ${({ theme }) => theme.spacing(2)};
2420
`;
2521

26-
export const RecordTableBodyFetchMoreLoader = ({
27-
objectNameSingular,
28-
}: RecordTableBodyFetchMoreLoaderProps) => {
29-
const { queryStateIdentifier } = useLoadRecordIndexTable(objectNameSingular);
22+
export const RecordTableBodyFetchMoreLoader = () => {
3023
const { setRecordTableLastRowVisible } = useRecordTable();
3124

32-
const isFetchingMoreRecords = useRecoilValue(
33-
isFetchingMoreRecordsFamilyState(queryStateIdentifier),
34-
);
35-
3625
const onLastRowVisible = useRecoilCallback(
3726
() => async (inView: boolean) => {
3827
setRecordTableLastRowVisible(inView);
@@ -44,24 +33,31 @@ export const RecordTableBodyFetchMoreLoader = ({
4433
RecordTableWithWrappersScrollWrapperContext,
4534
);
4635

36+
const hasRecordTableFetchedAllRecordsComponents = useRecoilComponentValue(
37+
hasRecordTableFetchedAllRecordsComponentStateV2,
38+
);
39+
40+
const showLoadingMoreRow = !hasRecordTableFetchedAllRecordsComponents;
41+
4742
const { ref: tbodyRef } = useInView({
4843
onChange: onLastRowVisible,
44+
delay: 1000,
4945
rootMargin: '1000px',
5046
root: scrollWrapperRef?.ref.current?.querySelector(
51-
'[data-overlayscrollbars-viewport="scrollbarHidden"]',
47+
'[data-overlayscrollbars-viewport]',
5248
),
5349
});
5450

51+
if (!showLoadingMoreRow) {
52+
return <></>;
53+
}
54+
5555
return (
56-
<tbody ref={tbodyRef}>
57-
{isFetchingMoreRecords && (
58-
<tr>
59-
<td colSpan={7}>
60-
<StyledText>Loading more...</StyledText>
61-
</td>
62-
<td colSpan={7} />
63-
</tr>
64-
)}
65-
</tbody>
56+
<tr ref={tbodyRef}>
57+
<td colSpan={7}>
58+
<StyledText>Loading more...</StyledText>
59+
</td>
60+
<td colSpan={7} />
61+
</tr>
6662
);
6763
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { RecordTableScopeInternalContext } from '@/object-record/record-table/scopes/scope-internal-context/RecordTableScopeInternalContext';
2+
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
3+
4+
export const hasRecordTableFetchedAllRecordsComponentStateV2 =
5+
createComponentStateV2<boolean>({
6+
key: 'hasRecordTableFetchedAllRecordsComponentStateV2',
7+
componentContext: RecordTableScopeInternalContext,
8+
defaultValue: false,
9+
});

0 commit comments

Comments
 (0)