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:
parent
efcfcfa347
commit
398f46c561
@ -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');
|
||||
}}/> 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');
|
||||
}}/> 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;
|
||||
|
71
frontend/src/component/strategies/edit-container.js
Normal file
71
frontend/src/component/strategies/edit-container.js
Normal 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);
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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';
|
@ -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,
|
||||
};
|
||||
|
@ -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} />;
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user