diff --git a/src/Modal.js b/src/Modal.js index 4d90e313ce..96dbd49324 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -124,6 +124,10 @@ class ModalManager { this.closeAll = this.closeAll.bind(this); } + hasDialogs() { + return this._priorityModal || this._staticModal || this._modals.length > 0; + } + getOrCreateContainer() { let container = document.getElementById(DIALOG_CONTAINER_ID); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2622a6bf93..b617e4ca02 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -48,6 +48,7 @@ import { _t, getCurrentLanguage } from '../../languageHandler'; import SettingsStore, {SettingLevel} from "../../settings/SettingsStore"; import { startAnyRegistrationFlow } from "../../Registration.js"; import { messageForSyncError } from '../../utils/ErrorUtils'; +import TimelineExplosionDialog from "../views/dialogs/TimelineExplosionDialog"; const AutoDiscovery = Matrix.AutoDiscovery; @@ -1278,6 +1279,17 @@ export default React.createClass({ return self._loggedInView.child.canResetTimelineInRoom(roomId); }); + cli.on('sync.unexpectedError', function(err) { + if (err.message && err.message.includes("live timeline ") && err.message.includes(" is no longer live ")) { + console.error("Caught timeline explosion - trying to ask user for more information"); + if (Modal.hasDialogs()) { + console.warn("User has another dialog open - skipping prompt"); + return; + } + Modal.createTrackedDialog('Timeline exploded', '', TimelineExplosionDialog, {}); + } + }); + cli.on('sync', function(state, prevState, data) { // LifecycleStore and others cannot directly subscribe to matrix client for // events because flux only allows store state changes during flux dispatches. diff --git a/src/components/views/dialogs/TimelineExplosionDialog.js b/src/components/views/dialogs/TimelineExplosionDialog.js new file mode 100644 index 0000000000..5c8fba8f9c --- /dev/null +++ b/src/components/views/dialogs/TimelineExplosionDialog.js @@ -0,0 +1,130 @@ +/* +Copyright 2019 New Vector 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 React from 'react'; +import sdk from '../../../index'; +import SdkConfig from '../../../SdkConfig'; +import { _t } from '../../../languageHandler'; + +// Dev note: this should be a temporary dialog while we work out what is +// actually going on. See https://github.com/vector-im/riot-web/issues/8593 +// for more details. This dialog is almost entirely a copy/paste job of +// BugReportDialog. +export default class TimelineExplosionDialog extends React.Component { + static propTypes = { + onFinished: React.PropTypes.func.isRequired, + }; + + constructor(props, context) { + super(props, context); + this.state = { + busy: false, + progress: null, + }; + } + + _onCancel() { + console.log("Reloading without sending logs for timeline explosion"); + window.location.reload(); + } + + _onSubmit = () => { + const userText = "Caught timeline explosion\n\nhttps://github.com/vector-im/riot-web/issues/8593"; + + this.setState({busy: true, progress: null}); + this._sendProgressCallback(_t("Preparing to send logs")); + + require(['../../../rageshake/submit-rageshake'], (s) => { + s(SdkConfig.get().bug_report_endpoint_url, { + userText, + sendLogs: true, + progressCallback: this._sendProgressCallback, + }).then(() => { + console.log("logs sent for timeline explosion - reloading riot"); + window.location.reload(); + }, (err) => { + console.error("Error sending logs for timeline explosion - reloading anyways. ", err); + window.location.reload(); + }); + }); + }; + + _sendProgressCallback = (progress) => { + this.setState({progress: progress}); + }; + + render() { + const Loader = sdk.getComponent("elements.Spinner"); + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + let progress = null; + if (this.state.busy) { + progress = ( +
+ {_t( + "Riot has run into a problem which makes it difficult to show you " + + "your messages right now. Nothing has been lost, and reloading the app " + + "should fix this for you. In order to assist us in troubleshooting the " + + "problem, we'd like to take a look at your debug logs. You do not need " + + "to send your logs unless you want to, but we would really appreciate " + + "it if you did. We'd also like to apologize for having to show this " + + "message to you - we hope your debug logs are the key to solving the " + + "issue once and for all. If you'd like more information on the bug you've " + + "accidentally run into, please visit the issue.", + {}, + { + 'a': (sub) => { + return {sub}; + }, + }, + )} +
++ {_t( + "Debug logs contain application usage data including your " + + "username, the IDs or aliases of the rooms or groups you " + + "have visited and the usernames of other users. They do " + + "not contain messages.", + )} +
+ {progress} +