fleet/frontend/components/TableContainer/DataTable/DataTable.jsx

161 lines
4.7 KiB
React
Raw Normal View History

import React, { useMemo, useEffect, useCallback } from "react";
2021-04-14 16:52:15 +00:00
import PropTypes from "prop-types";
import { useTable, useSortBy, useRowSelect } from "react-table";
2021-04-14 16:52:15 +00:00
import Spinner from "components/loaders/Spinner";
import Button from "../../buttons/Button";
2021-04-14 16:52:15 +00:00
const baseClass = "data-table-container";
// This data table uses react-table for implementation. The relevant documentation of the library
// can be found here https://react-table.tanstack.com/docs/api/useTable
const DataTable = (props) => {
const {
columns: tableColumns,
data: tableData,
isLoading,
sortHeader,
sortDirection,
onSort,
onSelectActionClick,
} = props;
const columns = useMemo(() => {
return tableColumns;
}, [tableColumns]);
// The table data needs to be ordered by the order we received from the API.
const data = useMemo(() => {
return tableData;
}, [tableData]);
const {
headerGroups,
rows,
prepareRow,
selectedFlatRows,
toggleAllRowsSelected,
state: tableState,
} = useTable(
{
columns,
data,
initialState: {
sortBy: useMemo(() => {
2021-04-14 16:52:15 +00:00
return [{ id: sortHeader, desc: sortDirection === "desc" }];
}, [sortHeader, sortDirection]),
},
disableMultiSort: true,
},
useSortBy,
useRowSelect
);
const { sortBy, selectedRowIds } = tableState;
// This is used to listen for changes to sort. If there is a change
// Then the sortHandler change is fired.
useEffect(() => {
const column = sortBy[0];
if (column !== undefined) {
2021-04-14 16:52:15 +00:00
if (
column.id !== sortHeader ||
column.desc !== (sortDirection === "desc")
) {
onSort(column.id, column.desc);
}
} else {
onSort(undefined);
}
}, [sortBy, sortHeader, onSort, sortDirection]);
const onSelectActionButtonClick = useCallback(() => {
const entityIds = selectedFlatRows.map((row) => row.original.id);
onSelectActionClick(entityIds);
}, [onSelectActionClick, selectedFlatRows]);
const onClearSelectionClick = useCallback(() => {
toggleAllRowsSelected(false);
}, [toggleAllRowsSelected]);
return (
<div className={baseClass}>
2021-04-14 16:52:15 +00:00
<div className={"data-table data-table__wrapper"}>
{isLoading && (
<div className={"loading-overlay"}>
<Spinner />
</div>
2021-04-14 16:52:15 +00:00
)}
<table className={"data-table__table"}>
{Object.keys(selectedRowIds).length !== 0 && (
<thead className={"active-selection"}>
<tr {...headerGroups[0].getHeaderGroupProps()}>
<th
{...headerGroups[0].headers[0].getHeaderProps(
headerGroups[0].headers[0].getSortByToggleProps()
)}
>
{headerGroups[0].headers[0].render("Header")}
</th>
<th className={"active-selection__container"}>
<div className={"active-selection__inner"}>
<p>
<span>{selectedFlatRows.length}</span> selected
</p>
<Button
onClick={onClearSelectionClick}
variant={"text-link"}
>
Clear selection
</Button>
<Button onClick={onSelectActionButtonClick}>
Transfer to team
</Button>
</div>
</th>
</tr>
</thead>
)}
<thead>
2021-04-14 16:52:15 +00:00
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
2021-04-14 16:52:15 +00:00
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
2021-04-14 16:52:15 +00:00
{column.render("Header")}
</th>
))}
</tr>
))}
</thead>
<tbody>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
2021-04-14 16:52:15 +00:00
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
2021-04-14 16:52:15 +00:00
})}
</tbody>
</table>
</div>
</div>
);
};
DataTable.propTypes = {
columns: PropTypes.arrayOf(PropTypes.object), // TODO: create proper interface for this
data: PropTypes.arrayOf(PropTypes.object), // TODO: create proper interface for this
isLoading: PropTypes.bool,
sortHeader: PropTypes.string,
sortDirection: PropTypes.string,
onSort: PropTypes.func,
onSelectActionClick: PropTypes.func,
};
export default DataTable;