Skip to content

Commit

Permalink
George, Shashi | #3064 | Support for expandAll & collapseAll on the o…
Browse files Browse the repository at this point in the history
…bsGroup
  • Loading branch information
yzeng committed Jan 16, 2017
1 parent 27fd1cc commit 5cbf7cd
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 15 deletions.
6 changes: 6 additions & 0 deletions src/components/Container.jsx
Expand Up @@ -86,6 +86,7 @@ export class Container extends Component {
render() {
const { metadata: { controls, name: formName, version: formVersion }, validate } = this.props;
const childProps = {
collapse: this.props.collapse,
errors: this.state.errors,
formName,
formVersion,
Expand All @@ -104,6 +105,7 @@ export class Container extends Component {
}

Container.propTypes = {
collapse: PropTypes.bool.isRequired,
metadata: PropTypes.shape({
controls: React.PropTypes.arrayOf(
React.PropTypes.shape({
Expand All @@ -117,3 +119,7 @@ Container.propTypes = {
observations: PropTypes.array.isRequired,
validate: PropTypes.bool.isRequired,
};

Container.defaultProps = {
collapse: false,
};
40 changes: 33 additions & 7 deletions src/components/ObsGroupControl.jsx
Expand Up @@ -3,16 +3,25 @@ import ComponentStore from 'src/helpers/componentStore';
import { getGroupedControls, displayRowControls } from '../helpers/controlsParser';
import { controlStateFactory, getErrors } from 'src/ControlState';
import each from 'lodash/each';
import classNames from 'classnames';

export class ObsGroupControl extends Component {

constructor(props) {
super(props);
const { formName, formVersion, obs, metadata } = this.props;
const { formName, formVersion, obs, metadata, collapse } = this.props;
const groupMembers = obs.getGroupMembers() || [];
const data = controlStateFactory(metadata, groupMembers, formName, formVersion);
this.state = { obs: this._getObsGroup(obs, data), errors: [], data };
this.state = { obs: this._getObsGroup(obs, data), errors: [], data, collapse };
this.onChange = this.onChange.bind(this);
this._onCollapse = this._onCollapse.bind(this);
}

componentWillReceiveProps(nextProps) {
if (nextProps.collapse !== this.props.collapse ||
nextProps.collapse !== this.state.collapse) {
this.setState({ collapse: nextProps.collapse });
}
}

onChange(obs, errors) {
Expand All @@ -34,23 +43,36 @@ export class ObsGroupControl extends Component {
return observations;
}

_onCollapse() {
const collapse = !this.state.collapse;
this.setState({ collapse });
}

render() {
const { formName, formVersion, metadata: { label }, validate } = this.props;
const childProps = { formName, formVersion, validate, onValueChanged: this.onChange };
const { collapse, formName, formVersion, metadata: { label }, validate } = this.props;
const childProps = { collapse, formName, formVersion, validate, onValueChanged: this.onChange };
const groupedRowControls = getGroupedControls(this.props.metadata.controls, 'row');
const records = this.state.data.getRecords();
const toggleClass = `form-builder-toggle ${classNames({ active: !this.state.collapse })}`;
const obsGroupClass =
this.state.collapse ? 'closing-obsGroup-controls' : 'active-obsGroup-controls';
return (
<fieldset className="form-builder-fieldset">
<legend>{label.value}</legend>
<div className="obsGroup-controls">
{displayRowControls(groupedRowControls, records, childProps)}
<legend className={toggleClass} onClick={ this._onCollapse}>
<i className="fa fa-caret-down"></i>
<i className="fa fa-caret-right"></i>
{label.value}
</legend>
<div className={`obsGroup-controls ${obsGroupClass}`}>
{ displayRowControls(groupedRowControls, records, childProps) }
</div>
</fieldset>
);
}
}

ObsGroupControl.propTypes = {
collapse: PropTypes.bool,
formName: PropTypes.string.isRequired,
formVersion: PropTypes.string.isRequired,
mapper: PropTypes.object.isRequired,
Expand All @@ -71,4 +93,8 @@ ObsGroupControl.propTypes = {
validate: PropTypes.bool.isRequired,
};

ObsGroupControl.defaultProps = {
collapse: false,
};

ComponentStore.registerComponent('obsGroupControl', ObsGroupControl);
1 change: 1 addition & 0 deletions src/components/Row.jsx
Expand Up @@ -35,6 +35,7 @@ export default class Row extends Component {
}

Row.propTypes = {
collapse: PropTypes.bool,
controls: PropTypes.array.isRequired,
formName: PropTypes.string.isRequired,
formVersion: PropTypes.string.isRequired,
Expand Down
11 changes: 6 additions & 5 deletions src/helpers/formRenderer.js
Expand Up @@ -2,8 +2,9 @@ import { Container } from 'components/Container.jsx';
import React from 'react';
import ReactDOM from 'react-dom';

window.renderWithControls = function renderWithControls(formDetails, observations, nodeId) {
const container = React.createElement(Container,
{ metadata: formDetails, observations, validate: true });
return ReactDOM.render(container, document.getElementById(nodeId));
};
window.renderWithControls =
function renderWithControls(formDetails, observations, nodeId, collapse) {
const container = React.createElement(Container,
{ metadata: formDetails, observations, validate: true, collapse });
return ReactDOM.render(container, document.getElementById(nodeId));
};
2 changes: 1 addition & 1 deletion stories/AbnormalObsControlStory.js
Expand Up @@ -104,10 +104,10 @@ storiesOf('Abnormal ObsControl', module)
.add('Basic View', () => (
<StoryWrapper json={metadata}>
<ObsGroupControl
errors={[]}
formName="f"
formVersion="1"
mapper={new ObsGroupMapper()}
errors={[]}
metadata={metadata}
obs={ pulseDataObs }
onValueChanged={() => {}}
Expand Down
25 changes: 25 additions & 0 deletions styles/bahmniAppsFormBuilder/_form.scss
Expand Up @@ -200,4 +200,29 @@

.form-builder-radio {
display: inline-block;
}

.form-builder-toggle {
.fa-caret-right{
display: block;
}
.fa-caret-down{
display: none;
}
&.active{
.fa-caret-right{
display: none;
}
.fa-caret-down{
display: block
}
}
}

.active-obsGroup-controls {
display: block;
}

.closing-obsGroup-controls {
display: none;
}
10 changes: 10 additions & 0 deletions test/components/Container.spec.js
Expand Up @@ -130,6 +130,16 @@ describe('Container', () => {
expect(wrapper).to.have.exactly(2).descendants('ObsControl');
});

it('should render form with collapse equals true', () => {
const wrapper = mount(
<Container collapse metadata={metadata} observations={[]} validate={false} />
);

expect(wrapper).to.have.exactly(3).descendants('Row');
expect(wrapper.find('Row').at(0).props().collapse).to.eql(true);
expect(wrapper.find('Row').at(1).props().collapse).to.eql(true);
});

it('should render form without controls when it is empty', () => {
const meta = { id: 100, name: 'Vitals', controls: [], uuid: 'uuid', version: '1' };
const wrapper = shallow(<Container metadata={meta} observations={[]} validate={false} />);
Expand Down
66 changes: 66 additions & 0 deletions test/components/ObsGroupControl.spec.js
Expand Up @@ -82,6 +82,24 @@ describe('ObsGroupControl', () => {
const obsGroupMapper = new ObsGroupMapper();

describe('render', () => {
it('should render obsGroup control collapse equals to true', () => {
const wrapper = mount(
<ObsGroupControl
collapse
formName={formName}
formVersion={formVersion}
mapper={obsGroupMapper}
metadata={metadata}
obs={observation}
onValueChanged={onChangeSpy}
validate={false}
/>);

expect(wrapper).to.have.exactly(3).descendants('DummyControl');
expect(wrapper.find('DummyControl').at(0).props().collapse).to.eql(true);
expect(wrapper.find('DummyControl').at(1).props().collapse).to.eql(true);
});

it('should render obsGroup control with observations', () => {
const wrapper = mount(
<ObsGroupControl
Expand Down Expand Up @@ -117,6 +135,54 @@ describe('ObsGroupControl', () => {
});


it('should collapse all child controls on click of collapse icon', () => {
const wrapper = mount(
<ObsGroupControl
collapse={false}
formName={formName}
formVersion={formVersion}
mapper={obsGroupMapper}
metadata={metadata}
obs={observation}
onValueChanged={onChangeSpy}
validate={false}
/>);

expect(wrapper.find('legend').props().className).to.eql('form-builder-toggle active');
expect(wrapper.find('div').at(0).props().className)
.to.eql('obsGroup-controls active-obsGroup-controls');

wrapper.find('legend').simulate('click');

expect(wrapper.find('legend').props().className).to.eql('form-builder-toggle ');
expect(wrapper.find('div').at(0).props().className)
.to.eql('obsGroup-controls closing-obsGroup-controls');
});

it('should collapse all child controls on change of collapse props', () => {
const wrapper = mount(
<ObsGroupControl
collapse={false}
formName={formName}
formVersion={formVersion}
mapper={obsGroupMapper}
metadata={metadata}
obs={observation}
onValueChanged={onChangeSpy}
validate={false}
/>);

expect(wrapper.find('legend').props().className).to.eql('form-builder-toggle active');
expect(wrapper.find('div').at(0).props().className)
.to.eql('obsGroup-controls active-obsGroup-controls');

wrapper.setProps({ collapse: true });

expect(wrapper.find('legend').props().className).to.eql('form-builder-toggle ');
expect(wrapper.find('div').at(0).props().className)
.to.eql('obsGroup-controls closing-obsGroup-controls');
});

it('should trigger onChange in obsGroup if its child obs has changed', () => {
const pulseNumericConcept = {
name: 'Pulse',
Expand Down
4 changes: 2 additions & 2 deletions test/helpers/formRenderer.spec.js
Expand Up @@ -46,11 +46,11 @@ describe('FormRenderer', () => {

it('should create container component with the supplied form details', () => {
React.createElement.withArgs(Container, sinon
.match({ metadata: formDetails })).returns('formControlsContainer');
.match({ metadata: formDetails, collapse: false })).returns('formControlsContainer');

document.getElementById.withArgs('someNodeId').returns('someOtherNodeId');

renderWithControls(formDetails, [], 'someNodeId'); // eslint-disable-line no-undef
renderWithControls(formDetails, [], 'someNodeId', false); // eslint-disable-line no-undef

sinon.assert.callCount(React.createElement, 1);
sinon.assert.calledWith(ReactDOM.render, 'formControlsContainer', 'someOtherNodeId');
Expand Down

0 comments on commit 5cbf7cd

Please sign in to comment.