mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-01 00:08:27 +01:00
Added ErrorStore
This commit is contained in:
parent
96600c5598
commit
8ba685b67a
@ -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')
|
||||
);
|
||||
|
@ -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;
|
||||
|
||||
|
36
public/js/components/ErrorMessages.ui.jsx
Normal file
36
public/js/components/ErrorMessages.ui.jsx
Normal 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;
|
@ -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;
|
||||
|
@ -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>;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
8
public/js/stores/ErrorActions.js
Normal file
8
public/js/stores/ErrorActions.js
Normal file
@ -0,0 +1,8 @@
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var ErrorActions = Reflux.createActions([
|
||||
"clear",
|
||||
"error"
|
||||
]);
|
||||
|
||||
module.exports = ErrorActions;
|
65
public/js/stores/ErrorStore.js
Normal file
65
public/js/stores/ErrorStore.js
Normal 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;
|
@ -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));
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user