Implement basic soft logout handling
Fixes https://github.com/vector-im/riot-web/issues/10235 CSS and copy are left as an exercise for a later iteration. Login page handling is left for https://github.com/vector-im/riot-web/issues/10236 This implementation reuses as much of the Lifecycle flow as it can without causing problems. Most importantly, it requires https://github.com/matrix-org/matrix-js-sdk/pull/975 to be able to detect a soft logout and react to it. When it comes time to starting/stopping the Lifecycle, additional parameters are provided so that the auxiliary services can (re)start themselves without the client starting to sync.
This commit is contained in:
parent
668d24111c
commit
42e6287bdb
12 changed files with 286 additions and 8 deletions
|
@ -36,6 +36,7 @@ export default class BasePlatform {
|
||||||
|
|
||||||
_onAction(payload: Object) {
|
_onAction(payload: Object) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this.setNotificationCount(0);
|
this.setNotificationCount(0);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -352,11 +352,14 @@ export function setLoggedIn(credentials) {
|
||||||
async function _doSetLoggedIn(credentials, clearStorage) {
|
async function _doSetLoggedIn(credentials, clearStorage) {
|
||||||
credentials.guest = Boolean(credentials.guest);
|
credentials.guest = Boolean(credentials.guest);
|
||||||
|
|
||||||
|
const softLogout = isSoftLogout();
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"setLoggedIn: mxid: " + credentials.userId +
|
"setLoggedIn: mxid: " + credentials.userId +
|
||||||
" deviceId: " + credentials.deviceId +
|
" deviceId: " + credentials.deviceId +
|
||||||
" guest: " + credentials.guest +
|
" guest: " + credentials.guest +
|
||||||
" hs: " + credentials.homeserverUrl,
|
" hs: " + credentials.homeserverUrl +
|
||||||
|
" softLogout: " + softLogout,
|
||||||
);
|
);
|
||||||
|
|
||||||
// This is dispatched to indicate that the user is still in the process of logging in
|
// This is dispatched to indicate that the user is still in the process of logging in
|
||||||
|
@ -414,7 +417,7 @@ async function _doSetLoggedIn(credentials, clearStorage) {
|
||||||
|
|
||||||
dis.dispatch({ action: 'on_logged_in' });
|
dis.dispatch({ action: 'on_logged_in' });
|
||||||
|
|
||||||
await startMatrixClient();
|
await startMatrixClient(/*startSyncing=*/!softLogout);
|
||||||
return MatrixClientPeg.get();
|
return MatrixClientPeg.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +490,25 @@ export function logout() {
|
||||||
).done();
|
).done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function softLogout() {
|
||||||
|
if (!MatrixClientPeg.get()) return;
|
||||||
|
|
||||||
|
// Track that we've detected and trapped a soft logout. This helps prevent other
|
||||||
|
// parts of the app from starting if there's no point (ie: don't sync if we've
|
||||||
|
// been soft logged out, despite having credentials and data for a MatrixClient).
|
||||||
|
localStorage.setItem("mx_soft_logout", "true");
|
||||||
|
|
||||||
|
_isLoggingOut = true; // to avoid repeated flags
|
||||||
|
stopMatrixClient(/*unsetClient=*/false);
|
||||||
|
dis.dispatch({action: 'on_client_not_viable'}); // generic version of on_logged_out
|
||||||
|
|
||||||
|
// DO NOT CALL LOGOUT. A soft logout preserves data, logout does not.
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSoftLogout() {
|
||||||
|
return localStorage.getItem("mx_soft_logout") === "true";
|
||||||
|
}
|
||||||
|
|
||||||
export function isLoggingOut() {
|
export function isLoggingOut() {
|
||||||
return _isLoggingOut;
|
return _isLoggingOut;
|
||||||
}
|
}
|
||||||
|
@ -494,8 +516,10 @@ export function isLoggingOut() {
|
||||||
/**
|
/**
|
||||||
* Starts the matrix client and all other react-sdk services that
|
* Starts the matrix client and all other react-sdk services that
|
||||||
* listen for events while a session is logged in.
|
* listen for events while a session is logged in.
|
||||||
|
* @param {boolean} startSyncing True (default) to actually start
|
||||||
|
* syncing the client.
|
||||||
*/
|
*/
|
||||||
async function startMatrixClient() {
|
async function startMatrixClient(startSyncing=true) {
|
||||||
console.log(`Lifecycle: Starting MatrixClient`);
|
console.log(`Lifecycle: Starting MatrixClient`);
|
||||||
|
|
||||||
// dispatch this before starting the matrix client: it's used
|
// dispatch this before starting the matrix client: it's used
|
||||||
|
@ -513,11 +537,19 @@ async function startMatrixClient() {
|
||||||
DMRoomMap.makeShared().start();
|
DMRoomMap.makeShared().start();
|
||||||
ActiveWidgetStore.start();
|
ActiveWidgetStore.start();
|
||||||
|
|
||||||
await MatrixClientPeg.start();
|
if (startSyncing) {
|
||||||
|
await MatrixClientPeg.start();
|
||||||
|
} else {
|
||||||
|
console.warn("Caller requested only auxiliary services be started");
|
||||||
|
}
|
||||||
|
|
||||||
// dispatch that we finished starting up to wire up any other bits
|
// dispatch that we finished starting up to wire up any other bits
|
||||||
// of the matrix client that cannot be set prior to starting up.
|
// of the matrix client that cannot be set prior to starting up.
|
||||||
dis.dispatch({action: 'client_started'});
|
dis.dispatch({action: 'client_started'});
|
||||||
|
|
||||||
|
if (isSoftLogout()) {
|
||||||
|
softLogout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -551,8 +583,10 @@ function _clearStorage() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop all the background processes related to the current client.
|
* Stop all the background processes related to the current client.
|
||||||
|
* @param {boolean} unsetClient True (default) to abandon the client
|
||||||
|
* on MatrixClientPeg after stopping.
|
||||||
*/
|
*/
|
||||||
export function stopMatrixClient() {
|
export function stopMatrixClient(unsetClient=true) {
|
||||||
Notifier.stop();
|
Notifier.stop();
|
||||||
UserActivity.sharedInstance().stop();
|
UserActivity.sharedInstance().stop();
|
||||||
TypingStore.sharedInstance().reset();
|
TypingStore.sharedInstance().reset();
|
||||||
|
@ -563,6 +597,9 @@ export function stopMatrixClient() {
|
||||||
if (cli) {
|
if (cli) {
|
||||||
cli.stopClient();
|
cli.stopClient();
|
||||||
cli.removeAllListeners();
|
cli.removeAllListeners();
|
||||||
MatrixClientPeg.unset();
|
|
||||||
|
if (unsetClient) {
|
||||||
|
MatrixClientPeg.unset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,10 @@ const VIEWS = {
|
||||||
|
|
||||||
// we are logged in with an active matrix client.
|
// we are logged in with an active matrix client.
|
||||||
LOGGED_IN: 7,
|
LOGGED_IN: 7,
|
||||||
|
|
||||||
|
// We are logged out (invalid token) but have our local state again. The user
|
||||||
|
// should log back in to rehydrate the client.
|
||||||
|
SOFT_LOGOUT: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Actions that are redirected through the onboarding process prior to being
|
// Actions that are redirected through the onboarding process prior to being
|
||||||
|
@ -432,6 +436,7 @@ export default React.createClass({
|
||||||
|
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case 'logout':
|
case 'logout':
|
||||||
|
console.log(payload);
|
||||||
Lifecycle.logout();
|
Lifecycle.logout();
|
||||||
break;
|
break;
|
||||||
case 'require_registration':
|
case 'require_registration':
|
||||||
|
@ -615,7 +620,12 @@ export default React.createClass({
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'on_logged_in':
|
case 'on_logged_in':
|
||||||
this._onLoggedIn();
|
if (!Lifecycle.isSoftLogout()) {
|
||||||
|
this._onLoggedIn();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
|
this._onSoftLogout();
|
||||||
break;
|
break;
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this._onLoggedOut();
|
this._onLoggedOut();
|
||||||
|
@ -1258,6 +1268,22 @@ export default React.createClass({
|
||||||
this._setPageSubtitle();
|
this._setPageSubtitle();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the session is softly logged out
|
||||||
|
*/
|
||||||
|
_onSoftLogout: function() {
|
||||||
|
this.notifyNewScreen('soft_logout');
|
||||||
|
this.setStateForNewView({
|
||||||
|
view: VIEWS.SOFT_LOGOUT,
|
||||||
|
ready: false,
|
||||||
|
collapseLhs: false,
|
||||||
|
collapsedRhs: false,
|
||||||
|
currentRoomId: null,
|
||||||
|
page_type: PageTypes.RoomDirectory,
|
||||||
|
});
|
||||||
|
this._setPageSubtitle();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called just before the matrix client is started
|
* Called just before the matrix client is started
|
||||||
* (useful for setting listeners)
|
* (useful for setting listeners)
|
||||||
|
@ -1337,8 +1363,16 @@ export default React.createClass({
|
||||||
call: call,
|
call: call,
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
cli.on('Session.logged_out', function(call) {
|
cli.on('Session.logged_out', function(errObj) {
|
||||||
if (Lifecycle.isLoggingOut()) return;
|
if (Lifecycle.isLoggingOut()) return;
|
||||||
|
|
||||||
|
if (errObj.httpStatus === 401 && errObj.data && errObj.data['soft_logout']) {
|
||||||
|
console.warn("Soft logout issued by server - avoiding data deletion");
|
||||||
|
Lifecycle.softLogout();
|
||||||
|
dis.dispatch({actions: 'soft_logout'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
|
Modal.createTrackedDialog('Signed out', '', ErrorDialog, {
|
||||||
title: _t('Signed Out'),
|
title: _t('Signed Out'),
|
||||||
|
@ -1908,6 +1942,13 @@ export default React.createClass({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.state.view === VIEWS.SOFT_LOGOUT) {
|
||||||
|
const SoftLogout = sdk.getComponent('structures.auth.SoftLogout');
|
||||||
|
return (
|
||||||
|
<SoftLogout />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
console.error(`Unknown view ${this.state.view}`);
|
console.error(`Unknown view ${this.state.view}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
123
src/components/structures/auth/SoftLogout.js
Normal file
123
src/components/structures/auth/SoftLogout.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
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 React from 'react';
|
||||||
|
import {_t} from '../../../languageHandler';
|
||||||
|
import sdk from '../../../index';
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
|
import * as Lifecycle from '../../../Lifecycle';
|
||||||
|
import Modal from '../../../Modal';
|
||||||
|
import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
|
||||||
|
import SdkConfig from "../../../SdkConfig";
|
||||||
|
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||||
|
|
||||||
|
export default class SoftLogout extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
// Nothing.
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const defaultServerConfig: ValidatedServerConfig = SdkConfig.get()["validated_server_config"];
|
||||||
|
|
||||||
|
const hsUrl = MatrixClientPeg.get().getHomeserverUrl();
|
||||||
|
const domainName = hsUrl === defaultServerConfig.hsUrl
|
||||||
|
? defaultServerConfig.hsName
|
||||||
|
: MatrixClientPeg.get().getHomeServerName();
|
||||||
|
|
||||||
|
const userId = MatrixClientPeg.get().getUserId();
|
||||||
|
const user = MatrixClientPeg.get().getUser(userId);
|
||||||
|
|
||||||
|
const displayName = user ? user.displayName : userId.substring(1).split(':')[0];
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
domainName,
|
||||||
|
userId,
|
||||||
|
displayName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onClearAll = () => {
|
||||||
|
const ConfirmWipeDeviceDialog = sdk.getComponent('dialogs.ConfirmWipeDeviceDialog');
|
||||||
|
Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, {
|
||||||
|
onFinished: (wipeData) => {
|
||||||
|
if (!wipeData) return;
|
||||||
|
|
||||||
|
console.log("Clearing data from soft-logged-out device");
|
||||||
|
Lifecycle.logout();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onLogin = () => {
|
||||||
|
dis.dispatch({action: 'start_login'});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const AuthPage = sdk.getComponent("auth.AuthPage");
|
||||||
|
const AuthHeader = sdk.getComponent("auth.AuthHeader");
|
||||||
|
const AuthBody = sdk.getComponent("auth.AuthBody");
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthPage>
|
||||||
|
<AuthHeader />
|
||||||
|
<AuthBody>
|
||||||
|
<h2>
|
||||||
|
{_t("You're signed out")}
|
||||||
|
</h2>
|
||||||
|
<div>
|
||||||
|
{_t(
|
||||||
|
"Your homeserver (%(domainName)s) admin has signed you out of your " +
|
||||||
|
"account %(displayName)s (%(userId)s).",
|
||||||
|
{
|
||||||
|
domainName: this.state.domainName,
|
||||||
|
displayName: this.state.displayName,
|
||||||
|
userId: this.state.userId,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{_t("I don't want to sign in")}</h3>
|
||||||
|
<div>
|
||||||
|
{_t(
|
||||||
|
"If this is a shared device, or you don't want to access your account " +
|
||||||
|
"again from it, clear all data stored locally on this device.",
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<AccessibleButton onClick={this.onClearAll} kind="primary">
|
||||||
|
{_t("Clear all data")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{_t("Sign in")}</h3>
|
||||||
|
<div>
|
||||||
|
{_t(
|
||||||
|
"Sign in again to regain access to your account, or a different one.",
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<AccessibleButton onClick={this.onLogin} kind="primary">
|
||||||
|
{_t("Sign in")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</AuthBody>
|
||||||
|
</AuthPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
60
src/components/views/dialogs/ConfirmWipeDeviceDialog.js
Normal file
60
src/components/views/dialogs/ConfirmWipeDeviceDialog.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
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 React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {_t} from "../../../languageHandler";
|
||||||
|
import sdk from "../../../index";
|
||||||
|
|
||||||
|
export default class ConfirmWipeDeviceDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
_onConfirm = () => {
|
||||||
|
this.props.onFinished(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
_onDecline = () => {
|
||||||
|
this.props.onFinished(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseDialog className='mx_ConfirmWipeDeviceDialog' hasCancel={true}
|
||||||
|
onFinished={this.props.onFinished}
|
||||||
|
title={_t("Clear all data on this device?")}>
|
||||||
|
<div className='mx_ConfirmWipeDeviceDialog_content'>
|
||||||
|
<p>
|
||||||
|
{_t(
|
||||||
|
"Deleting all data from this device is permanent. Encrypted messages will be lost " +
|
||||||
|
"unless their keys have been backed up.",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<DialogButtons
|
||||||
|
primaryButton={_t("Delete everything")}
|
||||||
|
onPrimaryButtonClick={this._onConfirm}
|
||||||
|
cancelButton={_t("Cancel")}
|
||||||
|
onCancel={this._onDecline}
|
||||||
|
/>
|
||||||
|
</BaseDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,6 +147,7 @@
|
||||||
"Changes your display nickname": "Changes your display nickname",
|
"Changes your display nickname": "Changes your display nickname",
|
||||||
"Changes your display nickname in the current room only": "Changes your display nickname in the current room only",
|
"Changes your display nickname in the current room only": "Changes your display nickname in the current room only",
|
||||||
"Changes your avatar in this current room only": "Changes your avatar in this current room only",
|
"Changes your avatar in this current room only": "Changes your avatar in this current room only",
|
||||||
|
"Changes your avatar in all rooms": "Changes your avatar in all rooms",
|
||||||
"Changes colour scheme of current room": "Changes colour scheme of current room",
|
"Changes colour scheme of current room": "Changes colour scheme of current room",
|
||||||
"Gets or sets the room topic": "Gets or sets the room topic",
|
"Gets or sets the room topic": "Gets or sets the room topic",
|
||||||
"This room has no topic.": "This room has no topic.",
|
"This room has no topic.": "This room has no topic.",
|
||||||
|
@ -1127,6 +1128,9 @@
|
||||||
"Start Chatting": "Start Chatting",
|
"Start Chatting": "Start Chatting",
|
||||||
"Confirm Removal": "Confirm Removal",
|
"Confirm Removal": "Confirm Removal",
|
||||||
"Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.",
|
"Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.",
|
||||||
|
"Clear all data on this device?": "Clear all data on this device?",
|
||||||
|
"Deleting all data from this device is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Deleting all data from this device is permanent. Encrypted messages will be lost unless their keys have been backed up.",
|
||||||
|
"Delete everything": "Delete everything",
|
||||||
"Community IDs cannot be empty.": "Community IDs cannot be empty.",
|
"Community IDs cannot be empty.": "Community IDs cannot be empty.",
|
||||||
"Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Community IDs may only contain characters a-z, 0-9, or '=_-./'",
|
"Community IDs may only contain characters a-z, 0-9, or '=_-./'": "Community IDs may only contain characters a-z, 0-9, or '=_-./'",
|
||||||
"Something went wrong whilst creating your community": "Something went wrong whilst creating your community",
|
"Something went wrong whilst creating your community": "Something went wrong whilst creating your community",
|
||||||
|
@ -1581,6 +1585,12 @@
|
||||||
"You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.",
|
"You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.",
|
||||||
"Registration Successful": "Registration Successful",
|
"Registration Successful": "Registration Successful",
|
||||||
"Create your account": "Create your account",
|
"Create your account": "Create your account",
|
||||||
|
"You're signed out": "You're signed out",
|
||||||
|
"Your homeserver (%(domainName)s) admin has signed you out of your account %(displayName)s (%(userId)s).": "Your homeserver (%(domainName)s) admin has signed you out of your account %(displayName)s (%(userId)s).",
|
||||||
|
"I don't want to sign in": "I don't want to sign in",
|
||||||
|
"If this is a shared device, or you don't want to access your account again from it, clear all data stored locally on this device.": "If this is a shared device, or you don't want to access your account again from it, clear all data stored locally on this device.",
|
||||||
|
"Clear all data": "Clear all data",
|
||||||
|
"Sign in again to regain access to your account, or a different one.": "Sign in again to regain access to your account, or a different one.",
|
||||||
"Commands": "Commands",
|
"Commands": "Commands",
|
||||||
"Results from DuckDuckGo": "Results from DuckDuckGo",
|
"Results from DuckDuckGo": "Results from DuckDuckGo",
|
||||||
"Emoji": "Emoji",
|
"Emoji": "Emoji",
|
||||||
|
|
|
@ -122,6 +122,7 @@ class CustomRoomTagStore extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out': {
|
case 'on_logged_out': {
|
||||||
// we assume to always have a tags object in the state
|
// we assume to always have a tags object in the state
|
||||||
this._state = {tags: {}};
|
this._state = {tags: {}};
|
||||||
|
|
|
@ -63,6 +63,7 @@ class LifecycleStore extends Store {
|
||||||
dis.dispatch(deferredAction);
|
dis.dispatch(deferredAction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this.reset();
|
this.reset();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -261,6 +261,7 @@ class RoomListStore extends Store {
|
||||||
// console.log("!! Optimistic tag failure: ", payload);
|
// console.log("!! Optimistic tag failure: ", payload);
|
||||||
// }
|
// }
|
||||||
// break;
|
// break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out': {
|
case 'on_logged_out': {
|
||||||
// Reset state without pushing an update to the view, which generally assumes that
|
// Reset state without pushing an update to the view, which generally assumes that
|
||||||
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
||||||
|
|
|
@ -103,6 +103,7 @@ class RoomViewStore extends Store {
|
||||||
case 'join_room_error':
|
case 'join_room_error':
|
||||||
this._joinRoomError(payload);
|
this._joinRoomError(payload);
|
||||||
break;
|
break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this.reset();
|
this.reset();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -68,6 +68,7 @@ class SessionStore extends Store {
|
||||||
cachedPassword: null,
|
cachedPassword: null,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out':
|
case 'on_logged_out':
|
||||||
this._setState({
|
this._setState({
|
||||||
cachedPassword: null,
|
cachedPassword: null,
|
||||||
|
|
|
@ -166,6 +166,7 @@ class TagOrderStore extends Store {
|
||||||
});
|
});
|
||||||
Analytics.trackEvent('FilterStore', 'deselect_tags');
|
Analytics.trackEvent('FilterStore', 'deselect_tags');
|
||||||
break;
|
break;
|
||||||
|
case 'on_client_not_viable':
|
||||||
case 'on_logged_out': {
|
case 'on_logged_out': {
|
||||||
// Reset state without pushing an update to the view, which generally assumes that
|
// Reset state without pushing an update to the view, which generally assumes that
|
||||||
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
// the matrix client isn't `null` and so causing a re-render will cause NPEs.
|
||||||
|
|
Loading…
Reference in a new issue