From 99923b7b8f67b3d82df069db032611430443262d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 3 Apr 2017 20:30:05 +0100 Subject: [PATCH 001/547] Escape HTML tags in Notifications (Linux) Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/vector/platform/ElectronPlatform.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index c10f2f83..ce14a22e 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -81,6 +81,15 @@ export default class ElectronPlatform extends VectorBasePlatform { } displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification { + + // GNOME notification spec parses HTML tags for styling... + // Electron Docs state all supported linux notification systems follow this markup spec + // https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux + // maybe we should pass basic styling (italics, bold, underline) through from MD + if (window.process.platform === 'linux') { + msg = msg.replace(//g, ">"); + } + // Notifications in Electron use the HTML5 notification API const notification = new global.Notification( title, From ab1b377a1db736f98960d17205c9a0f89c059f53 Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Mon, 10 Apr 2017 14:11:26 -0300 Subject: [PATCH 002/547] add config.json to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c28df64c..0978bc56 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ npm-debug.log electron/dist electron/pub +config.json From cbfa4dd1abc6f8081db32ca3b1b4941d8c9c41b3 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 11 Apr 2017 18:46:48 +0100 Subject: [PATCH 003/547] Get rageshake endpoint from SdkConfig instead of storing in rageshake - in preparation for factoring out the sending of the rageshake --- src/components/views/dialogs/BugReportDialog.js | 5 ++++- src/vector/index.js | 1 - src/vector/rageshake.js | 8 ++------ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index dcc0850e..c03c9b43 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import sdk from 'matrix-react-sdk'; import rageshake from '../../../vector/rageshake'; +import SdkConfig from 'matrix-react-sdk/lib/SdkConfig'; export default class BugReportDialog extends React.Component { constructor(props, context) { @@ -47,7 +48,9 @@ export default class BugReportDialog extends React.Component { return; } this.setState({ busy: true, err: null }); - rageshake.sendBugReport(userText, sendLogs).then(() => { + rageshake.sendBugReport( + SdkConfig.get().bug_report_endpoint_url, userText, sendLogs, + ).then(() => { this.setState({ busy: false }); this.props.onFinished(false); }, (err) => { diff --git a/src/vector/index.js b/src/vector/index.js index e08b7174..42a60e45 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -259,7 +259,6 @@ async function loadApp() { let configError; try { configJson = await getConfig(); - rageshake.setBugReportEndpoint(configJson.bug_report_endpoint_url); } catch (e) { configError = e; } diff --git a/src/vector/rageshake.js b/src/vector/rageshake.js index 0e5b5dac..c519f8b3 100644 --- a/src/vector/rageshake.js +++ b/src/vector/rageshake.js @@ -396,7 +396,6 @@ function selectQuery(store, keyRange, resultMapper) { let store = null; let logger = null; let initPromise = null; -let bugReportEndpoint = null; module.exports = { /** @@ -430,17 +429,14 @@ module.exports = { await store.consume(); }, - setBugReportEndpoint: function(url) { - bugReportEndpoint = url; - }, - /** * Send a bug report. + * @param {string} bugReportEndpoint HTTP url to send the report to * @param {string} userText Any additional user input. * @param {boolean} sendLogs True to send logs * @return {Promise} Resolved when the bug report is sent. */ - sendBugReport: async function(userText, sendLogs) { + sendBugReport: async function(bugReportEndpoint, userText, sendLogs) { if (!logger) { throw new Error( "No console logger, did you forget to call init()?" From 4efb2b6750c62646f427f204d6c67c54502db8c9 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 11 Apr 2017 18:47:55 +0100 Subject: [PATCH 004/547] Rageshake: Factor out `getLogsForReport` ... in preparation for factoring out sending the report --- src/vector/rageshake.js | 46 +++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/vector/rageshake.js b/src/vector/rageshake.js index c519f8b3..711cc298 100644 --- a/src/vector/rageshake.js +++ b/src/vector/rageshake.js @@ -429,6 +429,32 @@ module.exports = { await store.consume(); }, + /** + * Get a recent snapshot of the logs, ready for attaching to a bug report + * + * @return {Array<{lines: string, id, string}>} list of log data + */ + getLogsForReport: async function() { + if (!logger) { + throw new Error( + "No console logger, did you forget to call init()?" + ); + } + // If in incognito mode, store is null, but we still want bug report + // sending to work going off the in-memory console logs. + if (store) { + // flush most recent logs + await store.flush(); + return await store.consume(); + } + else { + return [{ + lines: logger.flush(true), + id: "-", + }]; + } + }, + /** * Send a bug report. * @param {string} bugReportEndpoint HTTP url to send the report to @@ -437,11 +463,6 @@ module.exports = { * @return {Promise} Resolved when the bug report is sent. */ sendBugReport: async function(bugReportEndpoint, userText, sendLogs) { - if (!logger) { - throw new Error( - "No console logger, did you forget to call init()?" - ); - } if (!bugReportEndpoint) { throw new Error("No bug report endpoint has been set."); } @@ -457,22 +478,11 @@ module.exports = { userAgent = window.navigator.userAgent; } - // If in incognito mode, store is null, but we still want bug report - // sending to work going off the in-memory console logs. console.log("Sending bug report."); + let logs = []; if (sendLogs) { - if (store) { - // flush most recent logs - await store.flush(); - logs = await store.consume(); - } - else { - logs.push({ - lines: logger.flush(true), - id: "-", - }); - } + logs = await this.getLogsForReport(); } await q.Promise((resolve, reject) => { From 6423f7ce03b68fd219fbd226def68a809e1c5494 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 11 Apr 2017 18:59:22 +0100 Subject: [PATCH 005/547] rageshake: factor out submission to a separate file This will mean we can load it asyncronously in future, if we want. --- .../views/dialogs/BugReportDialog.js | 4 +- src/vector/rageshake.js | 61 -------------- src/vector/submit-rageshake.js | 81 +++++++++++++++++++ 3 files changed, 83 insertions(+), 63 deletions(-) create mode 100644 src/vector/submit-rageshake.js diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index c03c9b43..62424cb1 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -16,7 +16,7 @@ limitations under the License. import React from 'react'; import sdk from 'matrix-react-sdk'; -import rageshake from '../../../vector/rageshake'; +import submit_rageshake from '../../../vector/submit-rageshake'; import SdkConfig from 'matrix-react-sdk/lib/SdkConfig'; export default class BugReportDialog extends React.Component { @@ -48,7 +48,7 @@ export default class BugReportDialog extends React.Component { return; } this.setState({ busy: true, err: null }); - rageshake.sendBugReport( + submit_rageshake( SdkConfig.get().bug_report_endpoint_url, userText, sendLogs, ).then(() => { this.setState({ busy: false }); diff --git a/src/vector/rageshake.js b/src/vector/rageshake.js index 711cc298..feaec26d 100644 --- a/src/vector/rageshake.js +++ b/src/vector/rageshake.js @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; -import request from "browser-request"; import q from "q"; // This module contains all the code needed to log the console, persist it to @@ -454,63 +452,4 @@ module.exports = { }]; } }, - - /** - * Send a bug report. - * @param {string} bugReportEndpoint HTTP url to send the report to - * @param {string} userText Any additional user input. - * @param {boolean} sendLogs True to send logs - * @return {Promise} Resolved when the bug report is sent. - */ - sendBugReport: async function(bugReportEndpoint, userText, sendLogs) { - if (!bugReportEndpoint) { - throw new Error("No bug report endpoint has been set."); - } - - let version = "UNKNOWN"; - try { - version = await PlatformPeg.get().getAppVersion(); - } - catch (err) {} // PlatformPeg already logs this. - - let userAgent = "UNKNOWN"; - if (window.navigator && window.navigator.userAgent) { - userAgent = window.navigator.userAgent; - } - - console.log("Sending bug report."); - - let logs = []; - if (sendLogs) { - logs = await this.getLogsForReport(); - } - - await q.Promise((resolve, reject) => { - request({ - method: "POST", - url: bugReportEndpoint, - body: { - logs: logs, - text: ( - userText || "User did not supply any additional text." - ), - app: 'riot-web', - version: version, - user_agent: userAgent, - }, - json: true, - timeout: 5 * 60 * 1000, - }, (err, res) => { - if (err) { - reject(err); - return; - } - if (res.status < 200 || res.status >= 400) { - reject(new Error(`HTTP ${res.status}`)); - return; - } - resolve(); - }) - }); - } }; diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js new file mode 100644 index 00000000..87188821 --- /dev/null +++ b/src/vector/submit-rageshake.js @@ -0,0 +1,81 @@ +/* +Copyright 2017 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 q from "q"; +import request from "browser-request"; + +import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; + +import rageshake from './rageshake' + +/** + * Send a bug report. + * @param {string} bugReportEndpoint HTTP url to send the report to + * @param {string} userText Any additional user input. + * @param {boolean} sendLogs True to send logs + * @return {Promise} Resolved when the bug report is sent. + */ +export default async function sendBugReport(bugReportEndpoint, userText, sendLogs) { + if (!bugReportEndpoint) { + throw new Error("No bug report endpoint has been set."); + } + + let version = "UNKNOWN"; + try { + version = await PlatformPeg.get().getAppVersion(); + } + catch (err) {} // PlatformPeg already logs this. + + let userAgent = "UNKNOWN"; + if (window.navigator && window.navigator.userAgent) { + userAgent = window.navigator.userAgent; + } + + console.log("Sending bug report."); + + let logs = []; + if (sendLogs) { + logs = await rageshake.getLogsForReport(); + } + + await q.Promise((resolve, reject) => { + request({ + method: "POST", + url: bugReportEndpoint, + body: { + logs: logs, + text: ( + userText || "User did not supply any additional text." + ), + app: 'riot-web', + version: version, + user_agent: userAgent, + }, + json: true, + timeout: 5 * 60 * 1000, + }, (err, res) => { + if (err) { + reject(err); + return; + } + if (res.status < 200 || res.status >= 400) { + reject(new Error(`HTTP ${res.status}`)); + return; + } + resolve(); + }) + }); +} From 76f140c62c20a2d92eb28def4ef90b4d691eb75d Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 12 Apr 2017 10:14:58 +0100 Subject: [PATCH 006/547] Back to develop js & react sdks --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8bdb2ba0..62b1f134 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,8 @@ "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", "linkifyjs": "^2.1.3", - "matrix-js-sdk": "0.7.6", - "matrix-react-sdk": "0.8.7", + "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", + "matrix-react-sdk": "matrix-org/matrix-react-sdk#develop", "modernizr": "^3.1.0", "q": "^1.4.1", "react": "^15.4.0", From 3f291aae5b01fe842757e1cce33dcc67025c3f68 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 12 Apr 2017 11:26:53 +0100 Subject: [PATCH 007/547] Use an opts arg for submit-rageshake --- src/components/views/dialogs/BugReportDialog.js | 7 ++++--- src/vector/submit-rageshake.js | 13 ++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index 62424cb1..badc994b 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -48,9 +48,10 @@ export default class BugReportDialog extends React.Component { return; } this.setState({ busy: true, err: null }); - submit_rageshake( - SdkConfig.get().bug_report_endpoint_url, userText, sendLogs, - ).then(() => { + submit_rageshake(SdkConfig.get().bug_report_endpoint_url, { + userText: userText, + sendLogs: sendLogs, + }).then(() => { this.setState({ busy: false }); this.props.onFinished(false); }, (err) => { diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js index 87188821..8c070076 100644 --- a/src/vector/submit-rageshake.js +++ b/src/vector/submit-rageshake.js @@ -24,15 +24,18 @@ import rageshake from './rageshake' /** * Send a bug report. * @param {string} bugReportEndpoint HTTP url to send the report to - * @param {string} userText Any additional user input. - * @param {boolean} sendLogs True to send logs + * @param {object} opts optional dictionary of options + * @param {string} opts.userText Any additional user input. + * @param {boolean} opts.sendLogs True to send logs * @return {Promise} Resolved when the bug report is sent. */ -export default async function sendBugReport(bugReportEndpoint, userText, sendLogs) { +export default async function sendBugReport(bugReportEndpoint, opts) { if (!bugReportEndpoint) { throw new Error("No bug report endpoint has been set."); } + opts = opts || {}; + let version = "UNKNOWN"; try { version = await PlatformPeg.get().getAppVersion(); @@ -47,7 +50,7 @@ export default async function sendBugReport(bugReportEndpoint, userText, sendLog console.log("Sending bug report."); let logs = []; - if (sendLogs) { + if (opts.sendLogs) { logs = await rageshake.getLogsForReport(); } @@ -58,7 +61,7 @@ export default async function sendBugReport(bugReportEndpoint, userText, sendLog body: { logs: logs, text: ( - userText || "User did not supply any additional text." + opts.userText || "User did not supply any additional text." ), app: 'riot-web', version: version, From 76008e8abd3e89eda16d39260e93e570d44cff7f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 12 Apr 2017 18:13:25 +0100 Subject: [PATCH 008/547] Remember and Recall window layout so that position+size persist Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron/src/electron-main.js | 16 +++++++++++++++- package.json | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 33b44ce9..8dd5e813 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -30,6 +30,8 @@ const tray = require('./tray'); const VectorMenu = require('./vectormenu'); +const windowStateKeeper = require('electron-window-state'); + let vectorConfig = {}; try { vectorConfig = require('../../webapp/config.json'); @@ -186,11 +188,21 @@ electron.app.on('ready', () => { process.platform == 'win32' ? 'ico' : 'png' ); + // Load the previous window state with fallback to defaults + let mainWindowState = windowStateKeeper({ + defaultWidth: 1024, + defaultHeight: 768, + }); + mainWindow = new electron.BrowserWindow({ icon: icon_path, - width: 1024, height: 768, show: false, autoHideMenuBar: true, + + x: mainWindowState.x, + y: mainWindowState.y, + width: mainWindowState.width, + height: mainWindowState.height, }); mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`); electron.Menu.setApplicationMenu(VectorMenu); @@ -226,6 +238,8 @@ electron.app.on('ready', () => { onLinkContextMenu(ev, params); } }); + + mainWindowState.manage(mainWindow); }); electron.app.on('window-all-closed', () => { diff --git a/package.json b/package.json index 28cde389..35ffb87b 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "css-raw-loader": "^0.1.1", "electron-builder": "^11.2.4", "electron-builder-squirrel-windows": "^11.2.1", + "electron-window-state": "^4.1.0", "emojione": "^2.2.7", "eslint": "^3.14.0", "eslint-config-google": "^0.7.1", From 3fb54029d7dff8b66f48d6a50ce4ac92ed268373 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 Apr 2017 13:39:15 +0100 Subject: [PATCH 009/547] Fix packaged functionality Improve dependency management for Electron main process deps Dependencies in /electron/package.json will be installed through a script in /package.json and will be bundled via electron-builder Does not affect standard webapp whatsoever Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .gitignore | 1 + electron/package.json | 6 ++++++ package.json | 11 ++++++----- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 electron/package.json diff --git a/.gitignore b/.gitignore index c28df64c..86baa127 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /key.pem /lib /node_modules +/electron/node_modules /packages/ /webapp /.npmrc diff --git a/electron/package.json b/electron/package.json new file mode 100644 index 00000000..e6e7e2a4 --- /dev/null +++ b/electron/package.json @@ -0,0 +1,6 @@ +{ + "description": "Electron main process dependencies", + "dependencies": { + "electron-window-state": "^4.1.0" + } +} diff --git a/package.json b/package.json index 35ffb87b..dc1e3bea 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "build": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:bundle:dev", "dist": "scripts/package.sh", + "postinstall": "cd electron && npm i", "start:res": "node scripts/copy-res.js -w", "start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress", "start:js:prod": "NODE_ENV=production webpack-dev-server -w --progress", @@ -96,7 +97,6 @@ "css-raw-loader": "^0.1.1", "electron-builder": "^11.2.4", "electron-builder-squirrel-windows": "^11.2.1", - "electron-window-state": "^4.1.0", "emojione": "^2.2.7", "eslint": "^3.14.0", "eslint-config-google": "^0.7.1", @@ -145,6 +145,7 @@ "dereference": true, "//files": "We bundle everything, so we only need to include webapp/", "files": [ + "electron/node_modules/**", "electron/src/**", "electron/img/**", "webapp/**", @@ -159,10 +160,10 @@ }, "win": { "target": "squirrel" + }, + "directories": { + "buildResources": "electron/build", + "output": "electron/dist" } - }, - "directories": { - "buildResources": "electron/build", - "output": "electron/dist" } } From 15accf33f59131752d49007ba92d18d0b3fa9721 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 15 Apr 2017 00:30:31 +0100 Subject: [PATCH 010/547] get rid of the evil blue outlines --- src/skins/vector/css/_components.scss | 1 + .../views/elements/_AccessibleButton.scss | 21 +++++++++++++++++++ .../views/rooms/_RoomTile.scss | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/skins/vector/css/matrix-react-sdk/views/elements/_AccessibleButton.scss diff --git a/src/skins/vector/css/_components.scss b/src/skins/vector/css/_components.scss index c22fbc06..df3c4600 100644 --- a/src/skins/vector/css/_components.scss +++ b/src/skins/vector/css/_components.scss @@ -19,6 +19,7 @@ @import "./matrix-react-sdk/views/dialogs/_EncryptedEventDialog.scss"; @import "./matrix-react-sdk/views/dialogs/_SetDisplayNameDialog.scss"; @import "./matrix-react-sdk/views/dialogs/_UnknownDeviceDialog.scss"; +@import "./matrix-react-sdk/views/elements/_AccessibleButton.scss"; @import "./matrix-react-sdk/views/elements/_AddressSelector.scss"; @import "./matrix-react-sdk/views/elements/_AddressTile.scss"; @import "./matrix-react-sdk/views/elements/_DirectorySearchBox.scss"; diff --git a/src/skins/vector/css/matrix-react-sdk/views/elements/_AccessibleButton.scss b/src/skins/vector/css/matrix-react-sdk/views/elements/_AccessibleButton.scss new file mode 100644 index 00000000..b82ebf01 --- /dev/null +++ b/src/skins/vector/css/matrix-react-sdk/views/elements/_AccessibleButton.scss @@ -0,0 +1,21 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +.mx_AccessibleButton:focus { + outline: 0; + filter: brightness(200%); +} + diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss index 08efa145..842228b9 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_RoomTile.scss @@ -156,7 +156,7 @@ limitations under the License. } .mx_RoomTile:focus { - outline: 0; + filter: none ! important; background-color: $roomtile-focused-bg-color; } From a74bbb424c7c07494d71329e8d4c6ef9fc37a7b9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 15 Apr 2017 11:37:09 +0100 Subject: [PATCH 011/547] cmd-k shortcut to the searchbox --- src/components/structures/SearchBox.js | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 729e7ef7..fb5beab1 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -21,6 +21,7 @@ var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +var KeyCode = require('matrix-react-sdk/lib/KeyCode'); module.exports = React.createClass({ displayName: 'SearchBox', @@ -38,10 +39,12 @@ module.exports = React.createClass({ componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); + document.addEventListener('keydown', this._onKeyDown); }, componentWillUnmount: function() { dis.unregister(this.dispatcherRef); + document.removeEventListener('keydown', this._onKeyDown); }, onAction: function(payload) { @@ -90,6 +93,33 @@ module.exports = React.createClass({ this.onChange(); }, + _onKeyDown: function(ev) { + let handled = false; + const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + let ctrlCmdOnly; + if (isMac) { + ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey; + } else { + ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey; + } + + switch (ev.keyCode) { + case KeyCode.KEY_K: + if (ctrlCmdOnly) { + if (this.refs.search) { + this.refs.search.focus(); + } + handled = true; + } + break; + } + + if (handled) { + ev.stopPropagation(); + ev.preventDefault(); + } + }, + render: function() { var TintableSvg = sdk.getComponent('elements.TintableSvg'); From e5e259e1f8e403383f5051e148c76229b59e0440 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 15 Apr 2017 12:02:16 +0100 Subject: [PATCH 012/547] put a ! on invite sublists --- src/components/structures/RoomSubList.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 4aa9ff00..de883932 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -248,10 +248,9 @@ var RoomSubList = React.createClass({ if (badges) { result[0] += notificationCount; - if (highlight) { - result[1] = true; - } } + + result[1] |= highlight; } return result; }, [0, false]); @@ -403,6 +402,9 @@ var RoomSubList = React.createClass({ if (subListNotifCount > 0) { badge =
{ FormattingUtils.formatCount(subListNotifCount) }
; } + else if (subListNotifHighlight) { + badge =
{ ! }
; + } // When collapsed, allow a long hover on the header to show user // the full tag name and room count From 27de972bfbba85a853c69c800519404826595f68 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 15 Apr 2017 12:02:50 +0100 Subject: [PATCH 013/547] oops --- src/components/structures/RoomSubList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index de883932..241a1efa 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -403,7 +403,7 @@ var RoomSubList = React.createClass({ badge =
{ FormattingUtils.formatCount(subListNotifCount) }
; } else if (subListNotifHighlight) { - badge =
{ ! }
; + badge =
!
; } // When collapsed, allow a long hover on the header to show user From 8351ec97380350b6c8ca8c63b920120b33468fa9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 15 Apr 2017 13:23:11 +0100 Subject: [PATCH 014/547] thread RoomTile focus events through RoomSubList up to RoomList --- src/components/structures/RoomSubList.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 241a1efa..a0c9a5e1 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -78,6 +78,7 @@ var RoomSubList = React.createClass({ showSpinner: React.PropTypes.bool, // true to show a spinner if 0 elements when expanded collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed? onHeaderClick: React.PropTypes.func, + onRoomTileFocus: React.PropTypes.func, alwaysShowHeader: React.PropTypes.bool, incomingCall: React.PropTypes.object, onShowMoreRooms: React.PropTypes.func, @@ -373,6 +374,7 @@ var RoomSubList = React.createClass({ refreshSubList={ self._updateSubListCount } incomingCall={ null } onClick={ self.onRoomTileClick } + onFocus={ self.props.onRoomTileFocus } /> ); }); From c6ee221ae4aaac5d37be994cf5afcf97de2b854e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 16 Apr 2017 15:58:00 +0100 Subject: [PATCH 015/547] typos --- src/components/structures/RoomSubList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index a0c9a5e1..a2d05d8a 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -28,7 +28,7 @@ var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); -// turn this on for drop & drag console debugging galore +// turn this on for drag & drop console debugging galore var debug = false; const TRUNCATE_AT = 10; @@ -502,7 +502,7 @@ var RoomSubList = React.createClass({ // gets triggered and another list is passed in. Doing it one at a time means that // we always correctly calculate the highest order for the list - stops multiple // rooms getting the same order. This is only really relevant for the first time this - // is run with historical room tag data, after that there should only be undefined + // is run with historical room tag data, after that there should only be one undefined // in the list at a time anyway. for (let i = 0; i < list.length; i++) { if (list[i].tags[self.props.tagName] && list[i].tags[self.props.tagName].order === undefined) { From cc7a58512639e78444f655039f7178ef02161614 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 17 Apr 2017 14:10:51 +0100 Subject: [PATCH 016/547] make ImageView Download work, based on props.name Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/ImageView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 42730aca..ab3e9ee8 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -176,7 +176,7 @@ module.exports = React.createClass({ { this.getName() } { eventMeta } - +
Download this file
{ size_res } From 5ff49f400000f05912b6b701f315885eb08768ca Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 17 Apr 2017 20:53:46 +0100 Subject: [PATCH 017/547] split out header from RoomSubList and let it update separately By moving the header into its own RoomSubListHeader, we can refresh it explicitly by poking it by the new constantTimeDispatcher without re-rendering the whole stack of room tiles *UNTESTED* --- src/component-index.js | 2 + src/components/structures/RoomSubList.js | 115 +++++++---------- .../structures/RoomSubListHeader.js | 116 ++++++++++++++++++ 3 files changed, 161 insertions(+), 72 deletions(-) create mode 100644 src/components/structures/RoomSubListHeader.js diff --git a/src/component-index.js b/src/component-index.js index 2b67aa15..4bf0b0f9 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -40,6 +40,8 @@ import structures$RoomDirectory from './components/structures/RoomDirectory'; structures$RoomDirectory && (module.exports.components['structures.RoomDirectory'] = structures$RoomDirectory); import structures$RoomSubList from './components/structures/RoomSubList'; structures$RoomSubList && (module.exports.components['structures.RoomSubList'] = structures$RoomSubList); +import structures$RoomSubListHeader from './components/structures/RoomSubListHeader'; +structures$RoomSubListHeader && (module.exports.components['structures.RoomSubListHeader'] = structures$RoomSubListHeader); import structures$SearchBox from './components/structures/SearchBox'; structures$SearchBox && (module.exports.components['structures.SearchBox'] = structures$SearchBox); import structures$ViewSource from './components/structures/ViewSource'; diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index a2d05d8a..1c02b416 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -27,6 +27,7 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); // turn this on for drag & drop console debugging galore var debug = false; @@ -101,13 +102,25 @@ var RoomSubList = React.createClass({ }, componentWillMount: function() { + constantTimeDispatcher.register("RoomSubList.sort", this.props.tagName, this.onSort); this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order); + this._fixUndefinedOrder(list); + }, + + componentWillUnmount: function() { + constantTimeDispatcher.unregister("RoomSubList.sort", this.props.tagName, this.onSort); }, componentWillReceiveProps: function(newProps) { // order the room list appropriately before we re-render //if (debug) console.log("received new props, list = " + newProps.list); this.sortList(this.applySearchFilter(newProps.list, newProps.searchFilter), newProps.order); + this._fixUndefinedOrder(list); + }, + + onSort: function() { + this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order); + // we deliberately don't waste time trying to fix undefined ordering here }, applySearchFilter: function(list, filter) { @@ -212,9 +225,6 @@ var RoomSubList = React.createClass({ if (order === "manual") comparator = this.manualComparator; if (order === "recent") comparator = this.recentsComparator; - // Fix undefined orders here, and make sure the backend gets updated as well - this._fixUndefinedOrder(list); - //if (debug) console.log("sorting list for sublist " + this.props.label + " with length " + list.length + ", this.props.list = " + this.props.list); this.setState({ sortedList: list.sort(comparator) }); }, @@ -380,73 +390,6 @@ var RoomSubList = React.createClass({ }); }, - _getHeaderJsx: function() { - var TintableSvg = sdk.getComponent("elements.TintableSvg"); - - var subListNotifications = this.roomNotificationCount(); - var subListNotifCount = subListNotifications[0]; - var subListNotifHighlight = subListNotifications[1]; - - var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; - - var chevronClasses = classNames({ - 'mx_RoomSubList_chevron': true, - 'mx_RoomSubList_chevronRight': this.state.hidden, - 'mx_RoomSubList_chevronDown': !this.state.hidden, - }); - - var badgeClasses = classNames({ - 'mx_RoomSubList_badge': true, - 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, - }); - - var badge; - if (subListNotifCount > 0) { - badge =
{ FormattingUtils.formatCount(subListNotifCount) }
; - } - else if (subListNotifHighlight) { - badge =
!
; - } - - // When collapsed, allow a long hover on the header to show user - // the full tag name and room count - var title; - if (this.props.collapsed) { - title = this.props.label; - if (roomCount !== '') { - title += " [" + roomCount + "]"; - } - } - - var incomingCall; - if (this.props.incomingCall) { - var self = this; - // Check if the incoming call is for this section - var incomingCallRoom = this.props.list.filter(function(room) { - return self.props.incomingCall.roomId === room.roomId; - }); - - if (incomingCallRoom.length === 1) { - var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); - incomingCall = ; - } - } - - var tabindex = this.props.searchFilter === "" ? "0" : "-1"; - - return ( -
- - { this.props.collapsed ? '' : this.props.label } -
{ roomCount }
-
- { badge } - { incomingCall } -
-
- ); - }, - _createOverflowTile: function(overflowCount, totalCount) { var content =
; @@ -536,6 +479,16 @@ var RoomSubList = React.createClass({ target = ; } + var roomCount = this.props.list.length > 0 ? this.props.list.length : ''; + + var isIncomingCallRoom; + if (this.props.incomingCall) { + // Check if the incoming call is for this section + isIncomingCallRoom = this.props.list.find(room=>{ + return this.props.incomingCall.roomId === room.roomId; + }) ? true : false; + } + if (this.state.sortedList.length > 0 || this.props.editable) { var subList; var classes = "mx_RoomSubList"; @@ -554,7 +507,15 @@ var RoomSubList = React.createClass({ return connectDropTarget(
- { this._getHeaderJsx() } +
); @@ -563,7 +524,17 @@ var RoomSubList = React.createClass({ var Loader = sdk.getComponent("elements.Spinner"); return (
- { this.props.alwaysShowHeader ? this._getHeaderJsx() : undefined } + { this.props.alwaysShowHeader ? +
); diff --git a/src/components/structures/RoomSubListHeader.js b/src/components/structures/RoomSubListHeader.js new file mode 100644 index 00000000..f97f9f47 --- /dev/null +++ b/src/components/structures/RoomSubListHeader.js @@ -0,0 +1,116 @@ +/* +Copyright 2017 Vector Creations 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. +*/ + +'use strict'; + +var React = require('react'); +var ReactDOM = require('react-dom'); +var classNames = require('classnames'); +var sdk = require('matrix-react-sdk') +var dis = require('matrix-react-sdk/lib/dispatcher'); +var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); +var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); +var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); + +module.exports = React.createClass({ + displayName: 'RoomSubListHeader', + + propTypes: { + label: React.PropTypes.string.isRequired, + tagName: React.PropTypes.string, + roomCount: React.PropTypes.string, + collapsed: React.PropTypes.bool.isRequired, // is LeftPanel collapsed? + isIncomingCallRoom: React.PropTypes.bool, + hidden: React.PropTypes.bool, + onHeaderClick: React.PropTypes.func, + }, + + getDefaultProps: function() { + return { + onHeaderClick: function() {}, // NOP + }; + }, + + componentWillMount: function() { + constantTimeDispatcher.register("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); + }, + + componentWillUnmount: function() { + constantTimeDispatcher.unregister("RoomSubList.refreshHeader", this.props.tagName, this.onRefresh); + }, + + onRefresh: function() { + this.forceUpdate(); + }, + + render: function() { + var TintableSvg = sdk.getComponent("elements.TintableSvg"); + + var subListNotifications = this.roomNotificationCount(); + var subListNotifCount = subListNotifications[0]; + var subListNotifHighlight = subListNotifications[1]; + + var chevronClasses = classNames({ + 'mx_RoomSubList_chevron': true, + 'mx_RoomSubList_chevronRight': this.props.hidden, + 'mx_RoomSubList_chevronDown': !this.props.hidden, + }); + + var badgeClasses = classNames({ + 'mx_RoomSubList_badge': true, + 'mx_RoomSubList_badgeHighlight': subListNotifHighlight, + }); + + var badge; + if (subListNotifCount > 0) { + badge =
{ FormattingUtils.formatCount(subListNotifCount) }
; + } + else if (subListNotifHighlight) { + badge =
!
; + } + + // When collapsed, allow a long hover on the header to show user + // the full tag name and room count + var title; + if (this.props.collapsed) { + title = this.props.label; + if (roomCount !== '') { + title += " [" + roomCount + "]"; + } + } + + if (this.props.isIncomingCallRoom) { + var IncomingCallBox = sdk.getComponent("voip.IncomingCallBox"); + incomingCall = ; + } + + var tabindex = this.props.searchFilter === "" ? "0" : "-1"; + + return ( +
+ + { this.props.collapsed ? '' : this.props.label } +
{ roomCount }
+
+ { badge } + { incomingCall } +
+
+ ); + }, +}); + From 44479f24dd26950462ef401cbe955cb69d37c7b1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 17 Apr 2017 22:10:56 +0100 Subject: [PATCH 018/547] add command line arg (--hidden) for electron app Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- electron/src/electron-main.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 33b44ce9..e6ffffac 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -201,9 +201,12 @@ electron.app.on('ready', () => { brand: vectorConfig.brand || 'Riot' }); - mainWindow.once('ready-to-show', () => { - mainWindow.show(); - }); + if (!process.argv.includes('--hidden')) { + mainWindow.once('ready-to-show', () => { + mainWindow.show(); + }); + } + mainWindow.on('closed', () => { mainWindow = null; }); From f8aa2c3487061881c1f4ca0cbe02af11981d6dfd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 18 Apr 2017 02:43:06 +0100 Subject: [PATCH 019/547] fix bugs in RoomSubListHeader splitout --- src/components/structures/RoomSubList.js | 15 +++++++++++---- src/components/structures/RoomSubListHeader.js | 16 +++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 1c02b416..7656149f 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -28,6 +28,7 @@ var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs'); var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var ConstantTimeDispatcher = require('matrix-react-sdk/lib/ConstantTimeDispatcher'); +var RoomSubListHeader = require('./RoomSubListHeader.js'); // turn this on for drag & drop console debugging galore var debug = false; @@ -104,7 +105,7 @@ var RoomSubList = React.createClass({ componentWillMount: function() { constantTimeDispatcher.register("RoomSubList.sort", this.props.tagName, this.onSort); this.sortList(this.applySearchFilter(this.props.list, this.props.searchFilter), this.props.order); - this._fixUndefinedOrder(list); + this._fixUndefinedOrder(this.props.list); }, componentWillUnmount: function() { @@ -115,7 +116,7 @@ var RoomSubList = React.createClass({ // order the room list appropriately before we re-render //if (debug) console.log("received new props, list = " + newProps.list); this.sortList(this.applySearchFilter(newProps.list, newProps.searchFilter), newProps.order); - this._fixUndefinedOrder(list); + this._fixUndefinedOrder(newProps.list); }, onSort: function() { @@ -133,7 +134,7 @@ var RoomSubList = React.createClass({ // The header is collapsable if it is hidden or not stuck // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsableOnClick: function() { - var stuck = this.refs.header.dataset.stuck; + var stuck = this.refs.header.refs.header.dataset.stuck; if (this.state.hidden || stuck === undefined || stuck === "none") { return true; } else { @@ -156,7 +157,7 @@ var RoomSubList = React.createClass({ this.props.onHeaderClick(isHidden); } else { // The header is stuck, so the click is to be interpreted as a scroll to the header - this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition); + this.props.onHeaderClick(this.state.hidden, this.refs.header.refs.header.dataset.originalPosition); } }, @@ -508,12 +509,15 @@ var RoomSubList = React.createClass({ return connectDropTarget(
{ this.props.alwaysShowHeader ?
@@ -110,6 +137,7 @@ export default class BugReportDialog extends React.Component { + {progress} {error}
@@ -117,8 +145,9 @@ export default class BugReportDialog extends React.Component { className="mx_Dialog_primary danger" onClick={this._onSubmit} autoFocus={true} + disabled={this.state.busy} > - {okLabel} + Send {cancelButton} diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js index 7430e3be..6ed49a1f 100644 --- a/src/vector/submit-rageshake.js +++ b/src/vector/submit-rageshake.js @@ -30,10 +30,17 @@ if (!TextEncoder) { /** * Send a bug report. + * * @param {string} bugReportEndpoint HTTP url to send the report to + * * @param {object} opts optional dictionary of options + * * @param {string} opts.userText Any additional user input. + * * @param {boolean} opts.sendLogs True to send logs + * + * @param {function(string)} opts.progressCallback Callback to call with progress updates + * * @return {Promise} Resolved when the bug report is sent. */ export default async function sendBugReport(bugReportEndpoint, opts) { @@ -42,7 +49,9 @@ export default async function sendBugReport(bugReportEndpoint, opts) { } opts = opts || {}; + const progressCallback = opts.progressCallback || (() => {}); + progressCallback("Collecting app version information"); let version = "UNKNOWN"; try { version = await PlatformPeg.get().getAppVersion(); @@ -63,6 +72,7 @@ export default async function sendBugReport(bugReportEndpoint, opts) { body.append('user_agent', userAgent); if (opts.sendLogs) { + progressCallback("Collecting logs"); const logs = await rageshake.getLogsForReport(); for (let entry of logs) { // encode as UTF-8 @@ -72,17 +82,20 @@ export default async function sendBugReport(bugReportEndpoint, opts) { } } - await _submitReport(bugReportEndpoint, body); + progressCallback("Uploading report"); + await _submitReport(bugReportEndpoint, body, progressCallback); } -function _submitReport(endpoint, body) { +function _submitReport(endpoint, body, progressCallback) { const deferred = q.defer(); const req = new XMLHttpRequest(); req.open("POST", endpoint); req.timeout = 5 * 60 * 1000; req.onreadystatechange = function() { - if (req.readyState === XMLHttpRequest.DONE) { + if (req.readyState === XMLHttpRequest.LOADING) { + progressCallback("Waiting for response from server"); + } else if (req.readyState === XMLHttpRequest.DONE) { on_done(); } }; From 25907301a3e4b13db87bc7421a88fd2933de7590 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 18 Apr 2017 12:53:15 +0100 Subject: [PATCH 025/547] More unmounted guards in BugReportDialog --- src/components/views/dialogs/BugReportDialog.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.js index 92b3c4b1..7a65ac58 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.js @@ -62,13 +62,17 @@ export default class BugReportDialog extends React.Component { sendLogs: sendLogs, progressCallback: this._sendProgressCallback, }).then(() => { - this.setState({ busy: false, progress: null }); - this.props.onFinished(false); + if (!this._unmounted) { + this.setState({ busy: false, progress: null }); + this.props.onFinished(false); + } }, (err) => { - this.setState({ - busy: false, progress: null, - err: `Failed to send report: ${err.message}`, - }); + if (!this._unmounted) { + this.setState({ + busy: false, progress: null, + err: `Failed to send report: ${err.message}`, + }); + } }); }); } From ccc33db9ddbd02a588bcf1624228fb33c213873a Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 18 Apr 2017 17:23:34 +0100 Subject: [PATCH 026/547] Compress uploaded rageshakes. (#3647) --- package.json | 1 + src/vector/submit-rageshake.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 62b1f134..0ad3c33b 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", "matrix-react-sdk": "matrix-org/matrix-react-sdk#develop", "modernizr": "^3.1.0", + "pako": "^1.0.5", "q": "^1.4.1", "react": "^15.4.0", "react-dnd": "^2.1.4", diff --git a/src/vector/submit-rageshake.js b/src/vector/submit-rageshake.js index 6ed49a1f..ef6fbabe 100644 --- a/src/vector/submit-rageshake.js +++ b/src/vector/submit-rageshake.js @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import pako from 'pako'; import q from "q"; import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; @@ -78,7 +79,10 @@ export default async function sendBugReport(bugReportEndpoint, opts) { // encode as UTF-8 const buf = new TextEncoder().encode(entry.lines); - body.append('log', new Blob([buf]), entry.id); + // compress + const compressed = pako.gzip(buf); + + body.append('compressed-log', new Blob([compressed]), entry.id); } } From 053beae035e55aed96dcf8c0899f13310f2ef52c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 18 Apr 2017 17:36:23 +0100 Subject: [PATCH 027/547] move focus-via-up/down cursors to LeftPanel --- src/components/structures/LeftPanel.js | 94 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index a9df37a8..2d97313a 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -19,9 +19,11 @@ limitations under the License. var React = require('react'); var DragDropContext = require('react-dnd').DragDropContext; var HTML5Backend = require('react-dnd-html5-backend'); +var KeyCode = require('matrix-react-sdk/lib/KeyCode'); var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); + var VectorConferenceHandler = require('../../VectorConferenceHandler'); var CallHandler = require("matrix-react-sdk/lib/CallHandler"); @@ -40,6 +42,10 @@ var LeftPanel = React.createClass({ }; }, + componentWillMount: function() { + this.focusedElement = null; + }, + componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); }, @@ -62,6 +68,91 @@ var LeftPanel = React.createClass({ } }, + _onFocus: function(ev) { + this.focusedElement = ev.target; + }, + + _onBlur: function(ev) { + this.focusedElement = null; + }, + + _onKeyDown: function(ev) { + if (!this.focusedElement) return; + let handled = false; + + switch (ev.keyCode) { + case KeyCode.UP: + this._onMoveFocus(true); + handled = true; + break; + case KeyCode.DOWN: + this._onMoveFocus(false); + handled = true; + break; + } + + if (handled) { + ev.stopPropagation(); + ev.preventDefault(); + } + }, + + _onMoveFocus: function(up) { + var element = this.focusedElement; + + // unclear why this isn't needed + // var descending = (up == this.focusDirection) ? this.focusDescending : !this.focusDescending; + // this.focusDirection = up; + + var descending = false; // are we currently descending or ascending through the DOM tree? + var classes; + + do { + var child = up ? element.lastElementChild : element.firstElementChild; + var sibling = up ? element.previousElementSibling : element.nextElementSibling; + + if (descending) { + if (child) { + element = child; + } + else if (sibling) { + element = sibling; + } + else { + descending = false; + element = element.parentElement; + } + } + else { + if (sibling) { + element = sibling; + descending = true; + } + else { + element = element.parentElement; + } + } + + if (element) { + classes = element.classList; + if (classes.contains("mx_LeftPanel")) { // we hit the top + element = up ? element.lastElementChild : element.firstElementChild; + descending = true; + } + } + + } while(element && !( + classes.contains("mx_RoomTile") || + classes.contains("mx_SearchBox_search") || + classes.contains("mx_RoomSubList_ellipsis"))); + + if (element) { + element.focus(); + this.focusedElement = element; + this.focusedDescending = descending; + } + }, + _recheckCallElement: function(selectedRoomId) { // if we aren't viewing a room with an ongoing call, but there is an // active call, show the call element - we need to do this to make @@ -120,7 +211,8 @@ var LeftPanel = React.createClass({ } return ( -