Skip to content

Commit 1f1cf9d

Browse files
author
Raphaël Benitte
committed
Merge pull request #77 from plouc/feat-restore-ws
Add ability to automatically reconnect websockets
2 parents fee8bb8 + 6d577dc commit 1f1cf9d

32 files changed

+1162
-239
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"gulp-stylus": "^2.0.0",
5454
"gulp-uglify": "^1.0.2",
5555
"gulp-util": "^3.0.3",
56-
"lodash": "^3.2.0",
56+
"lodash": "4.9.0",
5757
"memory-cache": "0.0.5",
5858
"react-mixin": "3.0.4",
5959
"reflux": "0.4.0",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Reflux from 'reflux';
2+
3+
4+
const ConnectionStatusActions = Reflux.createActions([
5+
'connecting',
6+
'connected',
7+
'disconnected',
8+
'delaying',
9+
'failed'
10+
]);
11+
12+
13+
export default ConnectionStatusActions;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Reflux from 'reflux';
2+
3+
4+
const NotificationsActions = Reflux.createActions([
5+
'notify',
6+
'update',
7+
'close'
8+
]);
9+
10+
11+
export default NotificationsActions;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import reactMixin from 'react-mixin';
3+
import { ListenerMixin } from 'reflux';
4+
import ConnectionStatusStore, {
5+
CONNECTION_STATUS_CONNECTING,
6+
CONNECTION_STATUS_CONNECTED,
7+
CONNECTION_STATUS_DISCONNECTED,
8+
CONNECTION_STATUS_DELAYING,
9+
CONNECTION_STATUS_FAILED
10+
} from '../stores/ConnectionStatusStore';
11+
12+
13+
class ConnectionStatus extends Component {
14+
constructor(props) {
15+
super(props);
16+
17+
this.state = ConnectionStatusStore.getState();
18+
}
19+
20+
componentWillMount() {
21+
this.listenTo(ConnectionStatusStore, this.onStatusUpdate);
22+
}
23+
24+
onStatusUpdate({ countdown, status, retry }) {
25+
this.setState({ countdown, status, retry });
26+
}
27+
28+
render() {
29+
const { countdown, status, retry } = this.state;
30+
31+
let message;
32+
let iconClass;
33+
if (status === CONNECTION_STATUS_CONNECTING) {
34+
message = 'connecting';
35+
iconClass = 'fa fa-question';
36+
} else if (status === CONNECTION_STATUS_CONNECTED) {
37+
message = 'connected';
38+
iconClass = 'fa fa-check';
39+
} else if (status === CONNECTION_STATUS_DISCONNECTED || status === CONNECTION_STATUS_DELAYING) {
40+
message = 'disconnected';
41+
iconClass = 'fa fa-warning';
42+
43+
if (status === CONNECTION_STATUS_DELAYING) {
44+
message = (
45+
<span>
46+
disconnected<br/>
47+
<span className="text-discrete">next attempt in {countdown}s</span>
48+
</span>
49+
);
50+
}
51+
} else if (status === CONNECTION_STATUS_FAILED) {
52+
iconClass = 'fa fa-frown-o';
53+
message = `unable to restore websockets after ${retry} attemps,
54+
please make sure Mozaïk server is running and that
55+
you can reach the internet if running on a remote server.`;
56+
}
57+
58+
return (
59+
<div className="connection-status">
60+
<i className={iconClass}/>
61+
{message}
62+
</div>
63+
);
64+
}
65+
}
66+
67+
ConnectionStatus.displayName = 'ConnectionStatus';
68+
69+
reactMixin(ConnectionStatus.prototype, ListenerMixin);
70+
71+
72+
export default ConnectionStatus;

src/browser/components/Mozaik.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import React, { Component, PropTypes } from 'react';
22
import reactMixin from 'react-mixin';
33
import { ListenerMixin } from 'reflux';
44
import Dashboard from './Dashboard.jsx';
5-
import ConfigStore from './../stores/ConfigStore';
5+
import Notifications from './Notifications.jsx';
6+
import ConfigStore from '../stores/ConfigStore';
67

78

89
class Mozaik extends Component {
@@ -35,6 +36,7 @@ class Mozaik extends Component {
3536
return (
3637
<div className="dashboard">
3738
{dashboardNodes}
39+
<Notifications />
3840
</div>
3941
);
4042
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import _ from 'lodash';
3+
import reactMixin from 'react-mixin';
4+
import { ListenerMixin } from 'reflux';
5+
import NotificationsStore from '../stores/NotificationsStore';
6+
import NotificationsItem from './NotificationsItem.jsx';
7+
8+
9+
class Notifications extends Component {
10+
constructor(props) {
11+
super(props);
12+
13+
this.state = { notifications: [] };
14+
}
15+
16+
componentWillMount() {
17+
this.listenTo(NotificationsStore, this.onNotificationsUpdate);
18+
}
19+
20+
onNotificationsUpdate(notifications) {
21+
this.setState({ notifications });
22+
}
23+
24+
render() {
25+
const { notifications } = this.state;
26+
27+
return (
28+
<div className="notifications">
29+
{notifications.map(notification => (
30+
<NotificationsItem
31+
key={`notification.${notification.id}`}
32+
notification={notification}
33+
/>
34+
))}
35+
</div>
36+
);
37+
}
38+
}
39+
40+
Notifications.displayName = 'Notifications';
41+
42+
Notifications.propTypes = {};
43+
44+
reactMixin(Notifications.prototype, ListenerMixin);
45+
46+
47+
export default Notifications;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import _ from 'lodash';
3+
4+
5+
class NotificationsItem extends Component {
6+
render() {
7+
const { notification } = this.props;
8+
9+
let content;
10+
if (notification.component) {
11+
content = React.createElement(notification.component, _.assign({}, notification.props, {
12+
notificationId: notification.id
13+
}));
14+
} else {
15+
content = notification.message;
16+
}
17+
18+
return (
19+
<div className={`notifications__item notifications__item--${notification.status}`}>
20+
{content}
21+
</div>
22+
);
23+
}
24+
}
25+
26+
NotificationsItem.displayName = 'NotificationsItem';
27+
28+
NotificationsItem.propTypes = {
29+
notification: PropTypes.object.isRequired
30+
};
31+
32+
33+
export default NotificationsItem;

0 commit comments

Comments
 (0)