mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-13 04:28:41 -09:00
simple version-based notifications system
This commit is contained in:
parent
71ae9b7e00
commit
d01d3868eb
9 changed files with 132 additions and 6 deletions
|
|
@ -1,5 +1,9 @@
|
|||
import {INIT} from '../constants/index';
|
||||
import rpc from '../rpc';
|
||||
|
||||
export function init() {
|
||||
rpc.emit('init');
|
||||
return {
|
||||
type: INIT
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import {NOTIFICATION_DISMISS} from '../constants/notifications';
|
||||
import ms from 'ms';
|
||||
import {version} from '../../package';
|
||||
import {satisfies} from 'semver';
|
||||
import {remote} from 'electron';
|
||||
import {
|
||||
NOTIFICATION_MESSAGE,
|
||||
NOTIFICATION_DISMISS
|
||||
} from '../constants/notifications';
|
||||
|
||||
export function dismissNotification(id) {
|
||||
return {
|
||||
|
|
@ -6,3 +13,59 @@ export function dismissNotification(id) {
|
|||
id
|
||||
};
|
||||
}
|
||||
|
||||
export function addNotificationMessage(text, url = null, dismissable = true) {
|
||||
return {
|
||||
type: NOTIFICATION_MESSAGE,
|
||||
text,
|
||||
url,
|
||||
dismissable
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchNotifications() {
|
||||
return dispatch => {
|
||||
const retry = err => {
|
||||
setTimeout(() => dispatch(fetchNotifications()), ms(err ? '10s' : '5m'));
|
||||
if (err) {
|
||||
console.error('Notification messages fetch error', err.stack);
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Checking for notification messages');
|
||||
fetch('https://hyper-news.now.sh')
|
||||
.then(res => {
|
||||
res.json()
|
||||
.then(data => {
|
||||
const {messages} = data || {};
|
||||
if (!messages) {
|
||||
throw new Error('Bad response');
|
||||
}
|
||||
const message = messages.filter(msg => {
|
||||
return matchVersion(msg.versions);
|
||||
})[0];
|
||||
if (message) {
|
||||
dispatch(addNotificationMessage(
|
||||
message.text,
|
||||
message.url,
|
||||
message.dismissable
|
||||
));
|
||||
} else {
|
||||
console.log('No matching notification messages');
|
||||
}
|
||||
retry();
|
||||
})
|
||||
.catch(retry);
|
||||
})
|
||||
.catch(retry);
|
||||
};
|
||||
}
|
||||
|
||||
function matchVersion(versions) {
|
||||
return versions.some(v => {
|
||||
if (v === '*') {
|
||||
return true;
|
||||
}
|
||||
return satisfies(version, v);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ export default class Notification extends Component {
|
|||
<a
|
||||
className={css('dismissLink')}
|
||||
onClick={this.handleDismiss}
|
||||
style={{ color: this.props.userDismissColor }}
|
||||
>[x]</a> :
|
||||
null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,34 @@ export default class Notifications extends Component {
|
|||
/>
|
||||
}
|
||||
|
||||
{
|
||||
this.props.messageShowing &&
|
||||
<Notification
|
||||
key="message"
|
||||
backgroundColor="#FE354E"
|
||||
text={this.props.messageText}
|
||||
onDismiss={this.props.onDismissMessage}
|
||||
userDismissable={this.props.messageDismissable}
|
||||
userDismissColor="#AA2D3C"
|
||||
>{
|
||||
this.props.messageURL ? [
|
||||
this.props.messageText,
|
||||
' (',
|
||||
<a
|
||||
key="link"
|
||||
style={{color: '#fff'}}
|
||||
onClick={ev => {
|
||||
window.require('electron').shell.openExternal(ev.target.href);
|
||||
ev.preventDefault();
|
||||
}}
|
||||
href={this.props.messageURL}
|
||||
>more</a>,
|
||||
')'
|
||||
] : null
|
||||
}
|
||||
</Notification>
|
||||
}
|
||||
|
||||
{
|
||||
this.props.updateShowing &&
|
||||
<Notification
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export const NOTIFICATION_MESSAGE = 'NOTIFICATION_MESSAGE';
|
||||
export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS';
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ const NotificationsContainer = connect(
|
|||
updateVersion: ui.updateVersion,
|
||||
updateNote: ui.updateNotes.split('\n')[0]
|
||||
});
|
||||
} else if (notifications.message) {
|
||||
Object.assign(state_, {
|
||||
messageShowing: true,
|
||||
messageText: ui.messageText,
|
||||
messageURL: ui.messageURL,
|
||||
messageDismissable: ui.messageDismissable
|
||||
});
|
||||
}
|
||||
|
||||
return state_;
|
||||
|
|
@ -51,6 +58,9 @@ const NotificationsContainer = connect(
|
|||
onDismissUpdate: () => {
|
||||
dispatch(dismissNotification('updates'));
|
||||
},
|
||||
onDismissMessage: () => {
|
||||
dispatch(dismissNotification('message'));
|
||||
},
|
||||
onUpdateInstall: () => {
|
||||
dispatch(installUpdate());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import * as uiActions from './actions/ui';
|
|||
import * as updaterActions from './actions/updater';
|
||||
import * as sessionActions from './actions/sessions';
|
||||
import * as termGroupActions from './actions/term-groups';
|
||||
import {fetchNotifications} from './actions/notifications';
|
||||
import HyperTermContainer from './containers/hyperterm';
|
||||
import {loadConfig, reloadConfig} from './actions/config';
|
||||
import configureStore from './store/configure-store';
|
||||
|
|
@ -36,6 +37,7 @@ config.subscribe(() => {
|
|||
// and subscribe to all user intents for example from menus
|
||||
rpc.on('ready', () => {
|
||||
store_.dispatch(init());
|
||||
store_.dispatch(fetchNotifications());
|
||||
store_.dispatch(uiActions.setFontSmoothing());
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
UI_WINDOW_MAXIMIZE,
|
||||
UI_WINDOW_UNMAXIMIZE
|
||||
} from '../constants/ui';
|
||||
import {NOTIFICATION_DISMISS} from '../constants/notifications';
|
||||
import {NOTIFICATION_MESSAGE, NOTIFICATION_DISMISS} from '../constants/notifications';
|
||||
import {
|
||||
SESSION_ADD,
|
||||
SESSION_RESIZE,
|
||||
|
|
@ -62,13 +62,17 @@ const initial = Immutable({
|
|||
notifications: {
|
||||
font: false,
|
||||
resize: false,
|
||||
updates: false
|
||||
updates: false,
|
||||
message: false
|
||||
},
|
||||
foregroundColor: '#fff',
|
||||
backgroundColor: '#000',
|
||||
maximized: false,
|
||||
updateVersion: null,
|
||||
updateNotes: null,
|
||||
messageText: null,
|
||||
messageURL: null,
|
||||
messageDismissable: null,
|
||||
bell: 'SOUND',
|
||||
bellSoundURL: 'lib-resource:hterm/audio/bell',
|
||||
copyOnSelect: false,
|
||||
|
|
@ -273,6 +277,14 @@ const reducer = (state = initial, action) => {
|
|||
}, {deep: true});
|
||||
break;
|
||||
|
||||
case NOTIFICATION_MESSAGE:
|
||||
state_ = state.merge({
|
||||
messageText: action.text,
|
||||
messageURL: action.url || null,
|
||||
messageDismissable: action.dismissable === true
|
||||
});
|
||||
break;
|
||||
|
||||
case UPDATE_AVAILABLE:
|
||||
state_ = state.merge({
|
||||
updateVersion: action.version,
|
||||
|
|
@ -296,6 +308,10 @@ const reducer = (state = initial, action) => {
|
|||
state_ = state_.merge({notifications: {resize: true}}, {deep: true});
|
||||
}
|
||||
|
||||
if (state.messageText !== state_.messageText || state.messageURL !== state_.messageURL) {
|
||||
state_ = state_.merge({notifications: {message: true}}, {deep: true});
|
||||
}
|
||||
|
||||
if (state.updateVersion !== state_.updateVersion) {
|
||||
state_ = state_.merge({notifications: {updates: true}}, {deep: true});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hyperterm",
|
||||
"version": "1.0.0",
|
||||
"version": "0.8.0",
|
||||
"description": "Web app that runs in the renderer process",
|
||||
"repository": "zeit/hyperterm",
|
||||
"license": "MIT",
|
||||
|
|
@ -28,8 +28,9 @@
|
|||
"redux": "3.6.0",
|
||||
"redux-thunk": "2.1.0",
|
||||
"reselect": "2.5.4",
|
||||
"uuid": "2.0.2",
|
||||
"seamless-immutable": "6.1.3"
|
||||
"seamless-immutable": "6.1.3",
|
||||
"semver": "5.3.0",
|
||||
"uuid": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^0.16.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue