Table.tsx 9.9 KB

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