From 64fdb290ebac99d425c9ab6d27b63f20fe47c378 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 2 Nov 2016 16:02:55 +0000 Subject: [PATCH 1/6] Move 'new version' support into Platform --- src/components/views/globals/NewVersionBar.js | 52 +++++++++++++------ src/vector/index.js | 7 +-- src/vector/platform/WebPlatform.js | 40 ++++++++++++++ src/vector/updater.js | 46 +++------------- 4 files changed, 86 insertions(+), 59 deletions(-) diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index 90b30f727..3ae958041 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -19,6 +19,7 @@ limitations under the License. var React = require('react'); var sdk = require('matrix-react-sdk'); import Modal from 'matrix-react-sdk/lib/Modal'; +import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; /** * Check a version string is compatible with the Changelog @@ -31,30 +32,50 @@ function checkVersion(ver) { export default function NewVersionBar(props) { const onChangelogClicked = () => { - const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog'); - - Modal.createDialog(ChangelogDialog, { - version: props.version, - newVersion: props.newVersion, - onFinished: (update) => { - if(update) { - window.location.reload(); + if (props.releaseNotes) { + const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); + Modal.createDialog(QuestionDialog, { + title: "What's New", + description:
{props.releaseNotes}
, + button: "Update", + onFinished: (update) => { + if(update && PlatformPeg.get()) { + PlatformPeg.get().installUpdate(); + } } - } - }); + }); + } else { + const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog'); + Modal.createDialog(ChangelogDialog, { + version: props.version, + newVersion: props.newVersion, + releaseNotes: releaseNotes, + onFinished: (update) => { + if(update && PlatformPeg.get()) { + PlatformPeg.get().installUpdate(); + } + } + }); + } }; - let changelog_button; - if (checkVersion(props.version) && checkVersion(props.newVersion)) { - changelog_button = ; + const onUpdateClicked = () => { + PlatformPeg.get().installUpdate(); + }; + + let action_button; + if (props.releaseNotes || (checkVersion(props.version) && checkVersion(props.newVersion))) { + action_button = ; + } else if (PlatformPeg.get()) { + action_button = ; } return (
/!\
- A new version of Riot is available. Refresh your browser. + A new version of Riot is available.
- {changelog_button} + {action_button}
); } @@ -62,4 +83,5 @@ export default function NewVersionBar(props) { NewVersionBar.propTypes = { version: React.PropTypes.string.isRequired, newVersion: React.PropTypes.string.isRequired, + releaseNotes: React.PropTypes.string, }; diff --git a/src/vector/index.js b/src/vector/index.js index f260ac01f..affa5042f 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -113,10 +113,6 @@ function onHashChange(ev) { routeUrl(window.location); } -function onVersion(current, latest) { - window.matrixChat.onVersion(current, latest); -} - var loaded = false; var lastLoadedScreen = null; @@ -165,8 +161,7 @@ window.onload = function() { if (!validBrowser) { return; } - UpdateChecker.setVersionListener(onVersion); - UpdateChecker.run(); + UpdateChecker.start(); routeUrl(window.location); loaded = true; if (lastLoadedScreen) { diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index 7ef2b6b8a..c521cf600 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -18,12 +18,14 @@ limitations under the License. import BasePlatform from 'matrix-react-sdk/lib/BasePlatform'; import Favico from 'favico.js'; +import request from 'browser-request'; import dis from 'matrix-react-sdk/lib/dispatcher.js'; import q from 'q'; export default class WebPlatform extends BasePlatform { constructor() { super(); + this.runningVersion = null; // The 'animations' are really low framerate and look terrible. // Also it re-starts the animationb every time you set the badge, // and we set the state each time, even if the value hasn't changed, @@ -88,4 +90,42 @@ export default class WebPlatform extends BasePlatform { notification.close(); }, 5 * 1000); } + + _getVersion() { + const deferred = q.defer(); + request( + { method: "GET", url: "version" }, + (err, response, body) => { + if (err || response.status < 200 || response.status >= 300) { + if (err == null) err = { status: response.status }; + deferred.reject(err); + return; + } + + const ver = body.trim(); + deferred.resolve(ver); + } + ); + return deferred.promise; + } + + pollForUpdate() { + this._getVersion().done((ver) => { + if (this.runningVersion == null) { + this.runningVersion = ver; + } else if (this.runningVersion != ver) { + dis.dispatch({ + action: 'new_version', + currentVersion: this.runningVersion, + newVersion: ver, + }); + } + }, (err) => { + console.error("Failed to poll for update", err); + }); + } + + installUpdate() { + window.location.reload(); + } } diff --git a/src/vector/updater.js b/src/vector/updater.js index e8d6830d0..19d40b4f3 100644 --- a/src/vector/updater.js +++ b/src/vector/updater.js @@ -13,48 +13,18 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + +import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; + var POKE_RATE_MS = 10 * 60 * 1000; // 10 min -var currentVersion = null; -var latestVersion = null; -var listener = function(){}; // NOP module.exports = { - setVersionListener: function(fn) { // invoked with fn(currentVer, newVer) - listener = fn; + start: function() { + module.exports.poll(); + setInterval(module.exports.poll, POKE_RATE_MS); }, - run: function() { - var req = new XMLHttpRequest(); - req.addEventListener("load", function() { - if (!req.responseText) { - return; - } - var ver = req.responseText.trim(); - if (!currentVersion) { - currentVersion = ver; - listener(currentVersion, currentVersion); - } - - if (ver !== latestVersion) { - latestVersion = ver; - if (module.exports.hasNewVersion()) { - console.log("Current=%s Latest=%s", currentVersion, latestVersion); - listener(currentVersion, latestVersion); - } - } - }); - var cacheBuster = "?ts=" + new Date().getTime(); - req.open("GET", "version" + cacheBuster); - req.send(); // can't suppress 404s from being logged. - - setTimeout(module.exports.run, POKE_RATE_MS); - }, - - getCurrentVersion: function() { - return currentVersion; - }, - - hasNewVersion: function() { - return currentVersion && latestVersion && (currentVersion !== latestVersion); + poll: function() { + PlatformPeg.get().pollForUpdate(); } }; From 17bb47676e2623d5a4b91fe1466e2be13e1aa042 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 2 Nov 2016 17:45:35 +0000 Subject: [PATCH 2/6] Make VectorBasePlatform For template methods that are only used from within vector (ie. new version support) --- src/vector/platform/VectorBasePlatform.js | 41 +++++++++++++++++++++++ src/vector/platform/WebPlatform.js | 4 +-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/vector/platform/VectorBasePlatform.js diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js new file mode 100644 index 000000000..a988a4c7a --- /dev/null +++ b/src/vector/platform/VectorBasePlatform.js @@ -0,0 +1,41 @@ +// @flow + +/* +Copyright 2016 Aviral Dasgupta and OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import BasePlatform from 'matrix-react-sdk/lib/BasePlatform' + +/** + * Vector-specific extensions to the BasePlatform template + */ +export default class VectorBasePlatform extends BasePlatform { + /** + * Check for the availability of an update to the version of the + * app that's currently running. + * If an update is available, this function should dispatch the + * 'new_version' action. + */ + pollForUpdate() { + } + + /** + * Update the currently running app to the latest available + * version and replace this instance of the app with the + * new version. + */ + installUpdate() { + } +} diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index c521cf600..9fac6c4a0 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -16,13 +16,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import BasePlatform from 'matrix-react-sdk/lib/BasePlatform'; +import VectorBasePlatform from './VectorBasePlatform'; import Favico from 'favico.js'; import request from 'browser-request'; import dis from 'matrix-react-sdk/lib/dispatcher.js'; import q from 'q'; -export default class WebPlatform extends BasePlatform { +export default class WebPlatform extends VectorBasePlatform { constructor() { super(); this.runningVersion = null; From 8c3fed755993fe78d2aac2844b596672d4881069 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 2 Nov 2016 17:48:47 +0000 Subject: [PATCH 3/6] CSS for changelogs --- src/skins/vector/css/common.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/skins/vector/css/common.css b/src/skins/vector/css/common.css index 5165e9c57..bb00bbd8c 100644 --- a/src/skins/vector/css/common.css +++ b/src/skins/vector/css/common.css @@ -288,3 +288,7 @@ textarea { cursor: pointer; display: inline; } + +.changelog_text { + font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; +} From e8494c3dc78f7e7919feb24f789724959ad0f846 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 2 Nov 2016 19:20:11 +0000 Subject: [PATCH 4/6] Split NewVersionBar release notes / changelog and change the class to use React createClass syntax while I'm at it, rather than a completely different third style we use nowhere else in the project. --- src/components/views/globals/NewVersionBar.js | 117 ++++++++++-------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index 3ae958041..bca4e3dea 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -16,8 +16,8 @@ limitations under the License. 'use strict'; -var React = require('react'); -var sdk = require('matrix-react-sdk'); +import React from 'react'; +import sdk from 'matrix-react-sdk'; import Modal from 'matrix-react-sdk/lib/Modal'; import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; @@ -30,58 +30,71 @@ function checkVersion(ver) { return parts[0] == 'vector' && parts[2] == 'react' && parts[4] == 'js'; } -export default function NewVersionBar(props) { - const onChangelogClicked = () => { - if (props.releaseNotes) { - const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); - Modal.createDialog(QuestionDialog, { - title: "What's New", - description:
{props.releaseNotes}
, - button: "Update", - onFinished: (update) => { - if(update && PlatformPeg.get()) { - PlatformPeg.get().installUpdate(); - } - } - }); - } else { - const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog'); - Modal.createDialog(ChangelogDialog, { - version: props.version, - newVersion: props.newVersion, - releaseNotes: releaseNotes, - onFinished: (update) => { - if(update && PlatformPeg.get()) { - PlatformPeg.get().installUpdate(); - } - } - }); +export default React.createClass({ + propTypes: { + version: React.PropTypes.string.isRequired, + newVersion: React.PropTypes.string.isRequired, + releaseNotes: React.PropTypes.string, + }, + + onChangelogClicked: function() { + // If we have release notes to display, we display them. Otherwise, + // we display the Changelog Dialog which takes two versions and + // automatically tells you what's changed (provided the versions + // are in the right format) + if (this.props.releaseNotes) { + this.displayReleaseNotes(this.props.releaseNotes); + } else if (checkVersion(this.props.version) && checkVersion(this.props.newVersion)) { + this.displayChangelog(); } - }; + }, - const onUpdateClicked = () => { + displayReleaseNotes: function(releaseNotes) { + const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); + Modal.createDialog(QuestionDialog, { + title: "What's New", + description:
{releaseNotes}
, + button: "Update", + onFinished: (update) => { + if(update && PlatformPeg.get()) { + PlatformPeg.get().installUpdate(); + } + } + }); + }, + + displayChangelog: function() { + const ChangelogDialog = sdk.getComponent('dialogs.ChangelogDialog'); + Modal.createDialog(ChangelogDialog, { + version: this.props.version, + newVersion: this.props.newVersion, + onFinished: (update) => { + if(update && PlatformPeg.get()) { + PlatformPeg.get().installUpdate(); + } + } + }); + }, + + onUpdateClicked: function() { PlatformPeg.get().installUpdate(); - }; + }, - let action_button; - if (props.releaseNotes || (checkVersion(props.version) && checkVersion(props.newVersion))) { - action_button = ; - } else if (PlatformPeg.get()) { - action_button = ; - } - return ( -
- /!\ -
- A new version of Riot is available. + render: function() { + let action_button; + if (this.props.releaseNotes || (checkVersion(this.props.version) && checkVersion(this.props.newVersion))) { + action_button = ; + } else if (PlatformPeg.get()) { + action_button = ; + } + return ( +
+ /!\ +
+ A new version of Riot is available. +
+ {action_button}
- {action_button} -
- ); -} - -NewVersionBar.propTypes = { - version: React.PropTypes.string.isRequired, - newVersion: React.PropTypes.string.isRequired, - releaseNotes: React.PropTypes.string, -}; + ); + } +}); From 108af83ae815be6776e70b20f37f5107f29067fe Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 3 Nov 2016 11:43:50 +0000 Subject: [PATCH 5/6] Just bind the right function to the button rather than deciding in onChangelogClicked --- src/components/views/globals/NewVersionBar.js | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index bca4e3dea..36d6bc71b 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -37,18 +37,6 @@ export default React.createClass({ releaseNotes: React.PropTypes.string, }, - onChangelogClicked: function() { - // If we have release notes to display, we display them. Otherwise, - // we display the Changelog Dialog which takes two versions and - // automatically tells you what's changed (provided the versions - // are in the right format) - if (this.props.releaseNotes) { - this.displayReleaseNotes(this.props.releaseNotes); - } else if (checkVersion(this.props.version) && checkVersion(this.props.newVersion)) { - this.displayChangelog(); - } - }, - displayReleaseNotes: function(releaseNotes) { const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); Modal.createDialog(QuestionDialog, { @@ -82,8 +70,14 @@ export default React.createClass({ render: function() { let action_button; - if (this.props.releaseNotes || (checkVersion(this.props.version) && checkVersion(this.props.newVersion))) { - action_button = ; + // If we have release notes to display, we display them. Otherwise, + // we display the Changelog Dialog which takes two versions and + // automatically tells you what's changed (provided the versions + // are in the right format) + if (this.props.releaseNotes) { + action_button = ; + } else if (checkVersion(this.props.version) && checkVersion(this.props.newVersion)) { + action_button = ; } else if (PlatformPeg.get()) { action_button = ; } From f1b72dfa098a5e896fa69e0100749271325a5d7c Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 3 Nov 2016 11:51:41 +0000 Subject: [PATCH 6/6] Fix copyright --- src/vector/platform/VectorBasePlatform.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js index a988a4c7a..d2ed8c344 100644 --- a/src/vector/platform/VectorBasePlatform.js +++ b/src/vector/platform/VectorBasePlatform.js @@ -1,7 +1,8 @@ // @flow /* -Copyright 2016 Aviral Dasgupta and OpenMarket Ltd +Copyright 2016 Aviral Dasgupta +Copyright 2016 OpenMarket Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.