1
0
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:
Mateusz Kwasniewski 2023-06-15 14:11:04 +02:00 committed by GitHub
parent 221e3218df
commit c7ff3b472e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 19 deletions

View File

@ -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,

View File

@ -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>
</> </>

View File

@ -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>
); );
}; };

View File

@ -54,7 +54,7 @@ export const resolveResultsWidth = (
} }
if (results && !matches) { if (results && !matches) {
return '65%'; return '60%';
} }
return '50%'; return '50%';

View File

@ -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;
}; };