simplify toast banner logic (#4853)
* simplify toast banner logic * expose toast * default back to title and desc, and replace brs with new lines
This commit is contained in:
parent
836e8f8ce9
commit
8943341605
@ -75,6 +75,7 @@ from reflex.components.core.client_side_routing import (
|
|||||||
from reflex.components.core.sticky import sticky
|
from reflex.components.core.sticky import sticky
|
||||||
from reflex.components.core.upload import Upload, get_upload_dir
|
from reflex.components.core.upload import Upload, get_upload_dir
|
||||||
from reflex.components.radix import themes
|
from reflex.components.radix import themes
|
||||||
|
from reflex.components.sonner.toast import toast
|
||||||
from reflex.config import ExecutorType, environment, get_config
|
from reflex.config import ExecutorType, environment, get_config
|
||||||
from reflex.event import (
|
from reflex.event import (
|
||||||
_EVENT_FIELDS,
|
_EVENT_FIELDS,
|
||||||
@ -84,7 +85,6 @@ from reflex.event import (
|
|||||||
EventType,
|
EventType,
|
||||||
IndividualEventType,
|
IndividualEventType,
|
||||||
get_hydrate_event,
|
get_hydrate_event,
|
||||||
window_alert,
|
|
||||||
)
|
)
|
||||||
from reflex.model import Model, get_db_status
|
from reflex.model import Model, get_db_status
|
||||||
from reflex.page import DECORATED_PAGES
|
from reflex.page import DECORATED_PAGES
|
||||||
@ -144,7 +144,7 @@ def default_backend_exception_handler(exception: Exception) -> EventSpec:
|
|||||||
EventSpec: The window alert event.
|
EventSpec: The window alert event.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from reflex.components.sonner.toast import Toaster, toast
|
from reflex.components.sonner.toast import toast
|
||||||
|
|
||||||
error = traceback.format_exc()
|
error = traceback.format_exc()
|
||||||
|
|
||||||
@ -155,18 +155,16 @@ def default_backend_exception_handler(exception: Exception) -> EventSpec:
|
|||||||
if is_prod_mode()
|
if is_prod_mode()
|
||||||
else [f"{type(exception).__name__}: {exception}.", "See logs for details."]
|
else [f"{type(exception).__name__}: {exception}.", "See logs for details."]
|
||||||
)
|
)
|
||||||
if Toaster.is_used:
|
|
||||||
return toast(
|
return toast(
|
||||||
"An error occurred.",
|
"An error occurred.",
|
||||||
level="error",
|
level="error",
|
||||||
description="<br/>".join(error_message),
|
fallback_to_alert=True,
|
||||||
position="top-center",
|
description="<br/>".join(error_message),
|
||||||
id="backend_error",
|
position="top-center",
|
||||||
style={"width": "500px"},
|
id="backend_error",
|
||||||
)
|
style={"width": "500px"},
|
||||||
else:
|
)
|
||||||
error_message.insert(0, "An error occurred.")
|
|
||||||
return window_alert("\n".join(error_message))
|
|
||||||
|
|
||||||
|
|
||||||
def extra_overlay_function() -> Optional[Component]:
|
def extra_overlay_function() -> Optional[Component]:
|
||||||
@ -414,7 +412,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
] = default_backend_exception_handler
|
] = default_backend_exception_handler
|
||||||
|
|
||||||
# Put the toast provider in the app wrap.
|
# Put the toast provider in the app wrap.
|
||||||
bundle_toaster: bool = True
|
toaster: Component | None = dataclasses.field(default_factory=toast.provider)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def api(self) -> FastAPI | None:
|
def api(self) -> FastAPI | None:
|
||||||
@ -1100,10 +1098,6 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
should_compile = self._should_compile()
|
should_compile = self._should_compile()
|
||||||
|
|
||||||
if not should_compile:
|
if not should_compile:
|
||||||
if self.bundle_toaster:
|
|
||||||
from reflex.components.sonner.toast import Toaster
|
|
||||||
|
|
||||||
Toaster.is_used = True
|
|
||||||
with console.timing("Evaluate Pages (Backend)"):
|
with console.timing("Evaluate Pages (Backend)"):
|
||||||
for route in self._unevaluated_pages:
|
for route in self._unevaluated_pages:
|
||||||
console.debug(f"Evaluating page: {route}")
|
console.debug(f"Evaluating page: {route}")
|
||||||
@ -1133,20 +1127,6 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
+ adhoc_steps_without_executor,
|
+ adhoc_steps_without_executor,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.bundle_toaster:
|
|
||||||
from reflex.components.component import memo
|
|
||||||
from reflex.components.sonner.toast import toast
|
|
||||||
|
|
||||||
internal_toast_provider = toast.provider()
|
|
||||||
|
|
||||||
@memo
|
|
||||||
def memoized_toast_provider():
|
|
||||||
return internal_toast_provider
|
|
||||||
|
|
||||||
toast_provider = Fragment.create(memoized_toast_provider())
|
|
||||||
|
|
||||||
app_wrappers[(1, "ToasterProvider")] = toast_provider
|
|
||||||
|
|
||||||
with console.timing("Evaluate Pages (Frontend)"):
|
with console.timing("Evaluate Pages (Frontend)"):
|
||||||
performance_metrics: list[tuple[str, float]] = []
|
performance_metrics: list[tuple[str, float]] = []
|
||||||
for route in self._unevaluated_pages:
|
for route in self._unevaluated_pages:
|
||||||
@ -1207,6 +1187,17 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
# Add the custom components from the page to the set.
|
# Add the custom components from the page to the set.
|
||||||
custom_components |= component._get_all_custom_components()
|
custom_components |= component._get_all_custom_components()
|
||||||
|
|
||||||
|
if (toaster := self.toaster) is not None:
|
||||||
|
from reflex.components.component import memo
|
||||||
|
|
||||||
|
@memo
|
||||||
|
def memoized_toast_provider():
|
||||||
|
return toaster
|
||||||
|
|
||||||
|
toast_provider = Fragment.create(memoized_toast_provider())
|
||||||
|
|
||||||
|
app_wrappers[(1, "ToasterProvider")] = toast_provider
|
||||||
|
|
||||||
# Add the app wraps to the app.
|
# Add the app wraps to the app.
|
||||||
for key, app_wrap in self.app_wraps.items():
|
for key, app_wrap in self.app_wraps.items():
|
||||||
component = app_wrap(self._state is not None)
|
component = app_wrap(self._state is not None)
|
||||||
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
|
from reflex.components.base.fragment import Fragment
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.core.cond import cond
|
from reflex.components.core.cond import cond
|
||||||
from reflex.components.el.elements.typography import Div
|
from reflex.components.el.elements.typography import Div
|
||||||
@ -16,7 +17,7 @@ from reflex.components.radix.themes.components.dialog import (
|
|||||||
)
|
)
|
||||||
from reflex.components.radix.themes.layout.flex import Flex
|
from reflex.components.radix.themes.layout.flex import Flex
|
||||||
from reflex.components.radix.themes.typography.text import Text
|
from reflex.components.radix.themes.typography.text import Text
|
||||||
from reflex.components.sonner.toast import Toaster, ToastProps
|
from reflex.components.sonner.toast import ToastProps, toast_ref
|
||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
from reflex.constants import Dirs, Hooks, Imports
|
from reflex.constants import Dirs, Hooks, Imports
|
||||||
from reflex.constants.compiler import CompileVars
|
from reflex.constants.compiler import CompileVars
|
||||||
@ -90,7 +91,7 @@ def default_connection_error() -> list[str | Var | Component]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ConnectionToaster(Toaster):
|
class ConnectionToaster(Fragment):
|
||||||
"""A connection toaster component."""
|
"""A connection toaster component."""
|
||||||
|
|
||||||
def add_hooks(self) -> list[str | Var]:
|
def add_hooks(self) -> list[str | Var]:
|
||||||
@ -113,11 +114,11 @@ class ConnectionToaster(Toaster):
|
|||||||
if environment.REFLEX_DOES_BACKEND_COLD_START.get():
|
if environment.REFLEX_DOES_BACKEND_COLD_START.get():
|
||||||
loading_message = Var.create("Backend is starting.")
|
loading_message = Var.create("Backend is starting.")
|
||||||
backend_is_loading_toast_var = Var(
|
backend_is_loading_toast_var = Var(
|
||||||
f"toast.loading({loading_message!s}, {{...toast_props, description: '', closeButton: false, onDismiss: () => setUserDismissed(true)}},)"
|
f"toast?.loading({loading_message!s}, {{...toast_props, description: '', closeButton: false, onDismiss: () => setUserDismissed(true)}},)"
|
||||||
)
|
)
|
||||||
backend_is_not_responding = Var.create("Backend is not responding.")
|
backend_is_not_responding = Var.create("Backend is not responding.")
|
||||||
backend_is_down_toast_var = Var(
|
backend_is_down_toast_var = Var(
|
||||||
f"toast.error({backend_is_not_responding!s}, {{...toast_props, description: '', onDismiss: () => setUserDismissed(true)}},)"
|
f"toast?.error({backend_is_not_responding!s}, {{...toast_props, description: '', onDismiss: () => setUserDismissed(true)}},)"
|
||||||
)
|
)
|
||||||
toast_var = Var(
|
toast_var = Var(
|
||||||
f"""
|
f"""
|
||||||
@ -138,10 +139,11 @@ setTimeout(() => {{
|
|||||||
f"Cannot connect to server: {connection_error}."
|
f"Cannot connect to server: {connection_error}."
|
||||||
)
|
)
|
||||||
toast_var = Var(
|
toast_var = Var(
|
||||||
f"toast.error({loading_message!s}, {{...toast_props, onDismiss: () => setUserDismissed(true)}},)"
|
f"toast?.error({loading_message!s}, {{...toast_props, onDismiss: () => setUserDismissed(true)}},)"
|
||||||
)
|
)
|
||||||
|
|
||||||
individual_hooks = [
|
individual_hooks = [
|
||||||
|
Var(f"const toast = {toast_ref};"),
|
||||||
f"const toast_props = {LiteralVar.create(props)!s};",
|
f"const toast_props = {LiteralVar.create(props)!s};",
|
||||||
"const [userDismissed, setUserDismissed] = useState(false);",
|
"const [userDismissed, setUserDismissed] = useState(false);",
|
||||||
"const [waitedForBackend, setWaitedForBackend] = useState(false);",
|
"const [waitedForBackend, setWaitedForBackend] = useState(false);",
|
||||||
@ -163,7 +165,7 @@ setTimeout(() => {{
|
|||||||
{toast_var!s}
|
{toast_var!s}
|
||||||
}}
|
}}
|
||||||
}} else {{
|
}} else {{
|
||||||
toast.dismiss("{toast_id}");
|
toast?.dismiss("{toast_id}");
|
||||||
setUserDismissed(false); // after reconnection reset dismissed state
|
setUserDismissed(false); // after reconnection reset dismissed state
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
@ -189,7 +191,6 @@ setTimeout(() => {{
|
|||||||
Returns:
|
Returns:
|
||||||
The connection toaster component.
|
The connection toaster component.
|
||||||
"""
|
"""
|
||||||
Toaster.is_used = True
|
|
||||||
return super().create(*children, **props)
|
return super().create(*children, **props)
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||||
|
|
||||||
|
from reflex.components.base.fragment import Fragment
|
||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.el.elements.typography import Div
|
from reflex.components.el.elements.typography import Div
|
||||||
from reflex.components.lucide.icon import Icon
|
from reflex.components.lucide.icon import Icon
|
||||||
from reflex.components.sonner.toast import Toaster, ToastProps
|
|
||||||
from reflex.constants.compiler import CompileVars
|
from reflex.constants.compiler import CompileVars
|
||||||
from reflex.event import EventType
|
from reflex.event import EventType
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
@ -41,48 +41,13 @@ class WebsocketTargetURL(Var):
|
|||||||
|
|
||||||
def default_connection_error() -> list[str | Var | Component]: ...
|
def default_connection_error() -> list[str | Var | Component]: ...
|
||||||
|
|
||||||
class ConnectionToaster(Toaster):
|
class ConnectionToaster(Fragment):
|
||||||
def add_hooks(self) -> list[str | Var]: ...
|
def add_hooks(self) -> list[str | Var]: ...
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
theme: Optional[Union[Var[str], str]] = None,
|
|
||||||
rich_colors: Optional[Union[Var[bool], bool]] = None,
|
|
||||||
expand: Optional[Union[Var[bool], bool]] = None,
|
|
||||||
visible_toasts: Optional[Union[Var[int], int]] = None,
|
|
||||||
position: Optional[
|
|
||||||
Union[
|
|
||||||
Literal[
|
|
||||||
"bottom-center",
|
|
||||||
"bottom-left",
|
|
||||||
"bottom-right",
|
|
||||||
"top-center",
|
|
||||||
"top-left",
|
|
||||||
"top-right",
|
|
||||||
],
|
|
||||||
Var[
|
|
||||||
Literal[
|
|
||||||
"bottom-center",
|
|
||||||
"bottom-left",
|
|
||||||
"bottom-right",
|
|
||||||
"top-center",
|
|
||||||
"top-left",
|
|
||||||
"top-right",
|
|
||||||
]
|
|
||||||
],
|
|
||||||
]
|
|
||||||
] = None,
|
|
||||||
close_button: Optional[Union[Var[bool], bool]] = None,
|
|
||||||
offset: Optional[Union[Var[str], str]] = None,
|
|
||||||
dir: Optional[Union[Var[str], str]] = None,
|
|
||||||
hotkey: Optional[Union[Var[str], str]] = None,
|
|
||||||
invert: Optional[Union[Var[bool], bool]] = None,
|
|
||||||
toast_options: Optional[Union[ToastProps, Var[ToastProps]]] = None,
|
|
||||||
gap: Optional[Union[Var[int], int]] = None,
|
|
||||||
loading_icon: Optional[Union[Icon, Var[Icon]]] = None,
|
|
||||||
pause_when_page_is_hidden: Optional[Union[Var[bool], bool]] = 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,
|
||||||
@ -110,20 +75,6 @@ class ConnectionToaster(Toaster):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the component.
|
*children: The children of the component.
|
||||||
theme: the theme of the toast
|
|
||||||
rich_colors: whether to show rich colors
|
|
||||||
expand: whether to expand the toast
|
|
||||||
visible_toasts: the number of toasts that are currently visible
|
|
||||||
position: the position of the toast
|
|
||||||
close_button: whether to show the close button
|
|
||||||
offset: offset of the toast
|
|
||||||
dir: directionality of the toast (default: ltr)
|
|
||||||
hotkey: Keyboard shortcut that will move focus to the toaster area.
|
|
||||||
invert: Dark toasts in light mode and vice versa.
|
|
||||||
toast_options: These will act as default options for all toasts. See toast() for all available options.
|
|
||||||
gap: Gap between toasts when expanded
|
|
||||||
loading_icon: Changes the default loading icon
|
|
||||||
pause_when_page_is_hidden: Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
|
||||||
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.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, ClassVar, Literal, Optional, Union
|
from typing import Any, Literal, Optional, Union
|
||||||
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
@ -17,6 +17,7 @@ from reflex.utils.serializers import serializer
|
|||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
from reflex.vars.function import FunctionVar
|
from reflex.vars.function import FunctionVar
|
||||||
|
from reflex.vars.number import ternary_operation
|
||||||
from reflex.vars.object import ObjectVar
|
from reflex.vars.object import ObjectVar
|
||||||
|
|
||||||
LiteralPosition = Literal[
|
LiteralPosition = Literal[
|
||||||
@ -217,9 +218,6 @@ class Toaster(Component):
|
|||||||
# Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
# Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
||||||
pause_when_page_is_hidden: Var[bool]
|
pause_when_page_is_hidden: Var[bool]
|
||||||
|
|
||||||
# Marked True when any Toast component is created.
|
|
||||||
is_used: ClassVar[bool] = False
|
|
||||||
|
|
||||||
def add_hooks(self) -> list[Var | str]:
|
def add_hooks(self) -> list[Var | str]:
|
||||||
"""Add hooks for the toaster component.
|
"""Add hooks for the toaster component.
|
||||||
|
|
||||||
@ -241,13 +239,17 @@ class Toaster(Component):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def send_toast(
|
def send_toast(
|
||||||
message: str | Var = "", level: str | None = None, **props
|
message: str | Var = "",
|
||||||
|
level: str | None = None,
|
||||||
|
fallback_to_alert: bool = False,
|
||||||
|
**props,
|
||||||
) -> EventSpec:
|
) -> EventSpec:
|
||||||
"""Send a toast message.
|
"""Send a toast message.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message: The message to display.
|
message: The message to display.
|
||||||
level: The level of the toast.
|
level: The level of the toast.
|
||||||
|
fallback_to_alert: Whether to fallback to an alert if the toaster is not created.
|
||||||
**props: The options for the toast.
|
**props: The options for the toast.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@ -256,11 +258,6 @@ class Toaster(Component):
|
|||||||
Returns:
|
Returns:
|
||||||
The toast event.
|
The toast event.
|
||||||
"""
|
"""
|
||||||
if not Toaster.is_used:
|
|
||||||
raise ValueError(
|
|
||||||
"Toaster component must be created before sending a toast. (use `rx.toast.provider()`)"
|
|
||||||
)
|
|
||||||
|
|
||||||
toast_command = (
|
toast_command = (
|
||||||
ObjectVar.__getattr__(toast_ref.to(dict), level) if level else toast_ref
|
ObjectVar.__getattr__(toast_ref.to(dict), level) if level else toast_ref
|
||||||
).to(FunctionVar)
|
).to(FunctionVar)
|
||||||
@ -277,6 +274,21 @@ class Toaster(Component):
|
|||||||
else:
|
else:
|
||||||
toast = toast_command.call(message)
|
toast = toast_command.call(message)
|
||||||
|
|
||||||
|
if fallback_to_alert:
|
||||||
|
toast = ternary_operation(
|
||||||
|
toast_ref.bool(),
|
||||||
|
toast,
|
||||||
|
FunctionVar("window.alert").call(
|
||||||
|
Var.create(
|
||||||
|
message
|
||||||
|
if isinstance(message, str) and message
|
||||||
|
else props.get("title", props.get("description", ""))
|
||||||
|
)
|
||||||
|
.to(str)
|
||||||
|
.replace("<br/>", "\n")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return run_script(toast)
|
return run_script(toast)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -379,7 +391,6 @@ class Toaster(Component):
|
|||||||
Returns:
|
Returns:
|
||||||
The toaster component.
|
The toaster component.
|
||||||
"""
|
"""
|
||||||
cls.is_used = True
|
|
||||||
return super().create(*children, **props)
|
return super().create(*children, **props)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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, ClassVar, Dict, Literal, Optional, Union, overload
|
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||||
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
@ -60,12 +60,13 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
|
|||||||
def dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
|
def dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
|
||||||
|
|
||||||
class Toaster(Component):
|
class Toaster(Component):
|
||||||
is_used: ClassVar[bool] = False
|
|
||||||
|
|
||||||
def add_hooks(self) -> list[Var | str]: ...
|
def add_hooks(self) -> list[Var | str]: ...
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def send_toast(
|
def send_toast(
|
||||||
message: str | Var = "", level: str | None = None, **props
|
message: str | Var = "",
|
||||||
|
level: str | None = None,
|
||||||
|
fallback_to_alert: bool = False,
|
||||||
|
**props,
|
||||||
) -> EventSpec: ...
|
) -> EventSpec: ...
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def toast_info(message: str | Var = "", **kwargs: Any): ...
|
def toast_info(message: str | Var = "", **kwargs: Any): ...
|
||||||
@ -185,13 +186,17 @@ class ToastNamespace(ComponentNamespace):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __call__(
|
def __call__(
|
||||||
message: Union[str, Var] = "", level: Optional[str] = None, **props
|
message: Union[str, Var] = "",
|
||||||
|
level: Optional[str] = None,
|
||||||
|
fallback_to_alert: bool = False,
|
||||||
|
**props,
|
||||||
) -> "EventSpec":
|
) -> "EventSpec":
|
||||||
"""Send a toast message.
|
"""Send a toast message.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
message: The message to display.
|
message: The message to display.
|
||||||
level: The level of the toast.
|
level: The level of the toast.
|
||||||
|
fallback_to_alert: Whether to fallback to an alert if the toaster is not created.
|
||||||
**props: The options for the toast.
|
**props: The options for the toast.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
|
@ -35,7 +35,6 @@ import reflex.config
|
|||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.app import App
|
from reflex.app import App
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.components.sonner.toast import Toaster
|
|
||||||
from reflex.constants import CompileVars, RouteVar, SocketEvent
|
from reflex.constants import CompileVars, RouteVar, SocketEvent
|
||||||
from reflex.event import Event, EventHandler
|
from reflex.event import Event, EventHandler
|
||||||
from reflex.state import (
|
from reflex.state import (
|
||||||
@ -1613,29 +1612,20 @@ async def test_state_with_invalid_yield(capsys, mock_app):
|
|||||||
rx.event.Event(token="fake_token", name="invalid_handler")
|
rx.event.Event(token="fake_token", name="invalid_handler")
|
||||||
):
|
):
|
||||||
assert not update.delta
|
assert not update.delta
|
||||||
if Toaster.is_used:
|
assert update.events == rx.event.fix_events(
|
||||||
assert update.events == rx.event.fix_events(
|
[
|
||||||
[
|
rx.toast(
|
||||||
rx.toast(
|
"An error occurred.",
|
||||||
"An error occurred.",
|
level="error",
|
||||||
description="TypeError: Your handler test_state_with_invalid_yield.<locals>.StateWithInvalidYield.invalid_handler must only return/yield: None, Events or other EventHandlers referenced by their class (not using `self`).<br/>See logs for details.",
|
fallback_to_alert=True,
|
||||||
level="error",
|
description="TypeError: Your handler test_state_with_invalid_yield.<locals>.StateWithInvalidYield.invalid_handler must only return/yield: None, Events or other EventHandlers referenced by their class (not using `self`).<br/>See logs for details.",
|
||||||
id="backend_error",
|
id="backend_error",
|
||||||
position="top-center",
|
position="top-center",
|
||||||
style={"width": "500px"},
|
style={"width": "500px"},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
token="",
|
token="",
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
assert update.events == rx.event.fix_events(
|
|
||||||
[
|
|
||||||
rx.window_alert(
|
|
||||||
"An error occurred.\nContact the website administrator."
|
|
||||||
)
|
|
||||||
],
|
|
||||||
token="",
|
|
||||||
)
|
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert "must only return/yield: None, Events or other EventHandlers" in captured.out
|
assert "must only return/yield: None, Events or other EventHandlers" in captured.out
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user