reflex-dev / reflex-examples

A repository full of Reflex example apps.
456 stars 352 forks source link

Refresh upload example to use latest best practices #201

Closed jackie-pc closed 7 months ago

jackie-pc commented 7 months ago

reflex export works - CI just does not have access to latest reflex yet.

jackie-pc commented 7 months ago

Looking much better.

Do we want to add in real progress tracking?

import asyncio
import os
from typing import List

import reflex as rx
from reflex.components.core.upload import get_uploaded_files_dir, get_uploaded_file_url

class State(rx.State):
    """The app state."""

    # Whether we are currently uploading files.
    is_uploading: bool
    upload_progress: int
    upload_size: int

    @rx.var
    def files(self) -> list[str]:
        """Get the string representation of the uploaded files."""
        return os.listdir(get_uploaded_files_dir())

    async def handle_upload(self, files: List[rx.UploadFile]):
        """Handle the file upload."""
        # Iterate through the uploaded files.
        for file in files:
            upload_data = await file.read()
            outfile = os.path.join(get_uploaded_files_dir(), file.filename)
            with open(outfile, "wb") as file_object:
                file_object.write(upload_data)

    def on_upload_progress(self, prog: dict):
        if prog["progress"] < 1:
            self.is_uploading = True
        else:
            self.is_uploading = False
        self.upload_progress = prog["loaded"]
        self.upload_size = prog["total"]

color = "rgb(107,99,246)"

def index():
    return rx.chakra.vstack(
        rx.upload(
            rx.chakra.button(
                "Select File(s)",
                height="70px",
                width="200px",
                color=color,
                bg="white",
                border=f"1px solid {color}",
            ),
            rx.chakra.text(
                "Drag and drop files here or click to select files",
                height="100px",
                width="200px",
            ),
            border="1px dotted black",
            padding="2em",
        ),
        rx.chakra.hstack(
            rx.chakra.button(
                "Upload",
                on_click=State.handle_upload(
                    rx.upload_files(
                        on_upload_progress=State.on_upload_progress,
                    )
                ),
            ),
        ),
        rx.chakra.heading("Files:"),
        rx.chakra.progress(
            value=State.upload_progress,
            max_=State.upload_size,
            color="blue",
            width="100%",
        ),
        rx.chakra.vstack(
           rx.foreach(State.files, lambda file: rx.link(file, href=get_uploaded_file_url(file)))
        ),
    )

app = rx.App()
app.add_page(index, title="Upload")

That's a good idea. May be we can tie up progress properly after Radix conversion? I.e.

  1. Merge this as is
  2. Convert to Radix 2.1. Hook up rx.progress (radix based). Last I tried there were some differences with how progress worked (like if None is supported).
masenf commented 7 months ago

i didn't put the get_upload_url and get_upload_dir names in the top level of main to avoid a conflict, but the code should work against the 0.4.0 branch