import React, { Component } from "react" import { telemetryClient } from "@src/utils/TelemetryClient" import { withTranslation, WithTranslation } from "react-i18next" import { enhanceErrorWithSourceMaps } from "@src/utils/sourceMapUtils" type ErrorProps = { children: React.ReactNode } & WithTranslation type ErrorState = { error?: string componentStack?: string | null timestamp?: number } class ErrorBoundary extends Component { constructor(props: ErrorProps) { super(props) this.state = {} } static getDerivedStateFromError(error: unknown) { let errorMessage = "" if (error instanceof Error) { errorMessage = error.stack ?? error.message } else { errorMessage = `${error}` } return { error: errorMessage, timestamp: Date.now(), } } async componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { const componentStack = errorInfo.componentStack || "" const enhancedError = await enhanceErrorWithSourceMaps(error, componentStack) telemetryClient.capture("error_boundary_caught_error", { error: enhancedError.message, stack: enhancedError.sourceMappedStack || enhancedError.stack, componentStack: enhancedError.sourceMappedComponentStack || componentStack, timestamp: Date.now(), errorType: enhancedError.name, }) this.setState({ error: enhancedError.sourceMappedStack || enhancedError.stack, componentStack: enhancedError.sourceMappedComponentStack || componentStack, }) } render() { const { t } = this.props if (!this.state.error) { return this.props.children } const errorDisplay = this.state.error const componentStackDisplay = this.state.componentStack const version = process.env.PKG_VERSION || "unknown" return (

{t("errorBoundary.title")} (v{version})

{t("errorBoundary.reportText")}{" "} {t("errorBoundary.githubText")}

{t("errorBoundary.copyInstructions")}

{t("errorBoundary.errorStack")}

{errorDisplay}
{componentStackDisplay && (

{t("errorBoundary.componentStack")}

{componentStackDisplay}
)}
) } } export default withTranslation("common")(ErrorBoundary)