in superset-frontend/src/components/Table/index.tsx [240:426]
export function Table<RecordType extends object>(
props: TableProps<RecordType>,
) {
const {
data,
bordered,
columns,
selectedRows = defaultRowSelection,
handleRowSelection,
size = TableSize.Small,
selectionType = SelectionType.Disabled,
sticky = true,
loading = false,
resizable = false,
reorderable = false,
usePagination = true,
defaultPageSize = 15,
pageSizeOptions = ['5', '15', '25', '50', '100'],
hideData = false,
locale,
height,
virtualize = false,
onChange = noop,
recordCount,
onRow,
allowHTML = false,
childrenColumnName,
} = props;
const wrapperRef = useRef<HTMLDivElement | null>(null);
const [derivedColumns, setDerivedColumns] = useState(columns);
const [pageSize, setPageSize] = useState(defaultPageSize);
const [mergedLocale, setMergedLocale] = useState<
Required<AntTableProps<RecordType>>['locale']
>({ ...defaultLocale });
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>(selectedRows);
const interactiveTableUtils = useRef<InteractiveTableUtils | null>(null);
const onSelectChange = (newSelectedRowKeys: Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
handleRowSelection?.(newSelectedRowKeys);
};
const selectionTypeValue = selectionMap[selectionType];
const rowSelection = {
type: selectionMap[selectionType] as RowSelectionType,
selectedRowKeys,
onChange: onSelectChange,
};
// Log use of experimental features
useEffect(() => {
if (reorderable === true) {
logging.warn(
'EXPERIMENTAL FEATURE ENABLED: The "reorderable" prop of Table is experimental and NOT recommended for use in production deployments.',
);
}
if (resizable === true) {
logging.warn(
'EXPERIMENTAL FEATURE ENABLED: The "resizable" prop of Table is experimental and NOT recommended for use in production deployments.',
);
}
}, [reorderable, resizable]);
useEffect(() => {
let updatedLocale;
if (locale) {
// This spread allows for locale to only contain a subset of locale overrides on props
updatedLocale = { ...defaultLocale, ...locale };
} else {
updatedLocale = { ...defaultLocale };
}
setMergedLocale(updatedLocale);
}, [locale]);
useEffect(() => setDerivedColumns(columns), [columns]);
useEffect(() => {
if (interactiveTableUtils.current) {
interactiveTableUtils.current?.clearListeners();
}
const table = wrapperRef.current?.getElementsByTagName('table')[0];
if (table) {
interactiveTableUtils.current = new InteractiveTableUtils(
table,
derivedColumns,
setDerivedColumns,
);
if (reorderable) {
interactiveTableUtils?.current?.initializeDragDropColumns(
reorderable,
table,
);
}
if (resizable) {
interactiveTableUtils?.current?.initializeResizableColumns(
resizable,
table,
);
}
}
return () => {
interactiveTableUtils?.current?.clearListeners?.();
};
/**
* We DO NOT want this effect to trigger when derivedColumns changes as it will break functionality
* The exclusion from the effect dependencies is intentional and should not be modified
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wrapperRef, reorderable, resizable, virtualize, interactiveTableUtils]);
const theme = useTheme();
const paginationSettings: PaginationProps | false = usePagination
? {
hideOnSinglePage: true,
pageSize,
pageSizeOptions,
onShowSizeChange: (page: number, size: number) => setPageSize(size),
}
: false;
/**
* When recordCount is provided it lets the user of Table control total number of pages
* independent from data.length. This allows the parent component do things like server side paging
* where the user can be shown the total mount of data they can page through, but the component can provide
* data one page at a time, and respond to the onPageChange event to fetch and set new data
*/
if (paginationSettings && recordCount) {
paginationSettings.total = recordCount;
}
let bodyHeight = height;
if (bodyHeight) {
bodyHeight -= HEADER_HEIGHT;
const hasPagination =
usePagination && recordCount && recordCount > pageSize;
if (hasPagination) {
bodyHeight -= PAGINATION_HEIGHT;
}
}
const sharedProps = {
loading: { spinning: loading ?? false, indicator: <Loading /> },
hasData: hideData ? false : data,
columns: derivedColumns,
dataSource: hideData ? undefined : data,
size,
pagination: paginationSettings,
locale: mergedLocale,
showSorterTooltip: false,
onChange,
onRow,
theme,
height: bodyHeight,
bordered,
expandable: {
childrenColumnName,
},
};
return (
<div ref={wrapperRef}>
{!virtualize && (
<StyledTable
{...sharedProps}
rowSelection={selectionTypeValue !== null ? rowSelection : undefined}
sticky={sticky}
/>
)}
{virtualize && (
<StyledVirtualTable
{...sharedProps}
scroll={{
y: 300,
x: '100vw',
// To avoid jest failure by scrollTo
...(process.env.WEBPACK_MODE === 'test' && {
scrollToFirstRowOnChange: false,
}),
}}
allowHTML={allowHTML}
/>
)}
</div>
);
}