1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-01 00:08:27 +01:00

Pass strategies as props

This commit is contained in:
Ivar Conradi Østhus 2015-03-17 22:01:46 +01:00
parent 31dd7fed5a
commit ebb1b3b0b7
11 changed files with 201 additions and 124 deletions

View File

@ -17,7 +17,7 @@ describe("FeatureForm", function () {
]; ];
Server.getArchivedFeatures.mockImplementation(function(cb) { Server.getArchivedFeatures.mockImplementation(function(cb) {
cb(archivedToggles); cb(null, archivedToggles);
}); });
FeatureToggleStore.initStore(archivedToggles); FeatureToggleStore.initStore(archivedToggles);

View File

@ -3,31 +3,19 @@ jest.dontMock("../../../components/feature/FeatureForm");
var React = require("react/addons"); var React = require("react/addons");
var TestUtils = React.addons.TestUtils; var TestUtils = React.addons.TestUtils;
var FeatureForm = require("../../../components/feature/FeatureForm"); var FeatureForm = require("../../../components/feature/FeatureForm");
var strategyStore = require("../../../stores/StrategyStore");
describe("FeatureForm", function () { describe("FeatureForm", function () {
var Component; var Component;
beforeEach(function() { var strategies = [
strategyStore.getStrategies.mockImplementation(function() { { name: "default"}
return { ];
then: function (callback) {
return callback({
strategies: [
{ name: "default"}
]
});
}
};
});
});
afterEach(function() { afterEach(function() {
React.unmountComponentAtNode(document.body); React.unmountComponentAtNode(document.body);
}); });
describe("new", function () { describe("new", function () {
it("should render empty form", function() { it("should render empty form", function() {
Component = TestUtils .renderIntoDocument(<FeatureForm />); Component = TestUtils .renderIntoDocument(<FeatureForm strategies={strategies} />);
var name = Component.getDOMNode().querySelectorAll("input"); var name = Component.getDOMNode().querySelectorAll("input");
expect(name[0].value).toEqual(undefined); expect(name[0].value).toEqual(undefined);
}); });
@ -37,11 +25,11 @@ describe("FeatureForm", function () {
var feature = {name: "Test", strategy: "unknown"}; var feature = {name: "Test", strategy: "unknown"};
it("should show unknown strategy as deleted", function () { it("should show unknown strategy as deleted", function () {
Component = TestUtils .renderIntoDocument(<FeatureForm feature={feature} />); Component = TestUtils .renderIntoDocument(<FeatureForm feature={feature} strategies={strategies} />);
var strategySelect = Component.getDOMNode().querySelector("select"); var strategySelect = Component.getDOMNode().querySelector("select");
expect(strategySelect.value).toEqual("unknown (deleted)"); expect(strategySelect.value).toEqual("unknown (deleted)");
}); });
}); });
}); });

View File

@ -13,7 +13,10 @@ describe("FeatureList", function () {
{ name: "featureX", strategy: "other" }, { name: "featureX", strategy: "other" },
{ name: "group.featureY", strategy: "default" } { name: "group.featureY", strategy: "default" }
]; ];
Component = TestUtils .renderIntoDocument(<FeatureList features={features} />); var strategies=[
{ name: "default"}
];
Component = TestUtils .renderIntoDocument(<FeatureList features={features} strategies={strategies} />);
}); });
afterEach(function() { afterEach(function() {
@ -52,4 +55,4 @@ describe("FeatureList", function () {
expect(features[0].textContent).toMatch(searchString); expect(features[0].textContent).toMatch(searchString);
}); });
}); });

View File

@ -44,7 +44,11 @@ var Feature = React.createClass({
return ( return (
<tr> <tr>
<td colSpan="4" className="pan man no-border"> <td colSpan="4" className="pan man no-border">
<FeatureForm feature={this.props.feature} onSubmit={this.saveFeature} onCancel={this.toggleEditMode} /> <FeatureForm
feature={this.props.feature}
onSubmit={this.saveFeature}
onCancel={this.toggleEditMode}
strategies={this.props.strategies} />
</td> </td>
</tr> </tr>
); );
@ -110,4 +114,4 @@ var Feature = React.createClass({
}); });
module.exports = Feature; module.exports = Feature;

View File

@ -1,22 +1,16 @@
var React = require('react'); var React = require('react');
var TextInput = require('../form/TextInput'); var TextInput = require('../form/TextInput');
var strategyStore = require('../../stores/StrategyStore');
var FeatureForm = React.createClass({ var FeatureForm = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
strategyOptions: [], strategyOptions: this.props.strategies,
requiredParams: [], requiredParams: [],
currentStrategy: this.props.feature ? this.props.feature.strategy : "default" currentStrategy: this.props.feature ? this.props.feature.strategy : "default"
}; };
}, },
componentWillMount: function() { componentWillMount: function() {
strategyStore.getStrategies().then(this.handleStrategyResponse);
},
handleStrategyResponse: function(response) {
this.setState({strategyOptions: response.strategies});
if(this.props.feature) { if(this.props.feature) {
this.setSelectedStrategy(this.props.feature.strategy); this.setSelectedStrategy(this.props.feature.strategy);
} }
@ -41,9 +35,7 @@ var FeatureForm = React.createClass({
})[0]; })[0];
if(selectedStrategy) { if(selectedStrategy) {
if(selectedStrategy.parametersTemplate) { this.setStrategyParams(selectedStrategy);
this.setStrategyParams(selectedStrategy);
}
} else { } else {
var updatedStrategyName = name + " (deleted)"; var updatedStrategyName = name + " (deleted)";
this.setState({ this.setState({
@ -64,9 +56,9 @@ var FeatureForm = React.createClass({
render: function() { render: function() {
var feature = this.props.feature || { var feature = this.props.feature || {
name: '', name: '',
strategy: 'default', strategy: 'default',
enabled: false enabled: false
}; };
var idPrefix = this.props.feature ? this.props.feature.name : 'new'; var idPrefix = this.props.feature ? this.props.feature.name : 'new';
@ -131,9 +123,9 @@ var FeatureForm = React.createClass({
renderStrategyOptions: function() { renderStrategyOptions: function() {
return this.state.strategyOptions.map(function(strategy) { return this.state.strategyOptions.map(function(strategy) {
return ( return (
<option key={strategy.name} value={strategy.name}> <option key={strategy.name} value={strategy.name}>
{strategy.name} {strategy.name}
</option> </option>
); );
}.bind(this)); }.bind(this));
}, },
@ -178,4 +170,4 @@ var FeatureForm = React.createClass({
} }
}); });
module.exports = FeatureForm; module.exports = FeatureForm;

View File

@ -5,7 +5,8 @@ var noop = function() {};
var FeatureList = React.createClass({ var FeatureList = React.createClass({
propTypes: { propTypes: {
features: React.PropTypes.array.isRequired features: React.PropTypes.array.isRequired,
strategies: React.PropTypes.array.isRequired
}, },
getDefaultProps: function() { getDefaultProps: function() {
@ -47,7 +48,9 @@ var FeatureList = React.createClass({
key={feature.name} key={feature.name}
feature={feature} feature={feature}
onChange={this.props.onFeatureChanged} onChange={this.props.onFeatureChanged}
onArchive={this.props.onFeatureArchive}/> onArchive={this.props.onFeatureArchive}
strategies={this.props.strategies}
/>
); );
}.bind(this)); }.bind(this));
@ -83,4 +86,4 @@ var FeatureList = React.createClass({
} }
}); });
module.exports = FeatureList; module.exports = FeatureList;

View File

@ -4,6 +4,7 @@ var FeatureForm = require('./FeatureForm');
var FeatureActions = require('../../stores/FeatureToggleActions'); var FeatureActions = require('../../stores/FeatureToggleActions');
var ErrorActions = require('../../stores/ErrorActions'); var ErrorActions = require('../../stores/ErrorActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore'); var FeatureToggleStore = require('../../stores/FeatureToggleStore');
var StrategyStore = require('../../stores/StrategyStore');
var FeatureTogglesComponent = React.createClass({ var FeatureTogglesComponent = React.createClass({
getInitialState: function() { getInitialState: function() {
@ -59,13 +60,17 @@ var FeatureTogglesComponent = React.createClass({
onFeatureArchive={this.archiveFeature} onFeatureArchive={this.archiveFeature}
onFeatureSubmit={this.createFeature} onFeatureSubmit={this.createFeature}
onFeatureCancel={this.cancelNewFeature} onFeatureCancel={this.cancelNewFeature}
onNewFeature={this.newFeature} /> onNewFeature={this.newFeature}
strategies={StrategyStore.getStrategies()} />
</div> </div>
); );
}, },
renderCreateView: function() { renderCreateView: function() {
return <FeatureForm onCancel={this.cancelNewFeature} onSubmit={this.createFeature} />; return <FeatureForm
onCancel={this.cancelNewFeature}
onSubmit={this.createFeature}
strategies={StrategyStore.getStrategies()} />;
}, },
renderCreateButton: function() { renderCreateButton: function() {

View File

@ -1,36 +1,27 @@
var React = require('react'); var React = require('react');
var StrategyList = require('./StrategyList'); var StrategyList = require('./StrategyList');
var StrategyForm = require('./StrategyForm'); var StrategyForm = require('./StrategyForm');
var strategyStore = require('../../stores/StrategyStore'); var StrategyStore = require('../../stores/StrategyStore');
var ErrorActions = require('../../stores/ErrorActions'); var StrategyActions = require('../../stores/StrategyActions');
var StrategiesComponent = React.createClass({ var StrategiesComponent = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
createView: false, createView: false,
strategies: [] strategies: StrategyStore.getStrategies()
}; };
}, },
componentDidMount: function () { onStoreChange: function() {
this.fetchStrategies(); this.setState({
strategies: StrategyStore.getStrategies()
});
}, },
componentDidMount: function() {
fetchStrategies: function() { this.unsubscribe = StrategyStore.listen(this.onStoreChange);
strategyStore.getStrategies()
.then(function(res) {
this.setState({strategies: res.strategies});
}.bind(this))
.catch(this.initError);
}, },
componentWillUnmount: function() {
initError: function() { this.unsubscribe();
this.onError("Could not load inital strategies from server");
},
onError: function(error) {
ErrorActions.error(error);
}, },
onNewStrategy: function() { onNewStrategy: function() {
@ -42,32 +33,19 @@ var StrategiesComponent = React.createClass({
}, },
onSave: function(strategy) { onSave: function(strategy) {
function handleSuccess() { StrategyActions.create.triggerPromise(strategy)
var strategies = this.state.strategies.concat([strategy]); .then(this.onCancelNewStrategy);
this.setState({
createView: false,
strategies: strategies
});
console.log("Saved strategy: ", strategy);
}
strategyStore.createStrategy(strategy)
.then(handleSuccess.bind(this))
.catch(this.onError);
}, },
onRemove: function(strategy) { onRemove: function(strategy) {
strategyStore.removeStrategy(strategy) StrategyActions.remove.triggerPromise(strategy);
.then(this.fetchStrategies)
.catch(this.onError);
}, },
render: function() { render: function() {
return ( return (
<div> <div>
{this.state.createView ? this.renderCreateView() : this.renderCreateButton()} {this.state.createView ?
this.renderCreateView() : this.renderCreateButton()}
<hr /> <hr />
<StrategyList <StrategyList
strategies={this.state.strategies} strategies={this.state.strategies}
@ -82,15 +60,15 @@ var StrategiesComponent = React.createClass({
onCancelNewStrategy={this.onCancelNewStrategy} onCancelNewStrategy={this.onCancelNewStrategy}
onSave={this.onSave} onSave={this.onSave}
/>); />);
}, },
renderCreateButton: function() { renderCreateButton: function() {
return ( return (
<button className="mal" onClick={this.onNewStrategy}> <button className="mal" onClick={this.onNewStrategy}>
Create strategy Create strategy
</button> </button>
); );
} }
}); });
module.exports = StrategiesComponent; module.exports = StrategiesComponent;

View File

@ -0,0 +1,52 @@
var reqwest = require('reqwest');
var TYPE = 'json';
var CONTENT_TYPE = 'application/json';
var StrategyAPI = {
createStrategy: function (strategy, cb) {
reqwest({
url: 'strategies',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(strategy),
error: function(error) {
cb(error);
},
success: function() {
cb(null, strategy);
}
});
},
removeStrategy: function (strategy, cb) {
reqwest({
url: 'strategies/'+strategy.name,
method: 'delete',
type: TYPE,
error: function(error) {
cb(error);
},
success: function() {
cb(null, strategy);
}
});
},
getStrategies: function (cb) {
reqwest({
url: 'strategies',
method: 'get',
type: TYPE,
error: function(error) {
cb(error);
},
success: function(data) {
cb(null, data.strategies);
}
});
}
};
module.exports = StrategyAPI;

View File

@ -0,0 +1,29 @@
var Reflux = require("reflux");
var StrategyAPI = require('./StrategyAPI');
var StrategyActions = Reflux.createActions({
'create': { asyncResult: true },
'remove': { asyncResult: true },
});
StrategyActions.create.listen(function(feature){
StrategyAPI.createStrategy(feature, function(err) {
if(err) {
this.failed(err);
} else {
this.completed(feature);
}
}.bind(this));
});
StrategyActions.remove.listen(function(feature){
StrategyAPI.removeStrategy(feature, function(err) {
if(err) {
this.failed(err);
} else {
this.completed(feature);
}
}.bind(this));
});
module.exports = StrategyActions;

View File

@ -1,34 +1,57 @@
var reqwest = require('reqwest'); var Reflux = require('reflux');
var ErrorActions = require('./ErrorActions');
var StrategyActions = require('./StrategyActions');
var StrategyAPI = require('./StrategyAPI');
var filter = require('lodash/collection/filter');
var TYPE = 'json'; var _strategies = [];
var CONTENT_TYPE = 'application/json';
var StrategyStore = { // Creates a DataStore
createStrategy: function (strategy) { var StrategyStore = Reflux.createStore({
return reqwest({
url: 'strategies', // Initial setup
method: 'post', init: function() {
type: TYPE, this.listenTo(StrategyActions.create.completed, this.onCreate);
contentType: CONTENT_TYPE, this.listenTo(StrategyActions.remove.completed, this.onRemove);
data: JSON.stringify(strategy) this.loadDataFromServer();
});
}, },
removeStrategy: function (strategy) { loadDataFromServer: function() {
return reqwest({ //TODO: this should not be part of the store!
url: 'strategies/'+strategy.name, StrategyAPI.getStrategies(function(err, strategies) {
method: 'delete',
type: TYPE if(err) {
}); ErrorActions.error(err);
return;
} else {
this.setStrategies(strategies);
}
}.bind(this));
}, },
getStrategies: function () { onCreate: function(strategy) {
return reqwest({ this.setStrategies(_strategies.concat([strategy]));
url: 'strategies', },
method: 'get',
type: TYPE onRemove: function(strategy) {
var strategies = filter(_strategies, function(item) {
return item.name !== strategy.name;
}); });
this.setStrategies(strategies);
},
setStrategies: function(strategies) {
_strategies = strategies;
this.trigger(_strategies);
},
getStrategies: function() {
return _strategies;
},
initStore: function(strategies) {
_strategies = strategies;
} }
}; });
module.exports = StrategyStore; module.exports = StrategyStore;