Newer
Older
piotr.kupczyk@id.ethz.ch
committed
import _ from 'lodash'
piotr.kupczyk@id.ethz.ch
committed
import React from 'react'
piotr.kupczyk@id.ethz.ch
committed
import autoBind from 'auto-bind'
piotr.kupczyk@id.ethz.ch
committed
import { withStyles } from '@material-ui/core/styles'
piotr.kupczyk@id.ethz.ch
committed
import Loading from '@src/js/components/common/loading/Loading.jsx'
piotr.kupczyk@id.ethz.ch
committed
import Table from '@material-ui/core/Table'
piotr.kupczyk@id.ethz.ch
committed
import TableHead from '@material-ui/core/TableHead'
piotr.kupczyk@id.ethz.ch
committed
import TableBody from '@material-ui/core/TableBody'
piotr.kupczyk@id.ethz.ch
committed
import Header from '@src/js/components/common/form/Header.jsx'
import GridController from '@src/js/components/common/grid/GridController.js'
piotr.kupczyk@id.ethz.ch
committed
import GridFilters from '@src/js/components/common/grid/GridFilters.jsx'
import GridHeaders from '@src/js/components/common/grid/GridHeaders.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridSelectionInfo from '@src/js/components/common/grid/GridSelectionInfo.jsx'
import GridRow from '@src/js/components/common/grid/GridRow.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridRowFullWidth from '@src/js/components/common/grid/GridRowFullWidth.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridExports from '@src/js/components/common/grid/GridExports.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridExportLoading from '@src/js/components/common/grid/GridExportLoading.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridExportWarnings from '@src/js/components/common/grid/GridExportWarnings.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridExportError from '@src/js/components/common/grid/GridExportError.jsx'
import GridPaging from '@src/js/components/common/grid/GridPaging.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridColumnsConfig from '@src/js/components/common/grid/GridColumnsConfig.jsx'
piotr.kupczyk@id.ethz.ch
committed
import GridFiltersConfig from '@src/js/components/common/grid/GridFiltersConfig.jsx'
piotr.kupczyk@id.ethz.ch
committed
import ComponentContext from '@src/js/components/common/ComponentContext.js'
piotr.kupczyk@id.ethz.ch
committed
import logger from '@src/js/common/logger.js'
piotr.kupczyk@id.ethz.ch
committed
const styles = theme => ({
piotr.kupczyk@id.ethz.ch
committed
container: {
piotr.kupczyk@id.ethz.ch
committed
minWidth: '800px',
piotr.kupczyk@id.ethz.ch
committed
height: '100%'
piotr.kupczyk@id.ethz.ch
committed
},
loadingContainer: {
flex: '1 1 auto'
},
piotr.kupczyk@id.ethz.ch
committed
loading: {
display: 'inline-block'
},
piotr.kupczyk@id.ethz.ch
committed
tableContainer: {
piotr.kupczyk@id.ethz.ch
committed
display: 'inline-block',
minWidth: '100%',
piotr.kupczyk@id.ethz.ch
committed
height: '100%'
},
piotr.kupczyk@id.ethz.ch
committed
table: {
piotr.kupczyk@id.ethz.ch
committed
borderCollapse: 'unset'
piotr.kupczyk@id.ethz.ch
committed
},
piotr.kupczyk@id.ethz.ch
committed
tableHead: {
position: 'sticky',
piotr.kupczyk@id.ethz.ch
committed
top: 0,
piotr.kupczyk@id.ethz.ch
committed
zIndex: '200',
backgroundColor: theme.palette.background.paper
},
piotr.kupczyk@id.ethz.ch
committed
titleCell: {
border: 0
},
piotr.kupczyk@id.ethz.ch
committed
titleContent: {
paddingLeft: theme.spacing(2)
},
piotr.kupczyk@id.ethz.ch
committed
title: {
paddingTop: theme.spacing(1),
paddingBottom: 0
},
piotr.kupczyk@id.ethz.ch
committed
pagingAndConfigsAndExportsContent: {
piotr.kupczyk@id.ethz.ch
committed
display: 'flex'
piotr.kupczyk@id.ethz.ch
committed
}
})
class Grid extends React.PureComponent {
piotr.kupczyk@id.ethz.ch
committed
static defaultProps = {
id: 'grid'
}
piotr.kupczyk@id.ethz.ch
committed
constructor(props) {
piotr.kupczyk@id.ethz.ch
committed
super(props)
piotr.kupczyk@id.ethz.ch
committed
autoBind(this)
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
this.state = {}
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
if (this.props.controller) {
this.controller = this.props.controller
} else {
this.controller = new GridController()
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
this.controller.init(new ComponentContext(this))
piotr.kupczyk@id.ethz.ch
committed
if (this.props.controllerRef) {
this.props.controllerRef(this.controller)
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
componentDidMount() {
piotr.kupczyk@id.ethz.ch
committed
this.controller.load()
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
handleClickContainer() {
piotr.kupczyk@id.ethz.ch
committed
this.controller.handleRowSelect(null)
piotr.kupczyk@id.ethz.ch
committed
}
handleClickTable(event) {
piotr.kupczyk@id.ethz.ch
committed
event.stopPropagation()
}
piotr.kupczyk@id.ethz.ch
committed
render() {
logger.log(logger.DEBUG, 'Grid.render')
piotr.kupczyk@id.ethz.ch
committed
if (!this.state.loaded) {
piotr.kupczyk@id.ethz.ch
committed
return <Loading loading={true}></Loading>
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
const { id, classes } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { loading, rows } = this.state
piotr.kupczyk@id.ethz.ch
committed
return (
piotr.kupczyk@id.ethz.ch
committed
<div
id={id}
onClick={this.handleClickContainer}
className={classes.container}
>
piotr.kupczyk@id.ethz.ch
committed
<div className={classes.loadingContainer}>
piotr.kupczyk@id.ethz.ch
committed
<Loading loading={loading} styles={{ root: classes.loading }}>
piotr.kupczyk@id.ethz.ch
committed
<div className={classes.tableContainer}>
piotr.kupczyk@id.ethz.ch
committed
<Table
classes={{ root: classes.table }}
piotr.kupczyk@id.ethz.ch
committed
onClick={this.handleClickTable}
>
piotr.kupczyk@id.ethz.ch
committed
<TableHead classes={{ root: classes.tableHead }}>
{this.renderTitle()}
{this.renderPagingAndConfigsAndExports()}
{this.renderHeaders()}
{this.renderFilters()}
piotr.kupczyk@id.ethz.ch
committed
{this.renderSelectionInfo()}
piotr.kupczyk@id.ethz.ch
committed
</TableHead>
<TableBody>
{rows.map(row => {
return this.renderRow(row)
})}
</TableBody>
</Table>
piotr.kupczyk@id.ethz.ch
committed
</div>
piotr.kupczyk@id.ethz.ch
committed
{this.renderExportState()}
piotr.kupczyk@id.ethz.ch
committed
</Loading>
</div>
</div>
piotr.kupczyk@id.ethz.ch
committed
)
}
piotr.kupczyk@id.ethz.ch
committed
renderTitle() {
const { header, multiselectable, classes } = this.props
if (header === null || header === undefined) {
return null
}
const visibleColumns = this.controller.getVisibleColumns()
return (
piotr.kupczyk@id.ethz.ch
committed
<GridRowFullWidth
multiselectable={multiselectable}
columns={visibleColumns}
styles={{ cell: classes.titleCell, content: classes.titleContent }}
>
<div onClick={this.handleClickContainer}>
<Header styles={{ root: classes.title }}>{header}</Header>
</div>
</GridRowFullWidth>
piotr.kupczyk@id.ethz.ch
committed
)
}
renderPagingAndConfigsAndExports() {
const { multiselectable, classes } = this.props
const visibleColumns = this.controller.getVisibleColumns()
return (
piotr.kupczyk@id.ethz.ch
committed
<GridRowFullWidth
multiselectable={multiselectable}
columns={visibleColumns}
styles={{
content: classes.pagingAndConfigsAndExportsContent
}}
>
{this.renderPaging()}
{this.renderConfigs()}
{this.renderExports()}
</GridRowFullWidth>
piotr.kupczyk@id.ethz.ch
committed
)
}
renderPaging() {
piotr.kupczyk@id.ethz.ch
committed
const { id } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { page, pageSize, totalCount } = this.state
return (
<GridPaging
piotr.kupczyk@id.ethz.ch
committed
id={id}
piotr.kupczyk@id.ethz.ch
committed
count={totalCount}
page={page}
pageSize={pageSize}
onPageChange={this.controller.handlePageChange}
onPageSizeChange={this.controller.handlePageSizeChange}
/>
)
}
renderConfigs() {
piotr.kupczyk@id.ethz.ch
committed
const { id, filterModes } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { loading, filterMode, columnsVisibility } = this.state
const allColumns = this.controller.getAllColumns()
return (
<React.Fragment>
<GridColumnsConfig
piotr.kupczyk@id.ethz.ch
committed
id={id}
piotr.kupczyk@id.ethz.ch
committed
columns={allColumns}
columnsVisibility={columnsVisibility}
loading={loading}
onVisibleChange={this.controller.handleColumnVisibleChange}
onOrderChange={this.controller.handleColumnOrderChange}
/>
<GridFiltersConfig
piotr.kupczyk@id.ethz.ch
committed
id={id}
piotr.kupczyk@id.ethz.ch
committed
filterModes={filterModes}
filterMode={filterMode}
loading={loading}
onFilterModeChange={this.controller.handleFilterModeChange}
/>
</React.Fragment>
)
}
renderExports() {
piotr.kupczyk@id.ethz.ch
committed
const { id, multiselectable } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { rows, multiselectedRows, exportOptions } = this.state
piotr.kupczyk@id.ethz.ch
committed
piotr.kupczyk@id.ethz.ch
committed
const exportable = this.controller.getExportable()
piotr.kupczyk@id.ethz.ch
committed
if (!exportable) {
return null
}
piotr.kupczyk@id.ethz.ch
committed
const visibleColumns = this.controller.getVisibleColumns()
piotr.kupczyk@id.ethz.ch
committed
return (
<GridExports
piotr.kupczyk@id.ethz.ch
committed
id={id}
piotr.kupczyk@id.ethz.ch
committed
disabled={rows.length === 0}
exportable={exportable}
piotr.kupczyk@id.ethz.ch
committed
exportOptions={exportOptions}
multiselectable={multiselectable}
piotr.kupczyk@id.ethz.ch
committed
multiselectedRows={multiselectedRows}
piotr.kupczyk@id.ethz.ch
committed
visibleColumns={visibleColumns}
piotr.kupczyk@id.ethz.ch
committed
onExport={this.controller.handleExport}
onExportOptionsChange={this.controller.handleExportOptionsChange}
/>
)
}
piotr.kupczyk@id.ethz.ch
committed
renderExportState() {
const { exportState } = this.state
if (!exportState) {
return null
}
return (
<React.Fragment>
<GridExportLoading loading={!!exportState.loading} />
<GridExportError
piotr.kupczyk@id.ethz.ch
committed
open={!_.isEmpty(exportState.error)}
piotr.kupczyk@id.ethz.ch
committed
error={exportState.error}
onClose={this.controller.handleExportCancel}
/>
piotr.kupczyk@id.ethz.ch
committed
<GridExportWarnings
piotr.kupczyk@id.ethz.ch
committed
open={!_.isEmpty(exportState.warnings)}
piotr.kupczyk@id.ethz.ch
committed
warnings={exportState.warnings}
piotr.kupczyk@id.ethz.ch
committed
onDownload={() =>
this.controller.handleExportDownload(
exportState.fileName,
exportState.fileUrl
)
}
onCancel={this.controller.handleExportCancel}
/>
</React.Fragment>
)
}
piotr.kupczyk@id.ethz.ch
committed
renderHeaders() {
const { multiselectable } = this.props
const { sortings, rows, multiselectedRows } = this.state
const visibleColumns = this.controller.getVisibleColumns()
return (
<GridHeaders
columns={visibleColumns}
rows={rows}
sortings={sortings}
onSortChange={this.controller.handleSortChange}
onMultiselectAllRowsChange={
this.controller.handleMultiselectAllRowsChange
}
multiselectable={multiselectable}
multiselectedRows={multiselectedRows}
/>
)
}
renderFilters() {
const { id, filterModes, multiselectable } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { filterMode, filters, globalFilter } = this.state
const visibleColumns = this.controller.getVisibleColumns()
return (
<GridFilters
piotr.kupczyk@id.ethz.ch
committed
columns={visibleColumns}
filterModes={filterModes}
filterMode={filterMode}
filters={filters}
onFilterChange={this.controller.handleFilterChange}
onFilterModeChange={this.controller.handleFilterModeChange}
globalFilter={globalFilter}
onGlobalFilterChange={this.controller.handleGlobalFilterChange}
multiselectable={multiselectable}
/>
)
}
piotr.kupczyk@id.ethz.ch
committed
renderSelectionInfo() {
piotr.kupczyk@id.ethz.ch
committed
const { multiselectable, actions } = this.props
const { rows, multiselectedRows } = this.state
const visibleColumns = this.controller.getVisibleColumns()
return (
piotr.kupczyk@id.ethz.ch
committed
<GridSelectionInfo
piotr.kupczyk@id.ethz.ch
committed
columns={visibleColumns}
rows={rows}
actions={actions}
onExecuteAction={this.controller.handleExecuteAction}
onMultiselectionClear={this.controller.handleMultiselectionClear}
multiselectable={multiselectable}
multiselectedRows={multiselectedRows}
/>
)
}
renderRow(row) {
const { selectable, multiselectable, onRowClick } = this.props
piotr.kupczyk@id.ethz.ch
committed
const { selectedRow, multiselectedRows, heights } = this.state
piotr.kupczyk@id.ethz.ch
committed
const visibleColumns = this.controller.getVisibleColumns()
return (
<GridRow
key={row.id}
columns={visibleColumns}
row={row}
piotr.kupczyk@id.ethz.ch
committed
heights={heights[row.id]}
piotr.kupczyk@id.ethz.ch
committed
clickable={onRowClick ? true : false}
selectable={selectable}
selected={selectedRow ? selectedRow.id === row.id : false}
multiselectable={multiselectable}
multiselected={multiselectedRows && multiselectedRows[row.id]}
onClick={this.controller.handleRowClick}
onSelect={this.controller.handleRowSelect}
onMultiselect={this.controller.handleRowMultiselect}
piotr.kupczyk@id.ethz.ch
committed
onMeasured={this.controller.handleMeasured}
piotr.kupczyk@id.ethz.ch
committed
/>
)
}
piotr.kupczyk@id.ethz.ch
committed
}
piotr.kupczyk@id.ethz.ch
committed
export default withStyles(styles)(Grid)