mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-12 20:18:41 -09:00
add auto update checking
This commit is contained in:
parent
76886669da
commit
db21e8e87d
6 changed files with 122 additions and 6 deletions
|
|
@ -63,3 +63,23 @@ header {
|
||||||
.resize-indicator.showing {
|
.resize-indicator.showing {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.update-indicator {
|
||||||
|
background: rgba(255, 51, 76, .8);
|
||||||
|
padding: 6px 14px;
|
||||||
|
color: #fff;
|
||||||
|
font: 11px Menlo;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 150ms ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-indicator a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-indicator.showing {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import classes from 'classnames';
|
||||||
import getTextMetrics from './text-metrics';
|
import getTextMetrics from './text-metrics';
|
||||||
import shallowCompare from 'react-addons-shallow-compare';
|
import shallowCompare from 'react-addons-shallow-compare';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import UpdateChecker from './update-checker';
|
||||||
|
|
||||||
export default class HyperTerm extends Component {
|
export default class HyperTerm extends Component {
|
||||||
constructor () {
|
constructor () {
|
||||||
|
|
@ -19,7 +20,8 @@ export default class HyperTerm extends Component {
|
||||||
active: null,
|
active: null,
|
||||||
activeMarkers: [],
|
activeMarkers: [],
|
||||||
mac: /Mac/.test(navigator.userAgent),
|
mac: /Mac/.test(navigator.userAgent),
|
||||||
resizeIndicatorShowing: false
|
resizeIndicatorShowing: false,
|
||||||
|
updateVersion: null
|
||||||
};
|
};
|
||||||
|
|
||||||
// we set this to true when the first tab
|
// we set this to true when the first tab
|
||||||
|
|
@ -34,6 +36,7 @@ export default class HyperTerm extends Component {
|
||||||
|
|
||||||
this.onResize = this.onResize.bind(this);
|
this.onResize = this.onResize.bind(this);
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
|
this.openExternal = this.openExternal.bind(this);
|
||||||
this.focusActive = this.focusActive.bind(this);
|
this.focusActive = this.focusActive.bind(this);
|
||||||
this.onHeaderMouseDown = this.onHeaderMouseDown.bind(this);
|
this.onHeaderMouseDown = this.onHeaderMouseDown.bind(this);
|
||||||
|
|
||||||
|
|
@ -80,9 +83,19 @@ export default class HyperTerm extends Component {
|
||||||
<div className={classes('resize-indicator', { showing: this.state.resizeIndicatorShowing })}>
|
<div className={classes('resize-indicator', { showing: this.state.resizeIndicatorShowing })}>
|
||||||
{ this.state.cols }x{ this.state.rows }
|
{ this.state.cols }x{ this.state.rows }
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classes('update-indicator', { showing: null !== this.state.updateVersion })}>
|
||||||
|
Update available (<b>{ this.state.updateVersion }</b>).
|
||||||
|
{' '}
|
||||||
|
<a href='https://hyperterm.now.sh' onClick={this.openExternal} target='_blank'>Download</a>
|
||||||
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openExternal (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
this.rpc.emit('open external', { url: ev.target.href });
|
||||||
|
}
|
||||||
|
|
||||||
requestTab () {
|
requestTab () {
|
||||||
this.rpc.emit('new', this.getDimensions());
|
this.rpc.emit('new', this.getDimensions());
|
||||||
}
|
}
|
||||||
|
|
@ -156,6 +169,7 @@ export default class HyperTerm extends Component {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.rpc = new RPC();
|
this.rpc = new RPC();
|
||||||
|
this.updateChecker = new UpdateChecker(this.onUpdateAvailable.bind(this));
|
||||||
this.setState(this.getDimensions());
|
this.setState(this.getDimensions());
|
||||||
|
|
||||||
// open a new tab upon mounting
|
// open a new tab upon mounting
|
||||||
|
|
@ -218,6 +232,10 @@ export default class HyperTerm extends Component {
|
||||||
Mousetrap.bind('command+alt+right', this.moveRight);
|
Mousetrap.bind('command+alt+right', this.moveRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateAvailable (updateVersion) {
|
||||||
|
this.setState({ updateVersion });
|
||||||
|
}
|
||||||
|
|
||||||
moveTo (n) {
|
moveTo (n) {
|
||||||
if (this.state.sessions[n]) {
|
if (this.state.sessions[n]) {
|
||||||
this.setActive(n);
|
this.setActive(n);
|
||||||
|
|
@ -359,5 +377,6 @@ export default class HyperTerm extends Component {
|
||||||
this.rpc.destroy();
|
this.rpc.destroy();
|
||||||
clearTimeout(this.resizeIndicatorTimeout);
|
clearTimeout(this.resizeIndicatorTimeout);
|
||||||
Mousetrap.reset();
|
Mousetrap.reset();
|
||||||
|
this.updateChecker.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
"mousetrap": "1.6.0",
|
"mousetrap": "1.6.0",
|
||||||
"classnames": "2.2.5",
|
"classnames": "2.2.5",
|
||||||
"react": "15.1.0",
|
"react": "15.1.0",
|
||||||
"react-dom": "15.1.0"
|
"react-dom": "15.1.0",
|
||||||
|
"semver-compare": "^1.0.0",
|
||||||
|
"json-loader": "^0.5.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "2.13.1",
|
"eslint": "2.13.1",
|
||||||
|
|
@ -30,10 +32,19 @@
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"yoda": 0,
|
"yoda": 0,
|
||||||
"semi": [2, "always"],
|
"semi": [
|
||||||
|
2,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
"no-unused-vars": 2,
|
"no-unused-vars": 2,
|
||||||
"no-extra-semi": 2,
|
"no-extra-semi": 2,
|
||||||
"semi-spacing": [2, { "before": false, "after": true }],
|
"semi-spacing": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
"before": false,
|
||||||
|
"after": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"react/jsx-uses-react": 1,
|
"react/jsx-uses-react": 1,
|
||||||
"react/jsx-uses-vars": 1
|
"react/jsx-uses-vars": 1
|
||||||
},
|
},
|
||||||
|
|
|
||||||
58
app/update-checker.js
Normal file
58
app/update-checker.js
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*global fetch:false*/
|
||||||
|
import { version as currentVersion } from '../package';
|
||||||
|
import compare from 'semver-compare';
|
||||||
|
|
||||||
|
export default class UpdateChecker {
|
||||||
|
|
||||||
|
constructor (fn, { interval = 5000 } = {}) {
|
||||||
|
this.callback = fn;
|
||||||
|
this.interval = interval;
|
||||||
|
this.check();
|
||||||
|
this.lastKnown = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
check () {
|
||||||
|
const done = () => {
|
||||||
|
this.checkTimer = setTimeout(() => {
|
||||||
|
this.check();
|
||||||
|
}, this.interval);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('checking for update');
|
||||||
|
fetch('https://hyperterm.now.sh/data.json')
|
||||||
|
.then((res) => {
|
||||||
|
if (200 !== res.status) {
|
||||||
|
console.error('Update check error. Status (%d)', res.status);
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json()
|
||||||
|
.then(({ version }) => {
|
||||||
|
if (this.lastKnown !== version) {
|
||||||
|
this.lastKnown = version;
|
||||||
|
|
||||||
|
if (1 === compare(version, currentVersion)) {
|
||||||
|
console.log('update found');
|
||||||
|
this.callback(version);
|
||||||
|
} else {
|
||||||
|
console.log('no update. latest:', version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Update JSON parse error', err.stack);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error('Update check error', err.stack);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy () {
|
||||||
|
this.aborted = true;
|
||||||
|
clearTimeout(this.checkTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,10 @@ module.exports = {
|
||||||
'babel-loader'
|
'babel-loader'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.json/,
|
||||||
|
loader: 'json-loader'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
loader: 'style-loader!css-loader'
|
loader: 'style-loader!css-loader'
|
||||||
|
|
|
||||||
6
index.js
6
index.js
|
|
@ -1,4 +1,4 @@
|
||||||
const { app, BrowserWindow, Menu } = require('electron');
|
const { app, BrowserWindow, shell, Menu } = require('electron');
|
||||||
const createRPC = require('./rpc');
|
const createRPC = require('./rpc');
|
||||||
const Session = require('./session');
|
const Session = require('./session');
|
||||||
const genUid = require('uid2');
|
const genUid = require('uid2');
|
||||||
|
|
@ -81,6 +81,10 @@ app.on('ready', () => {
|
||||||
sessions.get(uid).write(data);
|
sessions.get(uid).write(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rpc.on('open external', ({ url }) => {
|
||||||
|
shell.openExternal(url);
|
||||||
|
});
|
||||||
|
|
||||||
const deleteSessions = () => {
|
const deleteSessions = () => {
|
||||||
sessions.forEach((session, key) => {
|
sessions.forEach((session, key) => {
|
||||||
session.removeAllListeners();
|
session.removeAllListeners();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue