-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from marmelab/reference_many
[WIP] Add ReferenceManyField
- Loading branch information
Showing
31 changed files
with
490 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React, { PropTypes } from 'react'; | ||
import Chip from 'material-ui/Chip'; | ||
|
||
const ChipField = ({ source, record = {} }) => <Chip style={{ margin: 4 }}>{record[source]}</Chip>; | ||
|
||
ChipField.propTypes = { | ||
source: PropTypes.string.isRequired, | ||
label: PropTypes.string, | ||
record: PropTypes.object, | ||
}; | ||
|
||
export default ChipField; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import React, { Component, PropTypes } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import LinearProgress from 'material-ui/LinearProgress'; | ||
import { crudGetManyReference as crudGetManyReferenceAction } from '../../actions/dataActions'; | ||
import { getReferences, nameRelatedTo } from '../../reducer/references/oneToMany'; | ||
|
||
/** | ||
* Render related records in a list of a single field. | ||
* | ||
* The child field will be repeated as many times as there are related records. | ||
* | ||
* @example Display all the books by the current author | ||
* <ReferenceManyField reference="books" target="author_id"> | ||
* <ChipField source="title" /> | ||
* </ReferenceManyField> | ||
*/ | ||
export class ReferenceManyField extends Component { | ||
componentDidMount() { | ||
const relatedTo = nameRelatedTo(this.props.reference, this.props.record.id, this.props.resource, this.props.target); | ||
this.props.crudGetManyReference(this.props.reference, this.props.target, this.props.record.id, relatedTo); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
if (this.props.record.id !== nextProps.record.id) { | ||
const relatedTo = nameRelatedTo(nextProps.reference, nextProps.record.id, nextProps.resource, nextProps.target); | ||
this.props.crudGetManyReference(nextProps.reference, nextProps.target, nextProps.record.id, relatedTo); | ||
} | ||
} | ||
|
||
render() { | ||
const { resource, reference, referenceRecords, children, basePath } = this.props; | ||
if (React.Children.count(children) !== 1) { | ||
throw new Error('<ReferenceManyField> only accepts a single child'); | ||
} | ||
if (typeof referenceRecords === 'undefined') { | ||
return <LinearProgress style={{ marginTop: '1em' }} />; | ||
} | ||
const referenceBasePath = basePath.replace(resource, reference); // FIXME obviously very weak | ||
return ( | ||
<div style={{ display: 'flex', flexWrap: 'wrap' }}> | ||
{Object.keys(referenceRecords).map(index => | ||
React.cloneElement(children, { | ||
key: index, | ||
record: referenceRecords[index], | ||
resource: reference, | ||
basePath: referenceBasePath, | ||
}) | ||
)} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
ReferenceManyField.propTypes = { | ||
resource: PropTypes.string.isRequired, | ||
record: PropTypes.object, | ||
label: PropTypes.string, | ||
reference: PropTypes.string.isRequired, | ||
target: PropTypes.string.isRequired, | ||
referenceRecords: PropTypes.object, | ||
basePath: PropTypes.string.isRequired, | ||
children: PropTypes.element.isRequired, | ||
crudGetManyReference: PropTypes.func.isRequired, | ||
}; | ||
|
||
function mapStateToProps(state, props) { | ||
const relatedTo = nameRelatedTo(props.reference, props.record.id, props.resource, props.target); | ||
return { | ||
referenceRecords: getReferences(state, props.reference, relatedTo), | ||
}; | ||
} | ||
|
||
export default connect(mapStateToProps, { | ||
crudGetManyReference: crudGetManyReferenceAction, | ||
})(ReferenceManyField); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import React from 'react'; | ||
import assert from 'assert'; | ||
import { shallow } from 'enzyme'; | ||
import { ReferenceManyField } from './ReferenceManyField'; | ||
import TextField from './TextField'; | ||
|
||
describe('<ReferenceManyField />', () => { | ||
it('should render a loading indicator when related records are not yet fetched', () => { | ||
const wrapper = shallow( | ||
<ReferenceManyField | ||
resource="foo" | ||
reference="bar" | ||
target="foo_id" | ||
basePath="" | ||
crudGetManyReference={() => {}} | ||
> | ||
<TextField source="title" /> | ||
</ReferenceManyField> | ||
); | ||
const ProgressElements = wrapper.find('LinearProgress'); | ||
assert.equal(ProgressElements.length, 1); | ||
const TextFieldElements = wrapper.find('TextField'); | ||
assert.equal(TextFieldElements.length, 0); | ||
}); | ||
|
||
it('should render a list of the child component', () => { | ||
const referenceRecords = { | ||
1: { id: 1, title: 'hello' }, | ||
2: { id: 2, title: 'world' }, | ||
}; | ||
const wrapper = shallow( | ||
<ReferenceManyField | ||
resource="foo" | ||
reference="bar" | ||
target="foo_id" | ||
basePath="" | ||
referenceRecords={referenceRecords} | ||
crudGetManyReference={() => {}} | ||
> | ||
<TextField source="title" /> | ||
</ReferenceManyField> | ||
); | ||
const ProgressElements = wrapper.find('LinearProgress'); | ||
assert.equal(ProgressElements.length, 0); | ||
const TextFieldElements = wrapper.find('TextField'); | ||
assert.equal(TextFieldElements.length, 2); | ||
assert.equal(TextFieldElements.at(0).prop('resource'), 'bar'); | ||
assert.deepEqual(TextFieldElements.at(0).prop('record'), { id: 1, title: 'hello' }); | ||
assert.equal(TextFieldElements.at(1).prop('resource'), 'bar'); | ||
assert.deepEqual(TextFieldElements.at(1).prop('record'), { id: 2, title: 'world' }); | ||
}); | ||
|
||
it('should render nothing when there are no related records', () => { | ||
const wrapper = shallow( | ||
<ReferenceManyField | ||
resource="foo" | ||
reference="bar" | ||
target="foo_id" | ||
basePath="" | ||
referenceRecords={{}} | ||
crudGetManyReference={() => {}} | ||
> | ||
<TextField source="title" /> | ||
</ReferenceManyField> | ||
); | ||
const ProgressElements = wrapper.find('LinearProgress'); | ||
assert.equal(ProgressElements.length, 0); | ||
const TextFieldElements = wrapper.find('TextField'); | ||
assert.equal(TextFieldElements.length, 0); | ||
}); | ||
}); |
Oops, something went wrong.