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

Added ErrorStore

This commit is contained in:
Ivar Conradi Østhus 2015-03-17 20:29:03 +01:00
parent 96600c5598
commit 8ba685b67a
10 changed files with 241 additions and 187 deletions

View File

@ -2,6 +2,7 @@ var React = require('react');
var TabView = require('./components/TabView');
var Menu = require('./components/Menu');
var UserStore = require('./stores/UserStore');
var ErrorMessages = require('./components/ErrorMessages');
var LogEntriesComponent = React.createFactory(require('./components/log/LogEntriesComponent'));
var FeatureTogglesComponent = React.createFactory(require('./components/feature/FeatureTogglesComponent'));
var StrategiesComponent = React.createFactory(require('./components/strategy/StrategiesComponent'));
@ -37,10 +38,10 @@ React.render(
<Menu />
<div className="container">
<div className="page">
<ErrorMessages />
<TabView tabPanes={tabPanes} />
</div>
</div>
</div>
,
</div>,
document.getElementById('content')
);

View File

@ -1,37 +1,38 @@
var React = require('react');
var React = require('react');
var Ui = require('./ErrorMessages.ui');
var ErrorStore = require('../stores/ErrorStore');
var ErrorActions = require('../stores/ErrorActions');
var ErrorMessages = React.createClass({
getInitialState: function() {
return {
errors: ErrorStore.getErrors()
};
},
onStoreChange: function() {
this.setState({
errors: ErrorStore.getErrors()
});
},
componentDidMount: function() {
this.unsubscribe = ErrorStore.listen(this.onStoreChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
onClearErrors: function() {
ErrorActions.clear();
},
render: function() {
if (!this.props.errors.length) {
return <div/>;
}
var errorNodes = this.props.errors.map(function(e, i) {
return (<li key={e + i} className="largetext">{e}</li>);
});
return (
<div className="container">
<div className="mod shadow mtm mrn">
<div className="inner bg-red-lt">
<div className="bd">
<div className="media centerify">
<div className="imgExt">
<a onClick={this.props.onClearErrors}
className="icon-kryss1 linkblock sharp">
</a>
</div>
<div className="bd">
<ul>{errorNodes}</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<Ui errors={this.state.errors} onClearErrors={this.onClearErrors}></Ui>
);
}
});
module.exports = ErrorMessages;

View File

@ -0,0 +1,36 @@
var React = require('react');
var ErrorMessages = React.createClass({
render: function() {
if (!this.props.errors.length) {
return <div/>;
}
var errorNodes = this.props.errors.map(function(e, i) {
return (<li key={e + i} className="largetext">{e}</li>);
});
return (
<div className="container">
<div className="mod shadow mtm mrn">
<div className="inner bg-red-lt">
<div className="bd">
<div className="media centerify">
<div className="imgExt">
<a onClick={this.props.onClearErrors}
className="icon-kryss1 linkblock sharp">
</a>
</div>
<div className="bd">
<ul>{errorNodes}</ul>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
});
module.exports = ErrorMessages;

View File

@ -3,63 +3,63 @@ var FeatureActions = require('../../stores/FeatureToggleActions');
var FeatureToggleStore = require('../../stores/ArchivedToggleStore');
var ArchiveFeatureComponent = React.createClass({
getInitialState: function() {
return {
archivedFeatures: FeatureToggleStore.getArchivedToggles()
};
},
getInitialState: function() {
return {
archivedFeatures: FeatureToggleStore.getArchivedToggles()
};
},
onStoreChange: function() {
this.setState({
archivedFeatures: FeatureToggleStore.getArchivedToggles()
});
},
onStoreChange: function() {
this.setState({
archivedFeatures: FeatureToggleStore.getArchivedToggles()
});
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onStoreChange);
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onStoreChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
componentWillUnmount: function() {
this.unsubscribe();
},
onRevive: function(item) {
FeatureActions.revive(item);
},
onRevive: function(item) {
FeatureActions.revive.triggerPromise(item);
},
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>
);
},
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>
);
},
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>);
}
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;

View File

@ -1,15 +1,14 @@
var React = require('react');
var ErrorMessages = require('../ErrorMessages');
var FeatureList = require('./FeatureList');
var FeatureForm = require('./FeatureForm');
var FeatureActions = require('../../stores/FeatureToggleActions');
var ErrorActions = require('../../stores/ErrorActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore');
var FeatureTogglesComponent = React.createClass({
getInitialState: function() {
return {
features: FeatureToggleStore.getFeatureToggles(),
errors: [],
createView: false
};
},
@ -26,76 +25,31 @@ var FeatureTogglesComponent = React.createClass({
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))
} else if (error.status === 0) {
this.addError("server unreachable");
} else {
this.addError(error);
}
},
updateFeature: function (feature) {
FeatureActions.update.triggerPromise(feature)
.catch(this.handleError);
FeatureActions.update.triggerPromise(feature);
},
archiveFeature: function (feature) {
FeatureActions.archive.triggerPromise(feature)
.catch(this.handleError);
FeatureActions.archive.triggerPromise(feature);
},
createFeature: function (feature) {
FeatureActions.create.triggerPromise(feature)
.then(this.cancelNewFeature)
.catch(this.handleError);
.then(this.cancelNewFeature);
},
newFeature: function() {
this.setState({createView: true});
},
cancelNewFeature: function (feature) {
cancelNewFeature: function () {
this.setState({createView: false});
},
clearErrors: function() {
this.setState({errors: []});
},
addError: function(msg) {
var errors = this.state.errors;
if (errors[errors.length - 1] !== msg) {
errors.push(msg);
this.setState(errors);
}
},
isClientError: function(error) {
try {
return error.status >= 400 &&
error.status < 500 &&
JSON.parse(error.responseText);
} catch (e) {
if (e instanceof SyntaxError) {
// fall through;
} else {
throw e;
}
}
return false;
ErrorActions.clear();
},
render: function() {
return (
<div>
<ErrorMessages
errors={this.state.errors}
onClearErrors={this.clearErrors} />
{this.state.createView ? this.renderCreateView() : this.renderCreateButton()}
@ -111,11 +65,11 @@ var FeatureTogglesComponent = React.createClass({
},
renderCreateView: function() {
return <FeatureForm onCancel={this.cancelNewFeature} onSubmit={this.createFeature} />
return <FeatureForm onCancel={this.cancelNewFeature} onSubmit={this.createFeature} />;
},
renderCreateButton: function() {
return <button className="mal" onClick={this.newFeature}>Create feature toggle</button>
return <button className="mal" onClick={this.newFeature}>Create feature toggle</button>;
}
});

View File

@ -1,14 +1,13 @@
var React = require('react'),
LogEntryList = require('./LogEntryList'),
eventStore = require('../../stores/EventStore'),
ErrorMessages = require('../ErrorMessages');
var React = require('react');
var LogEntryList = require('./LogEntryList');
var eventStore = require('../../stores/EventStore');
var ErrorActions = require('../../stores/ErrorActions');
var LogEntriesComponent = React.createClass({
getInitialState: function() {
return {
createView: false,
events: [],
errors: []
events: []
};
},
@ -19,29 +18,17 @@ var LogEntriesComponent = React.createClass({
},
initError: function() {
this.onError("Could not load events from server");
},
clearErrors: function() {
this.setState({errors: []});
},
onError: function(error) {
var errors = this.state.errors.concat([error]);
this.setState({errors: errors});
ErrorActions.error("Could not load events from server");
},
render: function() {
return (
<div>
<ErrorMessages errors={this.state.errors} onClearErrors={this.clearErrors} />
<hr />
<LogEntryList events={this.state.events} />
</div>
);
},
});
module.exports = LogEntriesComponent;
module.exports = LogEntriesComponent;

View File

@ -1,15 +1,14 @@
var React = require('react'),
StrategyList = require('./StrategyList'),
StrategyForm = require('./StrategyForm'),
strategyStore = require('../../stores/StrategyStore'),
ErrorMessages = require('../ErrorMessages');
var React = require('react');
var StrategyList = require('./StrategyList');
var StrategyForm = require('./StrategyForm');
var strategyStore = require('../../stores/StrategyStore');
var ErrorActions = require('../../stores/ErrorActions');
var StrategiesComponent = React.createClass({
getInitialState: function() {
return {
createView: false,
strategies: [],
errors: []
strategies: []
};
},
@ -17,12 +16,12 @@ var StrategiesComponent = React.createClass({
this.fetchStrategies();
},
fetchStrategies: function(res) {
fetchStrategies: function() {
strategyStore.getStrategies()
.then(function(res) {
this.setState({strategies: res.strategies})
}.bind(this))
.catch(this.initError);
.then(function(res) {
this.setState({strategies: res.strategies});
}.bind(this))
.catch(this.initError);
},
@ -30,13 +29,8 @@ var StrategiesComponent = React.createClass({
this.onError("Could not load inital strategies from server");
},
clearErrors: function() {
this.setState({errors: []});
},
onError: function(error) {
var errors = this.state.errors.concat([error]);
this.setState({errors: errors});
ErrorActions.error(error);
},
onNewStrategy: function() {
@ -66,33 +60,37 @@ var StrategiesComponent = React.createClass({
onRemove: function(strategy) {
strategyStore.removeStrategy(strategy)
.then(this.fetchStrategies)
.catch(this.onError);
.then(this.fetchStrategies)
.catch(this.onError);
},
render: function() {
return (
<div>
<ErrorMessages errors={this.state.errors} onClearErrors={this.clearErrors} />
{this.state.createView ? this.renderCreateView() : this.renderCreateButton()}
{this.state.createView ? this.renderCreateView() : this.renderCreateButton()}
<hr />
<StrategyList strategies={this.state.strategies} onRemove={this.onRemove} />
<StrategyList
strategies={this.state.strategies}
onRemove={this.onRemove} />
</div>
);
);
},
renderCreateView: function() {
return (<StrategyForm onCancelNewStrategy={this.onCancelNewStrategy} onSave={this.onSave} />)
return (
<StrategyForm
onCancelNewStrategy={this.onCancelNewStrategy}
onSave={this.onSave}
/>);
},
renderCreateButton: function() {
return (
<button className="mal" onClick={this.onNewStrategy}>Create strategy</button>
<button className="mal" onClick={this.onNewStrategy}>
Create strategy
</button>
);
}
});
module.exports = StrategiesComponent;
module.exports = StrategiesComponent;

View File

@ -0,0 +1,8 @@
var Reflux = require('reflux');
var ErrorActions = Reflux.createActions([
"clear",
"error"
]);
module.exports = ErrorActions;

View File

@ -0,0 +1,65 @@
var Reflux = require('reflux');
var FeatureActions = require('./FeatureToggleActions');
var ErrorActions = require('./ErrorActions');
// Creates a DataStore
var FeatureStore = Reflux.createStore({
// Initial setup
init: function() {
this.listenTo(FeatureActions.create.failed, this.onError);
this.listenTo(FeatureActions.update.failed, this.onError);
this.listenTo(FeatureActions.archive.failed, this.onError);
this.listenTo(FeatureActions.revive.failed, this.onError);
this.listenTo(ErrorActions.error, this.onError);
this.listenTo(ErrorActions.clear, this.onClear);
this.errors = [];
},
onError: function (error) {
if (this.isClientError(error)) {
var errors = JSON.parse(error.responseText);
errors.forEach(function(e) { this.addError(e.msg); }.bind(this));
} else if (error.status === 0) {
this.addError("server unreachable");
} else {
this.addError(error);
}
},
onClear: function() {
this.errors = [];
this.trigger([]);
},
addError: function(msg) {
var errors = this.errors;
if (errors[errors.length - 1] !== msg) {
errors.push(msg);
this.errors = errors;
this.trigger(errors);
}
},
isClientError: function(error) {
try {
return error.status >= 400 &&
error.status < 500 &&
JSON.parse(error.responseText);
} catch (e) {
if (e instanceof SyntaxError) {
// fall through;
console.log("Syntax error!");
} else {
throw e;
}
}
return false;
},
getErrors: function() {
return this.errors;
}
});
module.exports = FeatureStore;

View File

@ -20,14 +20,18 @@ var FeatureStore = Reflux.createStore({
this.listenTo(FeatureActions.revive.completed, this.onRevive);
//TODO: this should not be part of the store!
this.timer = new Timer(this.loadDataFromServer, 30*1000);
this.timer = new Timer(this.loadDataFromServer, 3*1000);
this.timer.start();
},
loadDataFromServer: function() {
//TODO: this should not be part of the store!
Server.getFeatures(function(err, featureToggles) {
this.setToggles(featureToggles);
if(err) {
return;
} else {
this.setToggles(featureToggles);
}
}.bind(this));
},