mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-09 01:17:06 +02:00
add fields to strategies
This commit is contained in:
parent
66527bf085
commit
821bf0e19b
@ -29,9 +29,7 @@ export const HeaderTitle = ({ title, actions, subtitle }) => (
|
|||||||
{subtitle && <small>{subtitle}</small>}
|
{subtitle && <small>{subtitle}</small>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ flex: '1', textAlign: 'right' }}>
|
{actions && <div style={{ flex: '1', textAlign: 'right' }}>{actions}</div>}
|
||||||
{actions}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -14,9 +14,8 @@ class AddStrategy extends React.Component {
|
|||||||
addStrategy = (strategyName) => {
|
addStrategy = (strategyName) => {
|
||||||
const selectedStrategy = this.props.strategies.find(s => s.name === strategyName);
|
const selectedStrategy = this.props.strategies.find(s => s.name === strategyName);
|
||||||
const parameters = {};
|
const parameters = {};
|
||||||
const keys = Object.keys(selectedStrategy.parametersTemplate || {});
|
|
||||||
keys.forEach(prop => { parameters[prop] = ''; });
|
|
||||||
|
|
||||||
|
selectedStrategy.parameters.forEach(({ name }) => { parameters[name] = ''; });
|
||||||
|
|
||||||
this.props.addStrategy({
|
this.props.addStrategy({
|
||||||
name: selectedStrategy.name,
|
name: selectedStrategy.name,
|
||||||
@ -40,7 +39,9 @@ class AddStrategy extends React.Component {
|
|||||||
<IconButton name="add" id="strategies-add" raised accent title="Add Strategy" onClick={this.stopPropagation}/>
|
<IconButton name="add" id="strategies-add" raised accent title="Add Strategy" onClick={this.stopPropagation}/>
|
||||||
<Menu target="strategies-add" valign="bottom" align="right" ripple style={menuStyle}>
|
<Menu target="strategies-add" valign="bottom" align="right" ripple style={menuStyle}>
|
||||||
<MenuItem disabled>Add Strategy:</MenuItem>
|
<MenuItem disabled>Add Strategy:</MenuItem>
|
||||||
{this.props.strategies.map((s) => <MenuItem key={s.name} onClick={() => this.addStrategy(s.name)}>{s.name}</MenuItem>)}
|
{this.props.strategies.map((s) =>
|
||||||
|
<MenuItem key={s.name} title={s.description} onClick={() => this.addStrategy(s.name)}>{s.name}</MenuItem>)
|
||||||
|
}
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -22,13 +22,13 @@ class StrategiesList extends React.Component {
|
|||||||
return <i style={{ color: 'red' }}>No strategies added</i>;
|
return <i style={{ color: 'red' }}>No strategies added</i>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const blocks = configuredStrategies.map((strat, i) => (
|
const blocks = configuredStrategies.map((strategy, i) => (
|
||||||
<ConfigureStrategy
|
<ConfigureStrategy
|
||||||
key={`${strat.name}-${i}`}
|
key={`${strategy.name}-${i}`}
|
||||||
strategy={strat}
|
strategy={strategy}
|
||||||
removeStrategy={this.props.removeStrategy.bind(null, i)}
|
removeStrategy={this.props.removeStrategy.bind(null, i)}
|
||||||
updateStrategy={this.props.updateStrategy.bind(null, i)}
|
updateStrategy={this.props.updateStrategy.bind(null, i)}
|
||||||
strategyDefinition={strategies.find(s => s.name === strat.name)} />
|
strategyDefinition={strategies.find(s => s.name === strategy.name)} />
|
||||||
));
|
));
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||||
|
@ -47,24 +47,23 @@ class StrategyConfigure extends React.Component {
|
|||||||
this.props.removeStrategy();
|
this.props.removeStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInputFields (strategyDefinition) {
|
renderInputFields ({ parameters }) {
|
||||||
if (strategyDefinition.parametersTemplate) {
|
if (parameters && parameters.length > 0) {
|
||||||
const keys = Object.keys(strategyDefinition.parametersTemplate);
|
return parameters.map(({ name, type, description, required }) => {
|
||||||
if (keys.length === 0) {
|
let value = this.props.strategy.parameters[name];
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return keys.map(field => {
|
|
||||||
const type = strategyDefinition.parametersTemplate[field];
|
|
||||||
let value = this.props.strategy.parameters[field];
|
|
||||||
if (type === 'percentage') {
|
if (type === 'percentage') {
|
||||||
if (value == null || (typeof value === 'string' && value === '')) {
|
if (value == null || (typeof value === 'string' && value === '')) {
|
||||||
value = 50; // default value
|
value = 50; // default value
|
||||||
}
|
}
|
||||||
return (<StrategyInputPersentage
|
return (
|
||||||
key={field}
|
<div key={name}>
|
||||||
field={field}
|
<StrategyInputPersentage
|
||||||
onChange={this.handleConfigChange.bind(this, field)}
|
name={name}
|
||||||
value={1 * value} />);
|
onChange={this.handleConfigChange.bind(this, name)}
|
||||||
|
value={1 * value} />
|
||||||
|
{description && <p>{description}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else if (type === 'list') {
|
} else if (type === 'list') {
|
||||||
let list = [];
|
let list = [];
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
@ -73,33 +72,44 @@ class StrategyConfigure extends React.Component {
|
|||||||
.split(',')
|
.split(',')
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
return (<StrategyInputList key={field} field={field} list={list} setConfig={this.setConfig} />);
|
return (
|
||||||
|
<div key={name}>
|
||||||
|
<StrategyInputList name={name} list={list} setConfig={this.setConfig} />
|
||||||
|
{description && <p>{description}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else if (type === 'number') {
|
} else if (type === 'number') {
|
||||||
return (
|
return (
|
||||||
<Textfield
|
<div key={name}>
|
||||||
pattern="-?[0-9]*(\.[0-9]+)?"
|
<Textfield
|
||||||
error={`${field} is not a number!`}
|
pattern="-?[0-9]*(\.[0-9]+)?"
|
||||||
floatingLabel
|
error={`${name} is not a number!`}
|
||||||
style={{ width: '100%' }}
|
floatingLabel
|
||||||
key={field}
|
required={required}
|
||||||
name={field}
|
style={{ width: '100%' }}
|
||||||
label={field}
|
name={name}
|
||||||
onChange={this.handleConfigChange.bind(this, field)}
|
label={name}
|
||||||
value={value}
|
onChange={this.handleConfigChange.bind(this, name)}
|
||||||
/>
|
value={value}
|
||||||
|
/>
|
||||||
|
{description && <p>{description}</p>}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Textfield
|
<div key={name}>
|
||||||
floatingLabel
|
<Textfield
|
||||||
rows={2}
|
floatingLabel
|
||||||
style={{ width: '100%' }}
|
rows={2}
|
||||||
key={field}
|
style={{ width: '100%' }}
|
||||||
name={field}
|
required={required}
|
||||||
label={field}
|
name={name}
|
||||||
onChange={this.handleConfigChange.bind(this, field)}
|
label={name}
|
||||||
value={value}
|
onChange={this.handleConfigChange.bind(this, name)}
|
||||||
/>
|
value={value}
|
||||||
|
/>
|
||||||
|
{description && <p>{description}</p>}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,36 +1,80 @@
|
|||||||
import React from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import {
|
import {
|
||||||
Textfield,
|
Textfield,
|
||||||
IconButton,
|
IconButton,
|
||||||
Chip,
|
Chip,
|
||||||
} from 'react-mdl';
|
} from 'react-mdl';
|
||||||
|
|
||||||
export default ({ field, list, setConfig }) => (
|
export default class InputList extends Component {
|
||||||
<div style={{ margin: '16px 20px' }}>
|
|
||||||
<h6>{field}</h6>
|
|
||||||
{list.map((entryValue, index) => (
|
|
||||||
<Chip style={{ marginRight: '3px' }} onClose={() => {
|
|
||||||
list[index] = null;
|
|
||||||
setConfig(field, list.filter(Boolean).join(','));
|
|
||||||
}}>{entryValue}</Chip>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<form style={{ display: 'block', padding: 0, margin: 0 }} onSubmit={(e) => {
|
static propTypes = {
|
||||||
|
field: PropTypes.string.isRequired,
|
||||||
|
list: PropTypes.array.isRequired,
|
||||||
|
setConfig: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur = (e) => {
|
||||||
|
this.setValue(e);
|
||||||
|
window.removeEventListener('keydown', this.onKeyHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
window.addEventListener('keydown', this.onKeyHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyHandler = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.setValue();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue = (e) => {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { field, list, setConfig } = this.props;
|
||||||
|
const inputValue = document.querySelector(`[name="${field}_input"]`);
|
||||||
|
if (inputValue && inputValue.value) {
|
||||||
|
list.push(inputValue.value);
|
||||||
|
inputValue.value = '';
|
||||||
|
setConfig(field, list.join(','));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose (index) {
|
||||||
|
const { field, list, setConfig } = this.props;
|
||||||
|
list[index] = null;
|
||||||
|
setConfig(field, list.length === 1 ? '' : list.filter(Boolean).join(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { name, list } = this.props;
|
||||||
|
return (<div>
|
||||||
|
<p>{name}</p>
|
||||||
|
{list.map((entryValue, index) => (
|
||||||
|
<Chip
|
||||||
|
key={index + entryValue}
|
||||||
|
style={{ marginRight: '3px' }}
|
||||||
|
onClose={() => this.onClose(index)}>{entryValue}</Chip>
|
||||||
|
))}
|
||||||
|
|
||||||
const inputValue = document.querySelector(`[name="${field}_input"]`);
|
|
||||||
if (inputValue && inputValue.value) {
|
|
||||||
list.push(inputValue.value);
|
|
||||||
inputValue.value = '';
|
|
||||||
setConfig(field, list.join(','));
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
<Textfield name={`${field}_input`} style={{ width: '100%', flex: 1 }} floatingLabel label="Add list entry" />
|
<Textfield
|
||||||
<IconButton name="add" raised style={{ flex: 1, flexGrow: 0, margin: '20px 0 0 10px' }}/>
|
name={`${name}_input`}
|
||||||
|
style={{ width: '100%', flex: 1 }}
|
||||||
|
floatingLabel
|
||||||
|
label="Add list entry"
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onBlur={this.onBlur} />
|
||||||
|
<IconButton name="add" raised style={{ flex: 1, flexGrow: 0, margin: '20px 0 0 10px' }} onClick={this.setValue} />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>);
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
@ -8,9 +8,9 @@ const labelStyle = {
|
|||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ field, value, onChange }) => (
|
export default ({ name, value, onChange }) => (
|
||||||
<div>
|
<div>
|
||||||
<div style={labelStyle}>{field}: {value}%</div>
|
<div style={labelStyle}>{name}: {value}%</div>
|
||||||
<Slider min={0} max={100} defaultValue={value} value={value} onChange={onChange} label={field} />
|
<Slider min={0} max={100} defaultValue={value} value={value} onChange={onChange} label={name} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -57,8 +57,8 @@ export function createActions ({ id, prepare = (v) => v }) {
|
|||||||
dispatch(createPop({ id: getId(id, ownProps), key, index }));
|
dispatch(createPop({ id: getId(id, ownProps), key, index }));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateInList (key, index, newValue) {
|
updateInList (key, index, newValue, merge = false) {
|
||||||
dispatch(createUp({ id: getId(id, ownProps), key, index, newValue }));
|
dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge }));
|
||||||
},
|
},
|
||||||
|
|
||||||
incValue (key) {
|
incValue (key) {
|
||||||
|
@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
|||||||
import { createMapper, createActions } from '../input-helpers';
|
import { createMapper, createActions } from '../input-helpers';
|
||||||
import { createStrategy } from '../../store/strategy/actions';
|
import { createStrategy } from '../../store/strategy/actions';
|
||||||
|
|
||||||
import AddStrategy, { PARAM_PREFIX, TYPE_PREFIX } from './add-strategy';
|
import AddStrategy from './add-strategy';
|
||||||
|
|
||||||
const ID = 'add-strategy';
|
const ID = 'add-strategy';
|
||||||
|
|
||||||
@ -12,15 +12,28 @@ const prepare = (methods, dispatch) => {
|
|||||||
(e) => {
|
(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const parametersTemplate = {};
|
|
||||||
Object.keys(input).forEach(key => {
|
|
||||||
if (key.startsWith(PARAM_PREFIX)) {
|
|
||||||
parametersTemplate[input[key]] = input[key.replace(PARAM_PREFIX, TYPE_PREFIX)] || 'string';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
input.parametersTemplate = parametersTemplate;
|
|
||||||
|
|
||||||
createStrategy(input)(dispatch)
|
|
||||||
|
// clean
|
||||||
|
const parameters = input.parameters
|
||||||
|
.filter((name) => !!name)
|
||||||
|
.map(({
|
||||||
|
name,
|
||||||
|
type = 'string',
|
||||||
|
description = '',
|
||||||
|
required = false,
|
||||||
|
}) => ({
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
description,
|
||||||
|
required,
|
||||||
|
}));
|
||||||
|
|
||||||
|
createStrategy({
|
||||||
|
name: input.name,
|
||||||
|
description: input.description,
|
||||||
|
parameters,
|
||||||
|
})(dispatch)
|
||||||
.then(() => methods.clear())
|
.then(() => methods.clear())
|
||||||
// somewhat quickfix / hacky to go back..
|
// somewhat quickfix / hacky to go back..
|
||||||
.then(() => window.history.back());
|
.then(() => window.history.back());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
import { Textfield, IconButton, Menu, MenuItem } from 'react-mdl';
|
import { Textfield, IconButton, Menu, MenuItem, Checkbox } from 'react-mdl';
|
||||||
import { HeaderTitle, FormButtons } from '../common';
|
import { HeaderTitle, FormButtons } from '../common';
|
||||||
|
|
||||||
|
|
||||||
@ -15,40 +15,60 @@ const trim = (value) => {
|
|||||||
function gerArrayWithEntries (num) {
|
function gerArrayWithEntries (num) {
|
||||||
return Array.from(Array(num));
|
return Array.from(Array(num));
|
||||||
}
|
}
|
||||||
export const PARAM_PREFIX = 'param_';
|
|
||||||
export const TYPE_PREFIX = 'type_';
|
|
||||||
|
|
||||||
const genParams = (input, num = 0, setValue) => (<div>{gerArrayWithEntries(num).map((v, i) => {
|
const Parameter = ({ set, input = {}, index }) => (
|
||||||
const key = `${PARAM_PREFIX}${i + 1}`;
|
<div style={{ background: '#f1f1f1', margin: '20px 0', padding: '10px' }}>
|
||||||
const typeKey = `${TYPE_PREFIX}${i + 1}`;
|
<Textfield
|
||||||
return (
|
style={{ width: '50%' }}
|
||||||
<div key={key}>
|
floatingLabel
|
||||||
<Textfield
|
label={`Parameter name ${index + 1}`}
|
||||||
style={{ width: '50%' }}
|
onChange={({ target }) => set({ name: target.value }, true)}
|
||||||
floatingLabel
|
value={input.name} />
|
||||||
label={`Parameter name ${i + 1}`}
|
<div style={{ position: 'relative', display: 'inline-block' }}>
|
||||||
name={key}
|
<span id={`${index}-type-menu`}>
|
||||||
onChange={({ target }) => setValue(key, target.value)}
|
{input.type || 'string'}
|
||||||
value={input[key]} />
|
<IconButton name="arrow_drop_down" onClick={(evt) => evt.preventDefault()} />
|
||||||
<div style={{ position: 'relative', display: 'inline-block' }}>
|
</span>
|
||||||
<span id={`${key}-type-menu`}>
|
<Menu target={`${index}-type-menu`} align="right">
|
||||||
{input[typeKey] || 'string'}
|
<MenuItem onClick={() => set({ type: 'string' })}>String</MenuItem>
|
||||||
<IconButton name="arrow_drop_down" onClick={(evt) => evt.preventDefault()} />
|
<MenuItem onClick={() => set({ type: 'percentage' })}>Percentage</MenuItem>
|
||||||
</span>
|
<MenuItem onClick={() => set({ type: 'list' })}>List of values</MenuItem>
|
||||||
<Menu target={`${key}-type-menu`} align="right">
|
<MenuItem onClick={() => set({ type: 'number' })}>Number</MenuItem>
|
||||||
<MenuItem onClick={() => setValue(typeKey, 'string')}>String</MenuItem>
|
</Menu>
|
||||||
<MenuItem onClick={() => setValue(typeKey, 'percentage')}>Percentage</MenuItem>
|
|
||||||
<MenuItem onClick={() => setValue(typeKey, 'list')}>List of values</MenuItem>
|
|
||||||
<MenuItem onClick={() => setValue(typeKey, 'number')}>Number</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
<Textfield
|
||||||
})}</div>);
|
floatingLabel
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
rows={2}
|
||||||
|
label={`Parameter name ${index + 1} description`}
|
||||||
|
onChange={({ target }) => set({ description: target.value })}
|
||||||
|
value={input.description}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label="Required"
|
||||||
|
checked={!!input.required}
|
||||||
|
onChange={() => set({ required: !input.required })}
|
||||||
|
ripple
|
||||||
|
defaultChecked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Parameters = ({ input = [], count = 0, updateInList }) => (
|
||||||
|
<div>{
|
||||||
|
gerArrayWithEntries(count)
|
||||||
|
.map((v, i) => <Parameter
|
||||||
|
key={i}
|
||||||
|
set={(v) => updateInList('parameters', i, v, true)}
|
||||||
|
index={i}
|
||||||
|
input={input[i]}
|
||||||
|
/>)
|
||||||
|
}</div>);
|
||||||
|
|
||||||
const AddStrategy = ({
|
const AddStrategy = ({
|
||||||
input,
|
input,
|
||||||
setValue,
|
setValue,
|
||||||
|
updateInList,
|
||||||
incValue,
|
incValue,
|
||||||
// clear,
|
// clear,
|
||||||
onCancel,
|
onCancel,
|
||||||
@ -78,7 +98,7 @@ const AddStrategy = ({
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section style={{ margin: '0 20px' }}>
|
<section style={{ margin: '0 20px' }}>
|
||||||
{genParams(input, input._params, setValue)}
|
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
|
||||||
<IconButton raised name="add" title="Add parameter" onClick={(e) => {
|
<IconButton raised name="add" title="Add parameter" onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
incValue('_params');
|
incValue('_params');
|
||||||
@ -97,6 +117,7 @@ const AddStrategy = ({
|
|||||||
AddStrategy.propTypes = {
|
AddStrategy.propTypes = {
|
||||||
input: PropTypes.object,
|
input: PropTypes.object,
|
||||||
setValue: PropTypes.func,
|
setValue: PropTypes.func,
|
||||||
|
updateInList: PropTypes.func,
|
||||||
incValue: PropTypes.func,
|
incValue: PropTypes.func,
|
||||||
clear: PropTypes.func,
|
clear: PropTypes.func,
|
||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
import { List, ListItem, ListItemContent, Chip, Icon, IconButton } from 'react-mdl';
|
import { List, ListItem, ListItemContent, IconButton } from 'react-mdl';
|
||||||
import { HeaderTitle } from '../common';
|
import { HeaderTitle } from '../common';
|
||||||
|
|
||||||
class StrategiesListComponent extends Component {
|
class StrategiesListComponent extends Component {
|
||||||
@ -14,12 +14,6 @@ class StrategiesListComponent extends Component {
|
|||||||
this.props.fetchStrategies();
|
this.props.fetchStrategies();
|
||||||
}
|
}
|
||||||
|
|
||||||
getParameterMap ({ parametersTemplate }) {
|
|
||||||
return Object.keys(parametersTemplate || {}).map(k => (
|
|
||||||
<Chip key={k}><small>{k}</small></Chip>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { strategies, removeStrategy } = this.props;
|
const { strategies, removeStrategy } = this.props;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Grid, Cell } from 'react-mdl';
|
import { Grid, Cell, List, ListItem, ListItemContent } from 'react-mdl';
|
||||||
|
|
||||||
import { AppsLinkList, TogglesLinkList, HeaderTitle } from '../common';
|
import { AppsLinkList, TogglesLinkList, HeaderTitle } from '../common';
|
||||||
|
|
||||||
class ShowStrategyComponent extends Component {
|
class ShowStrategyComponent extends Component {
|
||||||
@ -16,13 +15,17 @@ class ShowStrategyComponent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderParameters (parametersTemplate) {
|
renderParameters (params) {
|
||||||
if (parametersTemplate) {
|
if (params) {
|
||||||
return Object.keys(parametersTemplate).map((name, i) => (
|
return params.map(({ name, type, description, required }, i) => (
|
||||||
<li key={`${name}-${i}`}><strong>{name}</strong> ({parametersTemplate[name]})</li>
|
<ListItem twoLine key={`${name}-${i}`} title={required ? 'Required' : ''}>
|
||||||
|
<ListItemContent avatar={required ? 'add' : ' '} subtitle={description}>
|
||||||
|
{name} <small>({type})</small>
|
||||||
|
</ListItemContent>
|
||||||
|
</ListItem>
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return <li>(no params)</li>;
|
return <ListItem>(no params)</ListItem>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,28 +44,28 @@ class ShowStrategyComponent extends Component {
|
|||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
parametersTemplate = {},
|
parameters = [],
|
||||||
} = strategy;
|
} = strategy;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<HeaderTitle title={name} subtitle={description} />
|
<HeaderTitle title={name} subtitle={description} />
|
||||||
<Grid>
|
<Grid>
|
||||||
<Cell col={4}>
|
<Cell col={12}>
|
||||||
<h6>Parameters</h6>
|
<h6>Parameters</h6>
|
||||||
<hr />
|
<hr />
|
||||||
<ol className="demo-list-item mdl-list">
|
<List>
|
||||||
{this.renderParameters(parametersTemplate)}
|
{this.renderParameters(parameters)}
|
||||||
</ol>
|
</List>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
||||||
<Cell col={4}>
|
<Cell col={6}>
|
||||||
<h6>Applications using this strategy</h6>
|
<h6>Applications using this strategy</h6>
|
||||||
<hr />
|
<hr />
|
||||||
<AppsLinkList apps={applications} />
|
<AppsLinkList apps={applications} />
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
||||||
<Cell col={4}>
|
<Cell col={6}>
|
||||||
<h6>Toggles using this strategy</h6>
|
<h6>Toggles using this strategy</h6>
|
||||||
<hr />
|
<hr />
|
||||||
<TogglesLinkList toggles={toggles} />
|
<TogglesLinkList toggles={toggles} />
|
||||||
|
@ -13,7 +13,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 createUp = ({ id, key, index, newValue }) => ({ type: actions.LIST_UP, id, key, index, newValue });
|
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 });
|
||||||
|
|
||||||
export default actions;
|
export default actions;
|
||||||
|
@ -48,11 +48,18 @@ function addToList (state, { id, key, value }) {
|
|||||||
return state.updateIn(id.concat([key]), (list) => list.push(value));
|
return state.updateIn(id.concat([key]), (list) => list.push(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateInList (state, { id, key, index, newValue }) {
|
function updateInList (state, { id, key, index, newValue, merge }) {
|
||||||
state = assertId(state, id);
|
state = assertId(state, id);
|
||||||
state = assertList(state, id, key);
|
state = assertList(state, id, key);
|
||||||
|
|
||||||
return state.updateIn(id.concat([key]), (list) => list.set(index, newValue));
|
return state.updateIn(id.concat([key]), (list) => {
|
||||||
|
if (merge && list.has(index)) {
|
||||||
|
newValue = list.get(index).merge(new $Map(newValue));
|
||||||
|
} else if (typeof newValue !== 'string' ) {
|
||||||
|
newValue = fromJS(newValue);
|
||||||
|
}
|
||||||
|
return list.set(index, newValue);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFromList (state, { id, key, index }) {
|
function removeFromList (state, { id, key, index }) {
|
||||||
|
Loading…
Reference in New Issue
Block a user