Skip to content
Snippets Groups Projects
Commit 538704b6 authored by Samed's avatar Samed Committed by Leonardo Christino
Browse files

feat: stack trace interface in error boundaries

parent f39e4339
No related branches found
No related tags found
1 merge request!321Feat/stack trace
Pipeline #141371 passed
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { Button } from '../buttons';
import { useAppDispatch } from '@graphpolaris/shared/lib/data-access';
import { addInfo } from '@graphpolaris/shared/lib/data-access/store/configSlice';
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
onError?: (error: Error, errorInfo: ErrorInfo) => void;
dispatch?: ReturnType<typeof useAppDispatch>;
}
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
errorInfo?: ErrorInfo;
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
this.handleRetry = this.handleRetry.bind(this);
this.handleCopyError = this.handleCopyError.bind(this);
}
static getDerivedStateFromError(): ErrorBoundaryState {
......@@ -22,20 +29,48 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.setState({ error, errorInfo });
if (this.props.onError) {
this.props.onError(error, errorInfo);
}
}
handleRetry() {
this.setState({ hasError: false });
this.setState({ hasError: false, error: undefined, errorInfo: undefined });
}
handleCopyError() {
const errorText = `Error: ${this.state.error?.toString()}\n\nStack trace: ${this.state.errorInfo?.componentStack}`;
navigator.clipboard.writeText(errorText);
if (this.props.dispatch) {
this.props.dispatch(addInfo('Stack trace copied to clipboard'));
}
}
render() {
if (this.state.hasError) {
return (
<div>
<div className="flex flex-col w-full h-full">
{this.props.fallback || <div>Something went wrong. Please try again later.</div>}
{import.meta.env.GRAPHPOLARIS_VERSION === 'dev' && (
<div className="overflow-auto max-h-[500px] p-2">
<div className="flex justify-end mb-2">
<Button
label="Copy Stack Trace"
variant="outline"
variantType="secondary"
size="xs"
onClick={this.handleCopyError}
/>
</div>
<pre className="whitespace-pre-wrap break-words text-sm">
{this.state.error?.toString()}
</pre>
<pre className="whitespace-pre-wrap break-words text-sm mt-2">
{this.state.errorInfo?.componentStack}
</pre>
</div>
)}
<Button label="Retry now" variant="outline" variantType="primary" onClick={this.handleRetry} />
</div>
);
......@@ -45,4 +80,9 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
}
}
export { ErrorBoundary };
function ErrorBoundaryWithDispatch(props: Omit<ErrorBoundaryProps, 'dispatch'>) {
const dispatch = useAppDispatch();
return <ErrorBoundary {...props} dispatch={dispatch} />;
}
export { ErrorBoundaryWithDispatch as ErrorBoundary };
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment