diff --git a/frontend/package.json b/frontend/package.json
index 33830e2bc6..fb008f2ff7 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -40,6 +40,8 @@
"normalize.css": "^5.0.0",
"react": "^15.3.1",
"react-addons-css-transition-group": "^15.3.1",
+ "react-dnd": "^2.1.4",
+ "react-dnd-html5-backend": "^2.1.2",
"react-dom": "^15.3.1",
"react-mdl": "^1.9.0",
"react-modal": "^1.6.4",
diff --git a/frontend/src/component/feature/form-add-container.jsx b/frontend/src/component/feature/form-add-container.jsx
index 3afb20b3c2..e153aee10c 100644
--- a/frontend/src/component/feature/form-add-container.jsx
+++ b/frontend/src/component/feature/form-add-container.jsx
@@ -39,6 +39,10 @@ const prepare = (methods, dispatch) => {
methods.updateInList('strategies', index, n);
};
+ methods.moveStrategy = (index, toIndex) => {
+ methods.moveItem('strategies', index, toIndex);
+ };
+
methods.removeStrategy = (index) => {
methods.removeFromList('strategies', index);
};
diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx
index 7f592804f8..7605b994af 100644
--- a/frontend/src/component/feature/form-edit-container.jsx
+++ b/frontend/src/component/feature/form-edit-container.jsx
@@ -45,6 +45,10 @@ const prepare = (methods, dispatch) => {
methods.removeFromList('strategies', index);
};
+ methods.moveStrategy = (index, toIndex) => {
+ methods.moveItem('strategies', index, toIndex);
+ };
+
methods.updateStrategy = (index, n) => {
methods.updateInList('strategies', index, n);
};
diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx
index ca570a41e2..40417d4e1a 100644
--- a/frontend/src/component/feature/form/index.jsx
+++ b/frontend/src/component/feature/form/index.jsx
@@ -29,6 +29,7 @@ class AddFeatureToggleComponent extends Component {
addStrategy,
removeStrategy,
updateStrategy,
+ moveStrategy,
onSubmit,
onCancel,
editmode = false,
@@ -81,6 +82,7 @@ class AddFeatureToggleComponent extends Component {
configuredStrategies={configuredStrategies}
addStrategy={addStrategy}
updateStrategy={updateStrategy}
+ moveStrategy={moveStrategy}
removeStrategy={removeStrategy} />
diff --git a/frontend/src/component/feature/form/strategies-list.jsx b/frontend/src/component/feature/form/strategies-list.jsx
index 1c4b04a576..3bf2d8d84a 100644
--- a/frontend/src/component/feature/form/strategies-list.jsx
+++ b/frontend/src/component/feature/form/strategies-list.jsx
@@ -1,6 +1,9 @@
import React, { PropTypes } from 'react';
import ConfigureStrategy from './strategy-configure';
+import { DragDropContext } from 'react-dnd';
+import HTML5Backend from 'react-dnd-html5-backend';
+@DragDropContext(HTML5Backend) // eslint-disable-line new-cap
class StrategiesList extends React.Component {
static propTypes () {
@@ -9,6 +12,7 @@ class StrategiesList extends React.Component {
configuredStrategies: PropTypes.array.isRequired,
updateStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired,
+ moveStrategy: PropTypes.func.isRequired,
};
}
@@ -16,6 +20,9 @@ class StrategiesList extends React.Component {
const {
strategies,
configuredStrategies,
+ moveStrategy,
+ removeStrategy,
+ updateStrategy,
} = this.props;
if (!configuredStrategies || configuredStrategies.length === 0) {
@@ -24,10 +31,12 @@ class StrategiesList extends React.Component {
const blocks = configuredStrategies.map((strategy, i) => (
s.name === strategy.name)} />
));
return (
diff --git a/frontend/src/component/feature/form/strategy-configure.jsx b/frontend/src/component/feature/form/strategy-configure.jsx
index 3da5d7bc18..12e09944a2 100644
--- a/frontend/src/component/feature/form/strategy-configure.jsx
+++ b/frontend/src/component/feature/form/strategy-configure.jsx
@@ -3,7 +3,8 @@ import {
Textfield, Button,
Card, CardTitle, CardText, CardActions, CardMenu,
IconButton, Icon,
-} from 'react-mdl';
+} from 'react-mdl';
+import { DragSource, DropTarget } from 'react-dnd';
import { Link } from 'react-router';
import StrategyInputPercentage from './strategy-input-percentage';
import StrategyInputList from './strategy-input-list';
@@ -13,7 +14,6 @@ const style = {
minWidth: '300px',
maxWidth: '100%',
margin: '5px 20px 15px 0px',
- background: '#f2f9fc',
};
const helpText = {
@@ -21,6 +21,34 @@ const helpText = {
fontSize: '12px',
lineHeight: '14px',
};
+
+
+const dragSource = {
+ beginDrag (props) {
+ return {
+ index: props.index,
+ };
+ },
+};
+
+const dragTarget = {
+ drop (props, monitor) {
+ const dragIndex = monitor.getItem().index;
+ const toIndex = props.index;
+ if (dragIndex !== toIndex) {
+ props.moveStrategy(dragIndex, toIndex);
+ }
+ },
+};
+
+@DropTarget('strategy', dragTarget, connect => ({ // eslint-disable-line new-cap
+ connectDropTarget: connect.dropTarget(),
+}))
+@DragSource('strategy', dragSource, (connect, monitor) => ({ // eslint-disable-line new-cap
+ connectDragSource: connect.dragSource(),
+ connectDragPreview: connect.dragPreview(),
+ isDragging: monitor.isDragging(),
+}))
class StrategyConfigure extends React.Component {
static propTypes () {
@@ -29,13 +57,14 @@ class StrategyConfigure extends React.Component {
strategyDefinition: PropTypes.object.isRequired,
updateStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired,
+ moveStrategy: PropTypes.func.isRequired,
+ isDragging: PropTypes.bool.isRequired,
+ connectDragPreview: PropTypes.func.isRequired,
+ connectDragSource: PropTypes.func.isRequired,
+ connectDropTarget: PropTypes.func.isRequired,
};
}
- // shouldComponentUpdate (props, nextProps) {
- // console.log({ props, nextProps });
- // }
-
handleConfigChange = (key, e) => {
this.setConfig(key, e.target.value);
};
@@ -98,7 +127,7 @@ class StrategyConfigure extends React.Component {
label={name}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
- />
+ />
{description && {description}
}
);
@@ -114,7 +143,7 @@ class StrategyConfigure extends React.Component {
label={name}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
- />
+ />
{description && {description}
}
);
@@ -125,9 +154,46 @@ class StrategyConfigure extends React.Component {
}
render () {
- if (!this.props.strategyDefinition) {
+ const { isDragging, connectDragPreview, connectDragSource, connectDropTarget } = this.props;
+
+ let item;
+ if (this.props.strategyDefinition) {
+ const inputFields = this.renderInputFields(this.props.strategyDefinition);
const { name } = this.props.strategy;
- return (
+ item = (
+
+
+ {name}
+
+
+ {this.props.strategyDefinition.description}
+
+ {
+ inputFields &&
+ {inputFields}
+
+ }
+
+
+
+
+
+
+ {connectDragSource(
+ )}
+
+
+ );
+ } else {
+ const { name } = this.props.strategy;
+ item = (
"{name}" deleted?
@@ -142,35 +208,9 @@ class StrategyConfigure extends React.Component {
);
}
- const inputFields = this.renderInputFields(this.props.strategyDefinition);
-
- const { name } = this.props.strategy;
-
- return (
-
-
- { name }
-
-
- {this.props.strategyDefinition.description}
-
- {
- inputFields &&
- {inputFields}
-
- }
-
-
-
-
-
-
-
-
- );
+ return (connectDropTarget(connectDragPreview(
+ {item}
+ )));
}
}
diff --git a/frontend/src/component/input-helpers.js b/frontend/src/component/input-helpers.js
index c0b24790bc..d3c734422c 100644
--- a/frontend/src/component/input-helpers.js
+++ b/frontend/src/component/input-helpers.js
@@ -6,6 +6,7 @@ import {
createPush,
createUp,
createInit,
+ createMove,
} from '../store/input-actions';
function getId (id, ownProps) {
@@ -57,6 +58,10 @@ export function createActions ({ id, prepare = (v) => v }) {
dispatch(createPop({ id: getId(id, ownProps), key, index }));
},
+ moveItem (key, index, toIndex) {
+ dispatch(createMove({ id: getId(id, ownProps), key, index, toIndex }));
+ },
+
updateInList (key, index, newValue, merge = false) {
dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge }));
},
diff --git a/frontend/src/store/input-actions.js b/frontend/src/store/input-actions.js
index 5b6f5bead6..39dbd3d707 100644
--- a/frontend/src/store/input-actions.js
+++ b/frontend/src/store/input-actions.js
@@ -6,6 +6,7 @@ export const actions = {
LIST_UP: 'LIST_UP',
CLEAR: 'CLEAR',
INIT: 'INIT',
+ MOVE: 'MOVE',
};
export const createInit = ({ id, value }) => ({ type: actions.INIT, id, value });
@@ -13,6 +14,7 @@ export const createInc = ({ id, key }) => ({ type: actions.INCREMENT_VALUE, id,
export const createSet = ({ id, key, value }) => ({ type: actions.SET_VALUE, id, key, value });
export const createPush = ({ id, key, value }) => ({ type: actions.LIST_PUSH, id, key, value });
export const createPop = ({ id, key, index }) => ({ type: actions.LIST_POP, id, key, index });
+export const createMove = ({ id, key, index, toIndex }) => ({ type: actions.MOVE, id, key, index, toIndex });
export const createUp = ({ id, key, index, newValue, merge }) => ({ type: actions.LIST_UP, id, key, index, newValue, merge });
export const createClear = ({ id }) => ({ type: actions.CLEAR, id });
diff --git a/frontend/src/store/input-store.js b/frontend/src/store/input-store.js
index 743c7c570f..cc0a3c7075 100644
--- a/frontend/src/store/input-store.js
+++ b/frontend/src/store/input-store.js
@@ -69,6 +69,13 @@ function removeFromList (state, { id, key, index }) {
return state.updateIn(id.concat([key]), (list) => list.remove(index));
}
+function move (state, { id, key, index, toIndex }) {
+ return state.updateIn(id.concat([key]), list => {
+ const olditem = list.get(index);
+ return list.delete(index).insert(toIndex, olditem);
+ });
+}
+
const inputState = (state = getInitState(), action) => {
if (!action.id) {
return state;
@@ -88,6 +95,8 @@ const inputState = (state = getInitState(), action) => {
return addToList(state, action);
case actions.LIST_POP:
return removeFromList(state, action);
+ case actions.MOVE:
+ return move(state, action);
case actions.LIST_UP:
return updateInList(state, action);
case actions.CLEAR:
diff --git a/frontend/typings.json b/frontend/typings.json
index a00f27177e..2f1203b9cc 100644
--- a/frontend/typings.json
+++ b/frontend/typings.json
@@ -1,5 +1,6 @@
{
"globalDependencies": {
+ "react-dnd": "registry:dt/react-dnd#2.0.2+20161111212335",
"react-mdl": "registry:dt/react-mdl#0.0.0+20160830142027"
}
}