mirror of
https://github.com/strapi/strapi.git
synced 2025-07-24 17:40:18 +00:00
Refacto table to make it dynamic for the CM migration
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
8b278955bc
commit
c3d639e912
@ -10,33 +10,29 @@ import {
|
||||
VisuallyHidden,
|
||||
} from '@strapi/parts';
|
||||
import { SortIcon, useQueryParams } from '@strapi/helper-plugin';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const TableHead = () => {
|
||||
const TableHead = ({ headers, withMainAction, withBulkActions }) => {
|
||||
const [{ query }, setQuery] = useQueryParams();
|
||||
const sort = query.sort;
|
||||
const [sortBy, sortOrder] = sort.split(':');
|
||||
const headers = [
|
||||
{ label: 'Name', value: 'firstname', isSortable: true },
|
||||
{ label: 'Email', value: 'email', isSortable: true },
|
||||
{ label: 'Roles', value: 'roles', isSortable: false },
|
||||
{ label: 'Username', value: 'username', isSortable: true },
|
||||
{ label: 'Active User', value: 'isActive', isSortable: false },
|
||||
];
|
||||
|
||||
return (
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>
|
||||
<BaseCheckbox aria-label="Select all entries" />
|
||||
</Th>
|
||||
{headers.map(({ label, value, isSortable }) => {
|
||||
const isSorted = sortBy === value;
|
||||
{withMainAction && (
|
||||
<Th>
|
||||
<BaseCheckbox aria-label="Select all entries" />
|
||||
</Th>
|
||||
)}
|
||||
{headers.map(({ name, metadatas: { sortable: isSortable, label } }) => {
|
||||
const isSorted = sortBy === name;
|
||||
const isUp = sortOrder === 'ASC';
|
||||
|
||||
const handleClickSort = (shouldAllowClick = true) => {
|
||||
if (isSortable && shouldAllowClick) {
|
||||
const nextSortOrder = isSorted && sortOrder === 'ASC' ? 'DESC' : 'ASC';
|
||||
const nextSort = `${value}:${nextSortOrder}`;
|
||||
const nextSort = `${name}:${nextSortOrder}`;
|
||||
|
||||
setQuery({
|
||||
sort: nextSort,
|
||||
@ -46,7 +42,7 @@ const TableHead = () => {
|
||||
|
||||
return (
|
||||
<Th
|
||||
key={value}
|
||||
key={name}
|
||||
action={
|
||||
isSorted ? (
|
||||
<IconButton
|
||||
@ -73,12 +69,26 @@ const TableHead = () => {
|
||||
);
|
||||
})}
|
||||
|
||||
<Th>
|
||||
<VisuallyHidden>Actions</VisuallyHidden>
|
||||
</Th>
|
||||
{withBulkActions && (
|
||||
<Th>
|
||||
<VisuallyHidden>Actions</VisuallyHidden>
|
||||
</Th>
|
||||
)}
|
||||
</Tr>
|
||||
</Thead>
|
||||
);
|
||||
};
|
||||
|
||||
TableHead.defaultProps = {
|
||||
headers: [],
|
||||
withBulkActions: false,
|
||||
withMainAction: false,
|
||||
};
|
||||
|
||||
TableHead.propTypes = {
|
||||
headers: PropTypes.array,
|
||||
withBulkActions: PropTypes.bool,
|
||||
withMainAction: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default TableHead;
|
||||
|
@ -0,0 +1,83 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BaseCheckbox, Box, IconButton, Tbody, Td, Text, Tr, Row } from '@strapi/parts';
|
||||
import { EditIcon, DeleteIcon } from '@strapi/icons';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
const TableRows = ({ canUpdate, canDelete, headers, withMainAction, withBulkActions, rows }) => {
|
||||
const {
|
||||
push,
|
||||
location: { pathname },
|
||||
} = useHistory();
|
||||
|
||||
return (
|
||||
<Tbody>
|
||||
{rows.map(data => {
|
||||
return (
|
||||
<Tr key={data.id}>
|
||||
{withMainAction && (
|
||||
<Td>
|
||||
<BaseCheckbox aria-label="Select all entries" />
|
||||
</Td>
|
||||
)}
|
||||
{headers.map(({ key, cellFormatter, name, ...rest }) => {
|
||||
return (
|
||||
<Td key={key}>
|
||||
{typeof cellFormatter === 'function' ? (
|
||||
cellFormatter(data, { key, name, ...rest })
|
||||
) : (
|
||||
<Text textColor="neutral800">{data[name] || '-'}</Text>
|
||||
)}
|
||||
</Td>
|
||||
);
|
||||
})}
|
||||
|
||||
{withBulkActions && (
|
||||
<Td>
|
||||
<Row>
|
||||
{canUpdate && (
|
||||
<IconButton
|
||||
onClick={() => push(`${pathname}/${data.id}`)}
|
||||
label="Edit"
|
||||
noBorder
|
||||
icon={<EditIcon />}
|
||||
/>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Box paddingLeft={1}>
|
||||
<IconButton
|
||||
onClick={() => console.log('delete')}
|
||||
label="Delete"
|
||||
noBorder
|
||||
icon={<DeleteIcon />}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Row>
|
||||
</Td>
|
||||
)}
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
</Tbody>
|
||||
);
|
||||
};
|
||||
|
||||
TableRows.defaultProps = {
|
||||
canDelete: false,
|
||||
canUpdate: false,
|
||||
rows: [],
|
||||
withBulkActions: false,
|
||||
withMainAction: false,
|
||||
};
|
||||
|
||||
TableRows.propTypes = {
|
||||
canDelete: PropTypes.bool,
|
||||
canUpdate: PropTypes.bool,
|
||||
headers: PropTypes.array.isRequired,
|
||||
rows: PropTypes.array,
|
||||
withBulkActions: PropTypes.bool,
|
||||
withMainAction: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default TableRows;
|
@ -1,25 +1,17 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
BaseCheckbox,
|
||||
Box,
|
||||
IconButton,
|
||||
Table as TableCompo,
|
||||
Tbody,
|
||||
Td,
|
||||
Text,
|
||||
Tr,
|
||||
Row,
|
||||
} from '@strapi/parts';
|
||||
import { EditIcon, DeleteIcon } from '@strapi/icons';
|
||||
import { EmptyBodyTable, Status, useQueryParams } from '@strapi/helper-plugin';
|
||||
import { Table as TableCompo } from '@strapi/parts';
|
||||
import { EmptyBodyTable, useQueryParams } from '@strapi/helper-plugin';
|
||||
import TableHead from './TableHead';
|
||||
import TableRows from './TableRows';
|
||||
|
||||
const Table = ({ canDelete, canUpdate, rows }) => {
|
||||
const Table = ({ canDelete, canUpdate, headers, rows, withBulkActions, withMainAction }) => {
|
||||
const [entriesToDelete, setEntriesToDelete] = useState([]);
|
||||
const [{ query }] = useQueryParams();
|
||||
const ROW_COUNT = rows.length + 1;
|
||||
const COL_COUNT = 7;
|
||||
const hasFilters = query.filters !== undefined;
|
||||
|
||||
const content = hasFilters
|
||||
? {
|
||||
id: 'content-manager.components.TableEmpty.withFilters',
|
||||
@ -30,75 +22,42 @@ const Table = ({ canDelete, canUpdate, rows }) => {
|
||||
|
||||
return (
|
||||
<TableCompo colCount={COL_COUNT} rowCount={ROW_COUNT}>
|
||||
<TableHead />
|
||||
<TableHead
|
||||
headers={headers}
|
||||
withMainAction={withMainAction}
|
||||
withBulkActions={withBulkActions}
|
||||
/>
|
||||
{!rows.length ? (
|
||||
<EmptyBodyTable colSpan={COL_COUNT} content={content} />
|
||||
) : (
|
||||
<Tbody>
|
||||
{rows.map(entry => (
|
||||
<Tr key={entry.id}>
|
||||
<Td>
|
||||
<BaseCheckbox aria-label={`Select ${entry.email}`} />
|
||||
</Td>
|
||||
<Td>
|
||||
<Text textColor="neutral800">
|
||||
{entry.firstname} {entry.lastname}
|
||||
</Text>
|
||||
</Td>
|
||||
<Td>{entry.email}</Td>
|
||||
<Td>
|
||||
<Text textColor="neutral800">{entry.roles.map(role => role.name).join(',\n')}</Text>
|
||||
</Td>
|
||||
<Td>
|
||||
<Text textColor="neutral800">{entry.username || '-'}</Text>
|
||||
</Td>
|
||||
<Td>
|
||||
<Row>
|
||||
<Status
|
||||
isActive={entry.isActive}
|
||||
variant={entry.isActive ? 'success' : 'danger'}
|
||||
/>
|
||||
<Text textColor="neutral800">{entry.isActive ? 'Active' : 'Inactive'}</Text>
|
||||
</Row>
|
||||
</Td>
|
||||
<Td>
|
||||
<Row>
|
||||
{canUpdate && (
|
||||
<IconButton
|
||||
onClick={() => console.log('edit')}
|
||||
label="Edit"
|
||||
noBorder
|
||||
icon={<EditIcon />}
|
||||
/>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Box paddingLeft={1}>
|
||||
<IconButton
|
||||
onClick={() => console.log('delete')}
|
||||
label="Delete"
|
||||
noBorder
|
||||
icon={<DeleteIcon />}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Row>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
<TableRows
|
||||
canDelete={canDelete}
|
||||
canUpdate={canUpdate}
|
||||
data={rows}
|
||||
headers={headers}
|
||||
rows={rows}
|
||||
withBulkActions={withBulkActions}
|
||||
withMainAction={withMainAction}
|
||||
/>
|
||||
)}
|
||||
</TableCompo>
|
||||
);
|
||||
};
|
||||
|
||||
Table.defaultProps = {
|
||||
headers: [],
|
||||
rows: [],
|
||||
withBulkActions: false,
|
||||
withMainAction: false,
|
||||
};
|
||||
|
||||
Table.propTypes = {
|
||||
canDelete: PropTypes.bool.isRequired,
|
||||
canUpdate: PropTypes.bool.isRequired,
|
||||
headers: PropTypes.array,
|
||||
rows: PropTypes.array,
|
||||
withBulkActions: PropTypes.bool,
|
||||
withMainAction: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Table;
|
||||
|
@ -17,9 +17,9 @@ import { useIntl } from 'react-intl';
|
||||
import { useQuery } from 'react-query';
|
||||
import get from 'lodash/get';
|
||||
import adminPermissions from '../../../permissions';
|
||||
|
||||
import Table from './Table';
|
||||
import fetchData from './utils/api';
|
||||
import tableHeaders from './utils/tableHeaders';
|
||||
|
||||
const ListPage = () => {
|
||||
const {
|
||||
@ -269,7 +269,10 @@ const ListPage = () => {
|
||||
canCreate={canCreate}
|
||||
canDelete={canDelete}
|
||||
canUpdate={canUpdate}
|
||||
headers={tableHeaders}
|
||||
rows={data?.results}
|
||||
withBulkActions
|
||||
withMainAction={canDelete}
|
||||
/>
|
||||
)}
|
||||
</CustomContentLayout>
|
||||
|
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { Text, Row } from '@strapi/parts';
|
||||
import { Status } from '@strapi/helper-plugin';
|
||||
|
||||
const tableHeaders = [
|
||||
{
|
||||
name: 'firstname',
|
||||
key: 'firstname',
|
||||
metadatas: { label: 'Name', sortable: true },
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
name: 'email',
|
||||
metadatas: { label: 'Email', sortable: true },
|
||||
},
|
||||
{
|
||||
key: 'roles',
|
||||
name: 'roles',
|
||||
metadatas: { label: 'Roles', sortable: false },
|
||||
/* eslint-disable react/prop-types */
|
||||
cellFormatter: ({ roles }) => {
|
||||
return <Text textColor="neutral800">{roles.map(role => role.name).join(',\n')}</Text>;
|
||||
},
|
||||
/* eslint-enable react/prop-types */
|
||||
},
|
||||
{
|
||||
key: 'username',
|
||||
name: 'username',
|
||||
metadatas: { label: 'Username', sortable: true },
|
||||
},
|
||||
{
|
||||
key: 'isActive',
|
||||
name: 'isActive',
|
||||
metadatas: { label: 'Active User', sortable: false },
|
||||
// eslint-disable-next-line react/prop-types
|
||||
cellFormatter: ({ isActive }) => {
|
||||
return (
|
||||
<Row>
|
||||
<Status isActive={isActive} variant={isActive ? 'success' : 'danger'} />
|
||||
<Text textColor="neutral800">{isActive ? 'Active' : 'Inactive'}</Text>
|
||||
</Row>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default tableHeaders;
|
Loading…
x
Reference in New Issue
Block a user