diff --git a/public/js/__tests__/components/feature/ArchiveFeatureComponent-test.js b/public/js/__tests__/components/feature/ArchiveFeatureComponent-test.js
index 871071f51f..a219abd55c 100644
--- a/public/js/__tests__/components/feature/ArchiveFeatureComponent-test.js
+++ b/public/js/__tests__/components/feature/ArchiveFeatureComponent-test.js
@@ -17,7 +17,7 @@ describe("FeatureForm", function () {
];
Server.getArchivedFeatures.mockImplementation(function(cb) {
- cb(archivedToggles);
+ cb(null, archivedToggles);
});
FeatureToggleStore.initStore(archivedToggles);
diff --git a/public/js/__tests__/components/feature/FeatureForm-test.js b/public/js/__tests__/components/feature/FeatureForm-test.js
index d42a0c9639..93fe28f78b 100644
--- a/public/js/__tests__/components/feature/FeatureForm-test.js
+++ b/public/js/__tests__/components/feature/FeatureForm-test.js
@@ -3,31 +3,19 @@ jest.dontMock("../../../components/feature/FeatureForm");
var React = require("react/addons");
var TestUtils = React.addons.TestUtils;
var FeatureForm = require("../../../components/feature/FeatureForm");
-var strategyStore = require("../../../stores/StrategyStore");
describe("FeatureForm", function () {
var Component;
- beforeEach(function() {
- strategyStore.getStrategies.mockImplementation(function() {
- return {
- then: function (callback) {
- return callback({
- strategies: [
- { name: "default"}
- ]
- });
- }
- };
- });
- });
-
+ var strategies = [
+ { name: "default"}
+ ];
afterEach(function() {
React.unmountComponentAtNode(document.body);
});
describe("new", function () {
it("should render empty form", function() {
- Component = TestUtils .renderIntoDocument();
+ Component = TestUtils .renderIntoDocument();
var name = Component.getDOMNode().querySelectorAll("input");
expect(name[0].value).toEqual(undefined);
});
@@ -37,11 +25,11 @@ describe("FeatureForm", function () {
var feature = {name: "Test", strategy: "unknown"};
it("should show unknown strategy as deleted", function () {
- Component = TestUtils .renderIntoDocument();
+ Component = TestUtils .renderIntoDocument();
var strategySelect = Component.getDOMNode().querySelector("select");
expect(strategySelect.value).toEqual("unknown (deleted)");
});
});
-});
\ No newline at end of file
+});
diff --git a/public/js/__tests__/components/feature/FeatureList-test.js b/public/js/__tests__/components/feature/FeatureList-test.js
index b86230a24b..7c970c66fd 100644
--- a/public/js/__tests__/components/feature/FeatureList-test.js
+++ b/public/js/__tests__/components/feature/FeatureList-test.js
@@ -13,7 +13,10 @@ describe("FeatureList", function () {
{ name: "featureX", strategy: "other" },
{ name: "group.featureY", strategy: "default" }
];
- Component = TestUtils .renderIntoDocument();
+ var strategies=[
+ { name: "default"}
+ ];
+ Component = TestUtils .renderIntoDocument();
});
afterEach(function() {
@@ -52,4 +55,4 @@ describe("FeatureList", function () {
expect(features[0].textContent).toMatch(searchString);
});
-});
\ No newline at end of file
+});
diff --git a/public/js/components/feature/Feature.jsx b/public/js/components/feature/Feature.jsx
index bad6ccd442..40b93747e3 100644
--- a/public/js/components/feature/Feature.jsx
+++ b/public/js/components/feature/Feature.jsx
@@ -44,7 +44,11 @@ var Feature = React.createClass({
return (
-
+
|
);
@@ -110,4 +114,4 @@ var Feature = React.createClass({
});
-module.exports = Feature;
\ No newline at end of file
+module.exports = Feature;
diff --git a/public/js/components/feature/FeatureForm.jsx b/public/js/components/feature/FeatureForm.jsx
index 26cb524186..87898da5dc 100644
--- a/public/js/components/feature/FeatureForm.jsx
+++ b/public/js/components/feature/FeatureForm.jsx
@@ -1,22 +1,16 @@
var React = require('react');
var TextInput = require('../form/TextInput');
-var strategyStore = require('../../stores/StrategyStore');
var FeatureForm = React.createClass({
getInitialState: function() {
- return {
- strategyOptions: [],
- requiredParams: [],
- currentStrategy: this.props.feature ? this.props.feature.strategy : "default"
- };
+ return {
+ strategyOptions: this.props.strategies,
+ requiredParams: [],
+ currentStrategy: this.props.feature ? this.props.feature.strategy : "default"
+ };
},
componentWillMount: function() {
- strategyStore.getStrategies().then(this.handleStrategyResponse);
- },
-
- handleStrategyResponse: function(response) {
- this.setState({strategyOptions: response.strategies});
if(this.props.feature) {
this.setSelectedStrategy(this.props.feature.strategy);
}
@@ -41,9 +35,7 @@ var FeatureForm = React.createClass({
})[0];
if(selectedStrategy) {
- if(selectedStrategy.parametersTemplate) {
- this.setStrategyParams(selectedStrategy);
- }
+ this.setStrategyParams(selectedStrategy);
} else {
var updatedStrategyName = name + " (deleted)";
this.setState({
@@ -64,9 +56,9 @@ var FeatureForm = React.createClass({
render: function() {
var feature = this.props.feature || {
- name: '',
- strategy: 'default',
- enabled: false
+ name: '',
+ strategy: 'default',
+ enabled: false
};
var idPrefix = this.props.feature ? this.props.feature.name : 'new';
@@ -131,9 +123,9 @@ var FeatureForm = React.createClass({
renderStrategyOptions: function() {
return this.state.strategyOptions.map(function(strategy) {
return (
-
+
);
}.bind(this));
},
@@ -178,4 +170,4 @@ var FeatureForm = React.createClass({
}
});
-module.exports = FeatureForm;
\ No newline at end of file
+module.exports = FeatureForm;
diff --git a/public/js/components/feature/FeatureList.jsx b/public/js/components/feature/FeatureList.jsx
index f62a9583bf..1e407aae83 100644
--- a/public/js/components/feature/FeatureList.jsx
+++ b/public/js/components/feature/FeatureList.jsx
@@ -5,7 +5,8 @@ var noop = function() {};
var FeatureList = React.createClass({
propTypes: {
- features: React.PropTypes.array.isRequired
+ features: React.PropTypes.array.isRequired,
+ strategies: React.PropTypes.array.isRequired
},
getDefaultProps: function() {
@@ -47,7 +48,9 @@ var FeatureList = React.createClass({
key={feature.name}
feature={feature}
onChange={this.props.onFeatureChanged}
- onArchive={this.props.onFeatureArchive}/>
+ onArchive={this.props.onFeatureArchive}
+ strategies={this.props.strategies}
+ />
);
}.bind(this));
@@ -83,4 +86,4 @@ var FeatureList = React.createClass({
}
});
-module.exports = FeatureList;
\ No newline at end of file
+module.exports = FeatureList;
diff --git a/public/js/components/feature/FeatureTogglesComponent.jsx b/public/js/components/feature/FeatureTogglesComponent.jsx
index b1023debac..683d362d3a 100644
--- a/public/js/components/feature/FeatureTogglesComponent.jsx
+++ b/public/js/components/feature/FeatureTogglesComponent.jsx
@@ -4,6 +4,7 @@ var FeatureForm = require('./FeatureForm');
var FeatureActions = require('../../stores/FeatureToggleActions');
var ErrorActions = require('../../stores/ErrorActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore');
+var StrategyStore = require('../../stores/StrategyStore');
var FeatureTogglesComponent = React.createClass({
getInitialState: function() {
@@ -59,13 +60,17 @@ var FeatureTogglesComponent = React.createClass({
onFeatureArchive={this.archiveFeature}
onFeatureSubmit={this.createFeature}
onFeatureCancel={this.cancelNewFeature}
- onNewFeature={this.newFeature} />
+ onNewFeature={this.newFeature}
+ strategies={StrategyStore.getStrategies()} />
);
},
renderCreateView: function() {
- return ;
+ return ;
},
renderCreateButton: function() {
diff --git a/public/js/components/strategy/StrategiesComponent.jsx b/public/js/components/strategy/StrategiesComponent.jsx
index 1a625d61d5..e913f6c03b 100644
--- a/public/js/components/strategy/StrategiesComponent.jsx
+++ b/public/js/components/strategy/StrategiesComponent.jsx
@@ -1,36 +1,27 @@
-var React = require('react');
-var StrategyList = require('./StrategyList');
-var StrategyForm = require('./StrategyForm');
-var strategyStore = require('../../stores/StrategyStore');
-var ErrorActions = require('../../stores/ErrorActions');
+var React = require('react');
+var StrategyList = require('./StrategyList');
+var StrategyForm = require('./StrategyForm');
+var StrategyStore = require('../../stores/StrategyStore');
+var StrategyActions = require('../../stores/StrategyActions');
var StrategiesComponent = React.createClass({
getInitialState: function() {
return {
createView: false,
- strategies: []
+ strategies: StrategyStore.getStrategies()
};
},
- componentDidMount: function () {
- this.fetchStrategies();
+ onStoreChange: function() {
+ this.setState({
+ strategies: StrategyStore.getStrategies()
+ });
},
-
- fetchStrategies: function() {
- strategyStore.getStrategies()
- .then(function(res) {
- this.setState({strategies: res.strategies});
- }.bind(this))
- .catch(this.initError);
-
+ componentDidMount: function() {
+ this.unsubscribe = StrategyStore.listen(this.onStoreChange);
},
-
- initError: function() {
- this.onError("Could not load inital strategies from server");
- },
-
- onError: function(error) {
- ErrorActions.error(error);
+ componentWillUnmount: function() {
+ this.unsubscribe();
},
onNewStrategy: function() {
@@ -42,32 +33,19 @@ var StrategiesComponent = React.createClass({
},
onSave: function(strategy) {
- function handleSuccess() {
- var strategies = this.state.strategies.concat([strategy]);
-
- this.setState({
- createView: false,
- strategies: strategies
- });
-
- console.log("Saved strategy: ", strategy);
- }
-
- strategyStore.createStrategy(strategy)
- .then(handleSuccess.bind(this))
- .catch(this.onError);
+ StrategyActions.create.triggerPromise(strategy)
+ .then(this.onCancelNewStrategy);
},
onRemove: function(strategy) {
- strategyStore.removeStrategy(strategy)
- .then(this.fetchStrategies)
- .catch(this.onError);
+ StrategyActions.remove.triggerPromise(strategy);
},
render: function() {
return (
- {this.state.createView ? this.renderCreateView() : this.renderCreateButton()}
+ {this.state.createView ?
+ this.renderCreateView() : this.renderCreateButton()}
);
- },
+ },
- renderCreateButton: function() {
- return (
-
- );
- }
-});
+ renderCreateButton: function() {
+ return (
+
+ );
+ }
+ });
-module.exports = StrategiesComponent;
+ module.exports = StrategiesComponent;
diff --git a/public/js/stores/StrategyAPI.js b/public/js/stores/StrategyAPI.js
new file mode 100644
index 0000000000..9ddbcb5ca8
--- /dev/null
+++ b/public/js/stores/StrategyAPI.js
@@ -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;
diff --git a/public/js/stores/StrategyActions.js b/public/js/stores/StrategyActions.js
new file mode 100644
index 0000000000..8dcc5f391a
--- /dev/null
+++ b/public/js/stores/StrategyActions.js
@@ -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;
diff --git a/public/js/stores/StrategyStore.js b/public/js/stores/StrategyStore.js
index 09388e6e34..f25c853fc0 100644
--- a/public/js/stores/StrategyStore.js
+++ b/public/js/stores/StrategyStore.js
@@ -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 CONTENT_TYPE = 'application/json';
+var _strategies = [];
-var StrategyStore = {
- createStrategy: function (strategy) {
- return reqwest({
- url: 'strategies',
- method: 'post',
- type: TYPE,
- contentType: CONTENT_TYPE,
- data: JSON.stringify(strategy)
- });
+// Creates a DataStore
+var StrategyStore = Reflux.createStore({
+
+ // Initial setup
+ init: function() {
+ this.listenTo(StrategyActions.create.completed, this.onCreate);
+ this.listenTo(StrategyActions.remove.completed, this.onRemove);
+ this.loadDataFromServer();
},
- removeStrategy: function (strategy) {
- return reqwest({
- url: 'strategies/'+strategy.name,
- method: 'delete',
- type: TYPE
- });
+ loadDataFromServer: function() {
+ //TODO: this should not be part of the store!
+ StrategyAPI.getStrategies(function(err, strategies) {
+
+ if(err) {
+ ErrorActions.error(err);
+ return;
+ } else {
+ this.setStrategies(strategies);
+ }
+ }.bind(this));
},
- getStrategies: function () {
- return reqwest({
- url: 'strategies',
- method: 'get',
- type: TYPE
+ onCreate: function(strategy) {
+ this.setStrategies(_strategies.concat([strategy]));
+ },
+
+ 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;