mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02: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 (
 | 
				
			||||||
        <VirtualizedTable
 | 
					        <Box
 | 
				
			||||||
            rows={rows}
 | 
					            ref={parentRef}
 | 
				
			||||||
            headerGroups={headerGroups}
 | 
					            sx={{
 | 
				
			||||||
            prepareRow={prepareRow}
 | 
					                overflow: 'auto',
 | 
				
			||||||
        />
 | 
					                maxHeight: '800px',
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <VirtualizedTable
 | 
				
			||||||
 | 
					                parentRef={parentRef}
 | 
				
			||||||
 | 
					                rows={rows}
 | 
				
			||||||
 | 
					                headerGroups={headerGroups}
 | 
				
			||||||
 | 
					                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