2016-03-18 14:42:45 +13:00
|
|
|
import React from 'react';
|
2016-03-29 15:38:48 +13:00
|
|
|
import { bindActionCreators } from 'redux';
|
|
|
|
import { connect } from 'react-redux';
|
2016-03-30 16:38:34 +13:00
|
|
|
import SilverStripeComponent from 'silverstripe-component';
|
2016-03-26 11:20:48 +13:00
|
|
|
import GridFieldTable from './table';
|
|
|
|
import GridFieldHeader from './header';
|
|
|
|
import GridFieldHeaderCell from './header-cell';
|
|
|
|
import GridFieldRow from './row';
|
|
|
|
import GridFieldCell from './cell';
|
|
|
|
import GridFieldAction from './action';
|
2016-03-29 15:38:48 +13:00
|
|
|
import * as actions from 'state/records/actions';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The component acts as a container for a grid field,
|
|
|
|
* with smarts around data retrieval from external sources.
|
|
|
|
*
|
2016-03-31 10:45:54 +13:00
|
|
|
* @todo Convert to higher order component which hooks up form
|
|
|
|
* schema data to an API backend as a grid data source
|
2016-03-29 15:38:48 +13:00
|
|
|
* @todo Replace "dumb" inner components with third party library (e.g. https://griddlegriddle.github.io)
|
|
|
|
*/
|
2016-03-18 14:42:45 +13:00
|
|
|
class GridField extends SilverStripeComponent {
|
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2016-03-26 11:20:48 +13:00
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
this.deleteRecord = this.deleteRecord.bind(this);
|
|
|
|
this.editRecord = this.editRecord.bind(this);
|
|
|
|
}
|
2016-03-29 15:38:48 +13:00
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
componentDidMount() {
|
|
|
|
super.componentDidMount();
|
2016-03-29 15:38:48 +13:00
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
const data = this.props.data;
|
2016-03-29 15:38:48 +13:00
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
this.props.actions.fetchRecords(
|
|
|
|
data.recordType,
|
|
|
|
data.collectionReadEndpoint.method,
|
|
|
|
data.collectionReadEndpoint.url
|
|
|
|
);
|
|
|
|
}
|
2016-03-18 14:42:45 +13:00
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
render() {
|
|
|
|
const records = this.props.records;
|
2016-04-12 10:24:16 +12:00
|
|
|
const handleDrillDown = this.props.data.handleDrillDown;
|
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
if (!records) {
|
|
|
|
return <div></div>;
|
2016-03-18 14:42:45 +13:00
|
|
|
}
|
|
|
|
|
2016-03-31 10:45:54 +13:00
|
|
|
const columns = this.props.data.columns;
|
|
|
|
|
|
|
|
// Placeholder to align the headers correctly with the content
|
|
|
|
const actionPlaceholder = <span key={'actionPlaceholder'} />;
|
|
|
|
const headerCells = columns.map((column, i) =>
|
|
|
|
<GridFieldHeaderCell key={i}>{column.name}</GridFieldHeaderCell>
|
|
|
|
);
|
|
|
|
const header = <GridFieldHeader>{headerCells.concat(actionPlaceholder)}</GridFieldHeader>;
|
|
|
|
|
|
|
|
const rows = records.map((record, i) => {
|
2016-04-12 10:24:16 +12:00
|
|
|
// Build cells
|
2016-03-31 10:45:54 +13:00
|
|
|
const cells = columns.map((column, j) => {
|
|
|
|
// Get value by dot notation
|
|
|
|
const val = column.field.split('.').reduce((a, b) => a[b], record);
|
2016-04-12 10:24:16 +12:00
|
|
|
const cellProps = {
|
|
|
|
handleDrillDown: handleDrillDown ? (event) => handleDrillDown(event, record) : null,
|
|
|
|
className: handleDrillDown ? 'grid-field-cell-component--drillable' : '',
|
|
|
|
key: j,
|
|
|
|
width: column.width,
|
|
|
|
};
|
|
|
|
return (
|
|
|
|
<GridFieldCell {...cellProps}>
|
|
|
|
{val}
|
|
|
|
</GridFieldCell>
|
|
|
|
);
|
2016-03-31 10:45:54 +13:00
|
|
|
});
|
|
|
|
|
|
|
|
const rowActions = (
|
|
|
|
<GridFieldCell key={`${i}-actions`}>
|
|
|
|
<GridFieldAction
|
|
|
|
icon={'cog'}
|
|
|
|
handleClick={this.editRecord}
|
|
|
|
key={`action-${i}-edit`}
|
|
|
|
record={record}
|
|
|
|
/>,
|
|
|
|
<GridFieldAction
|
|
|
|
icon={'cancel'}
|
|
|
|
handleClick={this.deleteRecord}
|
|
|
|
key={`action-${i}-delete`}
|
|
|
|
record={record}
|
|
|
|
/>,
|
|
|
|
</GridFieldCell>
|
|
|
|
);
|
|
|
|
|
2016-04-12 10:24:16 +12:00
|
|
|
const rowProps = {
|
|
|
|
key: i,
|
|
|
|
className: handleDrillDown ? 'grid-field-row-component--drillable' : '',
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<GridFieldRow {...rowProps}>
|
|
|
|
{cells.concat(rowActions)}
|
|
|
|
</GridFieldRow>
|
|
|
|
);
|
2016-03-31 10:45:54 +13:00
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<GridFieldTable header={header} rows={rows} />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param number int
|
|
|
|
* @param event
|
|
|
|
*/
|
|
|
|
deleteRecord(event, id) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.props.actions.deleteRecord(
|
|
|
|
this.props.data.recordType,
|
|
|
|
id,
|
|
|
|
this.props.data.itemDeleteEndpoint.method,
|
|
|
|
this.props.data.itemDeleteEndpoint.url
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
editRecord(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
// TODO
|
|
|
|
}
|
2016-03-24 12:32:38 +13:00
|
|
|
|
2016-03-18 14:42:45 +13:00
|
|
|
}
|
|
|
|
|
2016-03-29 15:38:48 +13:00
|
|
|
GridField.propTypes = {
|
2016-03-31 10:45:54 +13:00
|
|
|
data: React.PropTypes.shape({
|
|
|
|
recordType: React.PropTypes.string.isRequired,
|
|
|
|
headerColumns: React.PropTypes.array,
|
|
|
|
collectionReadEndpoint: React.PropTypes.object,
|
2016-04-12 10:24:16 +12:00
|
|
|
handleDrillDown: React.PropTypes.func,
|
2016-03-31 10:45:54 +13:00
|
|
|
}),
|
2016-03-29 15:38:48 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
function mapStateToProps(state, ownProps) {
|
2016-03-31 10:45:54 +13:00
|
|
|
const recordType = ownProps.data ? ownProps.data.recordType : null;
|
|
|
|
return {
|
|
|
|
records: (state.records && recordType) ? state.records[recordType] : [],
|
|
|
|
};
|
2016-03-29 15:38:48 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
function mapDispatchToProps(dispatch) {
|
2016-03-31 10:45:54 +13:00
|
|
|
return {
|
|
|
|
actions: bindActionCreators(actions, dispatch),
|
|
|
|
};
|
2016-03-29 15:38:48 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(GridField);
|