Bläddra i källkod

redesign error boundary screen (#4329)

* redesign error boundary screen

* pyi time

* add color

* i hate python 3.9
Khaleel Al-Adhami 6 månader sedan
förälder
incheckning
a1158cdb1c

+ 99 - 36
reflex/components/base/error_boundary.py

@@ -2,14 +2,15 @@
 
 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.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[Component]
 
     @classmethod
     def create(cls, *children, **props):
@@ -86,6 +56,99 @@ 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=Component,
+            )
+        else:
+            props["fallback_render"] = ArgsFunctionOperation.create(
+                ("event_args",),
+                props["fallback_render"],
+                _var_type=Component,
+            )
         return super().create(*children, **props)
 
 

+ 3 - 4
reflex/components/base/error_boundary.pyi

@@ -3,7 +3,7 @@
 # ------------------- DO NOT EDIT ----------------------
 # 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.event import BASE_STATE, EventType
@@ -15,13 +15,12 @@ def on_error_spec(
 ) -> Tuple[Var[str], Var[str]]: ...
 
 class ErrorBoundary(Component):
-    def add_custom_code(self) -> List[str]: ...
     @overload
     @classmethod
     def create(  # type: ignore
         cls,
         *children,
-        Fallback_component: Optional[Union[Component, Var[Component]]] = None,
+        fallback_render: Optional[Union[Component, Var[Component]]] = None,
         style: Optional[Style] = None,
         key: Optional[Any] = None,
         id: Optional[Any] = None,
@@ -57,7 +56,7 @@ class ErrorBoundary(Component):
         Args:
             *children: The children of the component.
             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.
             key: A unique key for the component.
             id: The id for the component.

+ 8 - 0
reflex/components/core/cond.py

@@ -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.
 

+ 26 - 13
reflex/components/datadisplay/logo.py

@@ -1,22 +1,23 @@
 """A Reflex logo component."""
 
+from typing import Union
+
 import reflex as rx
 
 
-def logo(**props):
-    """A Reflex logo.
+def svg_logo(color: Union[str, rx.Var[str]] = rx.color_mode_cond("#110F1F", "white")):
+    """A Reflex logo SVG.
 
     Args:
-        **props: The props to pass to the component.
+        color: The color of the logo.
 
     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 +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",
     ]
 
+    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",

+ 1 - 1
reflex/event.py

@@ -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.
 
     Args: