Merge remote-tracking branch 'upstream/main' into redis-hash
This commit is contained in:
commit
d44a684b37
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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]]
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user