1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

Renamed FeatureToggleStore and simplified action names.

This commit is contained in:
Ivar Conradi Østhus 2015-03-03 19:27:17 +01:00
parent cbf884dd76
commit 40dc6604f4
9 changed files with 330 additions and 268 deletions

View File

@ -1,32 +1,28 @@
jest.dontMock("../../../components/feature/ArchiveFeatureComponent");
jest.mock("../../../stores/FeatureToggleServerFacade");
jest.autoMockOff();
var React = require("react/addons");
var TestUtils = React.addons.TestUtils;
var FeatureArchive = require("../../../components/feature/ArchiveFeatureComponent");
var FeatureStore = require("../../../stores/FeatureStore");
var FeatureArchive = require("../../../components/feature/ArchiveFeatureComponent");
var Server = require("../../../stores/FeatureToggleServerFacade");
var FeatureToggleStore = require("../../../stores/FeatureToggleStore");
describe("FeatureForm", function () {
var Component;
beforeEach(function() {
FeatureStore.getArchivedFeatures.mockImplementation(function() {
return {
then: function (callback) {
return callback({
features: [
{ name: "featureX" },
{ name: "featureY" }
]
});
}
};
});
FeatureStore.reviveFeature.mockImplementation(function() {
return {
then: function (callback) {return callback();}
};
var archivedToggles = [
{ name: "featureX" },
{ name: "featureY" }
];
Server.getArchivedFeatures.mockImplementation(function(cb) {
cb(archivedToggles);
});
Component = TestUtils .renderIntoDocument(<FeatureArchive />);
FeatureToggleStore.initStore([], archivedToggles);
Component = TestUtils.renderIntoDocument(<FeatureArchive />);
});
afterEach(function() {
@ -35,17 +31,15 @@ describe("FeatureForm", function () {
it("should render two archived features", function() {
var rows = Component.getDOMNode().querySelectorAll("tbody tr");
expect(rows.length).toEqual(2);
});
it("should revive archived feature toggle", function() {
var button = Component.getDOMNode().querySelector("tbody button");
TestUtils.Simulate.click(button);
var rows = Component.getDOMNode().querySelectorAll("tbody tr");
var button = Component.getDOMNode().querySelector("tbody button");
TestUtils.Simulate.click(button);
expect(rows.length).toEqual(1);
expect(FeatureStore.reviveFeature).toBeCalledWith({
name: "featureX"
});
jest.runAllTimers();
expect(Server.reviveFeature).toBeCalled();
});
});
});

View File

@ -1,64 +1,65 @@
var React = require("react");
var FeatureStore = require('../../stores/FeatureStore');
var React = require("react");
var FeatureActions = require('../../stores/FeatureToggleActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore');
var ArchiveFeatureComponent = React.createClass({
getInitialState: function() {
return {
archivedFeatures: []
};
},
getInitialState: function() {
return {
archivedFeatures: FeatureToggleStore.getArchivedToggles()
};
},
removeToggleFromState: function(item) {
var updatedArchive = this.state.archivedFeatures.filter(function(f) {
return f.name !== item.name;
});
this.setState({archivedFeatures: updatedArchive});
},
onStoreChange: function() {
this.setState({
archivedFeatures: FeatureToggleStore.getArchivedToggles()
});
},
onRevive: function( item) {
FeatureStore.reviveFeature(item).then(this.removeToggleFromState.bind(this, item));
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onStoreChange);
},
componentDidMount: function () {
FeatureStore.getArchivedFeatures().then(function(data) {
this.setState({archivedFeatures: data.features});
}.bind(this))
},
componentWillUnmount: function() {
this.unsubscribe();
},
render: function () {
return (
<div>
<h1>Archived feature toggles</h1>
<table className="outerborder man">
<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.archivedFeatures.map(this.renderArchivedItem)}
</tbody>
</table>
</div>
);
},
onRevive: function(item) {
FeatureActions.revive(item);
},
renderArchivedItem: function(f) {
return (
<tr key={f.name}>
<td>
{f.name}<br />
<span className="opaque smalltext word-break">{f.description}</span>
render: function () {
return (
<div>
<h1>Archived feature toggles</h1>
<table className="outerborder man">
<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.archivedFeatures.map(this.renderArchivedItem)}
</tbody>
</table>
</div>
);
},
</td>
<td className="rightify" width="150">
<button onClick={this.onRevive.bind(this, f)} title="Revive feature toggle">
<span className="icon-svar"></span>
</button>
</td>
</tr>);
}
renderArchivedItem: function(f) {
return (
<tr key={f.name}>
<td>
{f.name}<br />
<span className="opaque smalltext word-break">{f.description}</span>
</td>
<td className="rightify" width="150">
<button onClick={this.onRevive.bind(this, f)} title="Revive feature toggle">
<span className="icon-svar"></span>
</button>
</td>
</tr>);
}
});
module.exports = ArchiveFeatureComponent;
module.exports = ArchiveFeatureComponent;

View File

@ -1,25 +1,33 @@
var React = require('react');
var Timer = require('../../utils/Timer');
var ErrorMessages = require('../ErrorMessages');
var FeatureList = require('./FeatureList');
var FeatureForm = require('./FeatureForm');
var FeatureStore = require('../../stores/FeatureStore');
var FeatureStore2 = require('../../stores/FeatureStore2');
var FeatureActions = require('../../stores/FeatureActions');
var Reflux = require('reflux');
var React = require('react');
var ErrorMessages = require('../ErrorMessages');
var FeatureList = require('./FeatureList');
var FeatureForm = require('./FeatureForm');
var FeatureActions = require('../../stores/FeatureToggleActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore');
var FeatureTogglesComponent = React.createClass({
getInitialState: function() {
return {
features: FeatureToggleStore.getFeatureToggles(),
errors: [],
createView: false,
featurePoller: new Timer(this.loadFeaturesFromServer, this.props.pollInterval)
createView: false
};
},
mixins: [Reflux.connect(FeatureStore2,"features")],
onFeatureToggleChange: function() {
this.setState({
features: FeatureToggleStore.getFeatureToggles()
});
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onFeatureToggleChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
handleError: function (error) {
console.log(error);
if (this.isClientError(error)) {
var errors = JSON.parse(error.responseText)
errors.forEach(function(e) { this.addError(e.msg); }.bind(this))
@ -28,57 +36,22 @@ var FeatureTogglesComponent = React.createClass({
} else {
this.addError(error);
}
this.forceUpdate();
},
updateFeature: function (feature) {
this.stopFeaturePoller();
FeatureStore
.updateFeature(feature)
.then(this.startFeaturePoller)
FeatureActions.update.triggerPromise(feature)
.catch(this.handleError);
},
archiveFeature: function (feature) {
var updatedFeatures = this.state.features.filter(function(item) {
return item.name !== feature.name;
});
FeatureStore
.archiveFeature(feature)
.then(function() {
this.setState({features: updatedFeatures})
}.bind(this))
FeatureActions.archive.triggerPromise(feature)
.catch(this.handleError);
},
startFeaturePoller: function () {
this.state.featurePoller.start();
},
stopFeaturePoller: function () {
if (this.state.featurePoller != null) {
this.state.featurePoller.stop();
}
},
createFeature: function (feature) {
//this.stopFeaturePoller();
FeatureActions.addToggle.triggerPromise(feature)
FeatureActions.create.triggerPromise(feature)
.then(this.cancelNewFeature)
.catch(this.handleError);
/*
FeatureStore
.createFeature(feature)
.then(this.cancelNewFeature)
.then(this.startFeaturePoller)
.catch(this.handleError);
*/
},
newFeature: function() {
@ -94,8 +67,10 @@ var FeatureTogglesComponent = React.createClass({
},
addError: function(msg) {
if (this.state.errors[this.state.errors.length - 1] !== msg) {
this.state.errors.push(msg);
var errors = this.state.errors;
if (errors[errors.length - 1] !== msg) {
errors.push(msg);
this.setState(errors);
}
},

View File

@ -1,4 +0,0 @@
var Reflux = require("reflux");
module.exports = {
addToggle: Reflux.createAction({ asyncResult: true })
};

View File

@ -1,62 +0,0 @@
var reqwest = require('reqwest');
var TYPE = 'json';
var CONTENT_TYPE = 'application/json';
FeatureStore = {
updateFeature: function (feature) {
return reqwest({
url: 'features/' + feature.name,
method: 'put',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature)
});
},
createFeature: function (feature) {
return reqwest({
url: 'features',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature)
});
},
archiveFeature: function (feature) {
return reqwest({
url: 'features/' + feature.name,
method: 'delete',
type: TYPE
});
},
getFeatures: function () {
return reqwest({
url: 'features',
method: 'get',
type: TYPE
});
},
getArchivedFeatures: function () {
return reqwest({
url: 'archive/features',
method: 'get',
type: TYPE
});
},
reviveFeature: function (feature) {
return reqwest({
url: 'archive/revive',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature)
});
}
};
module.exports = FeatureStore;

View File

@ -1,69 +0,0 @@
var reqwest = require('reqwest');
var Reflux = require('reflux');
var FeatureActions = require('./FeatureActions');
var TYPE = 'json';
var CONTENT_TYPE = 'application/json';
function getFeatures() {
return reqwest({
url: 'features',
method: 'get',
type: CONTENT_TYPE
});
}
var _toggles = [];
// Creates a DataStore
var FeatureStore = Reflux.createStore({
// Initial setup
init: function() {
this.listenTo(FeatureActions.addToggle, this.onAddToggle);
getFeatures()
.then(function(data) {
this.setToggles(JSON.parse(data.response).features);
}.bind(this))
.catch(this.handleError);
},
onAddToggle: function(feature) {
reqwest({
url: 'features',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature),
error: function (error) {
FeatureActions.addToggle.failed(error);
},
success: function () {
this.setToggles(_toggles.concat([feature]));
FeatureActions.addToggle.completed();
}.bind(this)
});
},
setToggles: function(toggles) {
_toggles = toggles;
this.trigger(_toggles);
},
handleError: function(er) {
console.log("error: "+ er);
},
//getter for notes
getToggles: function() {
return _toggles;
},
getInitialState: function() {
return _toggles;
}
});
module.exports = FeatureStore;

View File

@ -0,0 +1,7 @@
var Reflux = require("reflux");
module.exports = {
create: Reflux.createAction({ asyncResult: true }),
update: Reflux.createAction({ asyncResult: true }),
archive: Reflux.createAction({ asyncResult: true }),
revive: Reflux.createAction({ asyncResult: true })
};

View File

@ -0,0 +1,98 @@
var reqwest = require('reqwest');
var TYPE = 'json';
var CONTENT_TYPE = 'application/json';
var FeatureToggleServerFacade = {
updateFeature: function (feature, cb) {
reqwest({
url: 'features/' + feature.name,
method: 'put',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature),
error: function(error) {
cb(error);
},
success: function() {
cb();
}
});
},
createFeature: function (feature, cb) {
reqwest({
url: 'features',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature),
error: function(error) {
cb(error);
},
success: function() {
cb();
}
});
},
archiveFeature: function(feature, cb) {
reqwest({
url: 'features/' + feature.name,
method: 'delete',
type: TYPE,
error: function(error) {
cb(error);
},
success: function() {
cb();
}
});
},
getFeatures: function(cb) {
reqwest({
url: 'features',
method: 'get',
type: TYPE,
error: function(error) {
cb(error);
},
success: function(data) {
cb(null, data.features);
}
});
},
getArchivedFeatures: function(cb) {
reqwest({
url: 'archive/features',
method: 'get',
type: TYPE,
error: function(error) {
cb(error);
},
success: function(data) {
cb(null, data.features);
}
});
},
reviveFeature: function (feature, cb) {
reqwest({
url: 'archive/revive',
method: 'post',
type: TYPE,
contentType: CONTENT_TYPE,
data: JSON.stringify(feature),
error: function(error) {
cb(error);
},
success: function() {
cb();
}
});
}
};
module.exports = FeatureToggleServerFacade;

View File

@ -0,0 +1,122 @@
var Reflux = require('reflux');
var FeatureActions = require('./FeatureToggleActions');
var Server = require('./FeatureToggleServerFacade');
var _featureToggles = [];
var _archivedToggles = [];
// Creates a DataStore
var FeatureStore = Reflux.createStore({
// Initial setup
init: function() {
this.listenTo(FeatureActions.create, this.onCreate);
this.listenTo(FeatureActions.update, this.onUpdate);
this.listenTo(FeatureActions.archive, this.onArchive);
this.listenTo(FeatureActions.revive, this.onRevive);
Server.getFeatures(function(err, featureToggles) {
this.setToggles(featureToggles);
}.bind(this));
Server.getArchivedFeatures(function(err, archivedToggles) {
_archivedToggles = archivedToggles;
this.trigger();
}.bind(this));
},
onCreate: function(feature) {
Server.createFeature(feature, function(error) {
if(error) {
FeatureActions.create.failed(error);
} else {
this.setToggles([feature].concat(_featureToggles));
FeatureActions.create.completed();
}
}.bind(this));
},
onArchive: function(feature) {
Server.archiveFeature(feature, function(error) {
if(error) {
FeatureActions.archive.failed(error);
} else {
this.archiveToggle(feature);
FeatureActions.archive.completed();
}
}.bind(this));
},
onUpdate: function(feature) {
Server.updateFeature(feature, function(error) {
if(error) {
FeatureActions.update.failed(error);
} else {
this.updateToggle(feature);
FeatureActions.update.completed();
}
}.bind(this));
},
onRevive: function(feature) {
Server.reviveFeature(feature, function(error) {
if(error) {
FeatureActions.revive.failed(error);
} else {
this.revive(feature);
FeatureActions.revive.completed();
}
}.bind(this));
},
setToggles: function(toggles) {
_featureToggles = toggles;
this.trigger();
},
updateToggle: function(feature) {
var idx;
_featureToggles.forEach(function(item, i) {
if(item.name === feature.name) {
idx = i;
}
});
_featureToggles[idx] = feature;
this.trigger();
},
archiveToggle: function(feature) {
var idx;
_featureToggles.forEach(function(item, i) {
if(item.name === feature.name) {
idx = i;
}
});
_featureToggles.splice(idx, 1);
_archivedToggles.unshift(feature);
this.trigger();
},
revive: function(item) {
var newStore = _archivedToggles.filter(function(f) {
return f.name !== item.name;
});
_archivedToggles = newStore;
_featureToggles.push(item);
this.trigger();
},
getFeatureToggles: function() {
return _featureToggles;
},
getArchivedToggles: function() {
return _archivedToggles;
},
initStore: function(toggles, archivedToggles) {
_featureToggles = toggles;
_archivedToggles = archivedToggles;
}
});
module.exports = FeatureStore;