redesign error boundary screen (#4329)

* redesign error boundary screen

* pyi time

* add color

* i hate python 3.9
This commit is contained in:
Khaleel Al-Adhami 2024-11-12 12:36:42 -08:00 committed by GitHub
parent 7cf3050da0
commit a1158cdb1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 137 additions and 54 deletions

View File

@ -2,14 +2,15 @@
from __future__ import annotations from __future__ import annotations
from typing import Dict, List, Tuple from typing import Dict, Tuple
from reflex.compiler.compiler import _compile_component
from reflex.components.component import Component from reflex.components.component import Component
from reflex.components.el import div, p from reflex.components.datadisplay.logo import svg_logo
from reflex.event import EventHandler 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.state import FrontendEventExceptionState
from reflex.vars.base import Var from reflex.vars.base import Var
from reflex.vars.function import ArgsFunctionOperation
def on_error_spec( def on_error_spec(
@ -40,38 +41,7 @@ class ErrorBoundary(Component):
on_error: EventHandler[on_error_spec] on_error: EventHandler[on_error_spec]
# Rendered instead of the children when an error is caught. # Rendered instead of the children when an error is caught.
Fallback_component: Var[Component] = Var(_js_expr="Fallback")._replace( fallback_render: Var[Component]
_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}
);
}}
"""
]
@classmethod @classmethod
def create(cls, *children, **props): def create(cls, *children, **props):
@ -86,6 +56,99 @@ class ErrorBoundary(Component):
""" """
if "on_error" not in props: if "on_error" not in props:
props["on_error"] = FrontendEventExceptionState.handle_frontend_exception 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) return super().create(*children, **props)

View File

@ -3,7 +3,7 @@
# ------------------- DO NOT EDIT ---------------------- # ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`! # This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------ # ------------------------------------------------------
from typing import Any, Dict, List, Optional, Tuple, Union, overload from typing import Any, Dict, Optional, Tuple, Union, overload
from reflex.components.component import Component from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType from reflex.event import BASE_STATE, EventType
@ -15,13 +15,12 @@ def on_error_spec(
) -> Tuple[Var[str], Var[str]]: ... ) -> Tuple[Var[str], Var[str]]: ...
class ErrorBoundary(Component): class ErrorBoundary(Component):
def add_custom_code(self) -> List[str]: ...
@overload @overload
@classmethod @classmethod
def create( # type: ignore def create( # type: ignore
cls, cls,
*children, *children,
Fallback_component: Optional[Union[Component, Var[Component]]] = None, fallback_render: Optional[Union[Component, Var[Component]]] = None,
style: Optional[Style] = None, style: Optional[Style] = None,
key: Optional[Any] = None, key: Optional[Any] = None,
id: Optional[Any] = None, id: Optional[Any] = None,
@ -57,7 +56,7 @@ class ErrorBoundary(Component):
Args: Args:
*children: The children of the component. *children: The children of the component.
on_error: Fired when the boundary catches an error. on_error: Fired when the boundary catches an error.
Fallback_component: Rendered instead of the children when an error is caught. fallback_render: Rendered instead of the children when an error is caught.
style: The style of the component. style: The style of the component.
key: A unique key for the component. key: A unique key for the component.
id: The id for the component. id: The id for the component.

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: def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
"""Create a component or Prop based on color_mode. """Create a component or Prop based on color_mode.

View File

@ -1,22 +1,23 @@
"""A Reflex logo component.""" """A Reflex logo component."""
from typing import Union
import reflex as rx import reflex as rx
def logo(**props): def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white")):
"""A Reflex logo. """A Reflex logo SVG.
Args: Args:
**props: The props to pass to the component. color: The color of the logo.
Returns: Returns:
The logo component. The Reflex logo SVG.
""" """
def logo_path(d): def logo_path(d):
return rx.el.svg.path( return rx.el.svg.path(
d=d, d=d,
fill=rx.color_mode_cond("#110F1F", "white"),
) )
paths = [ paths = [
@ -28,18 +29,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", "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( return rx.center(
rx.link( rx.link(
rx.hstack( rx.hstack(
"Built with ", "Built with ",
rx.el.svg( svg_logo(),
*[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",
),
text_align="center", text_align="center",
align="center", align="center",
padding="1em", padding="1em",

View File

@ -899,7 +899,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. """Set the text in content in the clipboard.
Args: Args: