-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
moved error components to react-error
- Loading branch information
Showing
23 changed files
with
578 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,7 @@ | |
"rdns", | ||
"reinit", | ||
"rfdc", | ||
"Rollbar", | ||
"Tapjoy", | ||
"Tiktok", | ||
"Trouw", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { Typography } from '@mui/material' | ||
import { FlexCol } from '@xylabs/react-flexbox' | ||
import type { ErrorInfo, ReactNode } from 'react' | ||
import React, { Component } from 'react' | ||
|
||
export interface ErrorBoundaryProps { | ||
children: ReactNode | ||
// fallback as a static ReactNode value | ||
fallback?: ReactNode | ||
// fallback element that can receive the error as a prop | ||
fallbackWithError?: (error: Error) => ReactNode | ||
scope?: string | ||
} | ||
|
||
export interface ErrorBoundaryState { | ||
error?: Error | ||
} | ||
|
||
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { | ||
constructor(props: ErrorBoundaryProps) { | ||
super(props) | ||
this.state = { error: undefined } | ||
} | ||
|
||
static getDerivedStateFromError(error: Error) { | ||
return { error } | ||
} | ||
|
||
override componentDidCatch(error: Error, errorInfo: ErrorInfo) { | ||
console.error(`${error}: ${errorInfo}`) | ||
} | ||
|
||
override render() { | ||
if (this.state.error) { | ||
if (this.props.fallbackWithError) { | ||
return this.props.fallbackWithError(this.state.error) | ||
} | ||
return ( | ||
this.props.fallback ?? ( | ||
<FlexCol> | ||
<Typography variant="h1">Something went wrong.</Typography> | ||
{this.props.scope && ( | ||
<Typography variant="h2"> | ||
[ | ||
{this.props.scope} | ||
] | ||
</Typography> | ||
)} | ||
<Typography variant="body1"> | ||
[ | ||
{this.state.error?.message} | ||
] | ||
</Typography> | ||
</FlexCol> | ||
) | ||
) | ||
} | ||
|
||
return this.props.children | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
packages/error/src/components/ErrorBoundary/ThrownErrorBoundary.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { Alert, Button } from '@mui/material' | ||
import type { Meta, StoryFn } from '@storybook/react' | ||
import React from 'react' | ||
|
||
import { ThrownErrorBoundary } from './ThrownErrorBoundary.tsx' | ||
|
||
const StorybookEntry: Meta = { | ||
component: ThrownErrorBoundary, | ||
title: 'auth-service/ApiBoundary/ThrownErrorBoundary', | ||
} | ||
|
||
const Thrower: React.FC = () => { | ||
const [shouldThrow, setShouldThrow] = React.useState(false) | ||
if (shouldThrow) { | ||
throw new Error('Test Error') | ||
} | ||
return ( | ||
<Button onClick={() => { | ||
setShouldThrow(true) | ||
}} | ||
> | ||
Throw Error | ||
</Button> | ||
) | ||
} | ||
|
||
const Template: StoryFn<typeof ThrownErrorBoundary> = ({ errorComponent }) => { | ||
return ( | ||
<ThrownErrorBoundary errorComponent={errorComponent} boundaryName="StoryBook"> | ||
<Alert severity="info">Use React Dev Tools to trigger and error within the boundary</Alert> | ||
<Thrower /> | ||
</ThrownErrorBoundary> | ||
) | ||
} | ||
|
||
const Default = Template.bind({}) | ||
Default.args = {} | ||
|
||
const CustomErrorComponent = Template.bind({}) | ||
CustomErrorComponent.args = { | ||
errorComponent: e => ( | ||
<Alert severity="error"> | ||
Using Custom Error Component with error: | ||
{(e as Error).message} | ||
</Alert> | ||
), | ||
} | ||
|
||
export { CustomErrorComponent, Default } | ||
|
||
export default StorybookEntry |
72 changes: 72 additions & 0 deletions
72
packages/error/src/components/ErrorBoundary/ThrownErrorBoundary.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { useRollbar } from '@rollbar/react' | ||
import type { ErrorInfo, ReactNode } from 'react' | ||
import React, { Component } from 'react' | ||
import type Rollbar from 'rollbar' | ||
|
||
import { useErrorReporter } from '../../contexts/index.ts' | ||
import type { ErrorEx } from '../ErrorEx.ts' | ||
import { ErrorRender } from '../ErrorRender/index.ts' | ||
|
||
export interface ThrownErrorBoundaryProps<T = void> { | ||
boundaryName?: string | ||
children: ReactNode | ||
errorComponent?: (e: ErrorEx<T>, boundaryName?: string) => ReactNode | ||
rethrow?: boolean | ||
rollbar?: Rollbar | ||
scope?: string | ||
title?: string | ||
} | ||
|
||
export interface ThrownErrorBoundaryState<T = void> { | ||
errorEx?: ErrorEx<T> | ||
} | ||
|
||
class ThrownErrorBoundaryInner<T> extends Component<ThrownErrorBoundaryProps<T>, ThrownErrorBoundaryState<T>> { | ||
override state: ThrownErrorBoundaryState<T> = { errorEx: undefined } | ||
|
||
static getDerivedStateFromError<T = void>(error: ErrorEx<T>) { | ||
return { hasError: true, xyoError: this.normalizeError<T>(error) } as ThrownErrorBoundaryState<T> | ||
} | ||
|
||
static normalizeError<T>(_error: ErrorEx<T>): T { | ||
throw new Error('Method not implemented.') | ||
} | ||
|
||
override componentDidCatch(error: Error, errorInfo: ErrorInfo) { | ||
const { rethrow, rollbar } = this.props | ||
const { errorEx } = this.state | ||
|
||
rollbar?.error(error) | ||
|
||
console.error('Error:', errorEx, errorInfo) | ||
if (rethrow) { | ||
throw error | ||
} | ||
} | ||
|
||
override render() { | ||
const { errorEx } = this.state | ||
const { | ||
children, boundaryName, errorComponent, scope, title, | ||
} = this.props | ||
if (errorEx) { | ||
if (errorComponent) { | ||
return errorComponent(errorEx) | ||
} | ||
return <ErrorRender<T> error={errorEx} errorContext={`${boundaryName} Boundary`} scope={scope} title={title} /> | ||
} | ||
|
||
return children | ||
} | ||
} | ||
|
||
// calling the hook outside of the component since only can be called in functional component | ||
export function ThrownErrorBoundary<T = void>({ rollbar, ...props }: ThrownErrorBoundaryProps<T>): JSX.Element { | ||
const { rollbar: rollbarErrorReporter } = useErrorReporter() | ||
let rollbarFromHook: Rollbar | undefined | ||
// safely call the hook | ||
try { | ||
rollbarFromHook = useRollbar() | ||
} catch {} | ||
return <ThrownErrorBoundaryInner<T> rollbar={rollbar ?? rollbarErrorReporter ?? rollbarFromHook} {...props} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './ThrownErrorBoundary.tsx' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export type ErrorEx<T = void> = T extends void ? Error : T | Error |
41 changes: 41 additions & 0 deletions
41
packages/error/src/components/ErrorRender/ErrorAlert.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import type { Meta, StoryFn } from '@storybook/react' | ||
import React from 'react' | ||
|
||
import { ErrorAlert } from './ErrorAlert.tsx' | ||
|
||
const StorybookEntry: Meta = { | ||
argTypes: {}, | ||
component: ErrorAlert, | ||
parameters: { docs: { page: null } }, | ||
title: 'error/ErrorAlert', | ||
} | ||
|
||
const Template: StoryFn<typeof ErrorAlert> = (props) => { | ||
return <ErrorAlert {...props} /> | ||
} | ||
|
||
const Default = Template.bind({}) | ||
Default.args = {} | ||
|
||
const WithTitle = Template.bind({}) | ||
WithTitle.args = { title: 'Oh No!' } | ||
|
||
const WithError = Template.bind({}) | ||
WithError.args = { error: 'An error happened' } | ||
|
||
const WithScope = Template.bind({}) | ||
WithScope.args = { scope: 'Storybook' } | ||
|
||
const WithErrorAndScope = Template.bind({}) | ||
WithErrorAndScope.args = { error: 'An error happened', scope: 'Storybook' } | ||
|
||
const WithErrorAndScopeAndTitle = Template.bind({}) | ||
WithErrorAndScopeAndTitle.args = { | ||
error: 'An error happened', scope: 'Storybook', title: 'Oh No!', | ||
} | ||
|
||
export { | ||
Default, WithError, WithErrorAndScope, WithErrorAndScopeAndTitle, WithScope, WithTitle, | ||
} | ||
|
||
export default StorybookEntry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { ExitToApp as ExitIcon } from '@mui/icons-material' | ||
import type { AlertProps } from '@mui/material' | ||
import { | ||
Alert, AlertTitle, Typography, | ||
} from '@mui/material' | ||
import { ButtonEx } from '@xylabs/react-button' | ||
import React from 'react' | ||
|
||
export interface ErrorAlertProps<T = void> extends AlertProps { | ||
error?: T | Error | string | ||
onCancel?: () => void | ||
scope?: string | ||
} | ||
|
||
export function ErrorAlert<T = void>({ | ||
title = 'Whoops! Something went wrong', | ||
onCancel, | ||
error = 'An unknown error occurred', | ||
scope, | ||
...props | ||
}: ErrorAlertProps<T>): JSX.Element { | ||
return ( | ||
<Alert severity="error" {...props}> | ||
<AlertTitle>{title}</AlertTitle> | ||
{scope | ||
? ( | ||
<div> | ||
<Typography variant="caption" mr={0.5} fontWeight="bold"> | ||
Scope: | ||
</Typography> | ||
<Typography variant="caption">{scope}</Typography> | ||
</div> | ||
) | ||
: null} | ||
<div> | ||
<Typography variant="caption" mr={0.5} fontWeight="bold"> | ||
Error: | ||
</Typography> | ||
<Typography variant="caption">{typeof error === 'string' ? error : (error as Error)?.message}</Typography> | ||
</div> | ||
{onCancel | ||
? ( | ||
<ButtonEx | ||
variant="outlined" | ||
size="small" | ||
onClick={onCancel} | ||
position="absolute" | ||
style={{ right: 8, top: 8 }} | ||
> | ||
<ExitIcon fontSize="small" /> | ||
</ButtonEx> | ||
) | ||
: null} | ||
</Alert> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import type { FlexBoxProps } from '@xylabs/react-flexbox' | ||
import type { ReactNode } from 'react' | ||
import type { Location } from 'react-router-dom' | ||
|
||
import type { ErrorEx } from '../ErrorEx.ts' | ||
|
||
export interface ErrorRenderProps<T = void> extends FlexBoxProps { | ||
customError?: ReactNode | ||
error?: ErrorEx<T> | ||
errorContext?: string | ||
noErrorDisplay?: boolean | ||
noReAuth?: boolean | ||
onCancel?: () => void | ||
scope?: string | ||
useLocation?: () => Location | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { FlexCol } from '@xylabs/react-flexbox' | ||
import React, { useEffect } from 'react' | ||
|
||
import { ErrorAlert } from './ErrorAlert.tsx' | ||
import type { ErrorRenderProps } from './Props.ts' | ||
|
||
export function ErrorRender<T = void>({ | ||
onCancel, | ||
error, | ||
noErrorDisplay = false, | ||
customError = null, | ||
children, | ||
scope, | ||
useLocation, | ||
...props | ||
}: ErrorRenderProps<T>): JSX.Element { | ||
const location = useLocation?.() | ||
useEffect(() => { | ||
if (location) { | ||
// ensure we end up at the same place we are now after logging in | ||
location.state = { from: { pathname: globalThis.location.pathname } } | ||
} | ||
}, [location]) | ||
|
||
useEffect(() => { | ||
if (error) { | ||
globalThis.rollbar?.error(error) | ||
} | ||
}, [error]) | ||
|
||
return error | ||
? ( | ||
<FlexCol alignItems="stretch" {...props}> | ||
{noErrorDisplay | ||
? customError | ||
: ( | ||
<FlexCol alignItems="center" {...props}> | ||
<ErrorAlert error={error} onCancel={onCancel} scope={scope} /> | ||
</FlexCol> | ||
)} | ||
</FlexCol> | ||
) | ||
: <>{children}</> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './ErrorAlert.tsx' | ||
export * from './Props.ts' | ||
export * from './Render.tsx' |
Oops, something went wrong.