redesign error boundary screen

This commit is contained in:
Khaleel Al-Adhami 2024-11-07 14:49:08 -08:00
parent e457d53924
commit 99a2a4b003
4 changed files with 125 additions and 52 deletions

View File

@ -2,14 +2,15 @@
from __future__ import annotations
from typing import Dict, List, Tuple
from typing import Any, Callable, Dict, Tuple
from reflex.compiler.compiler import _compile_component
from reflex.components.component import Component
from reflex.components.el import div, p
from reflex.event import EventHandler
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
def on_error_spec(
@ -40,38 +41,7 @@ class ErrorBoundary(Component):
on_error: EventHandler[on_error_spec]
# Rendered instead of the children when an error is caught.
Fallback_component: Var[Component] = Var(_js_expr="Fallback")._replace(
_var_type=Component
)
def add_custom_code(self) -> List[str]:
"""Add custom Javascript code into the page that contains this component.
Custom code is inserted at module level, after any imports.
Returns:
The custom code to add.
"""
fallback_container = div(
p("Ooops...Unknown Reflex error has occured:"),
p(
Var(_js_expr="error.message"),
color="red",
),
p("Please contact the support."),
)
compiled_fallback = _compile_component(fallback_container)
return [
f"""
function Fallback({{ error, resetErrorBoundary }}) {{
return (
{compiled_fallback}
);
}}
"""
]
fallback_render: Var[Callable[[Any], Component]]
@classmethod
def create(cls, *children, **props):
@ -86,6 +56,93 @@ class 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=Callable[[Any], Component],
)
return super().create(*children, **props)

View File

@ -171,6 +171,14 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
)
@overload
def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # type: ignore
@overload
def color_mode_cond(light: Any, dark: Any = None) -> Var: ...
def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
"""Create a component or Prop based on color_mode.

View File

@ -3,20 +3,16 @@
import reflex as rx
def logo(**props):
"""A Reflex logo.
Args:
**props: The props to pass to the component.
def svg_logo(color: str | rx.Var[str] = rx.color_mode_cond("#110F1F", "white")):
"""A Reflex logo SVG.
Returns:
The logo component.
The Reflex logo SVG.
"""
def logo_path(d):
return rx.el.svg.path(
d=d,
fill=rx.color_mode_cond("#110F1F", "white"),
)
paths = [
@ -28,18 +24,30 @@ def logo(**props):
"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z",
]
return rx.el.svg(
*[logo_path(d) for d in paths],
width="56",
height="12",
viewBox="0 0 56 12",
fill=color,
xmlns="http://www.w3.org/2000/svg",
)
def logo(**props):
"""A Reflex logo.
Args:
**props: The props to pass to the component.
Returns:
The logo component.
"""
return rx.center(
rx.link(
rx.hstack(
"Built with ",
rx.el.svg(
*[logo_path(d) for d in paths],
width="56",
height="12",
viewBox="0 0 56 12",
fill="none",
xmlns="http://www.w3.org/2000/svg",
),
svg_logo(),
text_align="center",
align="center",
padding="1em",

View File

@ -898,7 +898,7 @@ def remove_session_storage(key: str) -> EventSpec:
)
def set_clipboard(content: str) -> EventSpec:
def set_clipboard(content: Union[str, Var[str]]) -> EventSpec:
"""Set the text in content in the clipboard.
Args: