Skip to content

Commit 88a9305

Browse files
committed
feat: scrolling
1 parent 2a5fd1b commit 88a9305

File tree

10 files changed

+330
-163
lines changed

10 files changed

+330
-163
lines changed

src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface PaginatedTableProps<T, F> {
2929
getRowClassName?: GetRowClassName<T>;
3030
rowHeight?: number;
3131
parentRef: React.RefObject<HTMLElement>;
32+
tableContainerRef: React.RefObject<HTMLDivElement>;
3233
initialSortParams?: SortParams;
3334
onColumnsResize?: HandleTableColumnsResize;
3435
renderEmptyDataMessage?: RenderEmptyDataMessage;
@@ -50,6 +51,7 @@ export const PaginatedTable = <T, F>({
5051
getRowClassName,
5152
rowHeight = DEFAULT_TABLE_ROW_HEIGHT,
5253
parentRef,
54+
tableContainerRef,
5355
initialSortParams,
5456
onColumnsResize,
5557
renderErrorMessage,
@@ -128,16 +130,22 @@ export const PaginatedTable = <T, F>({
128130
setTotalEntities(defaultTotal);
129131
setFoundEntities(defaultFound);
130132
setIsInitialLoad(true);
131-
if (parentRef?.current) {
132-
parentRef.current.scrollTo(0, 0);
133+
134+
if (tableContainerRef.current && parentRef.current) {
135+
// Scroll the parent container to the position of the table container
136+
const tableRect = tableContainerRef.current.getBoundingClientRect();
137+
const parentRect = parentRef.current.getBoundingClientRect();
138+
const scrollTop = tableRect.top - parentRect.top + parentRef.current.scrollTop;
139+
parentRef.current.scrollTo(0, scrollTop);
133140
}
134141
}, [
135142
rawFilters,
136143
initialEntitiesCount,
137-
parentRef,
144+
tableContainerRef,
138145
setTotalEntities,
139146
setFoundEntities,
140147
setIsInitialLoad,
148+
parentRef,
141149
]);
142150

143151
const renderChunks = () => {

src/components/PaginatedTable/ResizeablePaginatedTable.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ interface ResizeablePaginatedTableProps<T, F>
2222
export function ResizeablePaginatedTable<T, F>({
2323
columnsWidthLSKey,
2424
columns,
25+
tableContainerRef,
2526
...props
2627
}: ResizeablePaginatedTableProps<T, F>) {
2728
const [tableColumnsWidth, setTableColumnsWidth] = useTableResize(columnsWidthLSKey);
@@ -30,6 +31,7 @@ export function ResizeablePaginatedTable<T, F>({
3031

3132
return (
3233
<PaginatedTable
34+
tableContainerRef={tableContainerRef}
3335
columns={updatedColumns}
3436
onColumnsResize={setTableColumnsWidth}
3537
containerClassName={b('resizeable-table-container')}

src/components/TableWithControlsLayout/TableWithControlsLayout.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import React from 'react';
2+
13
import {cn} from '../../utils/cn';
24
import {TableSkeleton} from '../TableSkeleton/TableSkeleton';
35

@@ -32,10 +34,17 @@ TableWithControlsLayout.Controls = function TableControls({
3234
);
3335
};
3436

35-
TableWithControlsLayout.Table = function Table({children, loading, className}: TableProps) {
37+
TableWithControlsLayout.Table = React.forwardRef<HTMLDivElement, TableProps>(function Table(
38+
{children, loading, className},
39+
ref,
40+
) {
3641
if (loading) {
3742
return <TableSkeleton className={b('loader')} />;
3843
}
3944

40-
return <div className={b('table', className)}>{children}</div>;
41-
};
45+
return (
46+
<div ref={ref} className={b('table', className)}>
47+
{children}
48+
</div>
49+
);
50+
});

src/containers/Nodes/Nodes.tsx

Lines changed: 78 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {nodesApi} from '../../store/reducers/nodes/nodes';
2323
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
2424
import {useProblemFilter} from '../../store/reducers/settings/hooks';
2525
import type {AdditionalNodesProps} from '../../types/additionalProps';
26-
import type {NodesGroupByField} from '../../types/api/nodes';
26+
import type {NodesGroupByField, NodesPeerRole} from '../../types/api/nodes';
2727
import {useAutoRefreshInterval} from '../../utils/hooks';
2828
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
2929
import {useSelectedColumns} from '../../utils/hooks/useSelectedColumns';
@@ -169,6 +169,7 @@ function NodesComponent({
169169
const {searchValue, uptimeFilter, peerRoleFilter} = useNodesPageQueryParams(groupByParams);
170170
const {problemFilter} = useProblemFilter();
171171
const viewerNodesHandlerHasGrouping = useViewerNodesHandlerHasGrouping();
172+
const tableContainerRef = React.useRef<HTMLDivElement>(null);
172173

173174
const {columnsToShow, columnsToSelect, setColumns} = useSelectedColumns(
174175
columns,
@@ -190,7 +191,7 @@ function NodesComponent({
190191
handleSelectedColumnsUpdate={setColumns}
191192
/>
192193
</TableWithControlsLayout.Controls>
193-
<TableWithControlsLayout.Table>
194+
<TableWithControlsLayout.Table ref={tableContainerRef}>
194195
<NodesTable
195196
path={path}
196197
database={database}
@@ -200,6 +201,7 @@ function NodesComponent({
200201
peerRoleFilter={peerRoleFilter}
201202
columns={columnsToShow}
202203
parentRef={parentRef}
204+
tableContainerRef={tableContainerRef}
203205
/>
204206
</TableWithControlsLayout.Table>
205207
</TableWithControlsLayout>
@@ -237,6 +239,63 @@ function NodesControlsWithTableState({
237239
);
238240
}
239241

242+
interface NodeGroupProps {
243+
name: string;
244+
count: number;
245+
isExpanded: boolean;
246+
path?: string;
247+
database?: string;
248+
searchValue: string;
249+
peerRoleFilter?: NodesPeerRole;
250+
groupByParam?: NodesGroupByField;
251+
columns: Column<NodesPreparedEntity>[];
252+
parentRef: React.RefObject<HTMLElement>;
253+
onIsExpandedChange: (name: string, isExpanded: boolean) => void;
254+
}
255+
256+
const NodeGroup = React.memo(function NodeGroup({
257+
name,
258+
count,
259+
isExpanded,
260+
path,
261+
database,
262+
searchValue,
263+
peerRoleFilter,
264+
groupByParam,
265+
columns,
266+
parentRef,
267+
onIsExpandedChange,
268+
}: NodeGroupProps) {
269+
const tableContainerRef = React.useRef<HTMLDivElement>(null);
270+
271+
return (
272+
<TableGroup
273+
key={name}
274+
title={name}
275+
count={count}
276+
entityName={i18n('nodes')}
277+
expanded={isExpanded}
278+
onIsExpandedChange={onIsExpandedChange}
279+
ref={tableContainerRef}
280+
>
281+
<NodesTable
282+
path={path}
283+
database={database}
284+
searchValue={searchValue}
285+
problemFilter={'All'}
286+
uptimeFilter={NodesUptimeFilterValues.All}
287+
peerRoleFilter={peerRoleFilter}
288+
filterGroup={name}
289+
filterGroupBy={groupByParam}
290+
initialEntitiesCount={count}
291+
columns={columns}
292+
parentRef={parentRef}
293+
tableContainerRef={tableContainerRef}
294+
/>
295+
</TableGroup>
296+
);
297+
});
298+
240299
function GroupedNodesComponent({
241300
path,
242301
database,
@@ -250,6 +309,7 @@ function GroupedNodesComponent({
250309
}: NodesComponentProps) {
251310
const {searchValue, peerRoleFilter, groupByParam} = useNodesPageQueryParams(groupByParams);
252311
const [autoRefreshInterval] = useAutoRefreshInterval();
312+
const tableContainerRef = React.useRef<HTMLDivElement>(null);
253313

254314
const {columnsToShow, columnsToSelect, setColumns} = useSelectedColumns(
255315
columns,
@@ -299,28 +359,20 @@ function GroupedNodesComponent({
299359
const isExpanded = expandedGroups[name];
300360

301361
return (
302-
<TableGroup
362+
<NodeGroup
303363
key={name}
304-
title={name}
364+
name={name}
305365
count={count}
306-
entityName={i18n('nodes')}
307-
expanded={isExpanded}
366+
isExpanded={isExpanded}
367+
path={path}
368+
database={database}
369+
searchValue={searchValue}
370+
peerRoleFilter={peerRoleFilter}
371+
groupByParam={groupByParam}
372+
columns={columnsToShow}
373+
parentRef={parentRef}
308374
onIsExpandedChange={setIsGroupExpanded}
309-
>
310-
<NodesTable
311-
path={path}
312-
database={database}
313-
searchValue={searchValue}
314-
problemFilter={'All'}
315-
uptimeFilter={NodesUptimeFilterValues.All}
316-
peerRoleFilter={peerRoleFilter}
317-
filterGroup={name}
318-
filterGroupBy={groupByParam}
319-
initialEntitiesCount={count}
320-
columns={columnsToShow}
321-
parentRef={parentRef}
322-
/>
323-
</TableGroup>
375+
/>
324376
);
325377
});
326378
}
@@ -341,7 +393,11 @@ function GroupedNodesComponent({
341393
/>
342394
</TableWithControlsLayout.Controls>
343395
{error ? <ResponseError error={error} /> : null}
344-
<TableWithControlsLayout.Table loading={isLoading} className={b('groups-wrapper')}>
396+
<TableWithControlsLayout.Table
397+
ref={tableContainerRef}
398+
loading={isLoading}
399+
className={b('groups-wrapper')}
400+
>
345401
{renderGroups()}
346402
</TableWithControlsLayout.Table>
347403
</TableWithControlsLayout>

src/containers/Nodes/NodesTable.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ interface NodesTableProps {
2929

3030
columns: Column<NodesPreparedEntity>[];
3131
parentRef: React.RefObject<HTMLElement>;
32+
tableContainerRef: React.RefObject<HTMLDivElement>;
3233

3334
initialEntitiesCount?: number;
3435
onStateChange?: (state: PaginatedTableState) => void;
@@ -45,6 +46,7 @@ export function NodesTable({
4546
filterGroupBy,
4647
columns,
4748
parentRef,
49+
tableContainerRef,
4850
initialEntitiesCount,
4951
onStateChange,
5052
}: NodesTableProps) {
@@ -82,6 +84,7 @@ export function NodesTable({
8284
<ResizeablePaginatedTable
8385
columnsWidthLSKey={NODES_COLUMNS_WIDTH_LS_KEY}
8486
parentRef={parentRef}
87+
tableContainerRef={tableContainerRef}
8588
columns={columns}
8689
fetchData={getNodes}
8790
initialEntitiesCount={initialEntitiesCount}

0 commit comments

Comments
 (0)