Merge remote-tracking branch 'upstream/main' into redis-hash

This commit is contained in:
Benedikt Bartscher 2024-12-03 02:18:21 +01:00
commit d44a684b37
No known key found for this signature in database
9 changed files with 52 additions and 37 deletions

View File

@ -457,7 +457,7 @@ export const connect = async (
socket.current.on("reload", async (event) => { socket.current.on("reload", async (event) => {
event_processing = false; event_processing = false;
queueEvents([...initialEvents(), JSON5.parse(event)], socket); queueEvents([...initialEvents(), JSON5.parse(event)], socket);
}) });
document.addEventListener("visibilitychange", checkVisibility); document.addEventListener("visibilitychange", checkVisibility);
}; };
@ -490,23 +490,30 @@ export const uploadFiles = async (
return false; return false;
} }
// Track how many partial updates have been processed for this upload.
let resp_idx = 0; let resp_idx = 0;
const eventHandler = (progressEvent) => { const eventHandler = (progressEvent) => {
// handle any delta / event streamed from the upload event handler const event_callbacks = socket._callbacks.$event;
// Whenever called, responseText will contain the entire response so far.
const chunks = progressEvent.event.target.responseText.trim().split("\n"); const chunks = progressEvent.event.target.responseText.trim().split("\n");
// So only process _new_ chunks beyond resp_idx.
chunks.slice(resp_idx).map((chunk) => { chunks.slice(resp_idx).map((chunk) => {
try { event_callbacks.map((f, ix) => {
socket._callbacks.$event.map((f) => { f(chunk)
f(chunk); .then(() => {
}); if (ix === event_callbacks.length - 1) {
// Mark this chunk as processed.
resp_idx += 1; resp_idx += 1;
} catch (e) { }
})
.catch((e) => {
if (progressEvent.progress === 1) { if (progressEvent.progress === 1) {
// Chunk may be incomplete, so only report errors when full response is available. // Chunk may be incomplete, so only report errors when full response is available.
console.log("Error parsing chunk", chunk, e); console.log("Error parsing chunk", chunk, e);
} }
return; return;
} });
});
}); });
}; };
@ -852,7 +859,7 @@ export const useEventLoop = (
if (router.components[router.pathname].error) { if (router.components[router.pathname].error) {
delete router.components[router.pathname].error; delete router.components[router.pathname].error;
} }
} };
router.events.on("routeChangeStart", change_start); router.events.on("routeChangeStart", change_start);
router.events.on("routeChangeComplete", change_complete); router.events.on("routeChangeComplete", change_complete);
router.events.on("routeChangeError", change_error); router.events.on("routeChangeError", change_error);

View File

@ -293,13 +293,15 @@ class Upload(MemoizationLeaf):
format.to_camel_case(key): value for key, value in upload_props.items() format.to_camel_case(key): value for key, value in upload_props.items()
} }
use_dropzone_arguments = { use_dropzone_arguments = Var.create(
{
"onDrop": event_var, "onDrop": event_var,
**upload_props, **upload_props,
} }
)
left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} " left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} "
right_side = f"useDropzone({str(Var.create(use_dropzone_arguments))})" right_side = f"useDropzone({str(use_dropzone_arguments)})"
var_data = VarData.merge( var_data = VarData.merge(
VarData( VarData(
@ -307,6 +309,7 @@ class Upload(MemoizationLeaf):
hooks={Hooks.EVENTS: None}, hooks={Hooks.EVENTS: None},
), ),
event_var._get_all_var_data(), event_var._get_all_var_data(),
use_dropzone_arguments._get_all_var_data(),
VarData( VarData(
hooks={ hooks={
callback_str: None, callback_str: None,

View File

@ -570,6 +570,9 @@ class Textarea(BaseHTML):
# Visible width of the text control, in average character widths # Visible width of the text control, in average character widths
cols: Var[Union[str, int, bool]] cols: Var[Union[str, int, bool]]
# The default value of the textarea when initially rendered
default_value: Var[str]
# Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted # Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
dirname: Var[Union[str, int, bool]] dirname: Var[Union[str, int, bool]]

View File

@ -1350,6 +1350,7 @@ class Textarea(BaseHTML):
auto_focus: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, auto_focus: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
auto_height: Optional[Union[Var[bool], bool]] = None, auto_height: Optional[Union[Var[bool], bool]] = None,
cols: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, cols: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
default_value: Optional[Union[Var[str], str]] = None,
dirname: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, dirname: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
disabled: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, disabled: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
enter_key_submit: Optional[Union[Var[bool], bool]] = None, enter_key_submit: Optional[Union[Var[bool], bool]] = None,
@ -1439,6 +1440,7 @@ class Textarea(BaseHTML):
auto_focus: Automatically focuses the textarea when the page loads auto_focus: Automatically focuses the textarea when the page loads
auto_height: Automatically fit the content height to the text (use min-height with this prop) auto_height: Automatically fit the content height to the text (use min-height with this prop)
cols: Visible width of the text control, in average character widths cols: Visible width of the text control, in average character widths
default_value: The default value of the textarea when initially rendered
dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
disabled: Disables the textarea disabled: Disables the textarea
enter_key_submit: Enter key submits form (shift-enter adds new line) enter_key_submit: Enter key submits form (shift-enter adds new line)

View File

@ -41,6 +41,9 @@ class TextArea(RadixThemesComponent, elements.Textarea):
# Automatically focuses the textarea when the page loads # Automatically focuses the textarea when the page loads
auto_focus: Var[bool] auto_focus: Var[bool]
# The default value of the textarea when initially rendered
default_value: Var[str]
# Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted # Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
dirname: Var[str] dirname: Var[str]

View File

@ -123,6 +123,7 @@ class TextArea(RadixThemesComponent, elements.Textarea):
] = None, ] = None,
auto_complete: Optional[Union[Var[bool], bool]] = None, auto_complete: Optional[Union[Var[bool], bool]] = None,
auto_focus: Optional[Union[Var[bool], bool]] = None, auto_focus: Optional[Union[Var[bool], bool]] = None,
default_value: Optional[Union[Var[str], str]] = None,
dirname: Optional[Union[Var[str], str]] = None, dirname: Optional[Union[Var[str], str]] = None,
disabled: Optional[Union[Var[bool], bool]] = None, disabled: Optional[Union[Var[bool], bool]] = None,
form: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, form: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
@ -217,6 +218,7 @@ class TextArea(RadixThemesComponent, elements.Textarea):
radius: The radius of the text area: "none" | "small" | "medium" | "large" | "full" radius: The radius of the text area: "none" | "small" | "medium" | "large" | "full"
auto_complete: Whether the form control should have autocomplete enabled auto_complete: Whether the form control should have autocomplete enabled
auto_focus: Automatically focuses the textarea when the page loads auto_focus: Automatically focuses the textarea when the page loads
default_value: The default value of the textarea when initially rendered
dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted
disabled: Disables the textarea disabled: Disables the textarea
form: Associates the textarea with a form (by id) form: Associates the textarea with a form (by id)

View File

@ -3,7 +3,6 @@
from typing import Dict, Literal from typing import Dict, Literal
from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent
from reflex.utils import console
class Recharts(Component): class Recharts(Component):
@ -11,19 +10,8 @@ class Recharts(Component):
library = "recharts@2.13.0" library = "recharts@2.13.0"
def render(self) -> Dict: def _get_style(self) -> Dict:
"""Render the tag. return {"wrapperStyle": self.style}
Returns:
The rendered tag.
"""
tag = super().render()
if any(p.startswith("css") for p in tag["props"]):
console.warn(
f"CSS props do not work for {self.__class__.__name__}. Consult docs to style it with its own prop."
)
tag["props"] = [p for p in tag["props"] if not p.startswith("css")]
return tag
class RechartsCharts(NoSSRComponent, MemoizationLeaf): class RechartsCharts(NoSSRComponent, MemoizationLeaf):

View File

@ -11,7 +11,6 @@ from reflex.style import Style
from reflex.vars.base import Var from reflex.vars.base import Var
class Recharts(Component): class Recharts(Component):
def render(self) -> Dict: ...
@overload @overload
@classmethod @classmethod
def create( # type: ignore def create( # type: ignore

View File

@ -19,10 +19,14 @@ def UploadFile():
import reflex as rx import reflex as rx
LARGE_DATA = "DUMMY" * 1024 * 512
class UploadState(rx.State): class UploadState(rx.State):
_file_data: Dict[str, str] = {} _file_data: Dict[str, str] = {}
event_order: List[str] = [] event_order: List[str] = []
progress_dicts: List[dict] = [] progress_dicts: List[dict] = []
disabled: bool = False
large_data: str = ""
async def handle_upload(self, files: List[rx.UploadFile]): async def handle_upload(self, files: List[rx.UploadFile]):
for file in files: for file in files:
@ -33,6 +37,7 @@ def UploadFile():
for file in files: for file in files:
upload_data = await file.read() upload_data = await file.read()
self._file_data[file.filename or ""] = upload_data.decode("utf-8") self._file_data[file.filename or ""] = upload_data.decode("utf-8")
self.large_data = LARGE_DATA
yield UploadState.chain_event yield UploadState.chain_event
def upload_progress(self, progress): def upload_progress(self, progress):
@ -41,13 +46,15 @@ def UploadFile():
self.progress_dicts.append(progress) self.progress_dicts.append(progress)
def chain_event(self): def chain_event(self):
assert self.large_data == LARGE_DATA
self.large_data = ""
self.event_order.append("chain_event") self.event_order.append("chain_event")
def index(): def index():
return rx.vstack( return rx.vstack(
rx.input( rx.input(
value=UploadState.router.session.client_token, value=UploadState.router.session.client_token,
is_read_only=True, read_only=True,
id="token", id="token",
), ),
rx.heading("Default Upload"), rx.heading("Default Upload"),
@ -56,6 +63,7 @@ def UploadFile():
rx.button("Select File"), rx.button("Select File"),
rx.text("Drag and drop files here or click to select files"), rx.text("Drag and drop files here or click to select files"),
), ),
disabled=UploadState.disabled,
), ),
rx.button( rx.button(
"Upload", "Upload",