1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-13 11:17:26 +02:00
unleash.unleash/frontend/src/component/feature/form/strategy-configure.jsx
2020-05-22 19:34:47 +02:00

299 lines
11 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import {
Textfield,
Button,
Card,
CardTitle,
CardText,
CardActions,
CardMenu,
IconButton,
Icon,
Switch,
Tooltip,
} from 'react-mdl';
import { DragSource, DropTarget } from 'react-dnd';
import { Link } from 'react-router-dom';
import flow from 'lodash/flow';
import StrategyInputPercentage from './strategy-input-percentage';
import FlexibleRolloutStrategyInput from './flexible-rollout-strategy-input';
import StrategyInputList from './strategy-input-list';
import styles from './strategy.scss';
const dragSource = {
beginDrag(props) {
return {
id: props.id,
index: props.index,
};
},
endDrag(props, monitor) {
if (!monitor.didDrop()) {
return;
}
const result = monitor.getDropResult();
if (typeof result.index === 'number' && props.index !== result.index) {
props.moveStrategy(props.index, result.index);
}
},
};
const dragTarget = {
drop(props) {
return {
index: props.index,
};
},
};
/**
* Specifies which props to inject into your component.
*/
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging(),
};
}
function collectTarget(connect, monitor) {
return {
highlighted: monitor.canDrop(),
hovered: monitor.isOver(),
connectDropTarget: connect.dropTarget(),
};
}
class StrategyConfigure extends React.Component {
/* eslint-enable */
static propTypes = {
strategy: PropTypes.object.isRequired,
featureToggleName: PropTypes.string.isRequired,
strategyDefinition: PropTypes.object,
updateStrategy: PropTypes.func,
removeStrategy: PropTypes.func,
moveStrategy: PropTypes.func,
isDragging: PropTypes.bool.isRequired,
connectDragPreview: PropTypes.func.isRequired,
connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
};
handleConfigChange = (key, e) => {
this.setConfig(key, e.target.value);
};
handleSwitchChange = (key, currentValue) => {
const value = currentValue === 'false' ? 'true' : 'false';
this.setConfig(key, value);
};
setConfig = (key, value) => {
const parameters = this.props.strategy.parameters || {};
parameters[key] = value;
const updatedStrategy = Object.assign({}, this.props.strategy, {
parameters,
});
this.props.updateStrategy(updatedStrategy);
};
handleRemove = evt => {
evt.preventDefault();
this.props.removeStrategy();
};
renderStrategContent(strategyDefinition) {
if (strategyDefinition.name === 'default') {
return <h6>{strategyDefinition.description}</h6>;
}
if (strategyDefinition.name === 'flexibleRollout') {
return (
<FlexibleRolloutStrategyInput
strategy={this.props.strategy}
featureToggleName={this.props.featureToggleName}
updateStrategy={this.props.updateStrategy}
handleConfigChange={this.handleConfigChange.bind(this)}
/>
);
} else {
return <div>{this.renderInputFields(strategyDefinition)}</div>;
}
}
renderInputFields({ parameters }) {
if (parameters && parameters.length > 0) {
return parameters.map(({ name, type, description, required }) => {
let value = this.props.strategy.parameters[name];
if (type === 'percentage') {
if (value == null || (typeof value === 'string' && value === '')) {
this.setConfig(name, 50);
}
return (
<div key={name}>
<StrategyInputPercentage
name={name}
onChange={this.handleConfigChange.bind(this, name)}
value={1 * value}
minLabel="off"
maxLabel="on"
/>
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else if (type === 'list') {
let list = [];
if (typeof value === 'string') {
list = value
.trim()
.split(',')
.filter(Boolean);
}
return (
<div key={name}>
<StrategyInputList
name={name}
list={list}
disabled={!this.props.updateStrategy}
setConfig={this.setConfig}
/>
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else if (type === 'number') {
return (
<div key={name}>
<Textfield
pattern="-?[0-9]*(\.[0-9]+)?"
error={`${name} is not a number!`}
floatingLabel
required={required}
style={{ width: '100%' }}
name={name}
label={name}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
/>
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else if (type === 'boolean') {
if (!value) {
this.handleSwitchChange(name, value);
}
return (
<div key={name}>
<Switch
onChange={this.handleSwitchChange.bind(this, name, value)}
checked={value === 'true'}
>
{name}{' '}
{description && (
<Tooltip label={description}>
<Icon name="info" style={{ color: 'rgba(0, 0, 0, 0.7)', fontSize: '1em' }} />
</Tooltip>
)}
</Switch>
</div>
);
} else {
if (name === 'groupId' && !value) {
this.setConfig('groupId', this.props.featureToggleName);
}
return (
<div key={name}>
<Textfield
floatingLabel
rows={1}
style={{ width: '100%' }}
required={required}
name={name}
label={name}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
/>
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
}
});
}
return null;
}
render() {
const { isDragging, connectDragPreview, connectDragSource, connectDropTarget } = this.props;
let item;
if (this.props.strategyDefinition) {
const description = this.props.strategyDefinition.description;
const strategyContent = this.renderStrategContent(this.props.strategyDefinition);
const { name } = this.props.strategy;
item = (
<Card
shadow={0}
className={styles.card}
style={{ opacity: isDragging ? '0.1' : '1', overflow: 'visible' }}
>
<CardTitle className={styles.cardTitle} title={description}>
<Icon name="extension" />
&nbsp;
{name}
</CardTitle>
{strategyContent && <CardActions border>{strategyContent}</CardActions>}
<CardMenu className="mdl-color-text--white">
<Link
title="View strategy"
to={`/strategies/view/${name}`}
className={styles.editLink}
title={description}
>
<Icon name="info" />
</Link>
{this.props.removeStrategy ? (
<IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
) : (
<span />
)}
{connectDragSource(
<span className={styles.reorderIcon}>
<Icon name="reorder" />
</span>
)}
</CardMenu>
</Card>
);
} else {
const { name } = this.props.strategy;
item = (
<Card shadow={0} className={styles.card}>
<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 connectDragPreview(connectDropTarget(<div className={styles.item}>{item}</div>));
}
}
const type = 'strategy';
export default flow(
// eslint-disable-next-line new-cap
DragSource(type, dragSource, collect),
// eslint-disable-next-line new-cap
DropTarget(type, dragTarget, collectTarget)
)(StrategyConfigure);