banner.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """Banner components."""
  2. from __future__ import annotations
  3. from typing import Optional
  4. from reflex.components.base.bare import Bare
  5. from reflex.components.component import Component
  6. from reflex.components.core.cond import cond
  7. from reflex.components.radix.themes.components.dialog import (
  8. DialogContent,
  9. DialogRoot,
  10. DialogTitle,
  11. )
  12. from reflex.components.radix.themes.layout import Box
  13. from reflex.components.radix.themes.typography.text import Text
  14. from reflex.constants import Dirs, Hooks, Imports
  15. from reflex.utils import imports
  16. from reflex.vars import Var, VarData
  17. connect_error_var_data: VarData = VarData( # type: ignore
  18. imports=Imports.EVENTS,
  19. hooks={Hooks.EVENTS},
  20. )
  21. connection_error: Var = Var.create_safe(
  22. value="(connectError !== null) ? connectError.message : ''",
  23. _var_is_local=False,
  24. _var_is_string=False,
  25. )._replace(merge_var_data=connect_error_var_data)
  26. has_connection_error: Var = Var.create_safe(
  27. value="connectError !== null",
  28. _var_is_string=False,
  29. )._replace(_var_type=bool, merge_var_data=connect_error_var_data)
  30. class WebsocketTargetURL(Bare):
  31. """A component that renders the websocket target URL."""
  32. def _get_imports(self) -> imports.ImportDict:
  33. return {
  34. f"/{Dirs.STATE_PATH}": [imports.ImportVar(tag="getBackendURL")],
  35. "/env.json": [imports.ImportVar(tag="env", is_default=True)],
  36. }
  37. @classmethod
  38. def create(cls) -> Component:
  39. """Create a websocket target URL component.
  40. Returns:
  41. The websocket target URL component.
  42. """
  43. return super().create(contents="{getBackendURL(env.EVENT).href}")
  44. def default_connection_error() -> list[str | Var | Component]:
  45. """Get the default connection error message.
  46. Returns:
  47. The default connection error message.
  48. """
  49. return [
  50. "Cannot connect to server: ",
  51. connection_error,
  52. ". Check if server is reachable at ",
  53. WebsocketTargetURL.create(),
  54. ]
  55. class ConnectionBanner(Component):
  56. """A connection banner component."""
  57. @classmethod
  58. def create(cls, comp: Optional[Component] = None) -> Component:
  59. """Create a connection banner component.
  60. Args:
  61. comp: The component to render when there's a server connection error.
  62. Returns:
  63. The connection banner component.
  64. """
  65. if not comp:
  66. comp = Box.create(
  67. Text.create(
  68. *default_connection_error(),
  69. bg="red",
  70. color="white",
  71. ),
  72. textAlign="center",
  73. )
  74. return cond(has_connection_error, comp)
  75. class ConnectionModal(Component):
  76. """A connection status modal window."""
  77. @classmethod
  78. def create(cls, comp: Optional[Component] = None) -> Component:
  79. """Create a connection banner component.
  80. Args:
  81. comp: The component to render when there's a server connection error.
  82. Returns:
  83. The connection banner component.
  84. """
  85. if not comp:
  86. comp = Text.create(*default_connection_error())
  87. return cond(
  88. has_connection_error,
  89. DialogRoot.create(
  90. DialogContent.create(
  91. DialogTitle.create("Connection Error"),
  92. comp,
  93. ),
  94. open=has_connection_error,
  95. ),
  96. )