mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
feat: Virtualized table with parent ref (#3993)
This commit is contained in:
parent
221e3218df
commit
c7ff3b472e
@ -1,4 +1,4 @@
|
|||||||
import { useMemo } from 'react';
|
import { RefObject, useMemo } from 'react';
|
||||||
import { useTheme, TableBody, TableRow } from '@mui/material';
|
import { useTheme, TableBody, TableRow } from '@mui/material';
|
||||||
import { SortableTableHeader } from 'component/common/Table/SortableTableHeader/SortableTableHeader';
|
import { SortableTableHeader } from 'component/common/Table/SortableTableHeader/SortableTableHeader';
|
||||||
import { TableCell } from 'component/common/Table/TableCell/TableCell';
|
import { TableCell } from 'component/common/Table/TableCell/TableCell';
|
||||||
@ -21,11 +21,13 @@ export const VirtualizedTable = <T extends object>({
|
|||||||
headerGroups,
|
headerGroups,
|
||||||
rows,
|
rows,
|
||||||
prepareRow,
|
prepareRow,
|
||||||
|
parentRef,
|
||||||
}: {
|
}: {
|
||||||
rowHeight?: number;
|
rowHeight?: number;
|
||||||
headerGroups: HeaderGroup<T>[];
|
headerGroups: HeaderGroup<T>[];
|
||||||
rows: Row<T>[];
|
rows: Row<T>[];
|
||||||
prepareRow: (row: Row<T>) => void;
|
prepareRow: (row: Row<T>) => void;
|
||||||
|
parentRef?: RefObject<HTMLElement | null>;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const rowHeight = useMemo(
|
const rowHeight = useMemo(
|
||||||
@ -33,8 +35,12 @@ export const VirtualizedTable = <T extends object>({
|
|||||||
[rowHeightOverride, theme.shape.tableRowHeight]
|
[rowHeightOverride, theme.shape.tableRowHeight]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [firstRenderedIndex, lastRenderedIndex] =
|
const [firstRenderedIndex, lastRenderedIndex] = useVirtualizedRange(
|
||||||
useVirtualizedRange(rowHeight);
|
rowHeight,
|
||||||
|
40,
|
||||||
|
5,
|
||||||
|
parentRef?.current
|
||||||
|
);
|
||||||
|
|
||||||
const tableHeight = useMemo(
|
const tableHeight = useMemo(
|
||||||
() => rowHeight * rows.length + theme.shape.tableRowHeightCompact,
|
() => rowHeight * rows.length + theme.shape.tableRowHeightCompact,
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
import { ConditionallyRender } from '../../../../common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from '../../../../common/ConditionallyRender/ConditionallyRender';
|
||||||
import { Box, IconButton, Popover, styled, useTheme } from '@mui/material';
|
import {
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
Popover,
|
||||||
|
styled,
|
||||||
|
Typography,
|
||||||
|
useTheme,
|
||||||
|
} from '@mui/material';
|
||||||
import { flexRow } from '../../../../../themes/themeStyles';
|
import { flexRow } from '../../../../../themes/themeStyles';
|
||||||
import { PlaygroundResultChip } from '../../PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip';
|
import { PlaygroundResultChip } from '../../PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip';
|
||||||
import { InfoOutlined } from '@mui/icons-material';
|
import { InfoOutlined } from '@mui/icons-material';
|
||||||
@ -78,6 +85,7 @@ export const AdvancedPlaygroundEnvironmentCell = ({
|
|||||||
PaperProps={{
|
PaperProps={{
|
||||||
sx: {
|
sx: {
|
||||||
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
borderRadius: `${theme.shape.borderRadiusLarge}px`,
|
||||||
|
padding: theme.spacing(3),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
@ -87,6 +95,9 @@ export const AdvancedPlaygroundEnvironmentCell = ({
|
|||||||
horizontal: -320,
|
horizontal: -320,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Typography variant="subtitle2" sx={{ mb: 3 }}>
|
||||||
|
{value[0].environment}
|
||||||
|
</Typography>
|
||||||
<PlaygroundEnvironmentTable features={value} />
|
<PlaygroundEnvironmentTable features={value} />
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useMemo } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
useFlexLayout,
|
useFlexLayout,
|
||||||
useGlobalFilter,
|
useGlobalFilter,
|
||||||
@ -12,7 +12,7 @@ import {
|
|||||||
AdvancedPlaygroundEnvironmentFeatureSchema,
|
AdvancedPlaygroundEnvironmentFeatureSchema,
|
||||||
PlaygroundFeatureSchema,
|
PlaygroundFeatureSchema,
|
||||||
} from 'openapi';
|
} from 'openapi';
|
||||||
import { useMediaQuery, useTheme } from '@mui/material';
|
import { Box, useMediaQuery, useTheme } from '@mui/material';
|
||||||
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
|
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
|
||||||
import { FeatureStatusCell } from '../PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell';
|
import { FeatureStatusCell } from '../PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell';
|
||||||
import { FeatureResultInfoPopoverCell } from '../PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell';
|
import { FeatureResultInfoPopoverCell } from '../PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell';
|
||||||
@ -125,11 +125,22 @@ export const PlaygroundEnvironmentTable = ({
|
|||||||
COLUMNS
|
COLUMNS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const parentRef = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Box
|
||||||
|
ref={parentRef}
|
||||||
|
sx={{
|
||||||
|
overflow: 'auto',
|
||||||
|
maxHeight: '800px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<VirtualizedTable
|
<VirtualizedTable
|
||||||
|
parentRef={parentRef}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
headerGroups={headerGroups}
|
headerGroups={headerGroups}
|
||||||
prepareRow={prepareRow}
|
prepareRow={prepareRow}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -54,7 +54,7 @@ export const resolveResultsWidth = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (results && !matches) {
|
if (results && !matches) {
|
||||||
return '65%';
|
return '60%';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '50%';
|
return '50%';
|
||||||
|
@ -12,27 +12,38 @@ import { useEffect, useState } from 'react';
|
|||||||
export const useVirtualizedRange = (
|
export const useVirtualizedRange = (
|
||||||
rowHeight: number,
|
rowHeight: number,
|
||||||
scrollOffset = 40,
|
scrollOffset = 40,
|
||||||
dampening = 5
|
dampening = 5,
|
||||||
|
parentElement?: HTMLElement | null
|
||||||
) => {
|
) => {
|
||||||
|
const parent = parentElement ? parentElement : window;
|
||||||
|
|
||||||
const [scrollIndex, setScrollIndex] = useState(
|
const [scrollIndex, setScrollIndex] = useState(
|
||||||
Math.floor(window.pageYOffset / rowHeight)
|
Math.floor(
|
||||||
|
(parent instanceof HTMLElement
|
||||||
|
? parent.scrollTop
|
||||||
|
: parent.pageYOffset) / rowHeight
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
setScrollIndex(
|
setScrollIndex(
|
||||||
Math.floor(window.pageYOffset / (rowHeight * dampening)) *
|
Math.floor(
|
||||||
dampening
|
(parent instanceof HTMLElement
|
||||||
|
? parent.scrollTop
|
||||||
|
: parent.pageYOffset) /
|
||||||
|
(rowHeight * dampening)
|
||||||
|
) * dampening
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
parent.addEventListener('scroll', handleScroll, { passive: true });
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('scroll', handleScroll);
|
parent.removeEventListener('scroll', handleScroll);
|
||||||
};
|
};
|
||||||
}, [rowHeight, dampening]);
|
}, [rowHeight, dampening, parent]);
|
||||||
|
|
||||||
return [scrollIndex - scrollOffset, scrollIndex + scrollOffset] as const;
|
return [scrollIndex - scrollOffset, scrollIndex + scrollOffset] as const;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user