~cytrogen/masto-fe

6256cee0342d7ebeda407c4644330c7c6bc31b84 — Claire 2 years ago cf9affd
Change error boundary to upstream's (#2323)

4 files changed, 48 insertions(+), 105 deletions(-)

M app/javascript/flavours/glitch/components/error_boundary.jsx
M app/javascript/flavours/glitch/styles/basics.scss
D app/javascript/flavours/glitch/styles/components/error_boundary.scss
M app/javascript/flavours/glitch/styles/components/index.scss
M app/javascript/flavours/glitch/components/error_boundary.jsx => app/javascript/flavours/glitch/components/error_boundary.jsx +47 -74
@@ 7,8 7,7 @@ import { Helmet } from 'react-helmet';

import StackTrace from 'stacktrace-js';

import { source_url } from 'flavours/glitch/initial_state';
import { preferencesLink } from 'flavours/glitch/utils/backend_links';
import { version, source_url } from 'flavours/glitch/initial_state';

export default class ErrorBoundary extends PureComponent {



@@ 24,7 23,7 @@ export default class ErrorBoundary extends PureComponent {
    componentStack: undefined,
  };

  componentDidCatch(error, info) {
  componentDidCatch (error, info) {
    this.setState({
      hasError: true,
      errorMessage: error.toString(),


@@ 44,88 43,62 @@ export default class ErrorBoundary extends PureComponent {
    });
  }

  handleReload(e) {
    e.preventDefault();
    window.location.reload();
  }
  handleCopyStackTrace = () => {
    const { errorMessage, stackTrace, mappedStackTrace } = this.state;
    const textarea = document.createElement('textarea');

  render() {
    const { hasError, errorMessage, stackTrace, mappedStackTrace, componentStack } = this.state;
    let contents = [errorMessage, stackTrace];
    if (mappedStackTrace) {
      contents.push(mappedStackTrace);
    }

    if (!hasError) return this.props.children;
    textarea.textContent    = contents.join('\n\n\n');
    textarea.style.position = 'fixed';

    const likelyBrowserAddonIssue = errorMessage && errorMessage.includes('NotFoundError');
    document.body.appendChild(textarea);

    let debugInfo = '';
    if (stackTrace) {
      debugInfo += 'Stack trace\n-----------\n\n```\n' + errorMessage + '\n' + stackTrace.toString() + '\n```';
    }
    if (mappedStackTrace) {
      debugInfo += 'Mapped stack trace\n-----------\n\n```\n' + errorMessage + '\n' + mappedStackTrace.toString() + '\n```';
    }
    if (componentStack) {
      if (debugInfo) {
        debugInfo += '\n\n\n';
      }
      debugInfo += 'React component stack\n---------------------\n\n```\n' + componentStack.toString() + '\n```';
    try {
      textarea.select();
      document.execCommand('copy');
    } catch (e) {

    } finally {
      document.body.removeChild(textarea);
    }

    let issueTracker = source_url;
    if (source_url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/?$/)) {
      issueTracker = source_url + '/issues';
    this.setState({ copied: true });
    setTimeout(() => this.setState({ copied: false }), 700);
  };

  render() {
    const { hasError, copied, errorMessage } = this.state;

    if (!hasError) {
      return this.props.children;
    }

    const likelyBrowserAddonIssue = errorMessage && errorMessage.includes('NotFoundError');

    return (
      <div tabIndex={-1}>
        <div className='error-boundary'>
          <h1><FormattedMessage id='web_app_crash.title' defaultMessage="We're sorry, but something went wrong with the Mastodon app." /></h1>
          <p>
            <FormattedMessage id='web_app_crash.content' defaultMessage='You could try any of the following:' />
      <div className='error-boundary'>
        <div>
          <p className='error-boundary__error'>
            { likelyBrowserAddonIssue ? (
              <FormattedMessage id='error.unexpected_crash.explanation_addons' defaultMessage='This page could not be displayed correctly. This error is likely caused by a browser add-on or automatic translation tools.' />
            ) : (
              <FormattedMessage id='error.unexpected_crash.explanation' defaultMessage='Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.' />
            )}
          </p>
          <ul>
            { likelyBrowserAddonIssue && (
              <li>
                <FormattedMessage
                  id='web_app_crash.disable_addons'
                  defaultMessage='Disable browser add-ons or built-in translation tools'
                />
              </li>
            ) }
            <li>
              <FormattedMessage
                id='web_app_crash.report_issue'
                defaultMessage='Report a bug in the {issuetracker}'
                values={{ issuetracker: <a href={issueTracker} rel='noopener noreferrer' target='_blank'><FormattedMessage id='web_app_crash.issue_tracker' defaultMessage='issue tracker' /></a> }}
              />
              { debugInfo !== '' && (
                <details>
                  <summary><FormattedMessage id='web_app_crash.debug_info' defaultMessage='Debug information' /></summary>
                  <textarea
                    className='web_app_crash-stacktrace'
                    value={debugInfo}
                    rows='10'
                    readOnly
                  />
                </details>
              )}
            </li>
            <li>
              <FormattedMessage
                id='web_app_crash.reload_page'
                defaultMessage='{reload} the current page'
                values={{ reload: <a href='#' onClick={this.handleReload}><FormattedMessage id='web_app_crash.reload' defaultMessage='Reload' /></a> }}
              />
            </li>
            { preferencesLink !== undefined && (
              <li>
                <FormattedMessage
                  id='web_app_crash.change_your_settings'
                  defaultMessage='Change your {settings}'
                  values={{ settings: <a href={preferencesLink}><FormattedMessage id='web_app_crash.settings' defaultMessage='settings' /></a> }}
                />
              </li>

          <p>
            { likelyBrowserAddonIssue ? (
              <FormattedMessage id='error.unexpected_crash.next_steps_addons' defaultMessage='Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.' />
            ) : (
              <FormattedMessage id='error.unexpected_crash.next_steps' defaultMessage='Try refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.' />
            )}
          </ul>
          </p>

          <p className='error-boundary__footer'>Mastodon v{version} · <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='errors.unexpected_crash.report_issue' defaultMessage='Report issue' /></a> · <button onClick={this.handleCopyStackTrace} className={copied ? 'copied' : ''}><FormattedMessage id='errors.unexpected_crash.copy_stacktrace' defaultMessage='Copy stacktrace to clipboard' /></button></p>
        </div>

        <Helmet>

M app/javascript/flavours/glitch/styles/basics.scss => app/javascript/flavours/glitch/styles/basics.scss +1 -0
@@ 200,6 200,7 @@ button {
  }
}

.error-boundary,
.app-holder noscript {
  flex-direction: column;
  font-size: 16px;

D app/javascript/flavours/glitch/styles/components/error_boundary.scss => app/javascript/flavours/glitch/styles/components/error_boundary.scss +0 -30
@@ 1,30 0,0 @@
.error-boundary {
  color: $primary-text-color;
  font-size: 15px;
  line-height: 20px;

  h1 {
    font-size: 26px;
    line-height: 36px;
    font-weight: 400;
    margin-bottom: 8px;
  }

  a {
    color: $primary-text-color;
    text-decoration: underline;
  }

  ul {
    list-style: disc;
    margin-inline-start: 0;
    padding-inline-start: 1em;
  }

  textarea.web_app_crash-stacktrace {
    width: 100%;
    resize: none;
    white-space: pre;
    font-family: $font-monospace, monospace;
  }
}

M app/javascript/flavours/glitch/styles/components/index.scss => app/javascript/flavours/glitch/styles/components/index.scss +0 -1
@@ 17,7 17,6 @@
@import 'lists';
@import 'emoji_picker';
@import 'local_settings';
@import 'error_boundary';
@import 'single_column';
@import 'announcements';
@import 'explore';