From 51dc57236c6d082b9a8b0723dad65a5414216c97 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 00:05:52 +0000 Subject: [PATCH 1/2] refactor(common): convert error-boundary to TypeScript --- .../{DefaultError.js => DefaultError.js.flow} | 0 .../common/error-boundary/DefaultError.tsx | 20 +++++ ...ErrorBoundary.js => ErrorBoundary.js.flow} | 0 .../common/error-boundary/ErrorBoundary.tsx | 87 +++++++++++++++++++ .../{index.js => index.js.flow} | 0 src/elements/common/error-boundary/index.ts | 2 + ...rBoundary.js => withErrorBoundary.js.flow} | 0 .../error-boundary/withErrorBoundary.tsx | 24 +++++ 8 files changed, 133 insertions(+) rename src/elements/common/error-boundary/{DefaultError.js => DefaultError.js.flow} (100%) create mode 100644 src/elements/common/error-boundary/DefaultError.tsx rename src/elements/common/error-boundary/{ErrorBoundary.js => ErrorBoundary.js.flow} (100%) create mode 100644 src/elements/common/error-boundary/ErrorBoundary.tsx rename src/elements/common/error-boundary/{index.js => index.js.flow} (100%) create mode 100644 src/elements/common/error-boundary/index.ts rename src/elements/common/error-boundary/{withErrorBoundary.js => withErrorBoundary.js.flow} (100%) create mode 100644 src/elements/common/error-boundary/withErrorBoundary.tsx diff --git a/src/elements/common/error-boundary/DefaultError.js b/src/elements/common/error-boundary/DefaultError.js.flow similarity index 100% rename from src/elements/common/error-boundary/DefaultError.js rename to src/elements/common/error-boundary/DefaultError.js.flow diff --git a/src/elements/common/error-boundary/DefaultError.tsx b/src/elements/common/error-boundary/DefaultError.tsx new file mode 100644 index 0000000000..8316f93cea --- /dev/null +++ b/src/elements/common/error-boundary/DefaultError.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { FormattedMessage } from 'react-intl'; +import ErrorMask from '../../../components/error-mask/ErrorMask'; +import messages from '../messages'; +import './DefaultError.scss'; + +export interface DefaultErrorProps { + error?: Error; +} + +const DefaultError = (): JSX.Element => ( +
+ } + errorSubHeader={} + /> +
+); + +export default DefaultError; diff --git a/src/elements/common/error-boundary/ErrorBoundary.js b/src/elements/common/error-boundary/ErrorBoundary.js.flow similarity index 100% rename from src/elements/common/error-boundary/ErrorBoundary.js rename to src/elements/common/error-boundary/ErrorBoundary.js.flow diff --git a/src/elements/common/error-boundary/ErrorBoundary.tsx b/src/elements/common/error-boundary/ErrorBoundary.tsx new file mode 100644 index 0000000000..59b0f2e0ef --- /dev/null +++ b/src/elements/common/error-boundary/ErrorBoundary.tsx @@ -0,0 +1,87 @@ +import * as React from 'react'; +import noop from 'lodash/noop'; +import { ERROR_CODE_UNEXPECTED_EXCEPTION, IS_ERROR_DISPLAYED } from '../../../constants'; +import DefaultError, { DefaultErrorProps } from './DefaultError'; +import type { ElementsXhrError, ElementsError } from '../../../common/types/api'; +import type { ElementOrigin } from '../flowTypes'; + +export interface ErrorBoundaryProps { + children: React.ReactElement; + errorComponent: React.ComponentType; + errorOrigin: ElementOrigin; + onError: (error: ElementsError) => void; +} + +type State = { + error?: Error; +}; + +class ErrorBoundary extends React.Component { + static defaultProps = { + errorComponent: DefaultError, + onError: noop, + }; + + state: State = {}; + + componentDidCatch(error: Error, info: React.ErrorInfo): void { + this.setState({ error }, () => { + this.handleError( + error, + ERROR_CODE_UNEXPECTED_EXCEPTION, + { + ...info, + }, + this.props.errorOrigin, + ); + }); + } + + /** + * Formats the error and emits it to the top level onError prop + * + * @param error - the error which occurred + * @param code - the error code to identify what error occurred + * @param contextInfo - additional information which may be useful for the consumer of the error + * @param origin - the origin of the error + * @return void + */ + handleError = ( + error: ElementsXhrError | Error, + code: string, + contextInfo: Record = {}, + origin: ElementOrigin = this.props.errorOrigin, + ): void => { + if (!error || !code || !origin) { + return; + } + + const elementsError: ElementsError = { + type: 'error', + code, + message: error.message, + origin, + context_info: { + [IS_ERROR_DISPLAYED]: true, + ...contextInfo, + }, + }; + + this.props.onError(elementsError); + }; + + render(): React.ReactNode { + const { children, errorComponent: ErrorComponent, ...rest } = this.props; + const { error } = this.state; + if (error) { + return ; + } + + return React.cloneElement(children, { + ...rest, + onError: this.handleError, + }); + } +} + +export default ErrorBoundary; diff --git a/src/elements/common/error-boundary/index.js b/src/elements/common/error-boundary/index.js.flow similarity index 100% rename from src/elements/common/error-boundary/index.js rename to src/elements/common/error-boundary/index.js.flow diff --git a/src/elements/common/error-boundary/index.ts b/src/elements/common/error-boundary/index.ts new file mode 100644 index 0000000000..854a5a9100 --- /dev/null +++ b/src/elements/common/error-boundary/index.ts @@ -0,0 +1,2 @@ +export { default } from './ErrorBoundary'; +export { default as withErrorBoundary } from './withErrorBoundary'; diff --git a/src/elements/common/error-boundary/withErrorBoundary.js b/src/elements/common/error-boundary/withErrorBoundary.js.flow similarity index 100% rename from src/elements/common/error-boundary/withErrorBoundary.js rename to src/elements/common/error-boundary/withErrorBoundary.js.flow diff --git a/src/elements/common/error-boundary/withErrorBoundary.tsx b/src/elements/common/error-boundary/withErrorBoundary.tsx new file mode 100644 index 0000000000..fe31e05825 --- /dev/null +++ b/src/elements/common/error-boundary/withErrorBoundary.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import DefaultError, { DefaultErrorProps } from './DefaultError'; +import ErrorBoundary from './ErrorBoundary'; +import type { ElementOrigin } from '../flowTypes'; + +type ComponentWithRef = React.ComponentType

>; + +const withErrorBoundary = + (errorOrigin: ElementOrigin, errorComponent: React.ComponentType = DefaultError) => +

(WrappedComponent: ComponentWithRef) => { + const WithErrorBoundaryComponent = React.forwardRef((props: P, ref: React.Ref) => ( + )} + > + + + )); + + return WithErrorBoundaryComponent; + }; + +export default withErrorBoundary; From 9f720785e22588c39110b68d4751258626737080 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:36:30 +0000 Subject: [PATCH 2/2] refactor(common): rename DefaultErrorProps to ErrorComponentProps --- src/elements/common/error-boundary/DefaultError.tsx | 4 ++-- src/elements/common/error-boundary/ErrorBoundary.tsx | 6 +++--- .../common/error-boundary/withErrorBoundary.tsx | 10 ++++------ 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/elements/common/error-boundary/DefaultError.tsx b/src/elements/common/error-boundary/DefaultError.tsx index 8316f93cea..7126bcd8dd 100644 --- a/src/elements/common/error-boundary/DefaultError.tsx +++ b/src/elements/common/error-boundary/DefaultError.tsx @@ -4,11 +4,11 @@ import ErrorMask from '../../../components/error-mask/ErrorMask'; import messages from '../messages'; import './DefaultError.scss'; -export interface DefaultErrorProps { +export interface ErrorComponentProps { error?: Error; } -const DefaultError = (): JSX.Element => ( +const DefaultError = () => (

} diff --git a/src/elements/common/error-boundary/ErrorBoundary.tsx b/src/elements/common/error-boundary/ErrorBoundary.tsx index 59b0f2e0ef..c37f3c7802 100644 --- a/src/elements/common/error-boundary/ErrorBoundary.tsx +++ b/src/elements/common/error-boundary/ErrorBoundary.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import noop from 'lodash/noop'; +import DefaultError, { ErrorComponentProps } from './DefaultError'; import { ERROR_CODE_UNEXPECTED_EXCEPTION, IS_ERROR_DISPLAYED } from '../../../constants'; -import DefaultError, { DefaultErrorProps } from './DefaultError'; import type { ElementsXhrError, ElementsError } from '../../../common/types/api'; import type { ElementOrigin } from '../flowTypes'; export interface ErrorBoundaryProps { children: React.ReactElement; - errorComponent: React.ComponentType; + errorComponent: React.ComponentType; errorOrigin: ElementOrigin; onError: (error: ElementsError) => void; } @@ -70,7 +70,7 @@ class ErrorBoundary extends React.Component { this.props.onError(elementsError); }; - render(): React.ReactNode { + render() { const { children, errorComponent: ErrorComponent, ...rest } = this.props; const { error } = this.state; if (error) { diff --git a/src/elements/common/error-boundary/withErrorBoundary.tsx b/src/elements/common/error-boundary/withErrorBoundary.tsx index fe31e05825..8777f6e217 100644 --- a/src/elements/common/error-boundary/withErrorBoundary.tsx +++ b/src/elements/common/error-boundary/withErrorBoundary.tsx @@ -1,14 +1,14 @@ import * as React from 'react'; -import DefaultError, { DefaultErrorProps } from './DefaultError'; +import DefaultError, { ErrorComponentProps } from './DefaultError'; import ErrorBoundary from './ErrorBoundary'; import type { ElementOrigin } from '../flowTypes'; type ComponentWithRef = React.ComponentType

>; const withErrorBoundary = - (errorOrigin: ElementOrigin, errorComponent: React.ComponentType = DefaultError) => -

(WrappedComponent: ComponentWithRef) => { - const WithErrorBoundaryComponent = React.forwardRef((props: P, ref: React.Ref) => ( + (errorOrigin: ElementOrigin, errorComponent: React.ComponentType = DefaultError) => +

(WrappedComponent: ComponentWithRef) => { + return React.forwardRef((props: P, ref: React.Ref) => ( )); - - return WithErrorBoundaryComponent; }; export default withErrorBoundary;