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:
parent
cbf884dd76
commit
40dc6604f4
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
var Reflux = require("reflux");
|
||||
module.exports = {
|
||||
addToggle: Reflux.createAction({ asyncResult: true })
|
||||
};
|
@ -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;
|
@ -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;
|
7
public/js/stores/FeatureToggleActions.js
Normal file
7
public/js/stores/FeatureToggleActions.js
Normal 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 })
|
||||
};
|
98
public/js/stores/FeatureToggleServerFacade.js
Normal file
98
public/js/stores/FeatureToggleServerFacade.js
Normal 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;
|
122
public/js/stores/FeatureToggleStore.js
Normal file
122
public/js/stores/FeatureToggleStore.js
Normal 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;
|
Loading…
Reference in New Issue
Block a user