Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 16 additions & 27 deletions src/components/PaginatedTable/PaginatedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {
RenderErrorMessage,
SortParams,
} from './types';
import {useIntersectionObserver} from './useIntersectionObserver';
import {useScrollBasedChunks} from './useScrollBasedChunks';

import './PaginatedTable.scss';

Expand All @@ -32,7 +32,7 @@ export interface PaginatedTableProps<T, F> {
columns: Column<T>[];
getRowClassName?: GetRowClassName<T>;
rowHeight?: number;
parentContainer?: Element | null;
parentRef?: React.RefObject<HTMLElement>;
initialSortParams?: SortParams;
onColumnsResize?: HandleTableColumnsResize;
renderControls?: RenderControls;
Expand All @@ -50,7 +50,7 @@ export const PaginatedTable = <T, F>({
columns,
getRowClassName,
rowHeight = DEFAULT_TABLE_ROW_HEIGHT,
parentContainer,
parentRef,
initialSortParams,
onColumnsResize,
renderControls,
Expand All @@ -64,46 +64,36 @@ export const PaginatedTable = <T, F>({
const [sortParams, setSortParams] = React.useState<SortParams | undefined>(initialSortParams);
const [totalEntities, setTotalEntities] = React.useState(initialTotal);
const [foundEntities, setFoundEntities] = React.useState(initialFound);
const [activeChunks, setActiveChunks] = React.useState<number[]>([]);
const [isInitialLoad, setIsInitialLoad] = React.useState(true);

const tableContainer = React.useRef<HTMLDivElement>(null);
const tableRef = React.useRef<HTMLDivElement>(null);

const activeChunks = useScrollBasedChunks({
containerRef: parentRef ?? tableRef,
totalItems: foundEntities,
itemHeight: rowHeight,
chunkSize: limit,
});

const handleDataFetched = React.useCallback((total: number, found: number) => {
setTotalEntities(total);
setFoundEntities(found);
setIsInitialLoad(false);
}, []);

const onEntry = React.useCallback((id: string) => {
setActiveChunks((prev) => [...new Set([...prev, Number(id)])]);
}, []);

const onLeave = React.useCallback((id: string) => {
setActiveChunks((prev) => prev.filter((chunk) => chunk !== Number(id)));
}, []);

const observer = useIntersectionObserver({onEntry, onLeave, parentContainer});

// reset table on filters change
React.useLayoutEffect(() => {
setTotalEntities(initialTotal);
setFoundEntities(initialFound);
setIsInitialLoad(true);
if (parentContainer) {
parentContainer.scrollTo(0, 0);
if (parentRef?.current) {
parentRef.current.scrollTo(0, 0);
} else {
tableContainer.current?.scrollTo(0, 0);
tableRef.current?.scrollTo(0, 0);
}

setActiveChunks([0]);
}, [filters, initialFound, initialTotal, limit, parentContainer]);
}, [filters, initialFound, initialTotal, limit, parentRef]);

const renderChunks = () => {
if (!observer) {
return null;
}

if (!isInitialLoad && foundEntities === 0) {
return (
<tbody>
Expand Down Expand Up @@ -133,7 +123,6 @@ export const PaginatedTable = <T, F>({
renderErrorMessage={renderErrorMessage}
onDataFetched={handleDataFetched}
isActive={activeChunks.includes(value)}
observer={observer}
/>
));
};
Expand Down Expand Up @@ -161,7 +150,7 @@ export const PaginatedTable = <T, F>({
};

return (
<div ref={tableContainer} className={b(null, containerClassName)}>
<div ref={tableRef} className={b(null, containerClassName)}>
{renderContent()}
</div>
);
Expand Down
26 changes: 3 additions & 23 deletions src/components/PaginatedTable/TableChunk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import type {Column, FetchData, GetRowClassName, SortParams} from './types';

const DEBOUNCE_TIMEOUT = 200;

// With original memo generic types are lost
const typedMemo: <T>(Component: T) => T = React.memo;

interface TableChunkProps<T, F> {
id: number;
limit: number;
Expand All @@ -22,7 +19,6 @@ interface TableChunkProps<T, F> {
columns: Column<T>[];
filters?: F;
sortParams?: SortParams;
observer: IntersectionObserver;
isActive: boolean;
tableName: string;

Expand All @@ -33,7 +29,7 @@ interface TableChunkProps<T, F> {
}

// Memoisation prevents chunks rerenders that could cause perfomance issues on big tables
export const TableChunk = typedMemo(function TableChunk<T, F>({
export const TableChunk = <T, F>({
id,
limit,
totalLength,
Expand All @@ -43,13 +39,11 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
tableName,
filters,
sortParams,
observer,
getRowClassName,
renderErrorMessage,
onDataFetched,
isActive,
}: TableChunkProps<T, F>) {
const ref = React.useRef<HTMLTableSectionElement>(null);
}: TableChunkProps<T, F>) => {
const [isTimeoutActive, setIsTimeoutActive] = React.useState(true);
const [autoRefreshInterval] = useAutoRefreshInterval();

Expand Down Expand Up @@ -83,19 +77,6 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
};
}, [isActive, isTimeoutActive]);

React.useEffect(() => {
const el = ref.current;
if (el) {
observer.observe(el);
}

return () => {
if (el) {
observer.unobserve(el);
}
};
}, [observer]);

React.useEffect(() => {
if (currentData && isActive) {
const {total = 0, found = 0} = currentData;
Expand Down Expand Up @@ -154,7 +135,6 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({

return (
<tbody
ref={ref}
id={id.toString()}
style={{
height: `${chunkHeight}px`,
Expand All @@ -167,4 +147,4 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
{renderContent()}
</tbody>
);
});
};
43 changes: 0 additions & 43 deletions src/components/PaginatedTable/useIntersectionObserver.ts

This file was deleted.

69 changes: 69 additions & 0 deletions src/components/PaginatedTable/useScrollBasedChunks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';

import {throttle} from 'lodash';

import {getArray} from '../../utils';

interface UseScrollBasedChunksProps {
containerRef: React.RefObject<HTMLElement>;
totalItems: number;
itemHeight: number;
chunkSize: number;
}

const THROTTLE_DELAY = 100;
const CHUNKS_AHEAD_COUNT = 1;

export const useScrollBasedChunks = ({
containerRef,
totalItems,
itemHeight,
chunkSize,
}: UseScrollBasedChunksProps): number[] => {
const [activeChunks, setActiveChunks] = React.useState<number[]>(
getArray(1 + CHUNKS_AHEAD_COUNT).map((index) => index),
);

const calculateActiveChunks = React.useCallback(() => {
const container = containerRef.current;
if (!container) {
return;
}

const {scrollTop, clientHeight} = container;
const visibleStartIndex = Math.floor(scrollTop / itemHeight);
const visibleEndIndex = Math.min(
Math.ceil((scrollTop + clientHeight) / itemHeight),
totalItems - 1,
);

const startChunk = Math.floor(visibleStartIndex / chunkSize);
const endChunk = Math.floor(visibleEndIndex / chunkSize);

const newActiveChunks = getArray(endChunk - startChunk + 1 + CHUNKS_AHEAD_COUNT).map(
(index) => startChunk + index,
);

setActiveChunks(newActiveChunks);
}, [chunkSize, containerRef, itemHeight, totalItems]);

const throttledCalculateActiveChunks = React.useMemo(
() => throttle(calculateActiveChunks, THROTTLE_DELAY),
[calculateActiveChunks],
);

React.useEffect(() => {
const container = containerRef.current;
if (!container) {
return undefined;
}

container.addEventListener('scroll', throttledCalculateActiveChunks);
return () => {
container.removeEventListener('scroll', throttledCalculateActiveChunks);
throttledCalculateActiveChunks.cancel();
};
}, [containerRef, throttledCalculateActiveChunks]);

return activeChunks;
};
4 changes: 2 additions & 2 deletions src/containers/Cluster/Cluster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export function Cluster({
path={getLocationObjectFromHref(getClusterPath(clusterTabsIds.nodes)).pathname}
>
<NodesWrapper
parentContainer={container.current}
parentRef={container}
additionalNodesProps={additionalNodesProps}
/>
</Route>
Expand All @@ -173,7 +173,7 @@ export function Cluster({
getLocationObjectFromHref(getClusterPath(clusterTabsIds.storage)).pathname
}
>
<StorageWrapper parentContainer={container.current} />
<StorageWrapper parentRef={container} />
</Route>
<Route
path={
Expand Down
2 changes: 1 addition & 1 deletion src/containers/Node/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function Node(props: NodeProps) {
case STORAGE: {
return (
<div className={b('storage')}>
<StorageWrapper nodeId={nodeId} parentContainer={container.current} />
<StorageWrapper nodeId={nodeId} parentRef={container} />
</div>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/containers/Nodes/NodesWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import {PaginatedNodes} from './PaginatedNodes';
interface NodesWrapperProps {
path?: string;
database?: string;
parentContainer?: Element | null;
parentRef?: React.RefObject<HTMLElement>;
additionalNodesProps?: AdditionalNodesProps;
}

export const NodesWrapper = ({parentContainer, ...props}: NodesWrapperProps) => {
export const NodesWrapper = ({parentRef, ...props}: NodesWrapperProps) => {
const [usePaginatedTables] = useSetting<boolean>(USE_PAGINATED_TABLES_KEY);

if (usePaginatedTables) {
return <PaginatedNodes parentContainer={parentContainer} {...props} />;
return <PaginatedNodes parentRef={parentRef} {...props} />;
}

return <Nodes {...props} />;
Expand Down
11 changes: 3 additions & 8 deletions src/containers/Nodes/PaginatedNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,11 @@ const b = cn('ydb-nodes');
interface NodesProps {
path?: string;
database?: string;
parentContainer?: Element | null;
parentRef?: React.RefObject<HTMLElement>;
additionalNodesProps?: AdditionalNodesProps;
}

export const PaginatedNodes = ({
path,
database,
parentContainer,
additionalNodesProps,
}: NodesProps) => {
export const PaginatedNodes = ({path, database, parentRef, additionalNodesProps}: NodesProps) => {
const [queryParams, setQueryParams] = useQueryParams({
uptimeFilter: StringParam,
search: StringParam,
Expand Down Expand Up @@ -140,7 +135,7 @@ export const PaginatedNodes = ({
return (
<ResizeablePaginatedTable
columnsWidthLSKey={NODES_COLUMNS_WIDTH_LS_KEY}
parentContainer={parentContainer}
parentRef={parentRef}
columns={columnsToShow}
fetchData={getNodes}
limit={50}
Expand Down
Loading
Loading