1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

add sort strategies via react-dnd

This commit is contained in:
sveisvei 2016-12-30 23:24:46 +01:00
parent 4d5c901807
commit 7243dce22d
10 changed files with 119 additions and 41 deletions

View File

@ -40,6 +40,8 @@
"normalize.css": "^5.0.0", "normalize.css": "^5.0.0",
"react": "^15.3.1", "react": "^15.3.1",
"react-addons-css-transition-group": "^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-dom": "^15.3.1",
"react-mdl": "^1.9.0", "react-mdl": "^1.9.0",
"react-modal": "^1.6.4", "react-modal": "^1.6.4",

View File

@ -39,6 +39,10 @@ const prepare = (methods, dispatch) => {
methods.updateInList('strategies', index, n); methods.updateInList('strategies', index, n);
}; };
methods.moveStrategy = (index, toIndex) => {
methods.moveItem('strategies', index, toIndex);
};
methods.removeStrategy = (index) => { methods.removeStrategy = (index) => {
methods.removeFromList('strategies', index); methods.removeFromList('strategies', index);
}; };

View File

@ -45,6 +45,10 @@ const prepare = (methods, dispatch) => {
methods.removeFromList('strategies', index); methods.removeFromList('strategies', index);
}; };
methods.moveStrategy = (index, toIndex) => {
methods.moveItem('strategies', index, toIndex);
};
methods.updateStrategy = (index, n) => { methods.updateStrategy = (index, n) => {
methods.updateInList('strategies', index, n); methods.updateInList('strategies', index, n);
}; };

View File

@ -29,6 +29,7 @@ class AddFeatureToggleComponent extends Component {
addStrategy, addStrategy,
removeStrategy, removeStrategy,
updateStrategy, updateStrategy,
moveStrategy,
onSubmit, onSubmit,
onCancel, onCancel,
editmode = false, editmode = false,
@ -81,6 +82,7 @@ class AddFeatureToggleComponent extends Component {
configuredStrategies={configuredStrategies} configuredStrategies={configuredStrategies}
addStrategy={addStrategy} addStrategy={addStrategy}
updateStrategy={updateStrategy} updateStrategy={updateStrategy}
moveStrategy={moveStrategy}
removeStrategy={removeStrategy} /> removeStrategy={removeStrategy} />
<br /> <br />

View File

@ -1,6 +1,9 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import ConfigureStrategy from './strategy-configure'; 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 { class StrategiesList extends React.Component {
static propTypes () { static propTypes () {
@ -9,6 +12,7 @@ class StrategiesList extends React.Component {
configuredStrategies: PropTypes.array.isRequired, configuredStrategies: PropTypes.array.isRequired,
updateStrategy: PropTypes.func.isRequired, updateStrategy: PropTypes.func.isRequired,
removeStrategy: PropTypes.func.isRequired, removeStrategy: PropTypes.func.isRequired,
moveStrategy: PropTypes.func.isRequired,
}; };
} }
@ -16,6 +20,9 @@ class StrategiesList extends React.Component {
const { const {
strategies, strategies,
configuredStrategies, configuredStrategies,
moveStrategy,
removeStrategy,
updateStrategy,
} = this.props; } = this.props;
if (!configuredStrategies || configuredStrategies.length === 0) { if (!configuredStrategies || configuredStrategies.length === 0) {
@ -24,10 +31,12 @@ class StrategiesList extends React.Component {
const blocks = configuredStrategies.map((strategy, i) => ( const blocks = configuredStrategies.map((strategy, i) => (
<ConfigureStrategy <ConfigureStrategy
index={i}
key={`${strategy.name}-${i}`} key={`${strategy.name}-${i}`}
strategy={strategy} strategy={strategy}
removeStrategy={this.props.removeStrategy.bind(null, i)} moveStrategy={moveStrategy}
updateStrategy={this.props.updateStrategy.bind(null, i)} removeStrategy={removeStrategy.bind(null, i)}
updateStrategy={updateStrategy.bind(null, i)}
strategyDefinition={strategies.find(s => s.name === strategy.name)} /> strategyDefinition={strategies.find(s => s.name === strategy.name)} />
)); ));
return ( return (

View File

@ -4,6 +4,7 @@ import {
Card, CardTitle, CardText, CardActions, CardMenu, Card, CardTitle, CardText, CardActions, CardMenu,
IconButton, Icon, IconButton, Icon,
} from 'react-mdl'; } from 'react-mdl';
import { DragSource, DropTarget } from 'react-dnd';
import { Link } from 'react-router'; import { Link } from 'react-router';
import StrategyInputPercentage from './strategy-input-percentage'; import StrategyInputPercentage from './strategy-input-percentage';
import StrategyInputList from './strategy-input-list'; import StrategyInputList from './strategy-input-list';
@ -13,7 +14,6 @@ const style = {
minWidth: '300px', minWidth: '300px',
maxWidth: '100%', maxWidth: '100%',
margin: '5px 20px 15px 0px', margin: '5px 20px 15px 0px',
background: '#f2f9fc',
}; };
const helpText = { const helpText = {
@ -21,6 +21,34 @@ const helpText = {
fontSize: '12px', fontSize: '12px',
lineHeight: '14px', 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 { class StrategyConfigure extends React.Component {
static propTypes () { static propTypes () {
@ -29,13 +57,14 @@ class StrategyConfigure extends React.Component {
strategyDefinition: PropTypes.object.isRequired, strategyDefinition: PropTypes.object.isRequired,
updateStrategy: PropTypes.func.isRequired, updateStrategy: PropTypes.func.isRequired,
removeStrategy: 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) => { handleConfigChange = (key, e) => {
this.setConfig(key, e.target.value); this.setConfig(key, e.target.value);
}; };
@ -125,31 +154,16 @@ class StrategyConfigure extends React.Component {
} }
render () { render () {
if (!this.props.strategyDefinition) { const { isDragging, connectDragPreview, connectDragSource, connectDropTarget } = this.props;
const { name } = this.props.strategy;
return (
<Card shadow={0} style={style}>
<CardTitle>"{name}" deleted?</CardTitle>
<CardText>
The strategy "{name}" does not exist on this server.
<Link to={`/strategies/create?name=${name}`}>Want to create it now?</Link>
</CardText>
<CardActions>
<Button onClick={this.handleRemove} label="remove strategy" accent raised>Remove</Button>
</CardActions>
</Card>
);
}
let item;
if (this.props.strategyDefinition) {
const inputFields = this.renderInputFields(this.props.strategyDefinition); const inputFields = this.renderInputFields(this.props.strategyDefinition);
const { name } = this.props.strategy; const { name } = this.props.strategy;
item = (
return ( <Card shadow={0} style={{ background: '#f2f9fc', width: '100%', display: 'block', opacity: isDragging ? '0.1' : '1' }}>
<Card shadow={0} style={style}>
<CardTitle style={{ color: '#fff', height: '65px', background: '#607d8b' }}> <CardTitle style={{ color: '#fff', height: '65px', background: '#607d8b' }}>
<Icon name="extension" />&nbsp;{ name } <Icon name="extension" />&nbsp;{name}
</CardTitle> </CardTitle>
<CardText> <CardText>
{this.props.strategyDefinition.description} {this.props.strategyDefinition.description}
@ -168,9 +182,35 @@ class StrategyConfigure extends React.Component {
<Icon name="link" /> <Icon name="link" />
</Link> </Link>
<IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} /> <IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
{connectDragSource(
<span style={{
cursor: 'pointer',
display: 'inline-block',
verticalAlign: 'bottom',
}}><Icon name="reorder" /></span>)}
</CardMenu> </CardMenu>
</Card> </Card>
); );
} else {
const { name } = this.props.strategy;
item = (
<Card shadow={0} style={style}>
<CardTitle>"{name}" deleted?</CardTitle>
<CardText>
The strategy "{name}" does not exist on this server.
<Link to={`/strategies/create?name=${name}`}>Want to create it now?</Link>
</CardText>
<CardActions>
<Button onClick={this.handleRemove} label="remove strategy" accent raised>Remove</Button>
</CardActions>
</Card>
);
}
return (connectDropTarget(connectDragPreview(
<div style={style}>{item}</div>
)));
} }
} }

View File

@ -6,6 +6,7 @@ import {
createPush, createPush,
createUp, createUp,
createInit, createInit,
createMove,
} from '../store/input-actions'; } from '../store/input-actions';
function getId (id, ownProps) { function getId (id, ownProps) {
@ -57,6 +58,10 @@ export function createActions ({ id, prepare = (v) => v }) {
dispatch(createPop({ id: getId(id, ownProps), key, index })); 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) { updateInList (key, index, newValue, merge = false) {
dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge })); dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge }));
}, },

View File

@ -6,6 +6,7 @@ export const actions = {
LIST_UP: 'LIST_UP', LIST_UP: 'LIST_UP',
CLEAR: 'CLEAR', CLEAR: 'CLEAR',
INIT: 'INIT', INIT: 'INIT',
MOVE: 'MOVE',
}; };
export const createInit = ({ id, value }) => ({ type: actions.INIT, id, value }); 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 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 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 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 createUp = ({ id, key, index, newValue, merge }) => ({ type: actions.LIST_UP, id, key, index, newValue, merge });
export const createClear = ({ id }) => ({ type: actions.CLEAR, id }); export const createClear = ({ id }) => ({ type: actions.CLEAR, id });

View File

@ -69,6 +69,13 @@ function removeFromList (state, { id, key, index }) {
return state.updateIn(id.concat([key]), (list) => list.remove(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) => { const inputState = (state = getInitState(), action) => {
if (!action.id) { if (!action.id) {
return state; return state;
@ -88,6 +95,8 @@ const inputState = (state = getInitState(), action) => {
return addToList(state, action); return addToList(state, action);
case actions.LIST_POP: case actions.LIST_POP:
return removeFromList(state, action); return removeFromList(state, action);
case actions.MOVE:
return move(state, action);
case actions.LIST_UP: case actions.LIST_UP:
return updateInList(state, action); return updateInList(state, action);
case actions.CLEAR: case actions.CLEAR:

View File

@ -1,5 +1,6 @@
{ {
"globalDependencies": { "globalDependencies": {
"react-dnd": "registry:dt/react-dnd#2.0.2+20161111212335",
"react-mdl": "registry:dt/react-mdl#0.0.0+20160830142027" "react-mdl": "registry:dt/react-mdl#0.0.0+20160830142027"
} }
} }