Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column Virtualization - if filtered rows = 1, filters need to be cleared #344

Open
1 task done
dafer660acn opened this issue Jun 4, 2024 · 0 comments
Open
1 task done
Labels
V1 Issue with MRT V1

Comments

@dafer660acn
Copy link

dafer660acn commented Jun 4, 2024

mantine-react-table version

v1.3.4

react & react-dom versions

v18.2.0

Describe the bug and the steps to reproduce it

Hello,

I am trying to implement virtualization and using filters (also saving them) as per your manual using local storage as example, so when it re-renders, it's getting the filters from the local Storage, and it's working fine.

However, when data length is only 1, it doesn't display and I must clear the filter to show all of them.

When we have 2 rows, it displays just fine and we can see them both:
mantine_bug_001

However, when I delete one, have only one row to present, I need to clear out the filter and re-apply it again:
mantine_bug_002

Thanks in advance,
Daniel

Minimal, Reproducible Example - (Optional, but Recommended)

This is from the main component, which is imported from a custom component:

Component.jsx

<CustomMantineReactTable
    data={overtimes || []} columns={columns} isError={isError}
    isFetching={isFetching} isLoading={isLoading} refetch={refetch}
    rowVirtualization={true} columnVirtualization={false}
    enableFilter={true} enableSelection={true}
    grouping={grouping} setGrouping={setGrouping}
    sorting={sorting} setSorting={setSorting}
    visibility={visibility} setVisibility={setVisibility}
    order={order} setOrder={setOrder}
    filtering={filtering} setFiltering={setFiltering}
    selection={selection} setSelection={setSelection}
    CustomTopToolbarApplications={renderCustomTopToolbarApplications}
    CustomTopToolbarTools={renderCustomTopToolbarTools}
    CustomTopToolbarFilters={renderCustomTopToolbarFilters}
    CustomToolbarAlertBannerContent={renderToolbarAlertBannerContent}

Then I created the main component to style and customize...

function CustomMantineReactTable({
                                     columns, data, detailPanelBG, error, isError, refetch,
                                     isLoading, isFetching, isExpanded, CustomRowActions, CustomRowActionMenuItems,
                                     CustomBottomToolbar, CustomTopToolbarTools, CustomTopToolbarApplications,
                                     CustomToolbarAlertBannerContent,
                                     CustomTopToolbarFilters, CustomDetailPanel, CustomMantineEditTextInputProps,
                                     CustomMantineEditSelectProps, filtersWidth, noFilterLabel, PageSize,
                                     enableEditing, enableFilter, enablePagination, enableSelection, enableExpand,
                                     rowVirtualization, columnVirtualization,
                                     grouping, setGrouping, sorting, setSorting, selection, setSelection,
                                     visibility, setVisibility, order, setOrder, filtering, setFiltering,
                                 }) {
    // relevant local state:
    const rowVirtualizerInstanceRef = useRef(null)
    const tableInstanceRef = useRef(null)
    const [globalFilter, setGlobalFilter] = useState('')

    useEffect(() => {
        // scroll to the top of the table when the sorting changes
        // we must also verify if the scroll element is not null
        // otherwise it will throw an error.
        if (rowVirtualizerInstanceRef.current?.scrollElement !== null) {
            rowVirtualizerInstanceRef.current?.scrollToIndex(0)
        }
    }, [sorting])

    const containerHeight = (grouping, selection, enablePagination,) => {
            // calc(100vh - 315px) -> grouping, selection and pagination enabled
            // calc(100vh - 245px) -> grouping and selection enabled
            // calc(100vh - 185px) -> normal height
    
            if (grouping?.length > 0 && Object.keys(selection).length > 0 && enablePagination) {
                return 'calc(100vh - 375px)'
            } else if (Object.keys(selection).length > 0 && enablePagination) {
                return 'calc(100vh - 315px)'
            } else if (grouping?.length > 0 && enablePagination) {
                return 'calc(100vh - 315px)'
            } else if (grouping?.length > 0 && Object.keys(selection).length > 0) {
                return 'calc(100vh - 305px)'
            } else if (enablePagination) {
                return 'calc(100vh - 255px)'
            } else if (Object.keys(selection).length > 0) {
                return 'calc(100vh - 245px)'
            } else if (grouping?.length > 0) {
                return 'calc(100vh - 245px)'
            } else {
                return 'calc(100vh - 185px)'
            }
        }
    
    return (
        <MantineReactTable
            columns={columns}
            data={data}
            tableInstanceRef={tableInstanceRef}
            initialState={{
                showColumnFilters: enableFilter ? enableFilter : false,
                columnFilters: filtering,
                density: 'xs',
                columnVisibility: visibility,
                columnOrder: order,
                rowSelection: enableSelection ? selection : null,
                pagination: {
                    pageSize: CustomDetailPanel ?
                        (PageSize ? PageSize : 50) :
                        (PageSize ? PageSize : 75),
                    pageIndex: 0
                },
            }}

            // specify the layout mode here
            // layoutMode={!CustomDetailPanel ? 'grid' : 'semantic'}
            layoutMode={'grid'}
            // use memoMode cells which improve performance when using rowVirtualization
            memoMode={'rows'}

            // if we use global filters, declare how you want them to work here
            globalFilterFn={'contains'}
            globalFilterModeOptions={['contains']}

            // override display styles
            displayColumnDefOptions={{
                'mrt-row-actions': {
                    header: 'Actions', //change header text
                    size: 75, //make actions column wider
                },
                'mrt-row-expand': {
                    header: '',
                    size: (grouping?.length > 0 || enableExpand) ? 75 : 0,
                },
                'mrt-row-select': {
                    header: '',
                    size: enableSelection ? 75 : 0,
                    // size: Object.keys(selection).length > 0 ? 75 : 0, //make select column wider
                }
            }}

            // enable or disable functionalities here
            enableStickyHeader={true}
            enableStickyFooter={false}
            enableTableFooter={false}
            enableFullScreenToggle={false}
            enableBottomToolbar={enablePagination}
            enableClickToCopy={false}
            enableFacetedValues={true}
            enableHiding={true}
            enableDensityToggle={false}
            enablePinning={false}
            enableGrouping={true}

            // Editing the table
            enableEditing={enableEditing}
            editDisplayMode={"table"}
            mantineEditTextInputProps={CustomMantineEditTextInputProps}
            mantineEditSelectProps={CustomMantineEditSelectProps}

            // Expand detail panel
            // enableExpanding={grouping?.length > 0}
            enableExpanding={grouping?.length > 0 || enableExpand}
            enableExpandAll={false}

            // filters
            enableGlobalFilterModes={false}
            enableGlobalFilter={false}
            enableColumnFilterModes={enableFilter}

            // pagination
            enablePagination={enablePagination || false}
            paginationDisplayMode={'default'}
            // positionToolbarAlertBanner={'top'}

            // rows
            enableMultiRowSelection={enableSelection}
            enableRowSelection={enableSelection}
            enableSelectAll={enableSelection}
            enableSubRowSelection={enableSelection}
            enableRowActions={CustomRowActionMenuItems}
            enableRowNumbers={false}
            enableRowVirtualization={rowVirtualization}

            // columns
            enableColumnDragging={true}
            enableColumnOrdering={true}
            enableColumnResizing={true}
            enableColumnVirtualization={columnVirtualization}

            // mantine table props
            mantineTableContainerProps={{
                sx: {
                    maxHeight: containerHeight(grouping, selection, enablePagination),
                    minHeight: containerHeight(grouping, selection, enablePagination),
                    'thead': {
                        // we need to add z-index as 5 here if we display the display panel
                        zIndex: 5,
                    },
                    // 'tr.mantine-TableBodyCell-DetailPanel': {
                    //     width: '100%',
                    //     zIndex: 5,
                    //     backgroundColor: 'gray'
                    // },
                },
            }}

            // Top toolbar props
            mantineTopToolbarProps={{
                sx: {
                    maxHeight: grouping?.length > 0 && (selection ? Object.keys(selection).length > 0 : false) ? '180px' :
                        grouping?.length > 0 || (selection ? Object.keys(selection).length > 0 : false) ? '120px' : '60px',
                    minHeight: grouping?.length > 0 && (selection ? Object.keys(selection).length > 0 : false) ? '180px' :
                        grouping?.length > 0 || (selection ? Object.keys(selection).length > 0 : false) ? '120px' : '60px',
                    zIndex: 6,
                }
            }}

            // Bottom toolbar props
            mantineBottomToolbarProps={{
                sx: {
                    // maxHeight: 0,
                    minHeight: enablePagination ? '70px' : '0px',
                    maxHeight: enablePagination ? '70px' : '0px',
                    height: enablePagination ? '70px' : '0px',
                    padding: 0,
                    placeItems: 'center',
                    verticalAlign: 'center',
                    '& *': {
                        padding: 0,
                    },
                    '& input': {
                        padding: '5px 12px 5px 12px'
                    }
                }
            }}

            mantineTableFooterRowProps={{
                sx: {
                    padding: 0,
                    height: '100%'
                }
            }}

            mantineTableFooterCellProps={{
                sx: {
                    padding: 0,
                    height: '100%'
                }
            }}

            mantineDetailPanelProps={{
                sx: {
                    width: '100%',
                    backgroundColor: detailPanelBG ? detailPanelBG : 'rgb(225,225,225)',
                }
            }}

            mantineTableBodyRowProps={{
                sx: {
                    height: CustomDetailPanel ? null : '20px',
                }
            }}

            mantineTableBodyCellProps={{
                // height: '20px',
                sx: {
                    height: '10px',
                },
            }}

            mantineTableProps={{
                striped: false,
            }}

            mantineSelectAllCheckboxProps={{
                size: 'xs',
                color: 'red',
                variant: 'filled',
            }}

            // Pagination props
            mantinePaginationProps={{
                rowsPerPageOptions: ['10', '30', '50', '75', '100', '250'],
                showRowsPerPage: true,
                withEdges: true,
                radius: 'xs',
                size: 'xs',
            }}

            mantineToolbarAlertBannerProps={{color: 'dark', variant: 'light',}}
            mantineToolbarAlertBannerBadgeProps={{color: 'dark', variant: 'filled'}}
            mantineSelectCheckboxProps={{color: 'red', size: 'xs', variant: 'filled'}}

            renderToolbarAlertBannerContent={({table, groupedAlert, selectedAlert}) => {
                return (
                    CustomToolbarAlertBannerContent ?
                        <CustomToolbarAlertBannerContent table={table} groupedAlert={groupedAlert}
                                                         selectedAlert={selectedAlert}/> :
                        <Flex justify="space-between">
                            <Flex p="6px" gap="xl">
                                {groupedAlert?.props?.children}
                            </Flex>
                        </Flex>
                )
            }
            }

            // Render Custom Functions
            renderTopToolbarCustomActions={({table}) => {
                let allRows = table?.getPreFilteredRowModel()
                let filteredRows = table?.getFilteredRowModel()

                return (
                    <>
                        <Group spacing={'xs'}>
                            <Menu width={175} shadow={'xl'} position={'bottom-start'}
                                  transitionProps={{transition: 'scale-y', duration: 700}}>
                                <Menu.Target>
                                    <Button
                                        variant={'filled'} color={'accenture.6'} size={'sm'}
                                        leftIcon={<Image src={gearIcon} height={17} width={17}/>}
                                        styles={(theme) => ({
                                            root: {
                                                backgroundColor: theme.fn.lighten('#A100FF', 0.80),
                                                '&:not([data-disabled])': theme.fn.hover({
                                                    backgroundColor: theme.fn.lighten('#A100FF', 0.55),
                                                }),
                                            }
                                        })}
                                    >
                                        <Text fw={700} color={'black'}>Menu</Text>
                                    </Button>
                                </Menu.Target>

                                <Menu.Dropdown>
                                    <Menu.Label>Refetch data</Menu.Label>
                                    <CustomMantineMenuItem onClick={() => refetch()}>
                                        <Group>
                                            <Image src={refreshIcon} height={17} width={17}/>
                                            <Text fw={700} color={'black'} size={'xs'}>Refresh</Text>
                                        </Group>
                                    </CustomMantineMenuItem>


                                    {
                                        CustomTopToolbarApplications ?
                                            <>
                                                <Menu.Label>Applications</Menu.Label>
                                                <CustomTopToolbarApplications/>
                                            </> :
                                            <></>
                                    }

                                    {
                                        CustomTopToolbarTools ?
                                            <>
                                                <Menu.Label>Tools</Menu.Label>
                                                <CustomTopToolbarTools/>
                                            </> :
                                            <></>
                                    }
                                </Menu.Dropdown>
                            </Menu>
                            {
                                CustomTopToolbarFilters ?
                                    <Menu width={filtersWidth ? filtersWidth : 175} shadow={'xl'}
                                          position={'bottom-start'}
                                          transitionProps={{transition: 'scale-y', duration: 700}}>
                                        <Menu.Target>
                                            <Button
                                                variant={'filled'} size={'sm'}
                                                leftIcon={<Image src={filterIcon} height={17} width={17}/>}
                                                styles={(theme) => ({
                                                    root: {
                                                        backgroundColor: theme.fn.lighten('#c48300', 0.80),
                                                        '&:not([data-disabled])': theme.fn.hover({
                                                            backgroundColor: theme.fn.lighten('#c48300', 0.55),
                                                        }),
                                                    }
                                                })}
                                            >
                                                <Text fw={700} color={'black'}>Filters</Text>
                                            </Button>
                                        </Menu.Target>
                                        <Menu.Dropdown>
                                            {
                                                noFilterLabel ?
                                                    <></> :
                                                    <Menu.Label>Custom Filters</Menu.Label>
                                            }
                                            <CustomTopToolbarFilters/>
                                        </Menu.Dropdown>

                                    </Menu>
                                    :
                                    <></>
                            }
                        </Group>

                        {
                            !enablePagination ?
                                <Text style={{color: 'dark'}} fz={'xs'} color={'dimmed'}>
                                    Presenting {
                                    filteredRows.rows.length === allRows.rows.length ?
                                        allRows.rows.length :
                                        filteredRows.rows.length} of {allRows.rows.length} records
                                </Text>
                                :
                                <></>
                        }
                    </>
                )
            }}

            renderRowActionMenuItems={({table, row}) => {
                return (
                    CustomRowActionMenuItems ?
                        <CustomRowActionMenuItems table={table} row={row}/> :
                        <></>
                )
            }}

            renderEmptyRowsFallback={
                () => {
                    return (
                        <Container size={'lg'}>
                            <Text fw={700} fz={'lg'} ta={'center'} color={'accenture.6'}>Apologies, but no data
                                returned 😳</Text>
                            {
                                isError ?
                                    <>
                                        <Divider my={'sm'}/>
                                        <Text fw={500} fz={'md'} ta={'center'} color={'accenture.6'}>Error
                                            Details:</Text>
                                        <Text fw={300} fz={'sm'} ta={'center'}
                                              color={'accenture.6'}>{error ? error?.data?.message : "There was some error..."
                                        || error ? error?.error : "There was some error..."}</Text>
                                    </>
                                    :
                                    <></>
                            }
                        </Container>
                    )
                }
            }

            renderDetailPanel={CustomDetailPanel}
            renderBottomToolbarCustomActions={CustomBottomToolbar}

            // onChange events
            onSortingChange={setSorting}
            onColumnFiltersChange={setFiltering}
            onGlobalFilterChange={setGlobalFilter}
            onGroupingChange={setGrouping}
            onColumnVisibilityChange={setVisibility}
            onColumnOrderChange={setOrder}
            onRowSelectionChange={setSelection || null}

            // Virtualization
            rowVirtualizerInstanceRef={rowVirtualizerInstanceRef} //optional
            rowVirtualizerProps={{overscan: 8, estimateSize: () => 30}} //optionally customize the row virtualizer
            columnVirtualizerProps={{overscan: 5}} //optionally customize the column virtualizer

            // state for the table
            state={{
                columnFilters: filtering,
                globalFilter: globalFilter,
                isLoading: isLoading || isFetching,
                showAlertBanner: false,
                showGlobalFilter: false,
                showProgressBars: isLoading || isFetching,
                sorting: sorting,
                grouping: grouping,
                columnVisibility: visibility,
                columnOrder: order,
                rowSelection: selection || {}
            }}
        />
    )

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

No, because I do not know how

Terms

  • I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
@alessandrojcm alessandrojcm added V1 Issue with MRT V1 labels Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
V1 Issue with MRT V1
Projects
None yet
Development

No branches or pull requests

2 participants