Skip to content

Commit

Permalink
Merge pull request #1564 from nextstrain/feat/web-error-react-compone…
Browse files Browse the repository at this point in the history
…nt-stack
  • Loading branch information
ivan-aksamentov authored Jan 29, 2025
2 parents 11bb4ec + 8aab9fa commit 1600de2
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 15 deletions.
33 changes: 28 additions & 5 deletions packages/nextclade-web/src/components/Error/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
import React, { ReactNode } from 'react'

import React, { ReactNode, useState, useCallback, useMemo, ErrorInfo } from 'react'
import { ErrorBoundary as ErrorBoundaryBase, FallbackProps } from 'react-error-boundary'
import ErrorPage from 'src/pages/_error'

export function ErrorFallback({ error }: FallbackProps) {
return <ErrorPage error={error} />
export interface ExtendedFallbackProps extends FallbackProps {
errorInfo?: ErrorInfo
}

export function ErrorFallback({ error, errorInfo }: ExtendedFallbackProps) {
return <ErrorPage error={error} errorInfo={errorInfo} />
}

export interface ErrorBoundaryProps {
children?: ReactNode
}

export function ErrorBoundary({ children }: ErrorBoundaryProps) {
return <ErrorBoundaryBase FallbackComponent={ErrorFallback}>{children}</ErrorBoundaryBase>
const [errorInfo, setErrorInfo] = useState<ErrorInfo | undefined>(undefined)

const FallbackComponent = useMemo(() => {
return function ErrorFallbackMemoized(props: FallbackProps) {
return <ErrorFallback {...props} errorInfo={errorInfo} />
}
}, [errorInfo])

const handleError = useCallback((_: Error, info: ErrorInfo) => {
setErrorInfo(info)
}, [])

const handleReset = useCallback(() => {
setErrorInfo(undefined)
}, [])

return (
<ErrorBoundaryBase FallbackComponent={FallbackComponent} onError={handleError} onReset={handleReset}>
{children}
</ErrorBoundaryBase>
)
}
4 changes: 2 additions & 2 deletions packages/nextclade-web/src/components/Error/ErrorContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react'
import React, { ErrorInfo, useCallback, useMemo, useState } from 'react'
import { Button, Col, Row } from 'reactstrap'
import { useTranslationSafe } from 'src/helpers/useTranslationSafe'
import styled from 'styled-components'
Expand Down Expand Up @@ -56,7 +56,7 @@ export function ErrorContentMessage({ error }: { error: Error }) {
return <ErrorGeneric error={error} />
}

export function ErrorContent(props: { error?: unknown; detailed?: boolean }) {
export function ErrorContent(props: { error?: unknown; errorInfo?: ErrorInfo; detailed?: boolean }) {
const { t } = useTranslationSafe()
const error = useMemo(() => sanitizeError(props.error), [props.error])

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'
import React, { ErrorInfo, useMemo } from 'react'

import styled from 'styled-components'
import { useTranslationSafe as useTranslation } from 'src/helpers/useTranslationSafe'
Expand All @@ -18,11 +18,15 @@ const ExplanationText = styled.section`
hyphens: auto;
`

export function getErrorStackText(error: Error) {
export function getErrorStackText(error?: Error) {
return error?.stack?.replace(/webpack-internal:\/{3}\.\//g, '')?.replace(/https?:\/\/(.+):\d+\//g, '')
}

export function getErrorReportText(error: Error) {
export function getComponentStackText(errorInfo?: ErrorInfo) {
return errorInfo?.componentStack.replace(/webpack-internal:\/{3}\.\//g, '')?.replace(/https?:\/\/(.+):\d+\//g, '')
}

export function getErrorReportText(error: Error, errorInfo?: ErrorInfo) {
const bowser = typeof window !== 'undefined' ? Bowser.parse(window?.navigator?.userAgent) : 'N/A'

return `
Expand All @@ -39,6 +43,10 @@ Browser details: ${JSON.stringify(bowser)}
Call stack:
${getErrorStackText(error) ?? 'N/A'}
Component stack:
${getComponentStackText(errorInfo) ?? 'N/A'}
`
}

Expand Down
11 changes: 6 additions & 5 deletions packages/nextclade-web/src/pages/_error.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'
import React, { ErrorInfo, useMemo } from 'react'
import type { NextPageContext } from 'next'
import { Col, Container as ContainerBase, Row } from 'reactstrap'
import get from 'lodash/get'
Expand Down Expand Up @@ -39,10 +39,11 @@ export const MainContent = styled.main`
export interface ErrorPageProps {
statusCode?: number
title?: string
error?: Error | undefined
error?: Error
errorInfo?: ErrorInfo
}

function ErrorPage({ statusCode, title, error }: ErrorPageProps) {
function ErrorPage({ statusCode, title, error, errorInfo }: ErrorPageProps) {
const { t } = useTranslationSafe()

const titleText = useMemo(() => {
Expand All @@ -64,11 +65,11 @@ function ErrorPage({ statusCode, title, error }: ErrorPageProps) {
return (
<Row noGutters>
<Col>
<ErrorContent error={error} detailed />
<ErrorContent error={error} errorInfo={errorInfo} detailed />
</Col>
</Row>
)
}, [error])
}, [error, errorInfo])

return (
<Layout>
Expand Down

0 comments on commit 1600de2

Please sign in to comment.