reflex 0.8.5a1__py3-none-any.whl → 0.8.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/{web/vite.config.js → jinja/web/vite.config.js.jinja2} +11 -0
- reflex/.templates/web/utils/state.js +5 -0
- reflex/__init__.py +1 -0
- reflex/__init__.pyi +2 -0
- reflex/app.py +77 -13
- reflex/compiler/templates.py +3 -0
- reflex/compiler/utils.py +6 -12
- reflex/components/base/error_boundary.py +2 -0
- reflex/components/core/auto_scroll.py +14 -13
- reflex/components/datadisplay/dataeditor.py +3 -0
- reflex/components/datadisplay/dataeditor.pyi +2 -0
- reflex/components/el/__init__.pyi +4 -0
- reflex/components/el/elements/__init__.py +1 -0
- reflex/components/el/elements/__init__.pyi +5 -0
- reflex/components/el/elements/media.py +32 -0
- reflex/components/el/elements/media.pyi +261 -0
- reflex/components/lucide/icon.py +4 -1
- reflex/components/lucide/icon.pyi +4 -1
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +15 -0
- reflex/constants/base.py +7 -58
- reflex/environment.py +0 -10
- reflex/istate/manager.py +2 -1
- reflex/plugins/__init__.py +2 -0
- reflex/plugins/_screenshot.py +144 -0
- reflex/plugins/base.py +14 -1
- reflex/state.py +28 -6
- reflex/testing.py +11 -0
- reflex/utils/decorator.py +1 -0
- reflex/utils/monitoring.py +180 -0
- reflex/utils/prerequisites.py +17 -0
- reflex/utils/token_manager.py +215 -0
- {reflex-0.8.5a1.dist-info → reflex-0.8.6.dist-info}/METADATA +5 -2
- {reflex-0.8.5a1.dist-info → reflex-0.8.6.dist-info}/RECORD +37 -34
- {reflex-0.8.5a1.dist-info → reflex-0.8.6.dist-info}/WHEEL +0 -0
- {reflex-0.8.5a1.dist-info → reflex-0.8.6.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.5a1.dist-info → reflex-0.8.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -6162,6 +6162,265 @@ class Path(BaseHTML):
|
|
|
6162
6162
|
The component.
|
|
6163
6163
|
"""
|
|
6164
6164
|
|
|
6165
|
+
class Marker(BaseHTML):
|
|
6166
|
+
@classmethod
|
|
6167
|
+
def create(
|
|
6168
|
+
cls,
|
|
6169
|
+
*children,
|
|
6170
|
+
marker_height: Var[float | int | str] | float | int | str | None = None,
|
|
6171
|
+
marker_width: Var[float | int | str] | float | int | str | None = None,
|
|
6172
|
+
marker_units: Var[str] | str | None = None,
|
|
6173
|
+
orient: Var[float | int | str] | float | int | str | None = None,
|
|
6174
|
+
preserve_aspect_ratio: Var[str] | str | None = None,
|
|
6175
|
+
ref_x: Var[float | int | str] | float | int | str | None = None,
|
|
6176
|
+
ref_y: Var[float | int | str] | float | int | str | None = None,
|
|
6177
|
+
view_box: Var[str] | str | None = None,
|
|
6178
|
+
access_key: Var[str] | str | None = None,
|
|
6179
|
+
auto_capitalize: Literal[
|
|
6180
|
+
"characters", "none", "off", "on", "sentences", "words"
|
|
6181
|
+
]
|
|
6182
|
+
| Var[Literal["characters", "none", "off", "on", "sentences", "words"]]
|
|
6183
|
+
| None = None,
|
|
6184
|
+
content_editable: Literal["inherit", "plaintext-only", False, True]
|
|
6185
|
+
| Var[Literal["inherit", "plaintext-only", False, True]]
|
|
6186
|
+
| None = None,
|
|
6187
|
+
context_menu: Var[str] | str | None = None,
|
|
6188
|
+
dir: Var[str] | str | None = None,
|
|
6189
|
+
draggable: Var[bool] | bool | None = None,
|
|
6190
|
+
enter_key_hint: Literal[
|
|
6191
|
+
"done", "enter", "go", "next", "previous", "search", "send"
|
|
6192
|
+
]
|
|
6193
|
+
| Var[Literal["done", "enter", "go", "next", "previous", "search", "send"]]
|
|
6194
|
+
| None = None,
|
|
6195
|
+
hidden: Var[bool] | bool | None = None,
|
|
6196
|
+
input_mode: Literal[
|
|
6197
|
+
"decimal", "email", "none", "numeric", "search", "tel", "text", "url"
|
|
6198
|
+
]
|
|
6199
|
+
| Var[
|
|
6200
|
+
Literal[
|
|
6201
|
+
"decimal", "email", "none", "numeric", "search", "tel", "text", "url"
|
|
6202
|
+
]
|
|
6203
|
+
]
|
|
6204
|
+
| None = None,
|
|
6205
|
+
item_prop: Var[str] | str | None = None,
|
|
6206
|
+
lang: Var[str] | str | None = None,
|
|
6207
|
+
role: Literal[
|
|
6208
|
+
"alert",
|
|
6209
|
+
"alertdialog",
|
|
6210
|
+
"application",
|
|
6211
|
+
"article",
|
|
6212
|
+
"banner",
|
|
6213
|
+
"button",
|
|
6214
|
+
"cell",
|
|
6215
|
+
"checkbox",
|
|
6216
|
+
"columnheader",
|
|
6217
|
+
"combobox",
|
|
6218
|
+
"complementary",
|
|
6219
|
+
"contentinfo",
|
|
6220
|
+
"definition",
|
|
6221
|
+
"dialog",
|
|
6222
|
+
"directory",
|
|
6223
|
+
"document",
|
|
6224
|
+
"feed",
|
|
6225
|
+
"figure",
|
|
6226
|
+
"form",
|
|
6227
|
+
"grid",
|
|
6228
|
+
"gridcell",
|
|
6229
|
+
"group",
|
|
6230
|
+
"heading",
|
|
6231
|
+
"img",
|
|
6232
|
+
"link",
|
|
6233
|
+
"list",
|
|
6234
|
+
"listbox",
|
|
6235
|
+
"listitem",
|
|
6236
|
+
"log",
|
|
6237
|
+
"main",
|
|
6238
|
+
"marquee",
|
|
6239
|
+
"math",
|
|
6240
|
+
"menu",
|
|
6241
|
+
"menubar",
|
|
6242
|
+
"menuitem",
|
|
6243
|
+
"menuitemcheckbox",
|
|
6244
|
+
"menuitemradio",
|
|
6245
|
+
"navigation",
|
|
6246
|
+
"none",
|
|
6247
|
+
"note",
|
|
6248
|
+
"option",
|
|
6249
|
+
"presentation",
|
|
6250
|
+
"progressbar",
|
|
6251
|
+
"radio",
|
|
6252
|
+
"radiogroup",
|
|
6253
|
+
"region",
|
|
6254
|
+
"row",
|
|
6255
|
+
"rowgroup",
|
|
6256
|
+
"rowheader",
|
|
6257
|
+
"scrollbar",
|
|
6258
|
+
"search",
|
|
6259
|
+
"searchbox",
|
|
6260
|
+
"separator",
|
|
6261
|
+
"slider",
|
|
6262
|
+
"spinbutton",
|
|
6263
|
+
"status",
|
|
6264
|
+
"switch",
|
|
6265
|
+
"tab",
|
|
6266
|
+
"table",
|
|
6267
|
+
"tablist",
|
|
6268
|
+
"tabpanel",
|
|
6269
|
+
"term",
|
|
6270
|
+
"textbox",
|
|
6271
|
+
"timer",
|
|
6272
|
+
"toolbar",
|
|
6273
|
+
"tooltip",
|
|
6274
|
+
"tree",
|
|
6275
|
+
"treegrid",
|
|
6276
|
+
"treeitem",
|
|
6277
|
+
]
|
|
6278
|
+
| Var[
|
|
6279
|
+
Literal[
|
|
6280
|
+
"alert",
|
|
6281
|
+
"alertdialog",
|
|
6282
|
+
"application",
|
|
6283
|
+
"article",
|
|
6284
|
+
"banner",
|
|
6285
|
+
"button",
|
|
6286
|
+
"cell",
|
|
6287
|
+
"checkbox",
|
|
6288
|
+
"columnheader",
|
|
6289
|
+
"combobox",
|
|
6290
|
+
"complementary",
|
|
6291
|
+
"contentinfo",
|
|
6292
|
+
"definition",
|
|
6293
|
+
"dialog",
|
|
6294
|
+
"directory",
|
|
6295
|
+
"document",
|
|
6296
|
+
"feed",
|
|
6297
|
+
"figure",
|
|
6298
|
+
"form",
|
|
6299
|
+
"grid",
|
|
6300
|
+
"gridcell",
|
|
6301
|
+
"group",
|
|
6302
|
+
"heading",
|
|
6303
|
+
"img",
|
|
6304
|
+
"link",
|
|
6305
|
+
"list",
|
|
6306
|
+
"listbox",
|
|
6307
|
+
"listitem",
|
|
6308
|
+
"log",
|
|
6309
|
+
"main",
|
|
6310
|
+
"marquee",
|
|
6311
|
+
"math",
|
|
6312
|
+
"menu",
|
|
6313
|
+
"menubar",
|
|
6314
|
+
"menuitem",
|
|
6315
|
+
"menuitemcheckbox",
|
|
6316
|
+
"menuitemradio",
|
|
6317
|
+
"navigation",
|
|
6318
|
+
"none",
|
|
6319
|
+
"note",
|
|
6320
|
+
"option",
|
|
6321
|
+
"presentation",
|
|
6322
|
+
"progressbar",
|
|
6323
|
+
"radio",
|
|
6324
|
+
"radiogroup",
|
|
6325
|
+
"region",
|
|
6326
|
+
"row",
|
|
6327
|
+
"rowgroup",
|
|
6328
|
+
"rowheader",
|
|
6329
|
+
"scrollbar",
|
|
6330
|
+
"search",
|
|
6331
|
+
"searchbox",
|
|
6332
|
+
"separator",
|
|
6333
|
+
"slider",
|
|
6334
|
+
"spinbutton",
|
|
6335
|
+
"status",
|
|
6336
|
+
"switch",
|
|
6337
|
+
"tab",
|
|
6338
|
+
"table",
|
|
6339
|
+
"tablist",
|
|
6340
|
+
"tabpanel",
|
|
6341
|
+
"term",
|
|
6342
|
+
"textbox",
|
|
6343
|
+
"timer",
|
|
6344
|
+
"toolbar",
|
|
6345
|
+
"tooltip",
|
|
6346
|
+
"tree",
|
|
6347
|
+
"treegrid",
|
|
6348
|
+
"treeitem",
|
|
6349
|
+
]
|
|
6350
|
+
]
|
|
6351
|
+
| None = None,
|
|
6352
|
+
slot: Var[str] | str | None = None,
|
|
6353
|
+
spell_check: Var[bool] | bool | None = None,
|
|
6354
|
+
tab_index: Var[int] | int | None = None,
|
|
6355
|
+
title: Var[str] | str | None = None,
|
|
6356
|
+
style: Sequence[Mapping[str, Any]]
|
|
6357
|
+
| Mapping[str, Any]
|
|
6358
|
+
| Var[Mapping[str, Any]]
|
|
6359
|
+
| Breakpoints
|
|
6360
|
+
| None = None,
|
|
6361
|
+
key: Any | None = None,
|
|
6362
|
+
id: Any | None = None,
|
|
6363
|
+
ref: Var | None = None,
|
|
6364
|
+
class_name: Any | None = None,
|
|
6365
|
+
custom_attrs: dict[str, Var | Any] | None = None,
|
|
6366
|
+
on_blur: EventType[()] | None = None,
|
|
6367
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
6368
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
6369
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
6370
|
+
on_focus: EventType[()] | None = None,
|
|
6371
|
+
on_mount: EventType[()] | None = None,
|
|
6372
|
+
on_mouse_down: EventType[()] | None = None,
|
|
6373
|
+
on_mouse_enter: EventType[()] | None = None,
|
|
6374
|
+
on_mouse_leave: EventType[()] | None = None,
|
|
6375
|
+
on_mouse_move: EventType[()] | None = None,
|
|
6376
|
+
on_mouse_out: EventType[()] | None = None,
|
|
6377
|
+
on_mouse_over: EventType[()] | None = None,
|
|
6378
|
+
on_mouse_up: EventType[()] | None = None,
|
|
6379
|
+
on_scroll: EventType[()] | None = None,
|
|
6380
|
+
on_scroll_end: EventType[()] | None = None,
|
|
6381
|
+
on_unmount: EventType[()] | None = None,
|
|
6382
|
+
**props,
|
|
6383
|
+
) -> Marker:
|
|
6384
|
+
"""Create the component.
|
|
6385
|
+
|
|
6386
|
+
Args:
|
|
6387
|
+
*children: The children of the component.
|
|
6388
|
+
marker_height: The height of the marker viewport.
|
|
6389
|
+
marker_width: The width of the marker viewport.
|
|
6390
|
+
marker_units: The coordinate system for the marker attributes.
|
|
6391
|
+
orient: The orientation of the marker relative to the shape it is attached to.
|
|
6392
|
+
preserve_aspect_ratio: How the svg fragment must be deformed if it is embedded in a container with a different aspect ratio.
|
|
6393
|
+
ref_x: The x coordinate for the reference point of the marker.
|
|
6394
|
+
ref_y: The y coordinate for the reference point of the marker.
|
|
6395
|
+
view_box: The bound of the SVG viewport for the current SVG fragment.
|
|
6396
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
6397
|
+
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
6398
|
+
content_editable: Indicates whether the element's content is editable.
|
|
6399
|
+
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
6400
|
+
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
|
6401
|
+
draggable: Defines whether the element can be dragged.
|
|
6402
|
+
enter_key_hint: Hints what media types the media element is able to play.
|
|
6403
|
+
hidden: Defines whether the element is hidden.
|
|
6404
|
+
input_mode: Defines the type of the element.
|
|
6405
|
+
item_prop: Defines the name of the element for metadata purposes.
|
|
6406
|
+
lang: Defines the language used in the element.
|
|
6407
|
+
role: Defines the role of the element.
|
|
6408
|
+
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
|
6409
|
+
spell_check: Defines whether the element may be checked for spelling errors.
|
|
6410
|
+
tab_index: Defines the position of the current element in the tabbing order.
|
|
6411
|
+
title: Defines a tooltip for the element.
|
|
6412
|
+
style: The style of the component.
|
|
6413
|
+
key: A unique key for the component.
|
|
6414
|
+
id: The id for the component.
|
|
6415
|
+
ref: The Var to pass as the ref to the component.
|
|
6416
|
+
class_name: The class name for the component.
|
|
6417
|
+
custom_attrs: custom attribute
|
|
6418
|
+
**props: The props of the component.
|
|
6419
|
+
|
|
6420
|
+
Returns:
|
|
6421
|
+
The component.
|
|
6422
|
+
"""
|
|
6423
|
+
|
|
6165
6424
|
class G(BaseHTML):
|
|
6166
6425
|
@classmethod
|
|
6167
6426
|
def create(
|
|
@@ -6429,6 +6688,7 @@ class SVG(ComponentNamespace):
|
|
|
6429
6688
|
linear_gradient = staticmethod(LinearGradient.create)
|
|
6430
6689
|
radial_gradient = staticmethod(RadialGradient.create)
|
|
6431
6690
|
defs = staticmethod(Defs.create)
|
|
6691
|
+
marker = staticmethod(Marker.create)
|
|
6432
6692
|
g = staticmethod(G.create)
|
|
6433
6693
|
|
|
6434
6694
|
@staticmethod
|
|
@@ -6689,6 +6949,7 @@ stop = Stop.create
|
|
|
6689
6949
|
linear_gradient = LinearGradient.create
|
|
6690
6950
|
radial_gradient = RadialGradient.create
|
|
6691
6951
|
defs = Defs.create
|
|
6952
|
+
marker = Marker.create
|
|
6692
6953
|
g = G.create
|
|
6693
6954
|
area = Area.create
|
|
6694
6955
|
audio = Audio.create
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -6,7 +6,7 @@ from reflex.utils.imports import ImportVar
|
|
|
6
6
|
from reflex.vars.base import LiteralVar, Var
|
|
7
7
|
from reflex.vars.sequence import LiteralStringVar, StringVar
|
|
8
8
|
|
|
9
|
-
LUCIDE_LIBRARY = "lucide-react@0.
|
|
9
|
+
LUCIDE_LIBRARY = "lucide-react@0.536.0"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class LucideIconComponent(Component):
|
|
@@ -93,6 +93,7 @@ class DynamicIcon(LucideIconComponent):
|
|
|
93
93
|
tag = "DynamicIcon"
|
|
94
94
|
|
|
95
95
|
name: Var[str]
|
|
96
|
+
size: Var[int]
|
|
96
97
|
|
|
97
98
|
def _get_imports(self):
|
|
98
99
|
_imports = super()._get_imports()
|
|
@@ -874,6 +875,7 @@ LUCIDE_ICON_LIST = [
|
|
|
874
875
|
"hamburger",
|
|
875
876
|
"hammer",
|
|
876
877
|
"hand_coins",
|
|
878
|
+
"hand_fist",
|
|
877
879
|
"hand_heart",
|
|
878
880
|
"hand_helping",
|
|
879
881
|
"hand_metal",
|
|
@@ -1644,6 +1646,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1644
1646
|
"truck_electric",
|
|
1645
1647
|
"truck",
|
|
1646
1648
|
"turkish_lira",
|
|
1649
|
+
"turntable",
|
|
1647
1650
|
"turtle",
|
|
1648
1651
|
"tv_2",
|
|
1649
1652
|
"tv_minimal_play",
|
|
@@ -11,7 +11,7 @@ from reflex.components.core.breakpoints import Breakpoints
|
|
|
11
11
|
from reflex.event import EventType, PointerEventInfo
|
|
12
12
|
from reflex.vars.base import Var
|
|
13
13
|
|
|
14
|
-
LUCIDE_LIBRARY = "lucide-react@0.
|
|
14
|
+
LUCIDE_LIBRARY = "lucide-react@0.536.0"
|
|
15
15
|
|
|
16
16
|
class LucideIconComponent(Component):
|
|
17
17
|
@classmethod
|
|
@@ -125,6 +125,7 @@ class DynamicIcon(LucideIconComponent):
|
|
|
125
125
|
cls,
|
|
126
126
|
*children,
|
|
127
127
|
name: Var[str] | str | None = None,
|
|
128
|
+
size: Var[int] | int | None = None,
|
|
128
129
|
style: Sequence[Mapping[str, Any]]
|
|
129
130
|
| Mapping[str, Any]
|
|
130
131
|
| Var[Mapping[str, Any]]
|
|
@@ -939,6 +940,7 @@ LUCIDE_ICON_LIST = [
|
|
|
939
940
|
"hamburger",
|
|
940
941
|
"hammer",
|
|
941
942
|
"hand_coins",
|
|
943
|
+
"hand_fist",
|
|
942
944
|
"hand_heart",
|
|
943
945
|
"hand_helping",
|
|
944
946
|
"hand_metal",
|
|
@@ -1709,6 +1711,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1709
1711
|
"truck_electric",
|
|
1710
1712
|
"truck",
|
|
1711
1713
|
"turkish_lira",
|
|
1714
|
+
"turntable",
|
|
1712
1715
|
"turtle",
|
|
1713
1716
|
"tv_2",
|
|
1714
1717
|
"tv_minimal_play",
|
reflex/config.py
CHANGED
|
@@ -29,6 +29,9 @@ from reflex.plugins.sitemap import SitemapPlugin
|
|
|
29
29
|
from reflex.utils import console
|
|
30
30
|
from reflex.utils.exceptions import ConfigError
|
|
31
31
|
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from pyleak.base import LeakAction
|
|
34
|
+
|
|
32
35
|
|
|
33
36
|
@dataclasses.dataclass(kw_only=True)
|
|
34
37
|
class DBConfig:
|
|
@@ -186,6 +189,18 @@ class BaseConfig:
|
|
|
186
189
|
# Telemetry opt-in.
|
|
187
190
|
telemetry_enabled: bool = True
|
|
188
191
|
|
|
192
|
+
# PyLeak monitoring configuration for detecting event loop blocking and resource leaks.
|
|
193
|
+
enable_pyleak_monitoring: bool = False
|
|
194
|
+
|
|
195
|
+
# Threshold in seconds for detecting event loop blocking operations.
|
|
196
|
+
pyleak_blocking_threshold: float = 0.1
|
|
197
|
+
|
|
198
|
+
# Grace period in seconds for thread leak detection cleanup.
|
|
199
|
+
pyleak_thread_grace_period: float = 0.2
|
|
200
|
+
|
|
201
|
+
# Action to take when PyLeak detects issues
|
|
202
|
+
pyleak_action: "LeakAction | None" = None
|
|
203
|
+
|
|
189
204
|
# The bun path
|
|
190
205
|
bun_path: ExistingPath = constants.Bun.DEFAULT_PATH
|
|
191
206
|
|
reflex/constants/base.py
CHANGED
|
@@ -11,8 +11,6 @@ from typing import Literal
|
|
|
11
11
|
|
|
12
12
|
from platformdirs import PlatformDirs
|
|
13
13
|
|
|
14
|
-
from .utils import classproperty
|
|
15
|
-
|
|
16
14
|
IS_WINDOWS = platform.system() == "Windows"
|
|
17
15
|
IS_MACOS = platform.system() == "Darwin"
|
|
18
16
|
IS_LINUX = platform.system() == "Linux"
|
|
@@ -119,9 +117,6 @@ class ReflexHostingCLI(SimpleNamespace):
|
|
|
119
117
|
class Templates(SimpleNamespace):
|
|
120
118
|
"""Constants related to Templates."""
|
|
121
119
|
|
|
122
|
-
# The route on Reflex backend to query which templates are available and their URLs.
|
|
123
|
-
APP_TEMPLATES_ROUTE = "/app-templates"
|
|
124
|
-
|
|
125
120
|
# The default template
|
|
126
121
|
DEFAULT = "blank"
|
|
127
122
|
|
|
@@ -132,58 +127,12 @@ class Templates(SimpleNamespace):
|
|
|
132
127
|
CHOOSE_TEMPLATES = "choose-templates"
|
|
133
128
|
|
|
134
129
|
# The URL to find reflex templates.
|
|
135
|
-
REFLEX_TEMPLATES_URL =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
DEFAULT_TEMPLATE_URL = "https://blank-template.reflex.run"
|
|
130
|
+
REFLEX_TEMPLATES_URL = (
|
|
131
|
+
"https://reflex.dev/docs/getting-started/open-source-templates/"
|
|
132
|
+
)
|
|
139
133
|
|
|
140
134
|
# The reflex.build frontend host
|
|
141
|
-
REFLEX_BUILD_FRONTEND = "https://reflex.
|
|
142
|
-
|
|
143
|
-
# The reflex.build backend host
|
|
144
|
-
REFLEX_BUILD_BACKEND = "https://flexgen-prod-flexgen.fly.dev"
|
|
145
|
-
|
|
146
|
-
@classproperty
|
|
147
|
-
@classmethod
|
|
148
|
-
def REFLEX_BUILD_URL(cls):
|
|
149
|
-
"""The URL to redirect to reflex.build.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
The URL to redirect to reflex.build.
|
|
153
|
-
"""
|
|
154
|
-
from reflex.environment import environment
|
|
155
|
-
|
|
156
|
-
return (
|
|
157
|
-
environment.REFLEX_BUILD_FRONTEND.get()
|
|
158
|
-
+ "/gen?reflex_init_token={reflex_init_token}"
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
@classproperty
|
|
162
|
-
@classmethod
|
|
163
|
-
def REFLEX_BUILD_POLL_URL(cls):
|
|
164
|
-
"""The URL to poll waiting for the user to select a generation.
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
The URL to poll waiting for the user to select a generation.
|
|
168
|
-
"""
|
|
169
|
-
from reflex.environment import environment
|
|
170
|
-
|
|
171
|
-
return environment.REFLEX_BUILD_BACKEND.get() + "/api/init/{reflex_init_token}"
|
|
172
|
-
|
|
173
|
-
@classproperty
|
|
174
|
-
@classmethod
|
|
175
|
-
def REFLEX_BUILD_CODE_URL(cls):
|
|
176
|
-
"""The URL to fetch the generation's reflex code.
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
The URL to fetch the generation's reflex code.
|
|
180
|
-
"""
|
|
181
|
-
from reflex.environment import environment
|
|
182
|
-
|
|
183
|
-
return (
|
|
184
|
-
environment.REFLEX_BUILD_BACKEND.get()
|
|
185
|
-
+ "/api/gen/{generation_hash}/refactored"
|
|
186
|
-
)
|
|
135
|
+
REFLEX_BUILD_FRONTEND = "https://build.reflex.dev"
|
|
187
136
|
|
|
188
137
|
class Dirs(SimpleNamespace):
|
|
189
138
|
"""Folders used by the template system of Reflex."""
|
|
@@ -204,9 +153,6 @@ class Javascript(SimpleNamespace):
|
|
|
204
153
|
# The node modules directory.
|
|
205
154
|
NODE_MODULES = "node_modules"
|
|
206
155
|
|
|
207
|
-
# The package lock file.
|
|
208
|
-
PACKAGE_LOCK = "package-lock.json"
|
|
209
|
-
|
|
210
156
|
|
|
211
157
|
class ReactRouter(Javascript):
|
|
212
158
|
"""Constants related to React Router."""
|
|
@@ -214,6 +160,9 @@ class ReactRouter(Javascript):
|
|
|
214
160
|
# The react router config file
|
|
215
161
|
CONFIG_FILE = "react-router.config.js"
|
|
216
162
|
|
|
163
|
+
# The associated Vite config file
|
|
164
|
+
VITE_CONFIG_FILE = "vite.config.js"
|
|
165
|
+
|
|
217
166
|
# Regex to check for message displayed when frontend comes up
|
|
218
167
|
DEV_FRONTEND_LISTENING_REGEX = r"Local:[\s]+"
|
|
219
168
|
|
reflex/environment.py
CHANGED
|
@@ -563,16 +563,6 @@ class EnvironmentVariables:
|
|
|
563
563
|
# Whether to skip purging the web directory in dev mode.
|
|
564
564
|
REFLEX_PERSIST_WEB_DIR: EnvVar[bool] = env_var(False)
|
|
565
565
|
|
|
566
|
-
# The reflex.build frontend host.
|
|
567
|
-
REFLEX_BUILD_FRONTEND: EnvVar[str] = env_var(
|
|
568
|
-
constants.Templates.REFLEX_BUILD_FRONTEND
|
|
569
|
-
)
|
|
570
|
-
|
|
571
|
-
# The reflex.build backend host.
|
|
572
|
-
REFLEX_BUILD_BACKEND: EnvVar[str] = env_var(
|
|
573
|
-
constants.Templates.REFLEX_BUILD_BACKEND
|
|
574
|
-
)
|
|
575
|
-
|
|
576
566
|
# This env var stores the execution mode of the app
|
|
577
567
|
REFLEX_ENV_MODE: EnvVar[constants.Env] = env_var(constants.Env.DEV)
|
|
578
568
|
|
reflex/istate/manager.py
CHANGED
|
@@ -143,6 +143,8 @@ class StateManagerMemory(StateManager):
|
|
|
143
143
|
token: The token to set the state for.
|
|
144
144
|
state: The state to set.
|
|
145
145
|
"""
|
|
146
|
+
token = _split_substate_key(token)[0]
|
|
147
|
+
self.states[token] = state
|
|
146
148
|
|
|
147
149
|
@override
|
|
148
150
|
@contextlib.asynccontextmanager
|
|
@@ -165,7 +167,6 @@ class StateManagerMemory(StateManager):
|
|
|
165
167
|
async with self._states_locks[token]:
|
|
166
168
|
state = await self.get_state(token)
|
|
167
169
|
yield state
|
|
168
|
-
await self.set_state(token, state)
|
|
169
170
|
|
|
170
171
|
|
|
171
172
|
def _default_token_expiration() -> int:
|
reflex/plugins/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Reflex Plugin System."""
|
|
2
2
|
|
|
3
|
+
from ._screenshot import ScreenshotPlugin as _ScreenshotPlugin
|
|
3
4
|
from .base import CommonContext, Plugin, PreCompileContext
|
|
4
5
|
from .sitemap import SitemapPlugin
|
|
5
6
|
from .tailwind_v3 import TailwindV3Plugin
|
|
@@ -12,4 +13,5 @@ __all__ = [
|
|
|
12
13
|
"SitemapPlugin",
|
|
13
14
|
"TailwindV3Plugin",
|
|
14
15
|
"TailwindV4Plugin",
|
|
16
|
+
"_ScreenshotPlugin",
|
|
15
17
|
]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Plugin to enable screenshot functionality."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from reflex.plugins.base import Plugin as BasePlugin
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from starlette.requests import Request
|
|
9
|
+
from starlette.responses import Response
|
|
10
|
+
from typing_extensions import Unpack
|
|
11
|
+
|
|
12
|
+
from reflex.app import App
|
|
13
|
+
from reflex.plugins.base import PostCompileContext
|
|
14
|
+
from reflex.state import BaseState
|
|
15
|
+
|
|
16
|
+
ACTIVE_CONNECTIONS = "/_active_connections"
|
|
17
|
+
CLONE_STATE = "/_clone_state"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _deep_copy(state: "BaseState") -> "BaseState":
|
|
21
|
+
"""Create a deep copy of the state.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
state: The state to copy.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
A deep copy of the state.
|
|
28
|
+
"""
|
|
29
|
+
import copy
|
|
30
|
+
|
|
31
|
+
copy_of_state = copy.deepcopy(state)
|
|
32
|
+
|
|
33
|
+
def copy_substate(substate: "BaseState") -> "BaseState":
|
|
34
|
+
substate_copy = _deep_copy(substate)
|
|
35
|
+
|
|
36
|
+
substate_copy.parent_state = copy_of_state
|
|
37
|
+
|
|
38
|
+
return substate_copy
|
|
39
|
+
|
|
40
|
+
copy_of_state.substates = {
|
|
41
|
+
substate_name: copy_substate(substate)
|
|
42
|
+
for substate_name, substate in state.substates.items()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return copy_of_state
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ScreenshotPlugin(BasePlugin):
|
|
49
|
+
"""Plugin to handle screenshot functionality."""
|
|
50
|
+
|
|
51
|
+
def post_compile(self, **context: "Unpack[PostCompileContext]") -> None:
|
|
52
|
+
"""Called after the compilation of the plugin.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
context: The context for the plugin.
|
|
56
|
+
"""
|
|
57
|
+
app = context["app"]
|
|
58
|
+
self._add_active_connections_endpoint(app)
|
|
59
|
+
self._add_clone_state_endpoint(app)
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _add_active_connections_endpoint(app: "App") -> None:
|
|
63
|
+
"""Add an endpoint to the app that returns the active connections.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
app: The application instance to which the endpoint will be added.
|
|
67
|
+
"""
|
|
68
|
+
if not app._api:
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
async def active_connections(_request: "Request") -> "Response":
|
|
72
|
+
from starlette.responses import JSONResponse
|
|
73
|
+
|
|
74
|
+
if not app.event_namespace:
|
|
75
|
+
return JSONResponse({})
|
|
76
|
+
|
|
77
|
+
return JSONResponse(app.event_namespace.token_to_sid)
|
|
78
|
+
|
|
79
|
+
app._api.add_route(
|
|
80
|
+
ACTIVE_CONNECTIONS,
|
|
81
|
+
active_connections,
|
|
82
|
+
methods=["GET"],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _add_clone_state_endpoint(app: "App") -> None:
|
|
87
|
+
"""Add an endpoint to the app that clones the current state.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
app: The application instance to which the endpoint will be added.
|
|
91
|
+
"""
|
|
92
|
+
if not app._api:
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
async def clone_state(request: "Request") -> "Response":
|
|
96
|
+
import uuid
|
|
97
|
+
|
|
98
|
+
from starlette.responses import JSONResponse
|
|
99
|
+
|
|
100
|
+
from reflex.state import _substate_key
|
|
101
|
+
|
|
102
|
+
if not app.event_namespace:
|
|
103
|
+
return JSONResponse({})
|
|
104
|
+
|
|
105
|
+
token_to_clone = await request.json()
|
|
106
|
+
|
|
107
|
+
if not isinstance(token_to_clone, str):
|
|
108
|
+
return JSONResponse(
|
|
109
|
+
{"error": "Token to clone must be a string."}, status_code=400
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
old_state = await app.state_manager.get_state(token_to_clone)
|
|
113
|
+
|
|
114
|
+
new_state = _deep_copy(old_state)
|
|
115
|
+
|
|
116
|
+
new_token = uuid.uuid4().hex
|
|
117
|
+
|
|
118
|
+
all_states = [new_state]
|
|
119
|
+
|
|
120
|
+
found_new = True
|
|
121
|
+
|
|
122
|
+
while found_new:
|
|
123
|
+
found_new = False
|
|
124
|
+
|
|
125
|
+
for state in all_states:
|
|
126
|
+
for substate in state.substates.values():
|
|
127
|
+
substate._was_touched = True
|
|
128
|
+
|
|
129
|
+
if substate not in all_states:
|
|
130
|
+
all_states.append(substate)
|
|
131
|
+
|
|
132
|
+
found_new = True
|
|
133
|
+
|
|
134
|
+
await app.state_manager.set_state(
|
|
135
|
+
_substate_key(new_token, new_state), new_state
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return JSONResponse(new_token)
|
|
139
|
+
|
|
140
|
+
app._api.add_route(
|
|
141
|
+
CLONE_STATE,
|
|
142
|
+
clone_state,
|
|
143
|
+
methods=["POST"],
|
|
144
|
+
)
|