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 e1c7b6b..c9e1a90 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", @@ -23,7 +26,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", @@ -118,7 +121,8 @@ }, "files": [ "build/**/*", - "electron.js" + "electron.js", + "node_modules/**/*" ], "directories": { "buildResources": "resources" @@ -129,6 +133,11 @@ "schemes": [ "chassis" ] + }, + "artifactName": "chassis-desktop-${version}.${ext}", + "publish": { + "provider": "github", + "vPrefixedTagName": false } } } 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.js b/src/About.js index 937e95a..99d49fc 100644 --- a/src/About.js +++ b/src/About.js @@ -1,5 +1,6 @@ import React from 'react'; +import Updater from './About/Updater'; import packageData from '../package.json'; import './About.css'; @@ -18,6 +19,7 @@ export default class About extends React.Component { {' '} View releases
+Chassis is produced by {' '} Bronson Quick, {' '} 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 new file mode 100644 index 0000000..436e679 --- /dev/null +++ b/src/About/Updater.js @@ -0,0 +1,84 @@ +import { ipcRenderer } from 'electron'; +import React from 'react'; + +import Icon from '../Icon'; + +import './Updater.css'; + +export default class Updater extends React.Component { + constructor(props) { + super(props); + + this.state = { + status: null, + available: null, + }; + this.listener = (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; + } + } + ipcRenderer.on( 'update-status', this.listener ); + } + + componentWillUnmount() { + ipcRenderer.removeListener( 'update-status', this.listener ); + } + + onCheck() { + ipcRenderer.send( 'check-update' ); + } + + onInstall() { + ipcRenderer.send( 'install-update' ); + } + + render() { + const { available, status } = this.state; + + switch ( status ) { + case 'checking-for-update': + return
+
+
+ You're up to date! +
+ + case 'update-downloaded': + returnthis.onInstall()}> + +
; + + default: + return+ +
; + } + + } +}