123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- """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
|