From dedab147574b60a0e61ce600ef1994d42cf05d99 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 24 May 2017 16:50:50 +1000 Subject: [PATCH 1/8] Add mock UI for the updater --- src/About.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/About.js b/src/About.js index 937e95a..1af9f29 100644 --- a/src/About.js +++ b/src/About.js @@ -1,11 +1,23 @@ +import { remote } from 'electron'; import React from 'react'; import packageData from '../package.json'; +import Icon from './Icon'; import './About.css'; export default class About extends React.Component { + constructor(props) { + super(props); + + this.state = { + update: null, + } + } + render() { + const { update } = this.state; + return
@@ -18,6 +30,23 @@ export default class About extends React.Component { {' '} View releases

+ { update ? ( + update === 'download' ? ( +

this.setState({ update: 'ready' })}> + Downloading update… +

+ ) : ( +

{remote.app.relaunch();remote.app.quit();}}> + +

+ ) + ) : ( +

+ +

+ ) }

Chassis is produced by {' '} Bronson Quick, {' '} From be4319bd63acb1cd25a0442768e7e54e47f62e3d Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:40:51 +1000 Subject: [PATCH 2/8] Update electron-builder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b6950f..9427341 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "devtron": "^1.4.0", "dotenv": "2.0.0", "electron": "^1.6.8", - "electron-builder": "^11.7.0", + "electron-builder": "^18.0.1", "electron-debug": "^1.1.0", "eslint": "3.5.0", "eslint-config-react-app": "^0.2.1", From 95916dc0a8a8737c59c3946234fd196708ed4abf Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:41:15 +1000 Subject: [PATCH 3/8] Add electron-updater --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9427341..db4273c 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "description": "Manage local WordPress development environments through a handy UI.", "private": true, "main": "electron.js", + "dependencies": { + "electron-updater": "^1.16.0" + }, "devDependencies": { "ansi-html": "0.0.6", "autoprefixer": "6.4.1", @@ -118,7 +121,8 @@ }, "files": [ "build/**/*", - "electron.js" + "electron.js", + "node_modules/**/*" ], "directories": { "buildResources": "resources" From ba4636a5480e847c0655da15a780989d3f350d1a Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:41:46 +1000 Subject: [PATCH 4/8] Add and configure electron-updater --- electron.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- package.json | 5 +++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/electron.js b/electron.js index 214dbe1..a294721 100644 --- a/electron.js +++ b/electron.js @@ -1,4 +1,5 @@ -const { app, BrowserWindow, Menu, protocol, shell } = require('electron'); +const { app, BrowserWindow, ipcMain, Menu, protocol, shell } = require('electron'); +const { autoUpdater } = require("electron-updater"); const path = require('path'); if (process.env.NODE_ENV === 'development') { @@ -84,6 +85,49 @@ function createAboutWindow() { }) } +function sendEvent( event, data) { + if ( aboutWindow ) { + aboutWindow.webContents.send( event, data ); + } + if ( win ) { + win.webContents.send( event, data ); + } +} + +function configureAutoupdates() { + const sendStatusToWindow = data => sendEvent( 'update-status', data ); + + // Configure the updater. + autoUpdater.allowPrerelease = true; + + // Listen to events. + autoUpdater.on( 'checking-for-update', () => { + sendStatusToWindow( { type: 'checking-for-update' } ) + }) + autoUpdater.on( 'update-available', info => { + sendStatusToWindow( { type: 'update-available', info } ) + }) + autoUpdater.on( 'update-not-available', (ev, info) => { + console.log( ev, info ); + sendStatusToWindow( { type: 'update-not-available', info } ) + }) + autoUpdater.on( 'error', (ev, err) => { + sendStatusToWindow( { type: 'error', err } ) + }) + autoUpdater.on( 'update-downloaded', (ev, info) => { + sendStatusToWindow( { type: 'update-downloaded', info } ) + }) + // Not supported on Mac: + // https://github.com/electron-userland/electron-builder/issues/1167 + // https://github.com/Squirrel/Squirrel.Mac/issues/200 + autoUpdater.on( 'download-progress', (ev, progressObj) => { + sendStatusToWindow( { type: 'download-progress', progressObj } ) + }) + + ipcMain.on( 'check-update', () => autoUpdater.checkForUpdates() ) + ipcMain.on( 'install-update', () => autoUpdater.quitAndInstall() ) +} + // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. @@ -103,6 +147,7 @@ app.on('ready', () => { ); createWindow(); + configureAutoupdates(); const mainMenu = Menu.buildFromTemplate([ { diff --git a/package.json b/package.json index db4273c..36044e2 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,11 @@ "schemes": [ "chassis" ] + }, + "artifactName": "chassis-desktop-${version}.${ext}", + "publish": { + "provider": "github", + "vPrefixedTagName": false } } } From 713d5c8cc606197fdcf37e65d25a790987876fde Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:42:55 +1000 Subject: [PATCH 5/8] Use electron-updater for the about screen --- src/About.js | 31 ++---------------- src/About/Updater.js | 78 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 src/About/Updater.js diff --git a/src/About.js b/src/About.js index 1af9f29..99d49fc 100644 --- a/src/About.js +++ b/src/About.js @@ -1,23 +1,12 @@ -import { remote } from 'electron'; import React from 'react'; +import Updater from './About/Updater'; import packageData from '../package.json'; -import Icon from './Icon'; import './About.css'; export default class About extends React.Component { - constructor(props) { - super(props); - - this.state = { - update: null, - } - } - render() { - const { update } = this.state; - return

@@ -30,23 +19,7 @@ export default class About extends React.Component { {' '} View releases

- { update ? ( - update === 'download' ? ( -

this.setState({ update: 'ready' })}> - Downloading update… -

- ) : ( -

{remote.app.relaunch();remote.app.quit();}}> - -

- ) - ) : ( -

- -

- ) } +

Chassis is produced by {' '} Bronson Quick, {' '} diff --git a/src/About/Updater.js b/src/About/Updater.js new file mode 100644 index 0000000..3d3f318 --- /dev/null +++ b/src/About/Updater.js @@ -0,0 +1,78 @@ +import { ipcRenderer, remote } from 'electron'; +import React from 'react'; + +import Button from '../Button'; +import Icon from '../Icon'; + +export default class Updater extends React.Component { + constructor(props) { + super(props); + + this.state = { + status: null, + available: null, + }; + ipcRenderer.on( 'update-status', (e, data) => { + switch ( data.type ) { + case 'checking-for-update': + case 'update-not-available': + case 'update-downloaded': + this.setState({ status: data.type }); + break; + + case 'update-available': + this.setState({ + status: data.type, + available: data.info, + }); + break; + + default: + console.log( 'unknown', data ); + break; + } + }); + } + + onCheck() { + ipcRenderer.send( 'check-update' ); + } + + onInstall() { + ipcRenderer.send( 'install-update' ); + } + + render() { + const { available, status } = this.state; + + switch ( status ) { + case 'checking-for-update': + return

+ Checking for updates… +

; + + case 'update-available': + return

+ Downloading { available.version }… +

; + + case 'update-not-available': + return

+ You're up to date! +

+ + case 'update-downloaded': + return

this.onInstall()}> + +

; + + default: + return

+ +

; + } + + } +} From e268fbca4ef9849441b1bafa2560a47a546ae53b Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:54:16 +1000 Subject: [PATCH 6/8] Remove unused components --- src/About/Updater.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/About/Updater.js b/src/About/Updater.js index 3d3f318..187178f 100644 --- a/src/About/Updater.js +++ b/src/About/Updater.js @@ -1,7 +1,6 @@ -import { ipcRenderer, remote } from 'electron'; +import { ipcRenderer } from 'electron'; import React from 'react'; -import Button from '../Button'; import Icon from '../Icon'; export default class Updater extends React.Component { From 77e452114d8c5605fe762850f578e42acc6ea171 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:54:37 +1000 Subject: [PATCH 7/8] Move Updater component CSS into own file --- src/About.css | 3 --- src/About/Updater.css | 3 +++ src/About/Updater.js | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 src/About/Updater.css diff --git a/src/About.css b/src/About.css index d2482bc..c2c5675 100644 --- a/src/About.css +++ b/src/About.css @@ -30,9 +30,6 @@ html { margin-top: 0; margin-bottom: 0.75em; } -.About .update .fa-spinner { - animation: Splash-loader infinite 2s linear; -} .About .logo { width: 200px; padding: 1rem; diff --git a/src/About/Updater.css b/src/About/Updater.css new file mode 100644 index 0000000..eef65a0 --- /dev/null +++ b/src/About/Updater.css @@ -0,0 +1,3 @@ +.Updater .fa-spinner { + animation: Splash-loader infinite 2s linear; +} diff --git a/src/About/Updater.js b/src/About/Updater.js index 187178f..49bda3e 100644 --- a/src/About/Updater.js +++ b/src/About/Updater.js @@ -3,6 +3,8 @@ import React from 'react'; import Icon from '../Icon'; +import './Updater.css'; + export default class Updater extends React.Component { constructor(props) { super(props); @@ -46,27 +48,27 @@ export default class Updater extends React.Component { switch ( status ) { case 'checking-for-update': - return

+ return

Checking for updates…

; case 'update-available': - return

+ return

Downloading { available.version }…

; case 'update-not-available': - return

+ return

You're up to date!

case 'update-downloaded': - return

this.onInstall()}> + return

this.onInstall()}>

; default: - return

+ return

From 3b89c007bad70343313a602bd8f21e54b9895440 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 25 May 2017 14:56:53 +1000 Subject: [PATCH 8/8] Remove IPC listener when unrendering --- src/About/Updater.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/About/Updater.js b/src/About/Updater.js index 49bda3e..436e679 100644 --- a/src/About/Updater.js +++ b/src/About/Updater.js @@ -13,7 +13,7 @@ export default class Updater extends React.Component { status: null, available: null, }; - ipcRenderer.on( 'update-status', (e, data) => { + this.listener = (e, data) => { switch ( data.type ) { case 'checking-for-update': case 'update-not-available': @@ -32,7 +32,12 @@ export default class Updater extends React.Component { console.log( 'unknown', data ); break; } - }); + } + ipcRenderer.on( 'update-status', this.listener ); + } + + componentWillUnmount() { + ipcRenderer.removeListener( 'update-status', this.listener ); } onCheck() {