diff --git a/CHANGELOG.md b/CHANGELOG.md index 12ebad99..31973282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +Changes in [0.9.0](https://github.com/vector-im/vector-web/releases/tag/v0.9.0) (2016-11-19) +============================================================================================ +[Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4...v0.9.0) + + * Add a cachebuster to /version + [\#2596](https://github.com/vector-im/vector-web/pull/2596) + * Add a 'View decrypted source' button + [\#2587](https://github.com/vector-im/vector-web/pull/2587) + * Fix changelog dialog to read new version format + [\#2577](https://github.com/vector-im/vector-web/pull/2577) + * Build all of the vector dir in the build process + [\#2558](https://github.com/vector-im/vector-web/pull/2558) + * Support for get_app_version + [\#2553](https://github.com/vector-im/vector-web/pull/2553) + * Add CSS for mlist truncation + [\#2565](https://github.com/vector-im/vector-web/pull/2565) + * Add menu option for `external_url` if present + [\#2560](https://github.com/vector-im/vector-web/pull/2560) + * Make auto-update configureable + [\#2555](https://github.com/vector-im/vector-web/pull/2555) + * Missed files electron windows fixes + [\#2556](https://github.com/vector-im/vector-web/pull/2556) + * Add some CSS for scalar error popup + [\#2554](https://github.com/vector-im/vector-web/pull/2554) + * Catch unhandled errors in the electron process + [\#2552](https://github.com/vector-im/vector-web/pull/2552) + * Slight grab-bag of fixes for electron on Windows + [\#2551](https://github.com/vector-im/vector-web/pull/2551) + * Electron app (take 3) + [\#2535](https://github.com/vector-im/vector-web/pull/2535) + * Use webpack-dev-server instead of http-server + [\#2542](https://github.com/vector-im/vector-web/pull/2542) + * Better support no-config when loading from file + [\#2541](https://github.com/vector-im/vector-web/pull/2541) + * Fix loading with no config from HTTP + [\#2540](https://github.com/vector-im/vector-web/pull/2540) + * Move 'new version' support into Platform + [\#2532](https://github.com/vector-im/vector-web/pull/2532) + * Add Notification support to the Web Platform + [\#2533](https://github.com/vector-im/vector-web/pull/2533) + * Use the defaults if given a blank config file + [\#2534](https://github.com/vector-im/vector-web/pull/2534) + * Implement Platforms + [\#2531](https://github.com/vector-im/vector-web/pull/2531) + hanges in [0.8.4](https://github.com/vector-im/vector-web/releases/tag/v0.8.4) (2016-11-04) ============================================================================================ [Full Changelog](https://github.com/vector-im/vector-web/compare/v0.8.4-rc.2...v0.8.4) diff --git a/config.sample.json b/config.sample.json index 49303769..a25bdb11 100644 --- a/config.sample.json +++ b/config.sample.json @@ -31,6 +31,8 @@ "nativePattern": "[^\\s]+/[^\\s]+$" }, "irc:freenode": { + "protocol": "irc", + "domain": "chat.freenode.net", "portalRoomPattern": "#freenode_.*:matrix.org", "name": "Freenode", "icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", @@ -38,6 +40,8 @@ "nativePattern": "^#[^\\s]+$" }, "irc:mozilla": { + "protocol": "irc", + "domain": "irc.mozilla.org", "portalRoomPattern": "#mozilla_.*:matrix.org", "name": "Mozilla", "icon": "//matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", diff --git a/electron/config.json b/electron/config.json new file mode 100644 index 00000000..7bf4c4d8 --- /dev/null +++ b/electron/config.json @@ -0,0 +1,72 @@ +{ + "update_url": "https://riot.im/download/desktop/", + "default_hs_url": "https://matrix.org", + "default_is_url": "https://vector.im", + "brand": "Riot", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "enableLabs": true, + "roomDirectory": { + "servers": [ + "matrix.org" + ], + "serverConfig": { + "matrix.org": { + "networks": [ + "_matrix", + "gitter", + "irc:freenode", + "irc:mozilla", + "irc:snoonet", + "irc:oftc" + ] + } + }, + "networks": { + "gitter": { + "protocol": "gitter", + "portalRoomPattern": "#gitter_.*:matrix.org", + "name": "Gitter", + "icon": "https://gitter.im/favicon.ico", + "example": "org/community", + "nativePattern": "[^\\s]+/[^\\s]+$" + }, + "irc:freenode": { + "protocol": "irc", + "domain": "chat.freenode.net", + "portalRoomPattern": "#freenode_.*:matrix.org", + "name": "Freenode", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:mozilla": { + "protocol": "irc", + "domain": "chat.freenode.net", + "portalRoomPattern": "#mozilla_.*:matrix.org", + "name": "Mozilla", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:snoonet": { + "protocol": "irc", + "domain": "ipv6-irc.snoonet.org", + "portalRoomPattern": "#_snoonet_.*:matrix.org", + "name": "Snoonet", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:oftc": { + "protocol": "irc", + "domain": "irc.oftc.net", + "portalRoomPattern": "#_oftc_.*:matrix.org", + "name": "OFTC", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + } + } + } +} diff --git a/package.json b/package.json index 173b9e1d..fde6fbaa 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vector-web", "productName": "Riot", "main": "electron/src/electron-main.js", - "version": "0.8.4", + "version": "0.9.0", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "repository": { @@ -35,7 +35,7 @@ "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", - "build:electron": "build -lwm", + "build:electron": "npm run clean && npm run build && cpx electron/config.json webapp/ && build -lwm", "build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev", "dist": "scripts/package.sh", @@ -70,10 +70,10 @@ "matrix-react-sdk": "matrix-org/matrix-react-sdk#develop", "modernizr": "^3.1.0", "q": "^1.4.1", - "react": "^15.2.1", + "react": "^15.4.0", "react-dnd": "^2.1.4", "react-dnd-html5-backend": "^2.1.2", - "react-dom": "^15.2.1", + "react-dom": "^15.4.0", "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef", "sanitize-html": "^1.11.1", "ua-parser-js": "^0.7.10", @@ -115,8 +115,8 @@ "mocha": "^2.4.5", "parallelshell": "^1.2.0", "phantomjs-prebuilt": "^2.1.7", - "react-addons-perf": "^15.0", - "react-addons-test-utils": "^15.0.1", + "react-addons-perf": "^15.4.0", + "react-addons-test-utils": "^15.4.0", "rimraf": "^2.4.3", "source-map-loader": "^0.1.5", "webpack": "^1.12.14", diff --git a/scripts/package.sh b/scripts/package.sh index 05227e1b..5c1fdd5e 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -15,6 +15,11 @@ fi npm run clean npm run build$dev + +# include the sample config in the tarball. Arguably this should be done by +# `npm run build`, but it's just too painful. +cp config.sample.json webapp/ + mkdir -p dist cp -r webapp vector-$version echo $version > vector-$version/version diff --git a/src/components/structures/ViewSource.js b/src/components/structures/ViewSource.js index 1dbc5319..a0e198ce 100644 --- a/src/components/structures/ViewSource.js +++ b/src/components/structures/ViewSource.js @@ -22,7 +22,8 @@ module.exports = React.createClass({ displayName: 'ViewSource', propTypes: { - onFinished: React.PropTypes.func.isRequired + content: React.PropTypes.object.isRequired, + onFinished: React.PropTypes.func.isRequired, }, componentDidMount: function() { @@ -45,10 +46,9 @@ module.exports = React.createClass({ return (
-                    {JSON.stringify(this.props.mxEvent.event, null, 2)}
+                    {JSON.stringify(this.props.content, null, 2)}
                 
); } }); - diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 7786b9bd..e3640f77 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -47,7 +47,16 @@ module.exports = React.createClass({ onViewSourceClick: function() { var ViewSource = sdk.getComponent('structures.ViewSource'); Modal.createDialog(ViewSource, { - mxEvent: this.props.mxEvent + content: this.props.mxEvent.event, + }, 'mx_Dialog_viewsource'); + if (this.props.onFinished) this.props.onFinished(); + }, + + onViewClearSourceClick: function() { + const ViewSource = sdk.getComponent('structures.ViewSource'); + Modal.createDialog(ViewSource, { + // FIXME: _clearEvent is private + content: this.props.mxEvent._clearEvent, }, 'mx_Dialog_viewsource'); if (this.props.onFinished) this.props.onFinished(); }, @@ -97,6 +106,7 @@ module.exports = React.createClass({ var eventStatus = this.props.mxEvent.status; var resendButton; var viewSourceButton; + var viewClearSourceButton; var redactButton; var cancelButton; var permalinkButton; @@ -133,6 +143,14 @@ module.exports = React.createClass({ ); + if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) { + viewClearSourceButton = ( +
+ View Decrypted Source +
+ ); + } + if (this.props.eventTileOps) { if (this.props.eventTileOps.isWidgetHidden()) { unhidePreviewButton = ( @@ -174,6 +192,7 @@ module.exports = React.createClass({ {redactButton} {cancelButton} {viewSourceButton} + {viewClearSourceButton} {unhidePreviewButton} {permalinkButton} {UserSettingsStore.isFeatureEnabled('rich_text_editor') ? quoteButton : null} diff --git a/src/vector/index.js b/src/vector/index.js index 9c9d48fa..b791783b 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -54,7 +54,6 @@ var UpdateChecker = require("./updater"); var q = require('q'); var request = require('browser-request'); -import UAParser from 'ua-parser-js'; import url from 'url'; import {parseQs, parseQsFromFragment} from './url_utils'; @@ -120,6 +119,8 @@ var lastLoadedScreen = null; // so a web page can update the URL bar appropriately. var onNewScreen = function(screen) { console.log("newscreen "+screen); + // just remember the most recent screen while we are loading, so that the + // user doesn't see the URL bar doing a dance if (!loaded) { lastLoadedScreen = screen; } else { @@ -142,33 +143,7 @@ var makeRegistrationUrl = function() { '#/register'; } - -function getDefaultDeviceDisplayName() { - // strip query-string and fragment from uri - let u = url.parse(window.location.href); - u.search = ""; - u.hash = ""; - let app_name = u.format(); - - let ua = new UAParser(); - return app_name + " via " + ua.getBrowser().name + - " on " + ua.getOS().name; -} - window.addEventListener('hashchange', onHashChange); -window.onload = function() { - console.log("window.onload"); - if (!validBrowser) { - return; - } - UpdateChecker.start(); - routeUrl(window.location); - loaded = true; - if (lastLoadedScreen) { - onNewScreen(lastLoadedScreen); - lastLoadedScreen = null; - } -} function getConfig() { let deferred = q.defer(); @@ -259,6 +234,8 @@ async function loadApp() { Unable to load config file: please refresh the page to try again. , document.getElementById('matrixchat')); } else if (validBrowser) { + UpdateChecker.start(); + var MatrixChat = sdk.getComponent('structures.MatrixChat'); window.matrixChat = ReactDOM.render( @@ -271,10 +248,19 @@ async function loadApp() { startingFragmentQueryParams={fragparts.params} enableGuest={true} onLoadCompleted={onLoadCompleted} - defaultDeviceDisplayName={getDefaultDeviceDisplayName()} + defaultDeviceDisplayName={PlatformPeg.get().getDefaultDeviceDisplayName()} />, document.getElementById('matrixchat') ); + + routeUrl(window.location); + + // we didn't propagate screen changes to the URL bar while we were loading; do it now. + loaded = true; + if (lastLoadedScreen) { + onNewScreen(lastLoadedScreen); + lastLoadedScreen = null; + } } else { console.error("Browser is missing required features."); @@ -285,7 +271,6 @@ async function loadApp() { validBrowser = true; console.log("User accepts the compatibility risks."); loadApp(); - window.onload(); // still do the same code paths for compatible clients }} />, document.getElementById('matrixchat') ); diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index c7455a71..3894896a 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -35,6 +35,27 @@ function onUpdateDownloaded(ev, releaseNotes, ver, date, updateURL) { }); } +function platformFriendlyName() { + console.log(window.process); + switch (window.process.platform) { + case 'darwin': + return 'macOS'; + case 'freebsd': + return 'FreeBSD'; + case 'openbsd': + return 'OpenBSD'; + case 'sunos': + return 'SunOS'; + case 'win32': + return 'Windows'; + default: + // Sorry, Linux users: you get lumped into here, + // but only because Linux's capitalisation is + // normal. We do care about you. + return window.process.platform[0].toUpperCase + window.process.platform.slice(1); + } +} + export default class ElectronPlatform extends VectorBasePlatform { setNotificationCount(count: number) { super.setNotificationCount(count); @@ -101,4 +122,8 @@ export default class ElectronPlatform extends VectorBasePlatform { // it should exit. electron.ipcRenderer.send('install_update'); } + + getDefaultDeviceDisplayName() { + return "Riot Desktop on " + platformFriendlyName(); + } } diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js index d2ed8c34..5240f3f5 100644 --- a/src/vector/platform/VectorBasePlatform.js +++ b/src/vector/platform/VectorBasePlatform.js @@ -39,4 +39,12 @@ export default class VectorBasePlatform extends BasePlatform { */ installUpdate() { } + + /** + * Get a sensible default display name for the + * device Vector is running on + */ + getDefaultDeviceDisplayName() { + return "Unknown device"; + } } diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js index b5459aec..9998f7c7 100644 --- a/src/vector/platform/WebPlatform.js +++ b/src/vector/platform/WebPlatform.js @@ -23,6 +23,9 @@ import request from 'browser-request'; import dis from 'matrix-react-sdk/lib/dispatcher.js'; import q from 'q'; +import url from 'url'; +import UAParser from 'ua-parser-js'; + export default class WebPlatform extends VectorBasePlatform { constructor() { super(); @@ -128,8 +131,18 @@ export default class WebPlatform extends VectorBasePlatform { _getVersion() { const deferred = q.defer(); + + // We add a cachebuster to the request to make sure that we know about + // the most recent version on the origin server. That might not + // actually be the version we'd get on a reload (particularly in the + // presence of intermediate caching proxies), but still: we're trying + // to tell the user that there is a new version. request( - { method: "GET", url: "version" }, + { + method: "GET", + url: "version", + qs: { cachebuster: Date.now() }, + }, (err, response, body) => { if (err || response.status < 200 || response.status >= 300) { if (err == null) err = { status: response.status }; @@ -170,4 +183,16 @@ export default class WebPlatform extends VectorBasePlatform { installUpdate() { window.location.reload(); } + + getDefaultDeviceDisplayName() { + // strip query-string and fragment from uri + let u = url.parse(window.location.href); + u.search = ""; + u.hash = ""; + let app_name = u.format(); + + let ua = new UAParser(); + return app_name + " via " + ua.getBrowser().name + + " on " + ua.getOS().name; + } } diff --git a/webpack.config.js b/webpack.config.js index 4f350dd4..cad7b9a3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -57,7 +57,8 @@ module.exports = { alias: { // alias any requires to the react module to the one in our path, otherwise // we tend to get the react source included twice when using npm link. - react: path.resolve('./node_modules/react'), + "react": path.resolve('./node_modules/react'), + "react-dom": path.resolve('./node_modules/react-dom'), "react-addons-perf": path.resolve('./node_modules/react-addons-perf'), // same goes for js-sdk