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

Make edit strategy view

This commit is contained in:
ivaosthu 2016-12-17 14:37:11 +01:00
parent efcfcfa347
commit 398f46c561
8 changed files with 257 additions and 89 deletions

View File

@ -1,4 +1,4 @@
import React, { PropTypes } from 'react';
import React, { PropTypes, Component } from 'react';
import { Textfield, IconButton, Menu, MenuItem, Checkbox } from 'react-mdl';
import { HeaderTitle, FormButtons } from '../common';
@ -65,63 +65,85 @@ const Parameters = ({ input = [], count = 0, updateInList }) => (
/>)
}</div>);
const AddStrategy = ({
input,
setValue,
updateInList,
incValue,
// clear,
onCancel,
onSubmit,
}) => (
<form onSubmit={onSubmit(input)}>
<HeaderTitle title="Create new strategy" subtitle="It is not possible to edit a strategy after it is created."/>
<section style={{ margin: '16px 20px' }}>
<Textfield label="Strategy name"
floatingLabel
name="name"
required
pattern="^[0-9a-zA-Z\.\-]+$"
onChange={({ target }) => setValue('name', trim(target.value))}
value={input.name}
class AddStrategy extends Component {
static propTypes () {
return {
input: PropTypes.object,
setValue: PropTypes.func,
updateInList: PropTypes.func,
incValue: PropTypes.func,
clear: PropTypes.func,
onCancel: PropTypes.func,
onSubmit: PropTypes.func,
editmode: PropTypes.bool,
initCallRequired: PropTypes.bool,
init: PropTypes.func,
};
}
componentWillMount () {
// TODO unwind this stuff
if (this.props.initCallRequired === true) {
this.props.init(this.props.input);
}
}
render () {
const {
input,
setValue,
updateInList,
incValue,
onCancel,
editmode = false,
onSubmit,
} = this.props;
return (
<form onSubmit={onSubmit(input)}>
<HeaderTitle title="Create new strategy" subtitle="It is not possible to edit a strategy after it is created."/>
<section style={{ margin: '16px 20px' }}>
<Textfield label="Strategy name"
floatingLabel
name="name"
required
disabled={editmode}
pattern="^[0-9a-zA-Z\.\-]+$"
onChange={({ target }) => setValue('name', trim(target.value))}
value={input.name}
/>
<br />
<Textfield
floatingLabel
style={{ width: '100%' }}
rows={2}
label="Description"
name="description"
onChange={({ target }) => setValue('description', target.value)}
value={input.description}
/>
</section>
<section style={{ margin: '0 20px' }}>
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
<IconButton raised name="add" title="Add parameter" onClick={(e) => {
e.preventDefault();
incValue('_params');
}}/> &nbsp;Add parameter
</section>
<br />
<hr />
<FormButtons
submitText={editmode ? 'Update' : 'Create'}
onCancel={onCancel}
/>
<br />
<Textfield
floatingLabel
style={{ width: '100%' }}
rows={2}
label="Description"
name="description"
onChange={({ target }) => setValue('description', target.value)}
value={input.description}
/>
</section>
<section style={{ margin: '0 20px' }}>
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
<IconButton raised name="add" title="Add parameter" onClick={(e) => {
e.preventDefault();
incValue('_params');
}}/> &nbsp;Add parameter
</section>
<br />
<hr />
<FormButtons
onCancel={onCancel}
/>
</form>
);
AddStrategy.propTypes = {
input: PropTypes.object,
setValue: PropTypes.func,
updateInList: PropTypes.func,
incValue: PropTypes.func,
clear: PropTypes.func,
onCancel: PropTypes.func,
onSubmit: PropTypes.func,
};
</form>
);
}
}
export default AddStrategy;

View File

@ -0,0 +1,71 @@
import { connect } from 'react-redux';
import { createMapper, createActions } from '../input-helpers';
import { updateStrategy } from '../../store/strategy/actions';
import AddStrategy from './add-strategy';
const ID = 'edit-strategy';
function getId (props) {
return [ID, props.strategy.name];
}
// TODO: need to scope to the active strategy
// best is to emulate the "input-storage"?
const mapStateToProps = createMapper({
id: getId,
getDefault: (state, ownProps) => ownProps.strategy,
prepare: (props) => {
props.editmode = true;
return props;
},
});
const prepare = (methods, dispatch) => {
methods.onSubmit = (input) => (
(e) => {
e.preventDefault();
// clean
const parameters = input.parameters
.filter((name) => !!name)
.map(({
name,
type = 'string',
description = '',
required = false,
}) => ({
name,
type,
description,
required,
}));
updateStrategy({
name: input.name,
description: input.description,
parameters,
})(dispatch)
.then(() => methods.clear())
// somewhat quickfix / hacky to go back..
.then(() => window.history.back());
}
);
methods.onCancel = (e) => {
e.preventDefault();
methods.clear();
// somewhat quickfix / hacky to go back..
window.history.back();
};
return methods;
};
const actions = createActions({
id: getId,
prepare,
});
export default connect(mapStateToProps, actions)(AddStrategy);

View File

@ -1,19 +1,8 @@
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { Grid, Cell, List, ListItem, ListItemContent } from 'react-mdl';
import { AppsLinkList, TogglesLinkList, HeaderTitle } from '../common';
import { AppsLinkList, TogglesLinkList } from '../common';
class ShowStrategyComponent extends Component {
componentDidMount () {
if (!this.props.strategy) {
this.props.fetchStrategies();
};
if (!this.props.applications || this.props.applications.length === 0) {
this.props.fetchApplications();
}
if (!this.props.toggles || this.props.toggles.length === 0) {
this.props.fetchFeatureToggles();
}
}
class ShowStrategyComponent extends PureComponent {
renderParameters (params) {
if (params) {
@ -32,24 +21,17 @@ class ShowStrategyComponent extends Component {
render () {
const {
strategy,
strategyName,
applications,
toggles,
} = this.props;
if (!strategy) {
return <div>Cannot find Strategy "{strategyName}".</div>;
}
const {
name,
description,
parameters = [],
} = strategy;
return (
<div>
<HeaderTitle title={name} subtitle={description} />
<Grid>
<Cell col={12}>
<h6>Parameters</h6>

View File

@ -0,0 +1,62 @@
import React, { Component } from 'react';
import { Tabs, Tab, ProgressBar } from 'react-mdl';
import ShowStrategy from './show-strategy-component';
import EditStrategy from './edit-container';
import { HeaderTitle } from '../common';
const EDIT = 1;
export default class StrategyDetails extends Component {
constructor (props) {
super(props);
this.state = { activeTab: 0 };
}
componentDidMount () {
if (!this.props.strategy) {
this.props.fetchStrategies();
};
if (!this.props.applications || this.props.applications.length === 0) {
this.props.fetchApplications();
}
if (!this.props.toggles || this.props.toggles.length === 0) {
this.props.fetchFeatureToggles();
}
}
getTabContent (id) {
if (id === EDIT) {
return <EditStrategy strategy={this.props.strategy} />;
} else {
return (<ShowStrategy
strategy={this.props.strategy}
toggles={this.props.toggles}
applications={this.props.applications} />);
}
}
render () {
const strategy = this.props.strategy;
if (!strategy) {
return <ProgressBar indeterminate />;
}
const tabContent = this.getTabContent(this.state.activeTab);
return (
<div>
<HeaderTitle title={strategy.name} subtitle={strategy.description} />
<Tabs activeTab={this.state.activeTab}
onChange={(tabId) => this.setState({ activeTab: tabId })} ripple>
<Tab>Details</Tab>
<Tab>Edit</Tab>
</Tabs>
<section>
<div className="content">
{tabContent}
</div>
</section>
</div>
);
}
}

View File

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import ShowStrategy from './show-strategy-component';
import ShowStrategy from './strategy-details-component';
import { fetchStrategies } from '../../store/strategy/actions';
import { fetchAll } from '../../store/application/actions';
import { fetchFeatureToggles } from '../../store/feature-actions';

View File

@ -17,6 +17,15 @@ function create (strategy) {
}).then(throwIfNotSuccess);
}
function update (strategy) {
return fetch(`${URI}/${strategy.name}`, {
method: 'put',
headers,
body: JSON.stringify(strategy),
credentials: 'include',
}).then(throwIfNotSuccess);
}
function remove (strategy) {
return fetch(`${URI}/${strategy.name}`, {
method: 'DELETE',
@ -28,5 +37,6 @@ function remove (strategy) {
module.exports = {
fetchAll,
create,
update,
remove,
};

View File

@ -1,5 +1,5 @@
import React from 'react';
import ShowStrategy from '../../component/strategies/show-strategy-container';
import ShowStrategy from '../../component/strategies/strategy-details-container';
const render = ({ params }) => <ShowStrategy strategyName={params.strategyName} />;

View File

@ -1,22 +1,31 @@
import api from '../../data/strategy-api';
import { fetchApplicationsWithStrategyName } from '../../data/applications-api';
export const ADD_STRATEGY = 'ADD_STRATEGY';
export const REMOVE_STRATEGY = 'REMOVE_STRATEGY';
export const REQUEST_STRATEGIES = 'REQUEST_STRATEGIES';
export const START_CREATE_STRATEGY = 'START_CREATE_STRATEGY';
export const RECEIVE_STRATEGIES = 'RECEIVE_STRATEGIES';
export const ERROR_RECEIVE_STRATEGIES = 'ERROR_RECEIVE_STRATEGIES';
export const ERROR_CREATING_STRATEGY = 'ERROR_CREATING_STRATEGY';
export const ADD_STRATEGY = 'ADD_STRATEGY';
export const UPDATE_STRATEGY = 'UPDATE_STRATEGY';
export const REMOVE_STRATEGY = 'REMOVE_STRATEGY';
export const REQUEST_STRATEGIES = 'REQUEST_STRATEGIES';
export const START_CREATE_STRATEGY = 'START_CREATE_STRATEGY';
export const START_UPDATE_STRATEGY = 'START_UPDATE_STRATEGY';
export const RECEIVE_STRATEGIES = 'RECEIVE_STRATEGIES';
export const ERROR_RECEIVE_STRATEGIES = 'ERROR_RECEIVE_STRATEGIES';
export const ERROR_CREATING_STRATEGY = 'ERROR_CREATING_STRATEGY';
export const ERROR_UPDATING_STRATEGY = 'ERROR_UPDATING_STRATEGY';
const addStrategy = (strategy) => ({ type: ADD_STRATEGY, strategy });
const createRemoveStrategy = (strategy) => ({ type: REMOVE_STRATEGY, strategy });
const updatedStrategy = (strategy) => ({ type: UPDATE_STRATEGY, strategy });
const errorCreatingStrategy = (statusCode) => ({
type: ERROR_CREATING_STRATEGY,
statusCode,
});
const errorUpdatingStrategy = (statusCode) => ({
type: ERROR_UPDATING_STRATEGY,
statusCode,
});
const startRequest = () => ({ type: REQUEST_STRATEGIES });
@ -32,6 +41,8 @@ const errorReceiveStrategies = (statusCode) => ({
statusCode,
});
const startUpdate = () => ({ type: START_UPDATE_STRATEGY });
export function fetchStrategies () {
return dispatch => {
dispatch(startRequest());
@ -52,6 +63,16 @@ export function createStrategy (strategy) {
};
}
export function updateStrategy (strategy) {
return dispatch => {
dispatch(startUpdate());
return api.update(strategy)
.then(() => dispatch(updatedStrategy(strategy)))
.catch(error => dispatch(errorUpdatingStrategy(error)));
};
}
export function removeStrategy (strategy) {
return dispatch => api.remove(strategy)