-
Esko Ikkala authoredEsko Ikkala authored
import React from 'react';
import Immutable from 'immutable';
import PropTypes from 'prop-types';
import Grid from '@material-ui/core/Grid';
import { withStyles } from '@material-ui/core/styles';
import SearchField from '../components/SearchField';
import ResultFilterDialogSingle from './ResultFilterDialogSingle';
import {
AutoSizer,
Column,
Table,
SortIndicator
} from 'react-virtualized';
// https://github.com/bvaughn/react-virtualized/issues/650
// https://github.com/bvaughn/react-virtualized/blob/master/docs/usingAutoSizer.md
const styles = () => ({
root: {
display: 'flex',
height: '100%',
flexGrow: 1,
},
container: {
height: '100%',
width: '100%',
flexDirection: 'column'
},
resultsInfo: {
flexGrow: 0
},
searchField: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: 70
},
});
const tableStyles = {
tableRoot: {
fontFamily: 'Roboto',
},
headerRow: {
textTransform: 'none',
borderBottom: '1px solid rgba(224, 224, 224, 1)'
},
evenRow: {
borderBottom: '1px solid rgba(224, 224, 224, 1)',
//backgroundColor: '#fafafa'
},
oddRow: {
borderBottom: '1px solid rgba(224, 224, 224, 1)',
},
noRows: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '1em',
color: '#bdbdbd',
}
};
const columnWidth = 115;
const calculateRowStyle = ({ index }) => {
if (index < 0) {
return tableStyles.headerRow;
} else {
return index % 2 === 0 ? tableStyles.evenRow : tableStyles.oddRow;
}
};
class VirtualizedTable extends React.PureComponent {
constructor(props) {
super(props);
this._noRowsRenderer = this._noRowsRenderer.bind(this);
this._sort = this._sort.bind(this);
}
render() {
const { classes, list } = this.props;
const rowGetter = ({index}) => this._getDatum(list, index);
const headerRenderer = ({
dataKey,
label,
sortBy,
sortDirection,
}) => {
const showSortIndicator = sortBy === dataKey;
const children = [
<span
className="ReactVirtualized__Table__headerTruncatedText"
style={showSortIndicator ? {} : { marginRight: 16 }}
key="label"
title={label}>
{label}
</span>,
];
if (showSortIndicator) {
children.push(
<SortIndicator key="SortIndicator" sortDirection={sortDirection} />,
);
}
children.push(
<ResultFilterDialogSingle
key="resultFilter"
propertyLabel={label}
property={dataKey}
resultValues={this.props.resultValues[dataKey]}
updateResultsFilter={this.props.updateResultsFilter}
/>
);
return children;
};
// always render extra columns for now
const analysisView = true;
// Some extra columns for analysis view
let modifier = '';
let base = '';
let collector = '';
let collectionYear = '';
if (analysisView) {
modifier = (
<Column
label="Modifier"
cellDataGetter={({rowData}) => rowData.modifier}
dataKey="modifier"
headerRenderer={headerRenderer}
width={columnWidth}
/>
);
base = (
<Column
label="Base"
cellDataGetter={({rowData}) => rowData.basicElement}
dataKey="basicElement"
headerRenderer={headerRenderer}
width={columnWidth}
/>
);
collector = (
<Column
label="Collector"
cellDataGetter={({rowData}) => rowData.collector}
dataKey="collector"
headerRenderer={headerRenderer}
width={columnWidth}
/>
);
collectionYear = (
<Column
label="Year"
cellDataGetter={({rowData}) => rowData.collectionYear}
dataKey="collectionYear"
headerRenderer={headerRenderer}
width={columnWidth}
/>
);
}
const searchField = (
<SearchField
search={this.props.search}
fetchResults={this.props.fetchResults}
updateQuery={this.props.updateQuery}
clearResults={this.props.clearResults}
/>
);
return (
<div className={classes.root}>
<Grid container className={classes.container}>
<div className={classes.resultsInfo}>
<div className={classes.searchField}>
{searchField}
</div>
</div>
{this.props.list.size > 0 &&
<div style={{ flex: '1 1 auto' }}>
<AutoSizer>
{({ height, width }) => (
<Table
overscanRowCount={10}
rowHeight={40}
rowGetter={rowGetter}
rowCount={this.props.list.size}
sort={this._sort}
sortBy={this.props.search.sortBy}
sortDirection={this.props.search.sortDirection.toUpperCase()}
width={width}
height={height}
headerHeight={50}
noRowsRenderer={this._noRowsRenderer}
style={tableStyles.tableRoot}
rowStyle={calculateRowStyle}
>
<Column
label="Name"
cellDataGetter={({rowData}) => rowData.label}
dataKey="label"
headerRenderer={headerRenderer}
width={columnWidth}
/>
{modifier}
{base}
<Column
label="Type"
cellDataGetter={({rowData}) => rowData.typeLabel}
dataKey="typeLabel"
headerRenderer={headerRenderer}
width={columnWidth}
/>
<Column
label="Area"
cellDataGetter={({rowData}) => rowData.broaderAreaLabel}
dataKey="broaderAreaLabel"
headerRenderer={headerRenderer}
width={columnWidth}
/>
{collector}
{collectionYear}
<Column
label="Source"
cellDataGetter={({rowData}) => rowData.source}
dataKey="source"
headerRenderer={headerRenderer}
width={columnWidth}
/>
</Table>
)}
</AutoSizer>
</div>
}
</Grid>
</div>
);
}
_getDatum(list, index) {
return list.get(index % list.size);
}
_getRowHeight({index}) {
const list = this.props.list;
return this._getDatum(list, index).size;
}
_noRowsRenderer() {
return <div className={tableStyles.noRows}>No rows</div>;
}
// _onScrollToRowChange(event) {
// const {rowCount} = this.state;
// let scrollToIndex = Math.min(
// rowCount - 1,
// parseInt(event.target.value, 10),
// );
//
// if (isNaN(scrollToIndex)) {
// scrollToIndex = undefined;
// }
//
// this.setState({scrollToIndex});
// }
// https://stackoverflow.com/questions/40412114/how-to-do-proper-column-filtering-with-react-virtualized-advice-needed
_sort({ event, sortBy, sortDirection }) {
// console.log(event.target)
if (event.target.id.startsWith('filter') || event.target.className.startsWith('Mui')) {
event.stopPropagation();
} else {
this.props.sortResults({ sortBy, sortDirection: sortDirection.toLowerCase() });
}
}
}
VirtualizedTable.propTypes = {
classes: PropTypes.object.isRequired,
list: PropTypes.instanceOf(Immutable.List).isRequired,
search: PropTypes.object.isRequired,
resultValues: PropTypes.object.isRequired,
sortResults: PropTypes.func.isRequired,
updateResultsFilter: PropTypes.func.isRequired,
updateQuery: PropTypes.func.isRequired,
fetchSuggestions: PropTypes.func.isRequired,
clearSuggestions: PropTypes.func.isRequired,
fetchResults: PropTypes.func.isRequired,
clearResults: PropTypes.func.isRequired,
};
export default withStyles(styles)(VirtualizedTable);