Table.tsx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import { FC } from 'react';
  2. import Table from '@mui/material/Table';
  3. import TableBody from '@mui/material/TableBody';
  4. import TableCell from '@mui/material/TableCell';
  5. import TableContainer from '@mui/material/TableContainer';
  6. import TableRow from '@mui/material/TableRow';
  7. import Checkbox from '@mui/material/Checkbox';
  8. import { makeStyles } from '@mui/styles';
  9. import { TableType } from './Types';
  10. import { Box, Button, Typography, Theme } from '@mui/material';
  11. import EnhancedTableHead from './TableHead';
  12. import EditableTableHead from './TableEditableHead';
  13. import ActionBar from './ActionBar';
  14. import LoadingTable from './LoadingTable';
  15. import CopyButton from '../advancedSearch/CopyButton';
  16. import { useTranslation } from 'react-i18next';
  17. const useStyles = makeStyles((theme: Theme) => ({
  18. root: {
  19. width: '100%',
  20. flexGrow: 1,
  21. // /* set flex basis to make child item height 100% work on Safari */
  22. // flexBasis: 0,
  23. background: '#fff',
  24. },
  25. box: {
  26. backgroundColor: '#fff',
  27. },
  28. table: {
  29. minWidth: '100%',
  30. },
  31. tableCell: {
  32. background: theme.palette.common.white,
  33. padding: theme.spacing(1, 1.5),
  34. },
  35. cellContainer: {
  36. display: 'flex',
  37. whiteSpace: 'nowrap',
  38. },
  39. hoverActionCell: {
  40. transition: '0.2s all',
  41. padding: 0,
  42. width: '50px',
  43. backgroundColor: '#fff',
  44. '& span': {
  45. opacity: 0,
  46. },
  47. },
  48. checkbox: {
  49. background: theme.palette.common.white,
  50. },
  51. rowHover: {
  52. '&:hover': {
  53. backgroundColor: '#f3fcfe !important',
  54. '& td': {
  55. background: 'inherit',
  56. },
  57. '& $hoverActionCell': {
  58. backgroundColor: theme.palette.primary.main,
  59. '& span': {
  60. opacity: 1,
  61. },
  62. },
  63. },
  64. },
  65. selected: {
  66. backgroundColor: '#f3fcfe !important',
  67. '& td': {
  68. background: 'inherit',
  69. },
  70. },
  71. cell: {
  72. borderBottom: '1px solid #e9e9ed',
  73. '& p': {
  74. display: 'inline-block',
  75. verticalAlign: 'middle',
  76. overflow: 'hidden',
  77. textOverflow: 'ellipsis',
  78. whiteSpace: 'nowrap',
  79. maxWidth: (props: { tableCellMaxWidth: string }) =>
  80. props.tableCellMaxWidth,
  81. fontSize: '14px',
  82. lineHeight: '20px',
  83. },
  84. },
  85. noData: {
  86. paddingTop: theme.spacing(6),
  87. textAlign: 'center',
  88. letterSpacing: '0.5px',
  89. color: 'rgba(0, 0, 0, 0.6)',
  90. },
  91. copyBtn: {
  92. '& svg': {
  93. fontSize: '14px',
  94. },
  95. marginLeft: theme.spacing(0.5),
  96. },
  97. }));
  98. const EnhancedTable: FC<TableType> = props => {
  99. let {
  100. selected,
  101. onSelected,
  102. isSelected,
  103. onSelectedAll,
  104. rows = [],
  105. colDefinitions,
  106. primaryKey,
  107. // whether show checkbox in the first column
  108. // set true as default
  109. openCheckBox = true,
  110. disableSelect,
  111. noData,
  112. // whether change table row background color when mouse hover
  113. // set true as default
  114. showHoverStyle = true,
  115. isLoading,
  116. headEditable = false,
  117. // editable heads required param, contains heads components and its value
  118. editHeads = [],
  119. // if table cell max width not be passed, table row will use 300px as default
  120. tableCellMaxWidth = '300px',
  121. handleSort,
  122. order,
  123. orderBy,
  124. loadingRowCount,
  125. } = props;
  126. const classes = useStyles({ tableCellMaxWidth });
  127. const { t: commonTrans } = useTranslation();
  128. const copyTrans = commonTrans('copy');
  129. return (
  130. <TableContainer className={classes.root}>
  131. <Box height="100%" className={classes.box}>
  132. {!isLoading && (
  133. <Table
  134. stickyHeader
  135. className={classes.table}
  136. aria-labelledby="tableTitle"
  137. size="medium"
  138. aria-label="enhanced table"
  139. >
  140. {!headEditable ? (
  141. <EnhancedTableHead
  142. colDefinitions={colDefinitions}
  143. numSelected={selected.length}
  144. order={order}
  145. orderBy={orderBy}
  146. onSelectAllClick={onSelectedAll}
  147. handleSort={handleSort}
  148. rowCount={rows.length}
  149. openCheckBox={openCheckBox}
  150. disableSelect={disableSelect}
  151. />
  152. ) : (
  153. <EditableTableHead editHeads={editHeads} />
  154. )}
  155. <TableBody>
  156. {rows && rows.length ? (
  157. rows.map((row, index) => {
  158. const isItemSelected = isSelected(row);
  159. const labelId = `enhanced-table-checkbox-${index}`;
  160. return (
  161. <TableRow
  162. hover={showHoverStyle}
  163. key={'row' + row[primaryKey] + index}
  164. onClick={event => onSelected(event, row)}
  165. aria-checked={isItemSelected}
  166. tabIndex={-1}
  167. selected={isItemSelected && !disableSelect}
  168. classes={{
  169. hover: classes.rowHover,
  170. selected:
  171. isItemSelected && !disableSelect
  172. ? classes.selected
  173. : undefined,
  174. }}
  175. >
  176. {openCheckBox && (
  177. <TableCell
  178. padding="checkbox"
  179. className={classes.checkbox}
  180. >
  181. <Checkbox
  182. checked={isItemSelected}
  183. color="primary"
  184. disabled={disableSelect}
  185. inputProps={{
  186. 'aria-labelledby': labelId,
  187. role: 'checkbox',
  188. }}
  189. />
  190. </TableCell>
  191. )}
  192. {colDefinitions.map((colDef, i) => {
  193. const { actionBarConfigs = [], needCopy = false } =
  194. colDef;
  195. const cellStyle = colDef.getStyle
  196. ? colDef.getStyle(row[colDef.id])
  197. : {};
  198. return colDef.showActionCell ? (
  199. <TableCell
  200. className={`${classes.cell} ${classes.tableCell} ${
  201. colDef.isHoverAction
  202. ? classes.hoverActionCell
  203. : ''
  204. }`}
  205. key={colDef.id}
  206. style={cellStyle}
  207. >
  208. <ActionBar
  209. configs={actionBarConfigs}
  210. isHoverType={colDef.isHoverAction}
  211. row={row}
  212. ></ActionBar>
  213. </TableCell>
  214. ) : (
  215. <TableCell
  216. key={'cell' + row[primaryKey] + i}
  217. // padding={i === 0 ? 'none' : 'default'}
  218. align={colDef.align || 'left'}
  219. className={`${classes.cell} ${classes.tableCell}`}
  220. style={cellStyle}
  221. >
  222. <div className={classes.cellContainer}>
  223. {typeof row[colDef.id] !== 'undefined' && (
  224. <>
  225. {colDef.onClick ? (
  226. <Button
  227. color="primary"
  228. data-data={row[colDef.id]}
  229. data-index={index}
  230. size="small"
  231. onClick={e => {
  232. colDef.onClick &&
  233. colDef.onClick(e, row);
  234. }}
  235. >
  236. {colDef.formatter ? (
  237. colDef.formatter(row, row[colDef.id], i)
  238. ) : (
  239. <Typography title={row[colDef.id]}>
  240. {row[colDef.id]}
  241. </Typography>
  242. )}
  243. </Button>
  244. ) : colDef.formatter ? (
  245. colDef.formatter(row, row[colDef.id], i)
  246. ) : (
  247. <Typography title={row[colDef.id]}>
  248. {row[colDef.id]}
  249. </Typography>
  250. )}
  251. {needCopy && (
  252. <CopyButton
  253. label={copyTrans.label}
  254. value={row[colDef.id]}
  255. size="small"
  256. className={classes.copyBtn}
  257. />
  258. )}
  259. </>
  260. )}
  261. </div>
  262. </TableCell>
  263. );
  264. })}
  265. </TableRow>
  266. );
  267. })
  268. ) : (
  269. <tr>
  270. <td
  271. className={classes.noData}
  272. colSpan={
  273. openCheckBox
  274. ? colDefinitions.length + 1
  275. : colDefinitions.length
  276. }
  277. >
  278. {noData}
  279. </td>
  280. </tr>
  281. )}
  282. </TableBody>
  283. </Table>
  284. )}
  285. {isLoading && <LoadingTable count={loadingRowCount} />}
  286. </Box>
  287. </TableContainer>
  288. );
  289. };
  290. export default EnhancedTable;