
* improve var base typing * fix pyi * dang it darglint * drain _process in tests * fixes #4576 * dang it darglint
157 lines
6.2 KiB
Python
157 lines
6.2 KiB
Python
"""A React Error Boundary component that catches unhandled frontend exceptions."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Dict, Tuple
|
|
|
|
from reflex.components.component import Component
|
|
from reflex.components.datadisplay.logo import svg_logo
|
|
from reflex.components.el import a, button, details, div, h2, hr, p, pre, summary
|
|
from reflex.event import EventHandler, set_clipboard
|
|
from reflex.state import FrontendEventExceptionState
|
|
from reflex.vars.base import Var
|
|
from reflex.vars.function import ArgsFunctionOperation
|
|
from reflex.vars.object import ObjectVar
|
|
|
|
|
|
def on_error_spec(
|
|
error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
|
|
) -> Tuple[Var[str], Var[str]]:
|
|
"""The spec for the on_error event handler.
|
|
|
|
Args:
|
|
error: The error message.
|
|
info: Additional information about the error.
|
|
|
|
Returns:
|
|
The arguments for the event handler.
|
|
"""
|
|
return (
|
|
error.stack,
|
|
info.componentStack,
|
|
)
|
|
|
|
|
|
class ErrorBoundary(Component):
|
|
"""A React Error Boundary component that catches unhandled frontend exceptions."""
|
|
|
|
library = "react-error-boundary"
|
|
tag = "ErrorBoundary"
|
|
|
|
# Fired when the boundary catches an error.
|
|
on_error: EventHandler[on_error_spec]
|
|
|
|
# Rendered instead of the children when an error is caught.
|
|
fallback_render: Var[Component]
|
|
|
|
@classmethod
|
|
def create(cls, *children, **props):
|
|
"""Create an ErrorBoundary component.
|
|
|
|
Args:
|
|
*children: The children of the component.
|
|
**props: The props of the component.
|
|
|
|
Returns:
|
|
The ErrorBoundary component.
|
|
"""
|
|
if "on_error" not in props:
|
|
props["on_error"] = FrontendEventExceptionState.handle_frontend_exception
|
|
if "fallback_render" not in props:
|
|
props["fallback_render"] = ArgsFunctionOperation.create(
|
|
("event_args",),
|
|
Var.create(
|
|
div(
|
|
div(
|
|
div(
|
|
h2(
|
|
"An error occurred while rendering this page.",
|
|
font_size="1.25rem",
|
|
font_weight="bold",
|
|
),
|
|
p(
|
|
"This is an error with the application itself.",
|
|
opacity="0.75",
|
|
),
|
|
details(
|
|
summary("Error message", padding="0.5rem"),
|
|
div(
|
|
div(
|
|
pre(
|
|
Var(
|
|
_js_expr="event_args.error.stack",
|
|
),
|
|
),
|
|
padding="0.5rem",
|
|
width="fit-content",
|
|
),
|
|
width="100%",
|
|
max_height="50vh",
|
|
overflow="auto",
|
|
background="#000",
|
|
color="#fff",
|
|
border_radius="0.25rem",
|
|
),
|
|
button(
|
|
"Copy",
|
|
on_click=set_clipboard(
|
|
Var(_js_expr="event_args.error.stack"),
|
|
),
|
|
padding="0.35rem 0.75rem",
|
|
margin="0.5rem",
|
|
background="#fff",
|
|
color="#000",
|
|
border="1px solid #000",
|
|
border_radius="0.25rem",
|
|
font_weight="bold",
|
|
),
|
|
),
|
|
display="flex",
|
|
flex_direction="column",
|
|
gap="1rem",
|
|
max_width="50ch",
|
|
border="1px solid #888888",
|
|
border_radius="0.25rem",
|
|
padding="1rem",
|
|
),
|
|
hr(
|
|
border_color="currentColor",
|
|
opacity="0.25",
|
|
),
|
|
a(
|
|
div(
|
|
"Built with ",
|
|
svg_logo("currentColor"),
|
|
display="flex",
|
|
align_items="baseline",
|
|
justify_content="center",
|
|
font_family="monospace",
|
|
gap="0.5rem",
|
|
),
|
|
href="https://reflex.dev",
|
|
),
|
|
display="flex",
|
|
flex_direction="column",
|
|
gap="1rem",
|
|
),
|
|
height="100%",
|
|
width="100%",
|
|
position="absolute",
|
|
display="flex",
|
|
align_items="center",
|
|
justify_content="center",
|
|
)
|
|
),
|
|
_var_type=Component,
|
|
)
|
|
else:
|
|
props["fallback_render"] = ArgsFunctionOperation.create(
|
|
("event_args",),
|
|
props["fallback_render"],
|
|
_var_type=Component,
|
|
)
|
|
return super().create(*children, **props)
|
|
|
|
|
|
error_boundary = ErrorBoundary.create
|