|
import React, { useState } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import {
|
|
TableComposable,
|
|
Thead,
|
|
Tr,
|
|
Th,
|
|
Tbody,
|
|
Td,
|
|
ActionsColumn,
|
|
} from '@patternfly/react-table';
|
|
import { noop } from '../../../../common/helpers';
|
|
import { translate as __ } from '../../../../common/I18n';
|
|
import { useTableSort } from '../../Helpers/useTableSort';
|
|
import Pagination from '../../../Pagination';
|
|
import { DeleteModal } from './DeleteModal';
|
|
import EmptyPage from '../../../../routes/common/EmptyPage';
|
|
import { getColumnHelpers } from './helpers';
|
|
|
|
export const Table = ({
|
|
columns,
|
|
errorMessage,
|
|
getActions,
|
|
isDeleteable,
|
|
itemCount,
|
|
params,
|
|
refreshData,
|
|
results,
|
|
setParams,
|
|
url,
|
|
isPending,
|
|
isEmbedded,
|
|
showCheckboxes,
|
|
rowSelectTd,
|
|
children,
|
|
}) => {
|
|
const columnsToSortParams = {};
|
|
Object.keys(columns).forEach(key => {
|
|
if (columns[key].isSorted) {
|
|
columnsToSortParams[columns[key].title] = key;
|
|
}
|
|
});
|
|
const [columnNamesKeys, keysToColumnNames] = getColumnHelpers(columns);
|
|
const onSort = (_event, index, direction) => {
|
|
setParams({
|
|
...params,
|
|
order: `${Object.keys(columns)[index]} ${direction}`,
|
|
});
|
|
};
|
|
const onPagination = newPagination => {
|
|
setParams({ ...params, ...newPagination });
|
|
};
|
|
const { pfSortParams } = useTableSort({
|
|
allColumns: Object.keys(columns).map(k => columns[k].title),
|
|
columnsToSortParams,
|
|
onSort,
|
|
});
|
|
const [selectedItem, setSelectedItem] = useState({});
|
|
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
|
const onDeleteClick = ({ id, name }) => {
|
|
setSelectedItem({ id, name });
|
|
setDeleteModalOpen(true);
|
|
};
|
|
const actions = ({ can_delete: canDelete, id, name, ...item }) =>
|
|
[
|
|
isDeleteable && {
|
|
title: __('Delete'),
|
|
onClick: () => onDeleteClick({ id, name }),
|
|
isDisabled: !canDelete,
|
|
},
|
|
...((getActions && getActions({ id, name, canDelete, ...item })) ?? []),
|
|
].filter(Boolean);
|
|
const RowSelectTd = rowSelectTd;
|
|
return (
|
|
<>
|
|
<DeleteModal
|
|
isModalOpen={deleteModalOpen}
|
|
setIsModalOpen={setDeleteModalOpen}
|
|
selectedItem={selectedItem}
|
|
url={url}
|
|
refreshData={refreshData}
|
|
/>
|
|
<TableComposable variant="compact" ouiaId="table" isStriped>
|
|
<Thead>
|
|
<Tr ouiaId="table-header">
|
|
{showCheckboxes && <Th key="checkbox-th" />}
|
|
{columnNamesKeys.map(k => (
|
|
<Th
|
|
key={k}
|
|
sort={
|
|
Object.values(columnsToSortParams).includes(k) &&
|
|
pfSortParams(keysToColumnNames[k])
|
|
}
|
|
>
|
|
{keysToColumnNames[k]}
|
|
</Th>
|
|
))}
|
|
</Tr>
|
|
</Thead>
|
|
<Tbody>
|
|
{isPending && results.length === 0 && (
|
|
<Tr ouiaId="table-loading">
|
|
<Td colSpan={100}>
|
|
<EmptyPage
|
|
message={{
|
|
type: 'loading',
|
|
text: __('Loading...'),
|
|
}}
|
|
/>
|
|
</Td>
|
|
</Tr>
|
|
)}
|
|
{!isPending && !errorMessage && results.length === 0 && (
|
|
<Tr ouiaId="table-empty">
|
|
<Td colSpan={100}>
|
|
<EmptyPage />
|
|
</Td>
|
|
</Tr>
|
|
)}
|
|
{errorMessage && (
|
|
<Tr ouiaId="table-error">
|
|
<Td colSpan={100}>
|
|
<EmptyPage message={{ type: 'error', text: errorMessage }} />
|
|
</Td>
|
|
</Tr>
|
|
)}
|
|
{children ||
|
|
results.map((result, rowIndex) => {
|
|
const rowActions = actions(result);
|
|
return (
|
|
<Tr key={rowIndex} ouiaId={`table-row-${rowIndex}`} isHoverable>
|
|
{showCheckboxes && <RowSelectTd rowData={result} />}
|
|
{columnNamesKeys.map(k => (
|
|
<Td key={k} dataLabel={keysToColumnNames[k]}>
|
|
{columns[k].wrapper
|
|
? columns[k].wrapper(result)
|
|
: result[k]}
|
|
</Td>
|
|
))}
|
|
<Td isActionCell>
|
|
{rowActions.length ? (
|
|
<ActionsColumn items={rowActions} />
|
|
) : null}
|
|
</Td>
|
|
</Tr>
|
|
);
|
|
})}
|
|
</Tbody>
|
|
</TableComposable>
|
|
{results.length > 0 && !errorMessage && (
|
|
<Pagination
|
|
page={params.page}
|
|
perPage={params.perPage}
|
|
itemCount={itemCount}
|
|
onChange={onPagination}
|
|
updateParamsByUrl={!isEmbedded}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
Table.propTypes = {
|
|
children: PropTypes.node,
|
|
columns: PropTypes.object.isRequired,
|
|
params: PropTypes.shape({
|
|
page: PropTypes.number,
|
|
perPage: PropTypes.number,
|
|
order: PropTypes.string,
|
|
}).isRequired,
|
|
errorMessage: PropTypes.string,
|
|
getActions: PropTypes.func,
|
|
isDeleteable: PropTypes.bool,
|
|
itemCount: PropTypes.number,
|
|
refreshData: PropTypes.func.isRequired,
|
|
results: PropTypes.array,
|
|
setParams: PropTypes.func.isRequired,
|
|
url: PropTypes.string.isRequired,
|
|
isPending: PropTypes.bool.isRequired,
|
|
isEmbedded: PropTypes.bool,
|
|
rowSelectTd: PropTypes.func,
|
|
showCheckboxes: PropTypes.bool,
|
|
};
|
|
|
|
Table.defaultProps = {
|
|
children: null,
|
|
errorMessage: null,
|
|
isDeleteable: false,
|
|
itemCount: 0,
|
|
getActions: null,
|
|
results: [],
|
|
isEmbedded: false,
|
|
rowSelectTd: noop,
|
|
showCheckboxes: false,
|
|
};
|