Skip to content

Commit d00df7c

Browse files
fix: BROS-123: Grid scroll (#7906)
1 parent 6c3388a commit d00df7c

File tree

4 files changed

+51
-29
lines changed

4 files changed

+51
-29
lines changed

web/libs/datamanager/src/components/DataManager/Toolbar/GridWidthButton.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Button } from "../../Common/Button/Button";
44
import { Dropdown } from "../../Common/Dropdown/DropdownComponent";
55
import { Toggle } from "../../Common/Form";
66
import { IconSettings, IconMinus, IconPlus } from "@humansignal/icons";
7+
import debounce from "lodash.debounce";
78

89
const injector = inject(({ store }) => {
910
const view = store?.currentView;
@@ -23,12 +24,16 @@ const injector = inject(({ store }) => {
2324
export const GridWidthButton = injector(({ view, isGrid, gridWidth, fitImagesToWidth, hasImage, size }) => {
2425
const [width, setWidth] = useState(gridWidth);
2526

27+
const setGridWidthStore = debounce((value) => {
28+
view.setGridWidth(value);
29+
}, 200);
30+
2631
const setGridWidth = useCallback(
2732
(width) => {
2833
const newWidth = Math.max(1, Math.min(width, 10));
2934

3035
setWidth(newWidth);
31-
view.setGridWidth(newWidth);
36+
setGridWidthStore(newWidth);
3237
},
3338
[view],
3439
);

web/libs/datamanager/src/components/MainView/GridView/GridView.jsx

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export const GridCell = observer(({ view, selected, row, fields, onClick, column
129129
export const GridView = observer(({ data, view, loadMore, fields, onChange, hiddenFields }) => {
130130
const columnCount = view.gridWidth ?? 4;
131131

132-
const getCellIndex = (row, column) => columnCount * row + column;
132+
const getCellIndex = useCallback((row, column) => columnCount * row + column, [columnCount]);
133133

134134
const fieldsData = useMemo(() => {
135135
return prepareColumns(fields, hiddenFields);
@@ -148,11 +148,15 @@ export const GridView = observer(({ data, view, loadMore, fields, onChange, hidd
148148
const finalRowHeight =
149149
CELL_HEADER_HEIGHT + rowHeight * (hasImage ? Math.max(1, (IMAGE_SIZE_COEFFICIENT - columnCount) * 0.5) : 1);
150150

151+
// Calculate the total number of rows needed to display all items
152+
const itemCount = view.dataStore.total || data.length;
153+
const totalRows = Math.ceil(itemCount / columnCount);
154+
151155
const renderItem = useCallback(
152156
({ style, rowIndex, columnIndex }) => {
153157
const index = getCellIndex(rowIndex, columnIndex);
154-
if (!data || !(index in data)) return null;
155158
const row = data[index];
159+
if (!row) return null;
156160

157161
const props = {
158162
style: {
@@ -173,30 +177,42 @@ export const GridView = observer(({ data, view, loadMore, fields, onChange, hidd
173177
/>
174178
);
175179
},
176-
[data, columnCount, fieldsData, view.selected, view, view.selected.list, view.selected.all, getCellIndex],
180+
[data, columnCount, fieldsData, view, onChange, getCellIndex],
177181
);
178182

179-
const onItemsRenderedWrap =
183+
const onItemsRenderedWrap = useCallback(
180184
(cb) =>
181-
({ visibleRowStartIndex, visibleRowStopIndex, overscanRowStopIndex, overscanRowStartIndex }) => {
182-
cb({
183-
overscanStartIndex: overscanRowStartIndex,
184-
overscanStopIndex: overscanRowStopIndex,
185-
visibleStartIndex: visibleRowStartIndex,
186-
visibleStopIndex: visibleRowStopIndex,
187-
});
188-
};
189-
190-
const itemCount = Math.ceil(data.length / columnCount);
185+
({ visibleRowStartIndex, visibleRowStopIndex, overscanRowStopIndex, overscanRowStartIndex }) => {
186+
// Check if we're near the end and need to load more
187+
const visibleItemStopIndex = getCellIndex(visibleRowStopIndex, columnCount - 1);
188+
189+
// If we're showing items near the end of our loaded data, trigger loading
190+
if (
191+
visibleItemStopIndex >= data.length - columnCount * 2 &&
192+
view.dataStore.hasNextPage &&
193+
!view.dataStore.loading
194+
) {
195+
loadMore?.();
196+
}
197+
198+
cb({
199+
overscanStartIndex: overscanRowStartIndex,
200+
overscanStopIndex: overscanRowStopIndex,
201+
visibleStartIndex: visibleRowStartIndex,
202+
visibleStopIndex: visibleRowStopIndex,
203+
});
204+
},
205+
[data.length, columnCount, view.dataStore.hasNextPage, view.dataStore.loading, loadMore, getCellIndex],
206+
);
191207

208+
// Check if a specific item index is loaded
192209
const isItemLoaded = useCallback(
193210
(index) => {
194-
const rowIndex = index * columnCount;
195-
const rowFullfilled = data.slice(rowIndex, columnCount).length === columnCount;
196-
197-
return !view.dataStore.hasNextPage || rowFullfilled;
211+
const rowExists = index < data.length && !!data[index];
212+
const hasNextPage = view.dataStore.hasNextPage;
213+
return !hasNextPage || rowExists;
198214
},
199-
[columnCount, data, view.dataStore.hasNextPage],
215+
[data.length, view.dataStore.hasNextPage],
200216
);
201217

202218
return (
@@ -208,8 +224,8 @@ export const GridView = observer(({ data, view, loadMore, fields, onChange, hidd
208224
itemCount={itemCount}
209225
isItemLoaded={isItemLoaded}
210226
loadMoreItems={loadMore}
211-
threshold={Math.floor(view.dataStore.pageSize / 2)}
212-
minimumBatchSize={view.dataStore.pageSize}
227+
threshold={Math.max(1, Math.floor(view.dataStore.pageSize / 4))}
228+
minimumBatchSize={Math.max(1, Math.floor(view.dataStore.pageSize / 2))}
213229
>
214230
{({ onItemsRendered, ref }) => (
215231
<Elem
@@ -219,10 +235,10 @@ export const GridView = observer(({ data, view, loadMore, fields, onChange, hidd
219235
height={height}
220236
name="list"
221237
rowHeight={finalRowHeight}
222-
overscanRowCount={view.dataStore.pageSize}
238+
overscanRowCount={Math.max(2, Math.floor(view.dataStore.pageSize / 2))}
223239
columnCount={columnCount}
240+
rowCount={totalRows}
224241
columnWidth={width / columnCount - 9.5}
225-
rowCount={itemCount}
226242
onItemsRendered={onItemsRenderedWrap(onItemsRendered)}
227243
style={{ overflowX: "hidden" }}
228244
>

web/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"js-base64": "^3.7.7",
8383
"keymaster": "^1.6.2",
8484
"konva": "^8.1.3",
85+
"lodash.debounce": "^4.0.8",
8586
"lodash.get": "^4.4.0",
8687
"lodash.ismatch": "^4.4.0",
8788
"lodash.throttle": "^4.1.1",
@@ -106,7 +107,7 @@
106107
"react-router-dom": "^5.2.0",
107108
"react-singleton-hook": "^3.1.1",
108109
"react-virtualized-auto-sizer": "^1.0.20",
109-
"react-window": "^1.8.9",
110+
"react-window": "^1.8.11",
110111
"react-window-infinite-loader": "^1.0.5",
111112
"sanitize-html": "^2.14.0",
112113
"shadcn": "^2.1.8",

web/yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15865,10 +15865,10 @@ react-window-infinite-loader@^1.0.5:
1586515865
resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.9.tgz#d861c03d5cbc550e2f185371af820fd22d46c099"
1586615866
integrity sha512-5Hg89IdU4Vrp0RT8kZYKeTIxWZYhNkVXeI1HbKo01Vm/Z7qztDvXljwx16sMzsa9yapRJQW3ODZfMUw38SOWHw==
1586715867

15868-
react-window@^1.8.9:
15869-
version "1.8.10"
15870-
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.10.tgz#9e6b08548316814b443f7002b1cf8fd3a1bdde03"
15871-
integrity sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==
15868+
react-window@^1.8.11:
15869+
version "1.8.11"
15870+
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525"
15871+
integrity sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==
1587215872
dependencies:
1587315873
"@babel/runtime" "^7.0.0"
1587415874
memoize-one ">=3.1.1 <6"

0 commit comments

Comments
 (0)