From 757461d58bfb4577464a9e55ea9251f3430b7b74 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Tue, 2 May 2023 13:42:16 +0700 Subject: [PATCH] chore(deps): upgrade react-table to v8 [EE-4837] (#8245) --- app/react-table-config.d.ts | 150 +----- .../ListView/ContainersDatatable.tsx | 13 +- .../ListView/columns/helper.ts | 5 + .../ListView/columns/location.ts | 16 +- .../ListView/columns/name.tsx | 24 +- .../ListView/columns/ownership.tsx | 30 +- .../ListView/columns/ports.tsx | 22 +- .../components/DetailsTable/DetailsRow.tsx | 2 +- .../components/DetailsTable/DetailsTable.tsx | 2 +- .../datatables/ColumnVisibilityMenu.tsx | 12 +- app/react/components/datatables/Datatable.tsx | 237 +++++---- .../datatables/DatatableContent.tsx | 46 +- .../datatables/ExpandableDatatable.tsx | 14 +- .../datatables/ExpandableDatatableRow.tsx | 24 +- .../datatables/ExpandingCell.module.css | 9 - .../components/datatables/ExpandingCell.tsx | 32 -- app/react/components/datatables/Filter.tsx | 57 ++- app/react/components/datatables/NameCell.tsx | 42 +- .../components/datatables/NestedDatatable.tsx | 68 ++- .../components/datatables/NestedTable.css | 4 + app/react/components/datatables/Table.tsx | 20 +- .../components/datatables/TableContent.tsx | 16 +- .../components/datatables/TableHeaderCell.tsx | 21 +- .../components/datatables/TableHeaderRow.tsx | 78 +-- app/react/components/datatables/TableRow.tsx | 38 +- .../datatables/emptyReactTablePlugin.ts | 3 - .../components/datatables/expand-column.tsx | 60 +-- .../components/datatables/filter-types.ts | 15 +- .../components/datatables/select-column.tsx | 67 +++ .../datatables/useGoToHighlightedRow.ts | 2 +- .../components/datatables/useRowSelect.ts | 481 ------------------ .../components/datatables/useTableState.ts | 29 ++ .../createOwnershipColumn.tsx | 38 ++ .../ContainersDatatable.tsx | 50 +- .../ContainersDatatable/columns/created.tsx | 17 +- .../ContainersDatatable/columns/gpus.tsx | 17 +- .../ContainersDatatable/columns/helper.ts | 5 + .../ContainersDatatable/columns/host.tsx | 15 +- .../ContainersDatatable/columns/image.tsx | 24 +- .../ContainersDatatable/columns/index.tsx | 8 +- .../ContainersDatatable/columns/ip.tsx | 14 +- .../ContainersDatatable/columns/name.tsx | 23 +- .../ContainersDatatable/columns/ownership.tsx | 34 -- .../ContainersDatatable/columns/ports.tsx | 23 +- .../columns/quick-actions.tsx | 19 +- .../ContainersDatatable/columns/stack.tsx | 15 +- .../ContainersDatatable/columns/state.tsx | 31 +- .../ContainersDatatable/datatable-store.ts | 2 +- .../images/ItemView/DockerfileDetails.tsx | 4 +- .../ItemView/NetworkContainersTable.tsx | 90 ++-- .../networks/ItemView/NetworkDetailsTable.tsx | 136 +++-- .../networks/ItemView/NetworkOptionsTable.tsx | 18 +- .../ItemView/StackContainersDatatable.tsx | 111 ++-- .../WaitingRoomView/Datatable/Datatable.tsx | 15 +- .../WaitingRoomView/Datatable/columns.ts | 93 +--- .../ServicesDatatable/ServicesDatatable.tsx | 42 +- ...{externalIPLink.tsx => ExternalIPLink.tsx} | 0 .../ServicesDatatable/columns/application.tsx | 57 ++- .../ServicesDatatable/columns/clusterIP.tsx | 19 +- .../ServicesDatatable/columns/created.tsx | 21 +- .../ServicesDatatable/columns/externalIP.tsx | 201 ++++---- .../ServicesDatatable/columns/helper.ts | 5 + .../ServicesDatatable/columns/index.tsx | 24 +- .../ServicesDatatable/columns/name.tsx | 26 +- .../ServicesDatatable/columns/namespace.tsx | 50 +- .../ServicesDatatable/columns/ports.tsx | 114 ++--- .../ServicesDatatable/columns/targetPorts.tsx | 93 ++-- .../ServicesDatatable/columns/type.tsx | 26 +- .../ServicesDatatable/datatable-store.ts | 2 +- app/react/kubernetes/ServicesView/service.ts | 4 +- .../IngressClassDatatable.tsx | 19 +- .../columns/availability.tsx | 32 +- .../IngressClassDatatable/columns/helper.ts | 5 + .../IngressClassDatatable/columns/index.ts | 6 +- .../IngressClassDatatable/columns/name.tsx | 28 +- .../IngressClassDatatable/columns/type.tsx | 20 +- .../IngressDatatable/IngressDatatable.tsx | 13 +- .../IngressDatatable/columns/className.tsx | 13 +- .../IngressDatatable/columns/created.tsx | 22 +- .../IngressDatatable/columns/helper.ts | 5 + .../columns/{index.tsx => index.ts} | 0 .../IngressDatatable/columns/ingressRules.tsx | 67 +-- .../IngressDatatable/columns/name.tsx | 36 +- .../IngressDatatable/columns/namespace.tsx | 51 +- .../IngressDatatable/columns/type.tsx | 13 +- .../EventsDatatable/EventsDatatable.tsx | 20 +- .../EventsDatatable/columns/date.tsx | 18 +- .../EventsDatatable/columns/helper.ts | 5 + .../EventsDatatable/columns/index.tsx | 6 +- .../EventsDatatable/columns/message.tsx | 13 +- .../EventsDatatable/columns/type.tsx | 13 +- .../JobsView/JobsDatatable/JobsDatatable.tsx | 24 +- .../TasksDatatable/TasksDatatable.tsx | 6 +- .../TasksDatatable/columns/actions.tsx | 25 +- .../TasksDatatable/columns/allocationID.tsx | 17 +- .../TasksDatatable/columns/helper.ts | 5 + .../TasksDatatable/columns/index.tsx | 16 +- .../TasksDatatable/columns/started.tsx | 12 +- .../TasksDatatable/columns/taskGroup.tsx | 17 +- .../TasksDatatable/columns/taskName.tsx | 13 +- .../TasksDatatable/columns/taskStatus.tsx | 31 +- .../JobsDatatable/columns/actions.tsx | 29 +- .../JobsDatatable/columns/created.tsx | 21 +- .../JobsView/JobsDatatable/columns/helper.ts | 5 + .../JobsView/JobsDatatable/columns/index.tsx | 8 +- .../JobsView/JobsDatatable/columns/name.tsx | 26 +- .../JobsDatatable/columns/namespace.tsx | 17 +- .../JobsView/JobsDatatable/columns/status.tsx | 19 +- .../JobsView/JobsDatatable/datatable-store.ts | 10 +- .../update-schedules/ListView/ListView.tsx | 13 +- .../ListView/columns/created.tsx | 19 +- .../ListView/columns/groups.tsx | 22 +- .../ListView/columns/helper.ts | 5 + .../ListView/columns/index.ts | 7 +- .../ListView/columns/name.tsx | 27 - .../ListView/columns/schedule-status.tsx | 23 +- .../ListView/columns/scheduled-time.tsx | 14 +- .../ListView/columns/type.tsx | 21 +- .../notifications/NotificationsView.tsx | 12 +- .../notifications/columns/details.tsx | 21 +- .../portainer/notifications/columns/helper.ts | 5 + .../portainer/notifications/columns/time.tsx | 18 +- .../portainer/notifications/columns/title.tsx | 13 +- .../portainer/notifications/columns/type.tsx | 18 +- .../FDOProfilesDatatable.tsx | 17 +- .../FDOProfilesDatatable/columns/created.tsx | 20 +- .../FDOProfilesDatatable/columns/helper.ts | 5 + .../FDOProfilesDatatable/columns/index.tsx | 12 +- .../FDOProfilesDatatable/columns/name.tsx | 30 -- .../TeamAssociationSelector.tsx | 6 +- .../TeamMembersList/TeamMembersList.tsx | 181 +------ .../TeamMembersList/columns/helper.ts | 5 + .../TeamMembersList/columns/index.ts | 4 + .../{ => columns}/name-column.tsx | 26 +- .../{ => columns}/team-role-column.tsx | 28 +- .../UsersList/UsersList.tsx | 179 +------ .../UsersList/name-column.tsx | 19 +- .../TeamsDatatable/TeamsDatatable.tsx | 23 +- package.json | 4 +- yarn.lock | 49 +- 140 files changed, 1805 insertions(+), 2872 deletions(-) create mode 100644 app/react/azure/container-instances/ListView/columns/helper.ts delete mode 100644 app/react/components/datatables/ExpandingCell.module.css delete mode 100644 app/react/components/datatables/ExpandingCell.tsx delete mode 100644 app/react/components/datatables/emptyReactTablePlugin.ts create mode 100644 app/react/components/datatables/select-column.tsx delete mode 100644 app/react/components/datatables/useRowSelect.ts create mode 100644 app/react/components/datatables/useTableState.ts create mode 100644 app/react/docker/components/datatable-helpers/createOwnershipColumn.tsx create mode 100644 app/react/docker/containers/ListView/ContainersDatatable/columns/helper.ts delete mode 100644 app/react/docker/containers/ListView/ContainersDatatable/columns/ownership.tsx rename app/react/kubernetes/ServicesView/ServicesDatatable/columns/{externalIPLink.tsx => ExternalIPLink.tsx} (100%) create mode 100644 app/react/kubernetes/ServicesView/ServicesDatatable/columns/helper.ts create mode 100644 app/react/kubernetes/cluster/ingressClass/IngressClassDatatable/columns/helper.ts create mode 100644 app/react/kubernetes/ingresses/IngressDatatable/columns/helper.ts rename app/react/kubernetes/ingresses/IngressDatatable/columns/{index.tsx => index.ts} (100%) create mode 100644 app/react/nomad/jobs/EventsView/EventsDatatable/columns/helper.ts create mode 100644 app/react/nomad/jobs/JobsView/JobsDatatable/TasksDatatable/columns/helper.ts create mode 100644 app/react/nomad/jobs/JobsView/JobsDatatable/columns/helper.ts create mode 100644 app/react/portainer/environments/update-schedules/ListView/columns/helper.ts delete mode 100644 app/react/portainer/environments/update-schedules/ListView/columns/name.tsx create mode 100644 app/react/portainer/notifications/columns/helper.ts create mode 100644 app/react/portainer/settings/EdgeComputeView/FDOProfilesDatatable/columns/helper.ts delete mode 100644 app/react/portainer/settings/EdgeComputeView/FDOProfilesDatatable/columns/name.tsx create mode 100644 app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/columns/helper.ts create mode 100644 app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/columns/index.ts rename app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/{ => columns}/name-column.tsx (72%) rename app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/{ => columns}/team-role-column.tsx (85%) diff --git a/app/react-table-config.d.ts b/app/react-table-config.d.ts index f1a7d6381..a37055397 100644 --- a/app/react-table-config.d.ts +++ b/app/react-table-config.d.ts @@ -1,149 +1,9 @@ -import { - UseColumnOrderInstanceProps, - UseColumnOrderState, - UseExpandedHooks, - UseExpandedInstanceProps, - UseExpandedOptions, - UseExpandedRowProps, - UseExpandedState, - UseFiltersColumnOptions, - UseFiltersColumnProps, - UseFiltersInstanceProps, - UseFiltersOptions, - UseFiltersState, - UseGlobalFiltersColumnOptions, - UseGlobalFiltersInstanceProps, - UseGlobalFiltersOptions, - UseGlobalFiltersState, - UseGroupByCellProps, - UseGroupByColumnOptions, - UseGroupByColumnProps, - UseGroupByHooks, - UseGroupByInstanceProps, - UseGroupByOptions, - UseGroupByRowProps, - UseGroupByState, - UsePaginationInstanceProps, - UsePaginationOptions, - UsePaginationState, - UseResizeColumnsColumnOptions, - UseResizeColumnsColumnProps, - UseResizeColumnsOptions, - UseResizeColumnsState, - UseRowSelectHooks, - UseRowSelectInstanceProps, - UseRowSelectOptions, - UseRowSelectRowProps, - UseRowSelectState, - UseRowStateCellProps, - UseRowStateInstanceProps, - UseRowStateOptions, - UseRowStateRowProps, - UseRowStateState, - UseSortByColumnOptions, - UseSortByColumnProps, - UseSortByHooks, - UseSortByInstanceProps, - UseSortByOptions, - UseSortByState, -} from 'react-table'; -import { UseSelectColumnTableOptions } from '@lineup-lite/hooks'; +import '@tanstack/react-table'; -declare module 'react-table' { - // take this file as-is, or comment out the sections that don't apply to your plugin configuration - - export interface TableOptions> - extends UseExpandedOptions, - UseFiltersOptions, - UseGlobalFiltersOptions, - UseGroupByOptions, - UsePaginationOptions, - UseResizeColumnsOptions, - UseRowSelectOptions, - UseRowStateOptions, - UseSortByOptions, - UseSelectColumnTableOptions, - // note that having Record here allows you to add anything to the options, this matches the spirit of the - // underlying js library, but might be cleaner if it's replaced by a more specific type that matches your - // feature set, this is a safe default. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Record {} - - export interface Hooks< - D extends Record = Record - > extends UseExpandedHooks, - UseGroupByHooks, - UseRowSelectHooks, - UseSortByHooks {} - - export interface TableInstance< - D extends Record = Record - > extends UseColumnOrderInstanceProps, - UseExpandedInstanceProps, - UseFiltersInstanceProps, - UseGlobalFiltersInstanceProps, - UseGroupByInstanceProps, - UsePaginationInstanceProps, - UseRowSelectInstanceProps, - UseRowStateInstanceProps, - UseSortByInstanceProps {} - - export interface TableState< - D extends Record = Record - > extends UseColumnOrderState, - UseExpandedState, - UseFiltersState, - UseGlobalFiltersState, - UseGroupByState, - UsePaginationState, - UseResizeColumnsState, - UseRowSelectState, - UseRowStateState, - UseSortByState {} - - export interface ColumnInterface< - D extends Record = Record - > extends UseFiltersColumnOptions, - UseGlobalFiltersColumnOptions, - UseGroupByColumnOptions, - UseResizeColumnsColumnOptions, - UseSortByColumnOptions { +declare module '@tanstack/table-core' { + interface ColumnMeta { className?: string; - canHide?: boolean; - } - - export interface ColumnInstance< - D extends Record = Record - > extends UseFiltersColumnProps, - UseGroupByColumnProps, - UseResizeColumnsColumnProps, - UseSortByColumnProps { - className?: string; - } - - export interface Cell< - D extends Record = Record, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - V = any - > extends UseTableCellProps, - UseGroupByCellProps, - UseRowStateCellProps { - className?: string; - } - - export interface Row< - D extends Record = Record - > extends UseExpandedRowProps, - UseGroupByRowProps, - UseRowSelectRowProps, - UseRowStateRowProps {} - - export function makePropGetter( - hooks: Array, - ...meta: Record[] - ): PropGetter; - - export interface TableToggleRowsSelectedProps { - disabled: boolean; + filter?: Filter; + width?: number | 'auto' | string; } } diff --git a/app/react/azure/container-instances/ListView/ContainersDatatable.tsx b/app/react/azure/container-instances/ListView/ContainersDatatable.tsx index 23a9b25c4..3d7f4e872 100644 --- a/app/react/azure/container-instances/ListView/ContainersDatatable.tsx +++ b/app/react/azure/container-instances/ListView/ContainersDatatable.tsx @@ -1,5 +1,4 @@ import { Box, Plus, Trash2 } from 'lucide-react'; -import { useStore } from 'zustand'; import { ContainerGroup } from '@/react/azure/types'; import { Authorized } from '@/react/hooks/useUser'; @@ -9,7 +8,7 @@ import { Datatable } from '@@/datatables'; import { Button } from '@@/buttons'; import { Link } from '@@/Link'; import { createPersistedStore } from '@@/datatables/types'; -import { useSearchBarState } from '@@/datatables/SearchBar'; +import { useTableState } from '@@/datatables/useTableState'; import { columns } from './columns'; @@ -22,19 +21,13 @@ export interface Props { } export function ContainersDatatable({ dataset, onRemoveClick }: Props) { - const settings = useStore(settingsStore); - const [search, setSearch] = useSearchBarState(tableKey); + const tableState = useTableState(settingsStore, tableKey); return ( container.id} diff --git a/app/react/azure/container-instances/ListView/columns/helper.ts b/app/react/azure/container-instances/ListView/columns/helper.ts new file mode 100644 index 000000000..0090f0767 --- /dev/null +++ b/app/react/azure/container-instances/ListView/columns/helper.ts @@ -0,0 +1,5 @@ +import { createColumnHelper } from '@tanstack/react-table'; + +import { ContainerGroup } from '@/react/azure/types'; + +export const columnHelper = createColumnHelper(); diff --git a/app/react/azure/container-instances/ListView/columns/location.ts b/app/react/azure/container-instances/ListView/columns/location.ts index 8079661da..ddeffe5b4 100644 --- a/app/react/azure/container-instances/ListView/columns/location.ts +++ b/app/react/azure/container-instances/ListView/columns/location.ts @@ -1,13 +1,5 @@ -import { Column } from 'react-table'; +import { columnHelper } from './helper'; -import { ContainerGroup } from '@/react/azure/types'; - -export const location: Column = { - Header: 'Location', - accessor: (container) => container.location, - id: 'location', - disableFilters: true, - Filter: () => null, - canHide: true, - sortType: 'string', -}; +export const location = columnHelper.accessor('location', { + header: 'Location', +}); diff --git a/app/react/azure/container-instances/ListView/columns/name.tsx b/app/react/azure/container-instances/ListView/columns/name.tsx index a49e83c09..249caa98d 100644 --- a/app/react/azure/container-instances/ListView/columns/name.tsx +++ b/app/react/azure/container-instances/ListView/columns/name.tsx @@ -1,24 +1,22 @@ -import { CellProps, Column } from 'react-table'; +import { CellContext } from '@tanstack/react-table'; import { ContainerGroup } from '@/react/azure/types'; import { Link } from '@@/Link'; -export const name: Column = { - Header: 'Name', - accessor: (container) => container.name, - id: 'name', - Cell: NameCell, - disableFilters: true, - Filter: () => null, - canHide: true, - sortType: 'string', -}; +import { columnHelper } from './helper'; + +export const name = columnHelper.accessor('name', { + header: 'Name', + cell: NameCell, +}); export function NameCell({ - value: name, + getValue, row: { original: container }, -}: CellProps) { +}: CellContext) { + const name = getValue(); + return ( = { - Header: 'Ownership', - id: 'ownership', - accessor: (row) => +import { columnHelper } from './helper'; + +export const ownership = columnHelper.accessor( + (row) => row.Portainer && row.Portainer.ResourceControl ? determineOwnership(row.Portainer.ResourceControl) : ResourceControlOwnership.ADMINISTRATORS, - Cell: OwnershipCell, - disableFilters: true, - canHide: true, - sortType: 'string', - Filter: () => null, -}; + { + header: 'Ownership', + cell: OwnershipCell, + id: 'ownership', + } +); -interface Props { - value: 'public' | 'private' | 'restricted' | 'administrators'; -} +function OwnershipCell({ + getValue, +}: CellContext) { + const value = getValue(); -function OwnershipCell({ value }: Props) { return ( <> = { - Header: 'Published Ports', - accessor: (container) => getPorts(container), +import { columnHelper } from './helper'; + +export const ports = columnHelper.accessor(getPorts, { + header: 'Published Ports', + cell: PortsCell, id: 'ports', - disableFilters: true, - Filter: () => null, - canHide: true, - Cell: PortsCell, -}; +}); function PortsCell({ - value: ports, + getValue, row: { original: container }, -}: CellProps>) { +}: CellContext>) { + const ports = getValue(); + const ip = container.properties.ipAddress ? container.properties.ipAddress.ip : ''; diff --git a/app/react/components/DetailsTable/DetailsRow.tsx b/app/react/components/DetailsTable/DetailsRow.tsx index 6e9968482..32331bae2 100644 --- a/app/react/components/DetailsTable/DetailsRow.tsx +++ b/app/react/components/DetailsTable/DetailsRow.tsx @@ -19,7 +19,7 @@ export function DetailsRow({ {label} - {children && ( + {!!children && ( {children} diff --git a/app/react/components/DetailsTable/DetailsTable.tsx b/app/react/components/DetailsTable/DetailsTable.tsx index 12e34aca3..ee7967da6 100644 --- a/app/react/components/DetailsTable/DetailsTable.tsx +++ b/app/react/components/DetailsTable/DetailsTable.tsx @@ -21,7 +21,7 @@ export function DetailsTable({ )} - {children} + {children && {children}} ); } diff --git a/app/react/components/datatables/ColumnVisibilityMenu.tsx b/app/react/components/datatables/ColumnVisibilityMenu.tsx index 9bdcc99a3..7feba3520 100644 --- a/app/react/components/datatables/ColumnVisibilityMenu.tsx +++ b/app/react/components/datatables/ColumnVisibilityMenu.tsx @@ -1,12 +1,12 @@ import clsx from 'clsx'; import { Menu, MenuButton, MenuList } from '@reach/menu-button'; -import { ColumnInstance } from 'react-table'; import { Columns } from 'lucide-react'; +import { Column } from '@tanstack/react-table'; import { Checkbox } from '@@/form-components/Checkbox'; interface Props { - columns: ColumnInstance[]; + columns: Column[]; onChange: (value: string[]) => void; value: string[]; } @@ -40,8 +40,12 @@ export function ColumnVisibilityMenu({ {columns.map((column) => (
handleChangeColumnVisibility( diff --git a/app/react/components/datatables/Datatable.tsx b/app/react/components/datatables/Datatable.tsx index d40ba06ed..80fa33207 100644 --- a/app/react/components/datatables/Datatable.tsx +++ b/app/react/components/datatables/Datatable.tsx @@ -1,36 +1,40 @@ import { - useTable, - useFilters, - useGlobalFilter, - useSortBy, - usePagination, - Column, - Row, - TableInstance, + Table as TableInstance, TableState, - TableRowProps, - useExpanded, -} from 'react-table'; -import { ReactNode } from 'react'; -import { useRowSelectColumn } from '@lineup-lite/hooks'; + useReactTable, + Row, + getCoreRowModel, + getPaginationRowModel, + getFilteredRowModel, + getSortedRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFacetedMinMaxValues, + getExpandedRowModel, + TableOptions, +} from '@tanstack/react-table'; +import { ReactNode, useMemo } from 'react'; import clsx from 'clsx'; +import _ from 'lodash'; import { IconProps } from '@@/Icon'; -import { Table } from './Table'; -import { multiple } from './filter-types'; -import { useRowSelect } from './useRowSelect'; -import { BasicTableSettings } from './types'; import { DatatableHeader } from './DatatableHeader'; import { DatatableFooter } from './DatatableFooter'; -import { DatatableContent } from './DatatableContent'; import { defaultGetRowId } from './defaultGetRowId'; -import { emptyPlugin } from './emptyReactTablePlugin'; +import { Table } from './Table'; import { useGoToHighlightedRow } from './useGoToHighlightedRow'; +import { BasicTableSettings } from './types'; +import { DatatableContent } from './DatatableContent'; +import { createSelectColumn } from './select-column'; +import { TableRow } from './TableRow'; -export interface Props> { +export interface Props< + D extends Record, + TSettings extends BasicTableSettings = BasicTableSettings +> { dataset: D[]; - columns: readonly Column[]; + columns: TableOptions['columns']; renderTableSettings?(instance: TableInstance): ReactNode; renderTableActions?(selectedRows: D[]): ReactNode; disableSelect?: boolean; @@ -39,29 +43,20 @@ export interface Props> { emptyContentLabel?: string; title?: string; titleIcon?: IconProps['icon']; - initialTableState?: Partial>; + initialTableState?: Partial; isLoading?: boolean; totalCount?: number; description?: ReactNode; pageCount?: number; - initialSortBy?: BasicTableSettings['sortBy']; - initialPageSize?: BasicTableSettings['pageSize']; highlightedItemId?: string; - - searchValue: string; - onSearchChange(search: string): void; - onSortByChange(colId: string, desc: boolean): void; - onPageSizeChange(pageSize: number): void; - - // send state up onPageChange?(page: number): void; - renderRow?( - row: Row, - rowProps: TableRowProps, - highlightedItemId?: string - ): ReactNode; - expandable?: boolean; + settingsManager: TSettings & { + search: string; + setSearch: (value: string) => void; + }; + renderRow?(row: Row, highlightedItemId?: string): ReactNode; + getRowCanExpand?(row: Row): boolean; noWidget?: boolean; } @@ -81,78 +76,83 @@ export function Datatable>({ totalCount = dataset.length, description, pageCount, - - initialSortBy, - initialPageSize = 10, - onPageChange = () => {}, - - onPageSizeChange, - onSortByChange, - searchValue, - onSearchChange, - + onPageChange = () => null, + settingsManager: settings, renderRow = defaultRenderRow, - expandable = false, highlightedItemId, noWidget, + getRowCanExpand, }: Props) { const isServerSidePagination = typeof pageCount !== 'undefined'; - - const tableInstance = useTable( - { - defaultCanFilter: false, - columns, - data: dataset, - filterTypes: { multiple }, - initialState: { - pageSize: initialPageSize, - sortBy: initialSortBy ? [initialSortBy] : [], - globalFilter: searchValue, - ...initialTableState, - }, - isRowSelectable, - autoResetExpanded: false, - autoResetSelectedRows: false, - getRowId, - ...(isServerSidePagination ? { manualPagination: true, pageCount } : {}), - }, - useFilters, - useGlobalFilter, - useSortBy, - expandable ? useExpanded : emptyPlugin, - usePagination, - useRowSelect, - !disableSelect ? useRowSelectColumn : emptyPlugin + const enableRowSelection = getIsSelectionEnabled( + disableSelect, + isRowSelectable ); + const allColumns = useMemo( + () => _.compact([!disableSelect && createSelectColumn(), ...columns]), + [disableSelect, columns] + ); + + const tableInstance = useReactTable({ + columns: allColumns, + data: dataset, + initialState: { + pagination: { + pageSize: settings.pageSize, + }, + sorting: settings.sortBy ? [settings.sortBy] : [], + globalFilter: settings.search, + + ...initialTableState, + }, + defaultColumn: { + enableColumnFilter: false, + enableHiding: true, + }, + enableRowSelection, + autoResetExpanded: false, + globalFilterFn, + getRowId, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + getFacetedMinMaxValues: getFacetedMinMaxValues(), + getExpandedRowModel: getExpandedRowModel(), + getRowCanExpand, + ...(isServerSidePagination ? { manualPagination: true, pageCount } : {}), + }); + + const tableState = tableInstance.getState(); + useGoToHighlightedRow( isServerSidePagination, - tableInstance.state.pageSize, - tableInstance.rows, + tableState.pagination.pageSize, + tableInstance.getCoreRowModel().rows, handlePageChange, highlightedItemId ); - const selectedItems = tableInstance.selectedFlatRows.map( - (row) => row.original - ); + const selectedRowModel = tableInstance.getSelectedRowModel(); + const selectedItems = selectedRowModel.rows.map((row) => row.original); return ( renderTableActions(selectedItems)} renderTableSettings={() => renderTableSettings(tableInstance)} - description={description} /> tableInstance={tableInstance} - renderRow={(row, rowProps) => - renderRow(row, rowProps, highlightedItemId) - } + renderRow={(row) => renderRow(row, highlightedItemId)} emptyContentLabel={emptyContentLabel} isLoading={isLoading} onSortChange={handleSortChange} @@ -161,8 +161,8 @@ export function Datatable>({ @@ -171,38 +171,81 @@ export function Datatable>({ function handleSearchBarChange(value: string) { tableInstance.setGlobalFilter(value); - onSearchChange(value); + settings.setSearch(value); } function handlePageChange(page: number) { - tableInstance.gotoPage(page); + tableInstance.setPageIndex(page); onPageChange(page); } function handleSortChange(colId: string, desc: boolean) { - onSortByChange(colId, desc); + settings.setSortBy(colId, desc); } function handlePageSizeChange(pageSize: number) { tableInstance.setPageSize(pageSize); - onPageSizeChange(pageSize); + settings.setPageSize(pageSize); } } function defaultRenderRow>( row: Row, - rowProps: TableRowProps, highlightedItemId?: string ) { return ( - - key={rowProps.key} - cells={row.cells} - className={clsx(rowProps.className, { + + cells={row.getVisibleCells()} + className={clsx({ active: highlightedItemId === row.id, })} - role={rowProps.role} - style={rowProps.style} /> ); } + +function getIsSelectionEnabled>( + disabledSelect?: boolean, + isRowSelectable?: Props['isRowSelectable'] +) { + if (disabledSelect) { + return false; + } + + if (isRowSelectable) { + return isRowSelectable; + } + + return true; +} + +function globalFilterFn( + row: Row, + columnId: string, + filterValue: null | string +): boolean { + const value = row.getValue(columnId); + + if (filterValue === null || filterValue === '') { + return true; + } + + if (value == null) { + return false; + } + + const filterValueLower = filterValue.toLowerCase(); + + if ( + typeof value === 'string' || + typeof value === 'number' || + typeof value === 'boolean' + ) { + return value.toString().toLowerCase().includes(filterValueLower); + } + + if (Array.isArray(value)) { + return value.some((item) => item.toLowerCase().includes(filterValueLower)); + } + + return false; +} diff --git a/app/react/components/datatables/DatatableContent.tsx b/app/react/components/datatables/DatatableContent.tsx index 2f645454c..c3d034f37 100644 --- a/app/react/components/datatables/DatatableContent.tsx +++ b/app/react/components/datatables/DatatableContent.tsx @@ -1,10 +1,10 @@ -import { Row, TableInstance, TableRowProps } from 'react-table'; +import { Row, Table as TableInstance } from '@tanstack/react-table'; import { Table } from './Table'; interface Props> { tableInstance: TableInstance; - renderRow(row: Row, rowProps: TableRowProps): React.ReactNode; + renderRow(row: Row): React.ReactNode; onSortChange?(colId: string, desc: boolean): void; isLoading?: boolean; emptyContentLabel?: string; @@ -17,42 +17,24 @@ export function DatatableContent>({ isLoading, emptyContentLabel, }: Props) { - const { getTableProps, getTableBodyProps, headerGroups, page, prepareRow } = - tableInstance; + const headerGroups = tableInstance.getHeaderGroups(); + const pageRowModel = tableInstance.getPaginationRowModel(); - const tableProps = getTableProps(); - const tbodyProps = getTableBodyProps(); return ( - +
- {headerGroups.map((headerGroup) => { - const { key, className, role, style } = - headerGroup.getHeaderGroupProps(); - return ( - - key={key} - className={className} - role={role} - style={style} - headers={headerGroup.headers} - onSortChange={onSortChange} - /> - ); - })} + {headerGroups.map((headerGroup) => ( + + key={headerGroup.id} + headers={headerGroup.headers} + onSortChange={onSortChange} + /> + ))} - + - rows={page} + rows={pageRowModel.rows} isLoading={isLoading} - prepareRow={prepareRow} emptyContent={emptyContentLabel} renderRow={renderRow} /> diff --git a/app/react/components/datatables/ExpandableDatatable.tsx b/app/react/components/datatables/ExpandableDatatable.tsx index 3dcf7634c..7473237c2 100644 --- a/app/react/components/datatables/ExpandableDatatable.tsx +++ b/app/react/components/datatables/ExpandableDatatable.tsx @@ -1,4 +1,4 @@ -import { Row } from 'react-table'; +import { Row } from '@tanstack/react-table'; import { ReactNode } from 'react'; import { ExpandableDatatableTableRow } from './ExpandableDatatableRow'; @@ -7,25 +7,25 @@ import { Datatable, Props as DatatableProps } from './Datatable'; interface Props> extends Omit, 'renderRow' | 'expandable'> { renderSubRow(row: Row): ReactNode; + expandOnRowClick?: boolean; } export function ExpandableDatatable>({ renderSubRow, + getRowCanExpand = () => true, + expandOnRowClick, ...props }: Props) { return ( // eslint-disable-next-line react/jsx-props-no-spreading {...props} - expandable - renderRow={(row, { key, className, role, style }) => ( + getRowCanExpand={getRowCanExpand} + renderRow={(row) => ( - key={key} row={row} - className={className} - role={role} - style={style} renderSubRow={renderSubRow} + expandOnClick={expandOnRowClick} /> )} /> diff --git a/app/react/components/datatables/ExpandableDatatableRow.tsx b/app/react/components/datatables/ExpandableDatatableRow.tsx index 7a945075d..a624e0d4b 100644 --- a/app/react/components/datatables/ExpandableDatatableRow.tsx +++ b/app/react/components/datatables/ExpandableDatatableRow.tsx @@ -1,37 +1,33 @@ -import { CSSProperties, ReactNode } from 'react'; -import { Row } from 'react-table'; +import { ReactNode } from 'react'; +import { Row } from '@tanstack/react-table'; import { TableRow } from './TableRow'; interface Props> { row: Row; - className?: string; - role?: string; - style?: CSSProperties; disableSelect?: boolean; renderSubRow(row: Row): ReactNode; + expandOnClick?: boolean; } export function ExpandableDatatableTableRow>({ row, - className, - role, - style, disableSelect, renderSubRow, + expandOnClick, }: Props) { + const cells = row.getVisibleCells(); + return ( <> - cells={row.cells} - className={className} - role={role} - style={style} + cells={cells} + onClick={expandOnClick ? () => row.toggleExpanded() : undefined} /> - {row.isExpanded && ( + {row.getIsExpanded() && ( {!disableSelect && diff --git a/app/react/components/datatables/ExpandingCell.module.css b/app/react/components/datatables/ExpandingCell.module.css deleted file mode 100644 index 5283f7c65..000000000 --- a/app/react/components/datatables/ExpandingCell.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.expand-button { - background: none; - color: inherit; - border: none; - padding: 0; - font: inherit; - cursor: pointer; - outline: inherit; -} diff --git a/app/react/components/datatables/ExpandingCell.tsx b/app/react/components/datatables/ExpandingCell.tsx deleted file mode 100644 index 8275bdd39..000000000 --- a/app/react/components/datatables/ExpandingCell.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { PropsWithChildren } from 'react'; -import { Row } from 'react-table'; -import { ChevronDown, ChevronRight } from 'lucide-react'; - -import { Icon } from '@@/Icon'; - -import styles from './ExpandingCell.module.css'; - -interface Props = Record> { - row: Row; - showExpandArrow: boolean; -} - -export function ExpandingCell< - D extends Record = Record ->({ row, showExpandArrow, children }: PropsWithChildren>) { - return ( - <> - {showExpandArrow && ( - - )} - {children} - - ); -} diff --git a/app/react/components/datatables/Filter.tsx b/app/react/components/datatables/Filter.tsx index 56b992748..f2d4f1280 100644 --- a/app/react/components/datatables/Filter.tsx +++ b/app/react/components/datatables/Filter.tsx @@ -1,13 +1,11 @@ import clsx from 'clsx'; import { useMemo } from 'react'; import { Menu, MenuButton, MenuPopover } from '@reach/menu-button'; -import { ColumnInstance } from 'react-table'; +import { Column } from '@tanstack/react-table'; import { Check, Filter } from 'lucide-react'; import { Icon } from '@@/Icon'; -export const DefaultFilter = filterHOC('Filter by state'); - interface MultipleSelectionFilterProps { options: string[]; value: string[]; @@ -28,12 +26,12 @@ export function MultipleSelectionFilter({
- Filter - +
+ Filter + +
@@ -70,27 +68,54 @@ export function MultipleSelectionFilter({ } } -export function filterHOC(menuTitle: string) { +export function filterHOC>( + menuTitle: string +) { return function Filter({ - column: { filterValue, setFilter, preFilteredRows, id }, + column: { getFilterValue, setFilterValue, getFacetedRowModel, id }, }: { - column: ColumnInstance; + column: Column; }) { + const { flatRows } = getFacetedRowModel(); + const options = useMemo(() => { const options = new Set(); - preFilteredRows.forEach((row) => { - options.add(row.values[id]); + flatRows.forEach(({ getValue }) => { + const value = getValue(id); + + options.add(value); }); return Array.from(options); - }, [id, preFilteredRows]); + }, [flatRows, id]); + + const value = getFilterValue(); + + const valueAsArray = getValueAsArrayOfStrings(value); + return ( ); }; } + +function getValueAsArrayOfStrings(value: unknown): string[] { + if (Array.isArray(value)) { + return value; + } + + if (!value || (typeof value !== 'string' && typeof value !== 'number')) { + return []; + } + + if (typeof value === 'number') { + return [value.toString()]; + } + + return [value]; +} diff --git a/app/react/components/datatables/NameCell.tsx b/app/react/components/datatables/NameCell.tsx index 576a74026..9d5db635e 100644 --- a/app/react/components/datatables/NameCell.tsx +++ b/app/react/components/datatables/NameCell.tsx @@ -1,30 +1,36 @@ -import { CellProps, Column } from 'react-table'; +import { ColumnDef, CellContext } from '@tanstack/react-table'; import { Link } from '@@/Link'; export function buildNameColumn>( - nameKey: string, + nameKey: keyof T, idKey: string, path: string -) { - const name: Column = { - Header: 'Name', - accessor: (row) => row[nameKey], +): ColumnDef { + const cell = createCell(); + + return { + header: 'Name', + accessorKey: nameKey, id: 'name', - Cell: NameCell, - disableFilters: true, - Filter: () => null, - canHide: false, - sortType: 'string', + cell, + enableSorting: true, + sortingFn: 'text', }; - return name; + function createCell>() { + return function NameCell({ renderValue, row }: CellContext) { + const name = renderValue() || ''; - function NameCell({ value: name, row }: CellProps) { - return ( - - {name} - - ); + if (typeof name !== 'string') { + return null; + } + + return ( + + {name} + + ); + }; } } diff --git a/app/react/components/datatables/NestedDatatable.tsx b/app/react/components/datatables/NestedDatatable.tsx index d7fa50039..dff600a68 100644 --- a/app/react/components/datatables/NestedDatatable.tsx +++ b/app/react/components/datatables/NestedDatatable.tsx @@ -1,27 +1,28 @@ import { - useTable, - useFilters, - useSortBy, - Column, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + TableOptions, TableState, - usePagination, -} from 'react-table'; + useReactTable, +} from '@tanstack/react-table'; +import { defaultGetRowId } from './defaultGetRowId'; import { Table } from './Table'; -import { multiple } from './filter-types'; import { NestedTable } from './NestedTable'; import { DatatableContent } from './DatatableContent'; -import { defaultGetRowId } from './defaultGetRowId'; +import { BasicTableSettings } from './types'; interface Props> { dataset: D[]; - columns: readonly Column[]; + columns: TableOptions['columns']; getRowId?(row: D): string; emptyContentLabel?: string; - initialTableState?: Partial>; + initialTableState?: Partial; isLoading?: boolean; - defaultSortBy?: string; + initialSortBy?: BasicTableSettings['sortBy']; } export function NestedDatatable>({ @@ -31,25 +32,26 @@ export function NestedDatatable>({ emptyContentLabel, initialTableState = {}, isLoading, - defaultSortBy, + initialSortBy, }: Props) { - const tableInstance = useTable( - { - defaultCanFilter: false, - columns, - data: dataset, - filterTypes: { multiple }, - initialState: { - sortBy: defaultSortBy ? [{ id: defaultSortBy, desc: true }] : [], - ...initialTableState, - }, - autoResetSelectedRows: false, - getRowId, + const tableInstance = useReactTable({ + columns, + data: dataset, + initialState: { + sorting: initialSortBy ? [initialSortBy] : [], + ...initialTableState, }, - useFilters, - useSortBy, - usePagination - ); + defaultColumn: { + enableColumnFilter: false, + enableHiding: false, + }, + getRowId, + autoResetExpanded: false, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }); return ( @@ -58,15 +60,7 @@ export function NestedDatatable>({ tableInstance={tableInstance} isLoading={isLoading} emptyContentLabel={emptyContentLabel} - renderRow={(row, { key, className, role, style }) => ( - - cells={row.cells} - key={key} - className={className} - role={role} - style={style} - /> - )} + renderRow={(row) => cells={row.getVisibleCells()} />} /> diff --git a/app/react/components/datatables/NestedTable.css b/app/react/components/datatables/NestedTable.css index 91d8dd28a..3c6d03276 100644 --- a/app/react/components/datatables/NestedTable.css +++ b/app/react/components/datatables/NestedTable.css @@ -1,3 +1,7 @@ +.inner-datatable .widget { + border: 0 !important; +} + .inner-datatable { @apply rounded-md border border-solid border-gray-5 th-dark:border-gray-9; overflow: hidden; diff --git a/app/react/components/datatables/Table.tsx b/app/react/components/datatables/Table.tsx index 171f8a8f8..4429f62b3 100644 --- a/app/react/components/datatables/Table.tsx +++ b/app/react/components/datatables/Table.tsx @@ -1,24 +1,22 @@ import clsx from 'clsx'; import { PropsWithChildren } from 'react'; -import { TableProps } from 'react-table'; import { TableContainer } from './TableContainer'; import { TableActions } from './TableActions'; +import { TableFooter } from './TableFooter'; import { TableTitleActions } from './TableTitleActions'; -import { TableContent } from './TableContent'; -import { TableHeaderCell } from './TableHeaderCell'; import { TableSettingsMenu } from './TableSettingsMenu'; import { TableTitle } from './TableTitle'; +import { TableContent } from './TableContent'; +import { TableHeaderCell } from './TableHeaderCell'; import { TableHeaderRow } from './TableHeaderRow'; import { TableRow } from './TableRow'; -import { TableFooter } from './TableFooter'; -function MainComponent({ - children, - className, - role, - style, -}: PropsWithChildren) { +interface Props { + className?: string; +} + +function MainComponent({ children, className }: PropsWithChildren) { return (
} - + {renderSubRow(row)}
{children}
diff --git a/app/react/components/datatables/TableContent.tsx b/app/react/components/datatables/TableContent.tsx index 5ae126bc2..80f692dc5 100644 --- a/app/react/components/datatables/TableContent.tsx +++ b/app/react/components/datatables/TableContent.tsx @@ -1,12 +1,11 @@ -import { PropsWithChildren } from 'react'; -import { Row, TableRowProps } from 'react-table'; +import { Fragment, PropsWithChildren } from 'react'; +import { Row } from '@tanstack/react-table'; interface Props = Record> { isLoading?: boolean; rows: Row[]; emptyContent?: string; - prepareRow(row: Row): void; - renderRow(row: Row, rowProps: TableRowProps): React.ReactNode; + renderRow(row: Row): React.ReactNode; } export function TableContent< @@ -15,7 +14,6 @@ export function TableContent< isLoading = false, rows, emptyContent = 'No items available', - prepareRow, renderRow, }: Props) { if (isLoading) { @@ -28,11 +26,9 @@ export function TableContent< return ( <> - {rows.map((row) => { - prepareRow(row); - const { key, className, role, style } = row.getRowProps(); - return renderRow(row, { key, className, role, style }); - })} + {rows.map((row) => ( + {renderRow(row)} + ))} ); } diff --git a/app/react/components/datatables/TableHeaderCell.tsx b/app/react/components/datatables/TableHeaderCell.tsx index 2039dd748..e563b6eea 100644 --- a/app/react/components/datatables/TableHeaderCell.tsx +++ b/app/react/components/datatables/TableHeaderCell.tsx @@ -1,33 +1,33 @@ import clsx from 'clsx'; -import { PropsWithChildren, ReactNode } from 'react'; -import { TableHeaderProps } from 'react-table'; +import { CSSProperties, PropsWithChildren, ReactNode } from 'react'; -import { TableHeaderSortIcons } from './TableHeaderSortIcons'; import styles from './TableHeaderCell.module.css'; +import { TableHeaderSortIcons } from './TableHeaderSortIcons'; interface Props { - canFilter: boolean; canSort: boolean; - headerProps: TableHeaderProps; isSorted: boolean; isSortedDesc?: boolean; onSortClick: (desc: boolean) => void; render: () => ReactNode; - renderFilter: () => ReactNode; + renderFilter?: () => ReactNode; + className?: string; + style?: CSSProperties; } export function TableHeaderCell({ - headerProps: { className, role, style }, canSort, render, onSortClick, isSorted, isSortedDesc = true, - canFilter, + renderFilter, + className, + style, }: Props) { return ( - +
{render()} - {canFilter ? renderFilter() : null} + {renderFilter ? renderFilter() : null}
); @@ -76,7 +76,6 @@ function SortWrapper({
diff --git a/app/react/components/datatables/TableHeaderRow.tsx b/app/react/components/datatables/TableHeaderRow.tsx index 499735307..b3fdb3b42 100644 --- a/app/react/components/datatables/TableHeaderRow.tsx +++ b/app/react/components/datatables/TableHeaderRow.tsx @@ -1,48 +1,58 @@ -import { HeaderGroup, TableHeaderProps } from 'react-table'; +import { Header, flexRender } from '@tanstack/react-table'; +import { filterHOC } from './Filter'; import { TableHeaderCell } from './TableHeaderCell'; interface Props = Record> { - headers: HeaderGroup[]; + headers: Header[]; onSortChange?(colId: string, desc: boolean): void; } export function TableHeaderRow< D extends Record = Record ->({ - headers, - onSortChange, - className, - role, - style, -}: Props & TableHeaderProps) { +>({ headers, onSortChange }: Props) { return ( - - {headers.map((column) => ( - { - column.toggleSortBy(desc); - if (onSortChange) { - onSortChange(column.id, desc); + + {headers.map((header) => { + const sortDirection = header.column.getIsSorted(); + const { + meta: { className, width } = { className: '', width: undefined }, + } = header.column.columnDef; + + return ( + { + header.column.toggleSorting(desc); + if (onSortChange) { + onSortChange(header.id, desc); + } + }} + isSorted={!!sortDirection} + isSortedDesc={sortDirection ? sortDirection === 'desc' : false} + render={() => + flexRender(header.column.columnDef.header, header.getContext()) } - }} - isSorted={column.isSorted} - isSortedDesc={column.isSortedDesc} - render={() => column.render('Header')} - canFilter={!column.disableFilters} - renderFilter={() => column.render('Filter')} - /> - ))} + renderFilter={ + header.column.getCanFilter() + ? () => + flexRender( + header.column.columnDef.meta?.filter || + filterHOC('Filter'), + { + column: header.column, + } + ) + : undefined + } + /> + ); + })} ); } diff --git a/app/react/components/datatables/TableRow.tsx b/app/react/components/datatables/TableRow.tsx index c687bfcc3..2b3bda61e 100644 --- a/app/react/components/datatables/TableRow.tsx +++ b/app/react/components/datatables/TableRow.tsx @@ -1,31 +1,25 @@ -import { Cell, TableRowProps } from 'react-table'; +import { Cell, flexRender } from '@tanstack/react-table'; +import clsx from 'clsx'; -interface Props = Record> - extends Omit { - cells: Cell[]; +interface Props = Record> { + cells: Cell[]; + className?: string; + onClick?: () => void; } export function TableRow< D extends Record = Record ->({ cells, className, role, style }: Props) { +>({ cells, className, onClick }: Props) { return ( - - {cells.map((cell) => { - const cellProps = cell.getCellProps({ - className: cell.className, - }); - - return ( - - {cell.render('Cell')} - - ); - })} + + {cells.map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} ); } diff --git a/app/react/components/datatables/emptyReactTablePlugin.ts b/app/react/components/datatables/emptyReactTablePlugin.ts deleted file mode 100644 index 377ecc7a9..000000000 --- a/app/react/components/datatables/emptyReactTablePlugin.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function emptyPlugin() {} - -emptyPlugin.pluginName = 'emptyPlugin'; diff --git a/app/react/components/datatables/expand-column.tsx b/app/react/components/datatables/expand-column.tsx index 514c2cc3a..b293b4dae 100644 --- a/app/react/components/datatables/expand-column.tsx +++ b/app/react/components/datatables/expand-column.tsx @@ -1,49 +1,45 @@ import { ChevronDown, ChevronUp } from 'lucide-react'; -import { CellProps, Column, HeaderProps } from 'react-table'; +import { ColumnDef } from '@tanstack/react-table'; import { Button } from '@@/buttons'; -export function buildExpandColumn>( - isExpandable: (item: T) => boolean -): Column { +export function buildExpandColumn< + T extends Record +>(): ColumnDef { return { id: 'expand', - Header: ({ - filteredFlatRows, - getToggleAllRowsExpandedProps, - isAllRowsExpanded, - }: HeaderProps) => { - const hasExpandableItems = filteredFlatRows.some((item) => - isExpandable(item.original) - ); + header: ({ table }) => { + const hasExpandableItems = table.getExpandedRowModel().rows.length > 0; return ( hasExpandableItems && (