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.
This commit is contained in:
parent
7d07e7f958
commit
6af0b9618a
2 changed files with 24 additions and 5 deletions
|
@ -68,6 +68,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
childContextTypes: {
|
childContextTypes: {
|
||||||
appConfig: React.PropTypes.object,
|
appConfig: React.PropTypes.object,
|
||||||
|
authCache: React.PropTypes.object,
|
||||||
},
|
},
|
||||||
|
|
||||||
AuxPanel: {
|
AuxPanel: {
|
||||||
|
@ -77,6 +78,10 @@ module.exports = React.createClass({
|
||||||
getChildContext: function() {
|
getChildContext: function() {
|
||||||
return {
|
return {
|
||||||
appConfig: this.props.config,
|
appConfig: this.props.config,
|
||||||
|
authCache: {
|
||||||
|
auth: {},
|
||||||
|
lastUpdate: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,11 @@ import React from 'react';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import Modal from '../../../Modal';
|
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 {
|
export default class DevicesPanelEntry extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
|
@ -30,7 +35,6 @@ export default class DevicesPanelEntry extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
|
|
||||||
this._onDeleteClick = this._onDeleteClick.bind(this);
|
this._onDeleteClick = this._onDeleteClick.bind(this);
|
||||||
this._onDisplayNameChanged = this._onDisplayNameChanged.bind(this);
|
this._onDisplayNameChanged = this._onDisplayNameChanged.bind(this);
|
||||||
this._makeDeleteRequest = this._makeDeleteRequest.bind(this);
|
this._makeDeleteRequest = this._makeDeleteRequest.bind(this);
|
||||||
|
@ -53,8 +57,12 @@ export default class DevicesPanelEntry extends React.Component {
|
||||||
_onDeleteClick() {
|
_onDeleteClick() {
|
||||||
this.setState({deleting: true});
|
this.setState({deleting: true});
|
||||||
|
|
||||||
// try without interactive auth to start off
|
if (this.context.authCache.lastUpdate < Date.now() - AUTH_CACHE_AGE) {
|
||||||
this._makeDeleteRequest(null).catch((error) => {
|
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 (this._unmounted) { return; }
|
||||||
if (error.httpStatus !== 401 || !error.data || !error.data.flows) {
|
if (error.httpStatus !== 401 || !error.data || !error.data.flows) {
|
||||||
// doesn't look like an interactive-auth failure
|
// doesn't look like an interactive-auth failure
|
||||||
|
@ -83,6 +91,9 @@ export default class DevicesPanelEntry extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeDeleteRequest(auth) {
|
_makeDeleteRequest(auth) {
|
||||||
|
this.context.authCache.auth = auth;
|
||||||
|
this.context.authCache.lastUpdate = Date.now();
|
||||||
|
|
||||||
const device = this.props.device;
|
const device = this.props.device;
|
||||||
return MatrixClientPeg.get().deleteDevice(device.device_id, auth).then(
|
return MatrixClientPeg.get().deleteDevice(device.device_id, auth).then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -110,8 +121,7 @@ export default class DevicesPanelEntry extends React.Component {
|
||||||
|
|
||||||
let lastSeen = "";
|
let lastSeen = "";
|
||||||
if (device.last_seen_ts) {
|
if (device.last_seen_ts) {
|
||||||
// todo: format the timestamp as "5 minutes ago" or whatever.
|
const lastSeenDate = DateUtils.formatDate(new Date(device.last_seen_ts));
|
||||||
const lastSeenDate = new Date(device.last_seen_ts);
|
|
||||||
lastSeen = device.last_seen_ip + " @ " +
|
lastSeen = device.last_seen_ip + " @ " +
|
||||||
lastSeenDate.toLocaleString();
|
lastSeenDate.toLocaleString();
|
||||||
}
|
}
|
||||||
|
@ -160,6 +170,10 @@ DevicesPanelEntry.propTypes = {
|
||||||
onDeleted: React.PropTypes.func,
|
onDeleted: React.PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DevicesPanelEntry.contextTypes = {
|
||||||
|
authCache: React.PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
DevicesPanelEntry.defaultProps = {
|
DevicesPanelEntry.defaultProps = {
|
||||||
onDeleted: function() {},
|
onDeleted: function() {},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue