From 6af0b9618a6cb82a84a86a331321942a337bc736 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 21 Feb 2017 00:19:49 +0000 Subject: [PATCH] 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() {}, };