import React from 'react' import PropTypes from 'prop-types' import clsx from 'clsx' import withStyles from '@mui/styles/withStyles' import TableCell from '@mui/material/TableCell' import TableSortLabel from '@mui/material/TableSortLabel' import Tooltip from '@mui/material/Tooltip' import ResultTableCell from './ResultTableCell' import Paper from '@mui/material/Paper' import { AutoSizer, Column, Table } from 'react-virtualized' import intl from 'react-intl-universal' import CircularProgress from '@mui/material/CircularProgress' const styles = theme => ({ flexContainer: { display: 'flex', alignItems: 'center', boxSizing: 'border-box' }, table: { // temporary right-to-left patch, waiting for // https://github.com/bvaughn/react-virtualized/issues/454 '& .ReactVirtualized__Table__headerRow': { flip: false, paddingRight: theme.direction === 'rtl' ? '0 !important' : undefined }, '& .ReactVirtualized__Table__rowColumn': { marginRight: theme.spacing(3) } }, tableRow: { borderBottom: '1px solid rgba(224, 224, 224, 1)' }, tableRowHover: { '&:hover': { backgroundColor: theme.palette.grey[200] } }, tableCell: { flex: 1 }, tableCellWithSort: { marginRight: 16 } }) class MuiVirtualizedTable extends React.PureComponent { static defaultProps = { headerHeight: 48, rowHeight: 40 }; componentDidUpdate = prevProps => { if (prevProps.sortBy !== this.props.sortBy || prevProps.sortDirection !== this.props.sortDirection) { this.forceUpdate() } } getRowClassName = ({ index }) => { const { classes, onRowClick } = this.props return clsx(classes.tableRow, classes.flexContainer, { [classes.tableRowHover]: index !== -1 && onRowClick != null }) }; cellRenderer = ({ cellData, columnIndex }) => { const { columns /* classes, rowHeight, onRowClick */ } = this.props const { id, valueType, makeLink, externalLink, sortValues, numberedList, minWidth, collapsedMaxWords } = columns[columnIndex] return ( <ResultTableCell columnId={id} data={cellData} valueType={valueType} makeLink={makeLink} externalLink={externalLink} numberedList={numberedList} sortValues={sortValues} minWidth={minWidth} container='div' expanded={false} collapsedMaxWords={collapsedMaxWords} shortenLabel={false} /> ) }; headerRenderer = ({ label, columnIndex, dataKey }) => { const { headerHeight, columns, classes, sortBy, sortDirection } = this.props return ( <> <TableCell component='div' className={clsx( classes.tableCell, classes.flexContainer)} variant='head' style={{ height: headerHeight, textTransform: 'none' }} align={columns[columnIndex].numeric || false ? 'right' : 'left'} > <Tooltip title={`Sort by ${label}`} enterDelay={300} > <TableSortLabel active={sortBy === dataKey} direction={typeof sortDirection === 'string' ? sortDirection : 'asc'} hideSortIcon onClick={this.onSortBy(dataKey)} > {label} </TableSortLabel> </Tooltip> </TableCell> </> ) } onSortBy = sortBy => () => { this.props.sortFullTextResults({ resultClass: this.props.resultClass, sortBy }) } render () { const { classes, columns, rowHeight, headerHeight, sortDirection, ...tableProps } = this.props return ( <AutoSizer> {({ height, width }) => ( <Table height={height} width={width} rowHeight={rowHeight} gridStyle={{ direction: 'inherit' }} headerHeight={headerHeight} className={classes.table} {...tableProps} rowClassName={this.getRowClassName} > {columns.map(({ id, minWidth, ...other }, index) => { const label = intl.get(`perspectives.fullTextSearch.properties.${id}.label`) return ( <Column key={id} headerRenderer={(headerProps) => this.headerRenderer({ ...headerProps, label, columnIndex: index, dataKey: id })} className={classes.flexContainer} cellRenderer={this.cellRenderer} dataKey={id} width={minWidth} {...other} /> ) })} </Table> )} </AutoSizer> ) } } MuiVirtualizedTable.propTypes = { classes: PropTypes.object.isRequired, columns: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, numeric: PropTypes.bool, minWidth: PropTypes.number }) ).isRequired, headerHeight: PropTypes.number, onRowClick: PropTypes.func, rowHeight: PropTypes.number } const VirtualizedTable = withStyles(styles)(MuiVirtualizedTable) const rootStyle = { height: 'calc(100% - 58px)', fontFamily: 'Roboto' } const tableContainer = { width: 1100, height: '100%', marginLeft: 'auto', marginRight: 'auto' } const progressContainerStyle = { width: '100%', height: 'calc(100% - 58px)', display: 'flex', alignItems: 'center', justifyContent: 'center' } const ReactVirtualizedTable = props => { const { results, properties, sortBy, sortDirection, fetching } = props.fullTextSearch return ( <Paper square style={rootStyle}> {fetching ? ( <div style={progressContainerStyle}> <CircularProgress /> </div> ) : ( <div style={tableContainer}> <VirtualizedTable rowCount={results.length} rowGetter={({ index }) => results[index]} columns={properties} fetching={fetching} sortBy={sortBy} sortDirection={sortDirection} sortFullTextResults={props.sortFullTextResults} resultClass={props.resultClass} /> </div> )} </Paper> ) } export default ReactVirtualizedTable