diff --git a/frontend/src/component/strategies/add-strategy.jsx b/frontend/src/component/strategies/add-strategy.jsx index 3bf98184ba..01faf2c9ef 100644 --- a/frontend/src/component/strategies/add-strategy.jsx +++ b/frontend/src/component/strategies/add-strategy.jsx @@ -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 }) => ( />) }); -const AddStrategy = ({ - input, - setValue, - updateInList, - incValue, - // clear, - onCancel, - onSubmit, -}) => ( -
- -
- 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 ( + + +
+ setValue('name', trim(target.value))} + value={input.name} + /> +
+ setValue('description', target.value)} + value={input.description} + /> +
+ +
+ + { + e.preventDefault(); + incValue('_params'); + }}/>  Add parameter +
+ +
+
+ + -
- setValue('description', target.value)} - value={input.description} - /> -
- -
- - { - e.preventDefault(); - incValue('_params'); - }}/>  Add parameter -
- -
-
- - - -); - -AddStrategy.propTypes = { - input: PropTypes.object, - setValue: PropTypes.func, - updateInList: PropTypes.func, - incValue: PropTypes.func, - clear: PropTypes.func, - onCancel: PropTypes.func, - onSubmit: PropTypes.func, -}; + + ); + } +} export default AddStrategy; diff --git a/frontend/src/component/strategies/edit-container.js b/frontend/src/component/strategies/edit-container.js new file mode 100644 index 0000000000..752a327aad --- /dev/null +++ b/frontend/src/component/strategies/edit-container.js @@ -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); diff --git a/frontend/src/component/strategies/show-strategy-component.js b/frontend/src/component/strategies/show-strategy-component.js index 24fc36c56a..3101f25231 100644 --- a/frontend/src/component/strategies/show-strategy-component.js +++ b/frontend/src/component/strategies/show-strategy-component.js @@ -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
Cannot find Strategy "{strategyName}".
; - } - const { - name, - description, parameters = [], } = strategy; return (
- +
Parameters
diff --git a/frontend/src/component/strategies/strategy-details-component.jsx b/frontend/src/component/strategies/strategy-details-component.jsx new file mode 100644 index 0000000000..0f1697a75a --- /dev/null +++ b/frontend/src/component/strategies/strategy-details-component.jsx @@ -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 ; + } else { + return (); + } + } + + render () { + const strategy = this.props.strategy; + if (!strategy) { + return ; + } + + const tabContent = this.getTabContent(this.state.activeTab); + + return ( +
+ + this.setState({ activeTab: tabId })} ripple> + Details + Edit + +
+
+ {tabContent} +
+
+
+ ); + } +} diff --git a/frontend/src/component/strategies/show-strategy-container.js b/frontend/src/component/strategies/strategy-details-container.js similarity index 94% rename from frontend/src/component/strategies/show-strategy-container.js rename to frontend/src/component/strategies/strategy-details-container.js index ef8d0fee02..3f22c5522e 100644 --- a/frontend/src/component/strategies/show-strategy-container.js +++ b/frontend/src/component/strategies/strategy-details-container.js @@ -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'; diff --git a/frontend/src/data/strategy-api.js b/frontend/src/data/strategy-api.js index 7930f4c901..d400882487 100644 --- a/frontend/src/data/strategy-api.js +++ b/frontend/src/data/strategy-api.js @@ -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, }; diff --git a/frontend/src/page/strategies/show.js b/frontend/src/page/strategies/show.js index 5ee23a1f64..f39b2f3be8 100644 --- a/frontend/src/page/strategies/show.js +++ b/frontend/src/page/strategies/show.js @@ -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 }) => ; diff --git a/frontend/src/store/strategy/actions.js b/frontend/src/store/strategy/actions.js index 4648d7a78d..bd6269e62c 100644 --- a/frontend/src/store/strategy/actions.js +++ b/frontend/src/store/strategy/actions.js @@ -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)