Browse Source

chore(ts): Convert errorBoundary / detailedError (#15482)

Evan Purkhiser 5 years ago
parent
commit
b4914f0de9

+ 50 - 35
src/sentry/static/sentry/app/components/errorBoundary.jsx → src/sentry/static/sentry/app/components/errorBoundary.tsx

@@ -8,13 +8,24 @@ import {t} from 'app/locale';
 import Alert from 'app/components/alert';
 import DetailedError from 'app/components/errors/detailedError';
 
-const exclamation = ['Raspberries', 'Snap', 'Frig', 'Welp', 'Uhhhh', 'Hmmm'];
+type Props = {
+  mini?: boolean;
+  message?: React.ReactNode;
+  customComponent?: React.ReactNode;
+  className?: string;
+};
 
-const getExclamation = () => {
-  return exclamation[Math.floor(Math.random() * exclamation.length)];
+type State = {
+  error: Error | null;
 };
 
-class ErrorBoundary extends React.Component {
+const exclamation = ['Raspberries', 'Snap', 'Frig', 'Welp', 'Uhhhh', 'Hmmm'] as const;
+
+function getExclamation() {
+  return exclamation[Math.floor(Math.random() * exclamation.length)];
+}
+
+class ErrorBoundary extends React.Component<Props, State> {
   static propTypes = {
     mini: PropTypes.bool,
     message: PropTypes.node,
@@ -25,10 +36,12 @@ class ErrorBoundary extends React.Component {
     mini: false,
   };
 
-  constructor(props) {
-    super(props);
-    this.state = {error: null};
-  }
+  state: State = {
+    error: null,
+  };
+
+  // XXX: browserHistory.listen does not have a correct return type.
+  unlistenBrowserHistory: any;
 
   componentDidMount() {
     // Listen for route changes so we can clear error
@@ -37,7 +50,7 @@ class ErrorBoundary extends React.Component {
     );
   }
 
-  componentDidCatch(error, errorInfo) {
+  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
     this.setState({error});
     Sentry.withScope(scope => {
       scope.setExtra('errorInfo', errorInfo);
@@ -52,38 +65,40 @@ class ErrorBoundary extends React.Component {
   }
 
   render() {
-    if (this.state.error) {
-      const {customComponent, mini, message, className} = this.props;
+    const {error} = this.state;
+
+    if (!error) {
+      //when there's not an error, render children untouched
+      return this.props.children;
+    }
 
-      if (customComponent) {
-        return customComponent;
-      }
+    const {customComponent, mini, message, className} = this.props;
 
-      if (mini) {
-        return (
-          <Alert type="error" icon="icon-circle-exclamation" className={className}>
-            {message || t('There was a problem rendering this component')}
-          </Alert>
-        );
-      }
+    if (customComponent) {
+      return customComponent;
+    }
 
+    if (mini) {
       return (
-        <Wrapper>
-          <DetailedError
-            heading={getExclamation()}
-            message={t(
-              `Something went horribly wrong rendering this page.
-We use a decent error reporting service so this will probably be fixed soon. Unless our error reporting service is also broken. That would be awkward.
-Anyway, we apologize for the inconvenience.`
-            )}
-          />
-          <StackTrace>{this.state.error.toString()}</StackTrace>
-        </Wrapper>
+        <Alert type="error" icon="icon-circle-exclamation" className={className}>
+          {message || t('There was a problem rendering this component')}
+        </Alert>
       );
-    } else {
-      //when there's not an error, render children untouched
-      return this.props.children;
     }
+
+    return (
+      <Wrapper>
+        <DetailedError
+          heading={getExclamation()}
+          message={t(
+            `Something went horribly wrong rendering this page.
+We use a decent error reporting service so this will probably be fixed soon. Unless our error reporting service is also broken. That would be awkward.
+Anyway, we apologize for the inconvenience.`
+          )}
+        />
+        <StackTrace>{error.toString()}</StackTrace>
+      </Wrapper>
+    );
   }
 }
 

+ 29 - 14
src/sentry/static/sentry/app/components/errors/detailedError.jsx → src/sentry/static/sentry/app/components/errors/detailedError.tsx

@@ -7,16 +7,37 @@ import {t} from 'app/locale';
 import InlineSvg from 'app/components/inlineSvg';
 import Button from 'app/components/button';
 
-class DetailedError extends React.Component {
+type Props = {
+  className?: string;
+  /**
+   * Error heading
+   */
+  heading: React.ReactNode;
+  /**
+   * Detailed error explanation
+   */
+  message?: React.ReactNode;
+  /**
+   * Retry callback
+   */
+  onRetry?: (e: React.MouseEvent) => void;
+  /**
+   * Hide support links in footer of error message
+   */
+  hideSupportLinks?: boolean;
+};
+
+function openFeedback(e: React.MouseEvent) {
+  e.preventDefault();
+  Sentry.showReportDialog();
+}
+
+class DetailedError extends React.Component<Props> {
   static propTypes = {
     className: PropTypes.string,
-    /* Retry callback */
     onRetry: PropTypes.func,
-    /* Error heading */
     heading: PropTypes.string.isRequired,
-    /* Detailed error explanation */
     message: PropTypes.node,
-    /* Hide support links in footer of error message */
     hideSupportLinks: PropTypes.bool,
   };
 
@@ -25,14 +46,8 @@ class DetailedError extends React.Component {
   };
 
   componentDidMount() {
-    setTimeout(() => {
-      this.forceUpdate();
-    }, 100);
-  }
-
-  openFeedback(e) {
-    e.preventDefault();
-    Sentry.showReportDialog();
+    // XXX(epurkhiser): Why is this here?
+    setTimeout(() => this.forceUpdate(), 100);
   }
 
   render() {
@@ -64,7 +79,7 @@ class DetailedError extends React.Component {
               {!hideSupportLinks && (
                 <div className="detailed-error-support-links">
                   {Sentry.lastEventId() && (
-                    <Button priority="link" onClick={this.openFeedback}>
+                    <Button priority="link" onClick={openFeedback}>
                       {t('Fill out a report')}
                     </Button>
                   )}