1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-14 00:19:16 +01:00

Merge pull request #67 from finn-no/remove_strategies

Remove strategies
This commit is contained in:
Ivar Conradi Østhus 2014-12-09 15:40:09 +01:00
commit 6afd180a2e
12 changed files with 137 additions and 21 deletions

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
featureCreated : 'feature-created', featureCreated : 'feature-created',
featureUpdated : 'feature-updated', featureUpdated : 'feature-updated',
strategyCreated: 'strategy-created' strategyCreated: 'strategy-created',
strategyDeleted: 'strategy-deleted'
}; };

View File

@ -16,6 +16,18 @@ module.exports = function (app) {
.catch(function () { res.json(404, {error: 'Could not find strategy'}); }); .catch(function () { res.json(404, {error: 'Could not find strategy'}); });
}); });
app.delete('/strategies/:name', function (req, res) {
eventStore.create({
type: eventType.strategyDeleted,
createdBy: req.connection.remoteAddress,
data: {
name: req.params.name
}
})
.then(function () { res.status(200).end(); })
.catch(function () { res.status(500).end(); });
});
app.post('/strategies', function (req, res) { app.post('/strategies', function (req, res) {
req.checkBody('name', 'Name is required').notEmpty(); req.checkBody('name', 'Name is required').notEmpty();
req.checkBody('name', 'Name must match format ^[a-zA-Z\\.\\-]+$').matches(/^[a-zA-Z\\.\\-]+$/i); req.checkBody('name', 'Name must match format ^[a-zA-Z\\.\\-]+$').matches(/^[a-zA-Z\\.\\-]+$/i);

View File

@ -12,6 +12,15 @@ eventStore.on(eventType.strategyCreated, function (event) {
}); });
}); });
eventStore.on(eventType.strategyDeleted, function (event) {
knex('strategies')
.where('name', event.data.name)
.del()
.catch(function (err) {
logger.error('Could not delete strategy, error was: ', err);
});
});
function getStrategies() { function getStrategies() {
return knex return knex
.select(STRATEGY_COLUMNS) .select(STRATEGY_COLUMNS)

View File

@ -1,8 +1,8 @@
/** @jsx React.DOM */ /** @jsx React.DOM */
jest.dontMock("../components/Menu"); jest.dontMock("../../components/Menu");
var Menu = require("../components/Menu"); var Menu = require("../../components/Menu");
var React = require("react/addons"); var React = require("react/addons");
var TestUtils = React.addons.TestUtils; var TestUtils = React.addons.TestUtils;

View File

@ -0,0 +1,47 @@
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"}
]
});
}
};
});
});
afterEach(function() {
React.unmountComponentAtNode(document.body);
});
describe("new", function () {
it("should render empty form", function() {
Component = TestUtils .renderIntoDocument(<FeatureForm />);
var name = Component.getDOMNode().querySelectorAll("input");
expect(name[0].value).toEqual(undefined);
});
});
describe("edit", function () {
var feature = {name: "Test", strategy: "unknown"};
it("should show unknown strategy as deleted", function () {
Component = TestUtils .renderIntoDocument(<FeatureForm feature={feature} />);
var strategySelect = Component.getDOMNode().querySelector("select");
expect(strategySelect.value).toEqual("unknown (deleted)");
});
});
});

View File

@ -1,5 +1,5 @@
var React = require('react'); var React = require('react');
var TextInput = require('../form/TextInput'); var TextInput = require('../form/TextInput');
var strategyStore = require('../../stores/StrategyStore'); var strategyStore = require('../../stores/StrategyStore');
var FeatureForm = React.createClass({ var FeatureForm = React.createClass({
@ -36,20 +36,30 @@ var FeatureForm = React.createClass({
}, },
setSelectedStrategy: function(name) { setSelectedStrategy: function(name) {
var selected = this.state.strategyOptions.filter(function(strategy) { var selectedStrategy = this.state.strategyOptions.filter(function(strategy) {
return strategy.name === name; return strategy.name === name;
}); })[0];
if(selectedStrategy) {
if(selectedStrategy.parametersTemplate) {
this.setStrategyParams(selectedStrategy);
}
} else {
var updatedStrategyName = name + " (deleted)";
this.setState({
currentStrategy: updatedStrategyName,
strategyOptions: this.state.strategyOptions.concat([{name: updatedStrategyName}])
});
}
},
setStrategyParams: function(strategy) {
var requiredParams = []; var requiredParams = [];
var key; var key;
for(key in strategy.parametersTemplate) {
if(selected[0] && selected[0].parametersTemplate) { requiredParams.push({name: key, value: this.getParameterValue(key)});
for(key in selected[0].parametersTemplate) {
requiredParams.push({name: key, value: this.getParameterValue(key)});
}
} }
this.setState({requiredParams: requiredParams}); this.setState({requiredParams: requiredParams});
}, },
render: function() { render: function() {

View File

@ -14,9 +14,16 @@ var StrategiesComponent = React.createClass({
}, },
componentDidMount: function () { componentDidMount: function () {
strategyStore.getStrategies().then(function(res) { this.fetchStrategies();
this.setState({strategies: res.strategies}); },
}.bind(this), this.initError);
fetchStrategies: function(res) {
strategyStore.getStrategies()
.then(function(res) {
this.setState({strategies: res.strategies})
}.bind(this))
.catch(this.initError);
}, },
initError: function() { initError: function() {
@ -57,6 +64,12 @@ var StrategiesComponent = React.createClass({
.catch(this.onError); .catch(this.onError);
}, },
onRemove: function(strategy) {
strategyStore.removeStrategy(strategy)
.then(this.fetchStrategies)
.catch(this.onError);
},
render: function() { render: function() {
return ( return (
<div> <div>
@ -66,7 +79,7 @@ var StrategiesComponent = React.createClass({
<hr /> <hr />
<StrategyList strategies={this.state.strategies} /> <StrategyList strategies={this.state.strategies} onRemove={this.onRemove} />
</div> </div>
); );
}, },

View File

@ -5,12 +5,20 @@ var Strategy = React.createClass({
strategy: React.PropTypes.object.isRequired strategy: React.PropTypes.object.isRequired
}, },
onRemove: function(event) {
event.preventDefault();
if (confirm("Are you sure you want to delete strategy '"+this.props.strategy.name+"'?")) {
this.props.onRemove(this.props.strategy);
}
},
render: function() { render: function() {
return ( return (
<div className="line mal"> <div className="line mal">
<div className="unit"> <div className="unit">
<strong>{this.props.strategy.name}</strong><br /> <strong>{this.props.strategy.name} </strong>
<em>{this.props.strategy.description}</em> <a href="" title="Delete strategy" onClick={this.onRemove}>(remove)</a><br />
<em>{this.props.strategy.description}</em><br />
</div> </div>
</div> </div>
); );

View File

@ -8,8 +8,8 @@ var StrategyList = React.createClass({
render: function() { render: function() {
var strategyNodes = this.props.strategies.map(function(strategy) { var strategyNodes = this.props.strategies.map(function(strategy) {
return <Strategy strategy={strategy} key={strategy.name} />; return <Strategy strategy={strategy} key={strategy.name} onRemove={this.props.onRemove} />;
}); }.bind(this));
return ( return (
<div>{strategyNodes}</div> <div>{strategyNodes}</div>
); );

View File

@ -14,6 +14,14 @@ var StrategyStore = {
}); });
}, },
removeStrategy: function (strategy) {
return reqwest({
url: 'strategies/'+strategy.name,
method: 'delete',
type: TYPE
});
},
getStrategies: function () { getStrategies: function () {
return reqwest({ return reqwest({
url: 'strategies', url: 'strategies',

View File

@ -44,5 +44,9 @@ describe('The strategy api', function () {
.expect(403, done); .expect(403, done);
}); });
it('deletes a new strategy', function (done) {
request
.delete('/strategies/deletable')
.expect(200, done);
});
}); });

View File

@ -11,6 +11,10 @@ var strategies = [
parametersTemplate: { parametersTemplate: {
emails: "String" emails: "String"
} }
},
{
name: "deletable",
description: "deletable"
} }
]; ];