add download event (#1797)

This commit is contained in:
Thomas Brandého 2023-09-13 18:56:00 +02:00 committed by GitHub
parent f2b0915aff
commit b378827b83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 7 deletions

View File

@ -73,7 +73,7 @@ export const getToken = () => {
* @param delta The delta to apply. * @param delta The delta to apply.
*/ */
export const applyDelta = (state, delta) => { export const applyDelta = (state, delta) => {
const new_state = {...state} const new_state = { ...state }
for (const substate in delta) { for (const substate in delta) {
let s = new_state; let s = new_state;
const path = substate.split(".").slice(1); const path = substate.split(".").slice(1);
@ -153,6 +153,15 @@ export const applyEvent = async (event, socket) => {
navigator.clipboard.writeText(content); navigator.clipboard.writeText(content);
return false; return false;
} }
if (event.name == "_download") {
const a = document.createElement('a');
a.hidden = true;
a.href = event.payload.url;
a.download = event.payload.filename;
a.click();
a.remove();
return false;
}
if (event.name == "_alert") { if (event.name == "_alert") {
alert(event.payload.message); alert(event.payload.message);
@ -413,7 +422,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
for (const key in delta[substate]) { for (const key in delta[substate]) {
const state_key = `${substate}.${key}` const state_key = `${substate}.${key}`
if (client_storage.cookies && state_key in client_storage.cookies) { if (client_storage.cookies && state_key in client_storage.cookies) {
const cookie_options = {...client_storage.cookies[state_key]} const cookie_options = { ...client_storage.cookies[state_key] }
const cookie_name = cookie_options.name || state_key const cookie_name = cookie_options.name || state_key
delete cookie_options.name // name is not a valid cookie option delete cookie_options.name // name is not a valid cookie option
cookies.set(cookie_name, delta[substate][key], cookie_options); cookies.set(cookie_name, delta[substate][key], cookie_options);
@ -445,18 +454,18 @@ export const useEventLoop = (
const router = useRouter() const router = useRouter()
const [state, dispatch] = useReducer(applyDelta, initial_state) const [state, dispatch] = useReducer(applyDelta, initial_state)
const [connectError, setConnectError] = useState(null) const [connectError, setConnectError] = useState(null)
// Function to add new events to the event queue. // Function to add new events to the event queue.
const Event = (events, _e) => { const Event = (events, _e) => {
preventDefault(_e); preventDefault(_e);
queueEvents(events, socket) queueEvents(events, socket)
} }
const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode
// initial state hydrate // initial state hydrate
useEffect(() => { useEffect(() => {
if (router.isReady && !sentHydrate.current) { if (router.isReady && !sentHydrate.current) {
Event(initial_events.map((e) => ({...e}))) Event(initial_events.map((e) => ({ ...e })))
sentHydrate.current = true sentHydrate.current = true
} }
}, [router.isReady]) }, [router.isReady])

View File

@ -23,6 +23,7 @@ from .event import EventChain as EventChain
from .event import FileUpload as upload_files from .event import FileUpload as upload_files
from .event import clear_local_storage as clear_local_storage from .event import clear_local_storage as clear_local_storage
from .event import console_log as console_log from .event import console_log as console_log
from .event import download as download
from .event import redirect as redirect from .event import redirect as redirect
from .event import remove_cookie as remove_cookie from .event import remove_cookie as remove_cookie
from .event import remove_local_storage as remove_local_storage from .event import remove_local_storage as remove_local_storage

View File

@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
import inspect import inspect
from typing import Any, Callable, Dict, List, Tuple from typing import Any, Callable, Dict, List, Optional, Tuple
from reflex import constants from reflex import constants
from reflex.base import Base from reflex.base import Base
@ -330,6 +330,34 @@ def set_clipboard(content: str) -> EventSpec:
) )
def download(url: str, filename: Optional[str] = None) -> EventSpec:
"""Download the file at a given path.
Args:
url : The URL to the file to download.
filename : The name that the file should be saved as after download.
Raises:
ValueError: If the URL provided is invalid.
Returns:
EventSpec: An event to download the associated file.
"""
if not url.startswith("/"):
raise ValueError("The URL argument should start with a /")
# if filename is not provided, infer it from url
if filename is None:
filename = url.rpartition("/")[-1]
return server_side(
"_download",
get_fn_signature(download),
url=url,
filename=filename,
)
def get_event(state, event): def get_event(state, event):
"""Get the event from the given state. """Get the event from the given state.