Commit a477e61a authored by hh1966's avatar hh1966
Browse files

Add drag and drop to research plan and reorganize components

parent 56087d86
Pipeline #50245 failed with stage
......@@ -5,6 +5,7 @@ export default {
WELLPLATE: 'wellplate',
MOLECULE: 'molecule',
RESEARCH_PLAN: 'research_plan',
RESEARCH_PLAN_FIELD: 'research_plan_field',
LAYOUT: 'layout',
GENERAL: 'general',
DATA: 'data',
......
......@@ -23,9 +23,9 @@ import SpinnerPencilIcon from './common/SpinnerPencilIcon';
import ImageModal from './common/ImageModal';
import LoadingActions from './actions/LoadingActions';
import NameField from './research_plan/NameField';
import RichTextField from './research_plan/RichTextField';
import KetcherField from './research_plan/KetcherField';
import ResearchPlanDetailsNameField from './research_plan/ResearchPlanDetailsNameField';
import ResearchPlanDetailsBody from './research_plan/ResearchPlanDetailsBody';
const editorTooltip = exts => <Tooltip id="editor_tooltip">Available extensions: {exts}</Tooltip>;
......@@ -373,33 +373,28 @@ export default class ResearchPlanDetails extends Component {
});
}
handleBodyDrop(source, target) {
let {research_plan} = this.state
research_plan.body.splice(target, 0, research_plan.body.splice(source, 1)[0]);
this.setState({
research_plan: research_plan
});
}
propertiesTab(research_plan) {
const { name, body } = research_plan;
const submitLabel = research_plan.isNew ? "Create" : "Save";
const disabled = research_plan.isMethodDisabled('body')
let bodyFields = body.map((field, index) => {
switch (field.type) {
case 'richtext':
return <RichTextField key={field.id}
field={field} index={index} disabled={disabled}
onChange={this.handleBodyChange.bind(this)} />
break;
case 'ketcher':
return <KetcherField key={field.id}
field={field} index={index} disabled={disabled}
onChange={this.handleBodyChange.bind(this)} />
break;
}
})
return (
<ListGroup fill="true">
<ListGroupItem>
<NameField value={name} disabled={research_plan.isMethodDisabled('name')}
<ResearchPlanDetailsNameField value={name} disabled={research_plan.isMethodDisabled('name')}
onChange={this.handleNameChange.bind(this)} />
{bodyFields}
<ResearchPlanDetailsBody body={body} disabled={research_plan.isMethodDisabled('body')}
onChange={this.handleBodyChange.bind(this)}
onDrop={this.handleBodyDrop.bind(this)} />
<Row>
<Col md={12}>
<FormGroup>
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Row } from 'react-bootstrap';
import Field from './ResearchPlanDetailsField';
export default class ResearchPlanDetailsBody extends Component {
constructor(props) {
super(props)
const { body, disabled, onChange, onDrop } = props
this.state = {
body,
disabled,
onChange,
onDrop
}
}
render() {
let { body, disabled, onChange, onDrop } = this.state
let fields = body.map((field, index) => {
return <Field key={field.id}
field={field} index={index} disabled={disabled}
onChange={onChange.bind(this)}
onDrop={onDrop.bind(this)} />
})
return (
<Row className="research-plan-details-body">
{fields}
</Row>
)
}
}
ResearchPlanDetailsBody.propTypes = {
body: PropTypes.array,
disabled: PropTypes.bool,
onChange: PropTypes.func,
onDrop: PropTypes.func,
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { DragSource } from 'react-dnd';
import DragDropItemTypes from '../DragDropItemTypes';
const spec = {
beginDrag(props) {
return {
index: props.index
}
},
endDrag(props, monitor) {
let target = monitor.getDropResult()
props.onDrop(props.index, target.index)
}
};
const collect = (connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
});
class ResearchPlanDetailsDragSource extends Component {
render() {
const { connectDragSource, index } = this.props
return connectDragSource(<span className="fa fa-arrows dnd-arrow-enable text-info drag-source" />)
}
};
export default DragSource(DragDropItemTypes.RESEARCH_PLAN_FIELD, spec, collect)(ResearchPlanDetailsDragSource)
ResearchPlanDetailsDragSource.propTypes = {
index: PropTypes.number,
onChange: PropTypes.func,
};
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import DragDropItemTypes from '../DragDropItemTypes';
const spec = {
drop(props) {
return {
index: props.index
}
}
};
const collect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
});
class ResearchPlanDetailsDropTarget extends Component {
render() {
const {index, connectDropTarget, isOver, canDrop} = this.props;
let className = 'drop-target'
if (isOver) {
className += ' is-over'
}
if (canDrop) {
className += ' can-drop'
}
return connectDropTarget(
<div className={className}>
<div className="indicator" />
</div>
)
}
};
export default DropTarget(DragDropItemTypes.RESEARCH_PLAN_FIELD, spec, collect)(ResearchPlanDetailsDropTarget);
ResearchPlanDetailsDropTarget.propTypes = {
index: PropTypes.number
};
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Col } from 'react-bootstrap';
import ResearchPlanDetailsDragSource from './ResearchPlanDetailsDragSource'
import ResearchPlanDetailsDropTarget from './ResearchPlanDetailsDropTarget';
import RichTextField from './ResearchPlanDetailsRichTextField';
import KetcherField from './ResearchPlanDetailsKetcherField';
export default class ResearchPlanDetailsField extends Component {
render() {
let { field, index, disabled, onChange, onDrop } = this.props
let field_component
switch (field.type) {
case 'richtext':
field_component = <RichTextField key={field.id}
field={field} index={index} disabled={disabled}
onChange={onChange.bind(this)} />
break;
case 'ketcher':
field_component = <KetcherField key={field.id}
field={field} index={index} disabled={disabled}
onChange={onChange.bind(this)} />
break;
}
return (
<Col md={12}>
<ResearchPlanDetailsDragSource index={index} onDrop={onDrop.bind(this)}/>
<ResearchPlanDetailsDropTarget index={index}/>
<FormGroup>
{field_component}
</FormGroup>
</Col>
)
}
}
ResearchPlanDetailsField.propTypes = {
field: PropTypes.object,
index: PropTypes.number,
disabled: PropTypes.bool,
onChange: PropTypes.func,
onDrop: PropTypes.func,
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Row, Col, Glyphicon } from 'react-bootstrap';
import { Glyphicon } from 'react-bootstrap';
import SVG from 'react-inlinesvg';
import { includes, last, findKey, values } from 'lodash';
......@@ -8,7 +8,7 @@ import ResearchPlansFetcher from '../fetchers/ResearchPlansFetcher';
import StructureEditorModal from '../structure_editor/StructureEditorModal';
import QuillEditor from '../QuillEditor';
export default class KetcherField extends Component {
export default class ResearchPlanDetailsKetcherField extends Component {
constructor(props) {
super(props)
......@@ -91,23 +91,17 @@ export default class KetcherField extends Component {
const imageDefault = !includes(svgPath, 'no_image_180.svg');
return (
<Row>
<Col md={12}>
<FormGroup>
<div className={className}
onClick={this.showStructureEditor.bind(this)} >
<Glyphicon className="pull-right" glyph="pencil" />
<SVG key={svgPath} src={svgPath} className="molecule-mid" />
</div>
</FormGroup>
</Col>
<div className={className}
onClick={this.showStructureEditor.bind(this)} >
<Glyphicon className="pull-right" glyph="pencil" />
<SVG key={svgPath} src={svgPath} className="molecule-mid" />
{this.renderStructureEditorModal(field)}
</Row>
</div>
)
}
}
KetcherField.propTypes = {
ResearchPlanDetailsKetcherField.propTypes = {
field: PropTypes.object,
index: PropTypes.number,
disabled: PropTypes.bool,
......
......@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { ControlLabel, FormControl, FormGroup, Row, Col } from 'react-bootstrap';
export default class NameField extends Component {
export default class ResearchPlanDetailsNameField extends Component {
constructor(props) {
super(props)
......@@ -47,7 +47,7 @@ export default class NameField extends Component {
}
}
NameField.propTypes = {
ResearchPlanDetailsNameField.propTypes = {
value: PropTypes.string,
disabled: PropTypes.bool,
onChange: PropTypes.func,
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Row, Col } from 'react-bootstrap';
import QuillEditor from '../QuillEditor';
export default class RichTextField extends Component {
export default class ResearchPlanDetailsRichTextField extends Component {
constructor(props) {
super(props)
......@@ -33,21 +32,15 @@ export default class RichTextField extends Component {
let { field, disabled } = this.state
return (
<Row>
<Col md={12}>
<FormGroup>
<QuillEditor value={field.value}
onChange={this.handleChange.bind(this)}
disabled={disabled}
/>
</FormGroup>
</Col>
</Row>
<QuillEditor value={field.value}
onChange={this.handleChange.bind(this)}
disabled={disabled}
/>
)
}
}
RichTextField.propTypes = {
ResearchPlanDetailsRichTextField.propTypes = {
field: PropTypes.object,
index: PropTypes.number,
disabled: PropTypes.bool,
......
.research-plan-details-body {
.form-group {
position: relative;
margin-bottom: 0;
}
.drag-source {
float: right;
margin-top: 10px;
margin-bottom: 6px;
}
.drop-target {
height: 40px;
.indicator {
height: 24px;
margin-right: 35px;
}
&.can-drop {
.indicator {
border-bottom: 4px dashed lightgray;
}
}
&.is-over {
.indicator {
border-bottom: 4px solid lightgray;
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment