From 6af0b9618a6cb82a84a86a331321942a337bc736 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 21 Feb 2017 00:19:49 +0000 Subject: [PATCH 1/3] first cut of improving UX for deleting devices. This adds a 5 minute auth cache to speed up the process of deleting old devices. It has the following nastinesses (mainly due to being written on a flight whilst juggling kids): * the auth cache is done as context attached to MatrixChat. one could argue that it should be per-client instead, but we don't yet have multiple clients. * the auth cache is only maintained currently in DevicesPanelEntry (i.e. set & invalidated). One could argue that it might be better maintained in InteractiveAuth.js or a dedicated cache object abstraction, but given the only use I can think of is when managing devices, perhaps this is good enough for now. --- src/components/structures/MatrixChat.js | 5 ++++ .../views/settings/DevicesPanelEntry.js | 24 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 3265249105..8cc966607c 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -68,6 +68,7 @@ module.exports = React.createClass({ childContextTypes: { appConfig: React.PropTypes.object, + authCache: React.PropTypes.object, }, AuxPanel: { @@ -77,6 +78,10 @@ module.exports = React.createClass({ getChildContext: function() { return { appConfig: this.props.config, + authCache: { + auth: {}, + lastUpdate: 0, + }, }; }, diff --git a/src/components/views/settings/DevicesPanelEntry.js b/src/components/views/settings/DevicesPanelEntry.js index 4fa7d961ac..e889f88222 100644 --- a/src/components/views/settings/DevicesPanelEntry.js +++ b/src/components/views/settings/DevicesPanelEntry.js @@ -19,6 +19,11 @@ import React from 'react'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; +import DateUtils from '../../../DateUtils'; +import utils from 'matrix-js-sdk/lib/utils'; + + +const AUTH_CACHE_AGE = 5 * 60 * 1000; // 5 minutes export default class DevicesPanelEntry extends React.Component { constructor(props, context) { @@ -30,7 +35,6 @@ export default class DevicesPanelEntry extends React.Component { }; this._unmounted = false; - this._onDeleteClick = this._onDeleteClick.bind(this); this._onDisplayNameChanged = this._onDisplayNameChanged.bind(this); this._makeDeleteRequest = this._makeDeleteRequest.bind(this); @@ -53,8 +57,12 @@ export default class DevicesPanelEntry extends React.Component { _onDeleteClick() { this.setState({deleting: true}); - // try without interactive auth to start off - this._makeDeleteRequest(null).catch((error) => { + if (this.context.authCache.lastUpdate < Date.now() - AUTH_CACHE_AGE) { + this.context.authCache.auth = null; + } + + // try with auth cache (which is null, so no interactive auth, to start off) + this._makeDeleteRequest(this.context.authCache.auth).catch((error) => { if (this._unmounted) { return; } if (error.httpStatus !== 401 || !error.data || !error.data.flows) { // doesn't look like an interactive-auth failure @@ -83,6 +91,9 @@ export default class DevicesPanelEntry extends React.Component { } _makeDeleteRequest(auth) { + this.context.authCache.auth = auth; + this.context.authCache.lastUpdate = Date.now(); + const device = this.props.device; return MatrixClientPeg.get().deleteDevice(device.device_id, auth).then( () => { @@ -110,8 +121,7 @@ export default class DevicesPanelEntry extends React.Component { let lastSeen = ""; if (device.last_seen_ts) { - // todo: format the timestamp as "5 minutes ago" or whatever. - const lastSeenDate = new Date(device.last_seen_ts); + const lastSeenDate = DateUtils.formatDate(new Date(device.last_seen_ts)); lastSeen = device.last_seen_ip + " @ " + lastSeenDate.toLocaleString(); } @@ -160,6 +170,10 @@ DevicesPanelEntry.propTypes = { onDeleted: React.PropTypes.func, }; +DevicesPanelEntry.contextTypes = { + authCache: React.PropTypes.object, +}; + DevicesPanelEntry.defaultProps = { onDeleted: function() {}, }; From aabf9255d2c84ff19609a7aa15be1b0e203d0895 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 21 Feb 2017 01:03:22 +0000 Subject: [PATCH 2/3] anchor the authcache on LoggedInView to prevent it persisting over logouts --- src/components/structures/LoggedInView.js | 5 +++++ src/components/structures/MatrixChat.js | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js index aa9470f126..c2243820cd 100644 --- a/src/components/structures/LoggedInView.js +++ b/src/components/structures/LoggedInView.js @@ -49,11 +49,16 @@ export default React.createClass({ childContextTypes: { matrixClient: React.PropTypes.instanceOf(Matrix.MatrixClient), + authCache: React.PropTypes.object, }, getChildContext: function() { return { matrixClient: this._matrixClient, + authCache: { + auth: {}, + lastUpdate: 0, + }, }; }, diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 8cc966607c..3265249105 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -68,7 +68,6 @@ module.exports = React.createClass({ childContextTypes: { appConfig: React.PropTypes.object, - authCache: React.PropTypes.object, }, AuxPanel: { @@ -78,10 +77,6 @@ module.exports = React.createClass({ getChildContext: function() { return { appConfig: this.props.config, - authCache: { - auth: {}, - lastUpdate: 0, - }, }; }, From 629f8caad7015bbfc18f0448fab04c1adbac8501 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 21 Feb 2017 09:50:10 +0000 Subject: [PATCH 3/3] oops, remove unneeded import --- src/components/views/settings/DevicesPanelEntry.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/views/settings/DevicesPanelEntry.js b/src/components/views/settings/DevicesPanelEntry.js index e889f88222..60501e326f 100644 --- a/src/components/views/settings/DevicesPanelEntry.js +++ b/src/components/views/settings/DevicesPanelEntry.js @@ -20,8 +20,6 @@ import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import DateUtils from '../../../DateUtils'; -import utils from 'matrix-js-sdk/lib/utils'; - const AUTH_CACHE_AGE = 5 * 60 * 1000; // 5 minutes