phase 3b T8: <UploadDialog> + UploadQueue context#638
Merged
Conversation
Adds a modal sheet that drives the multi-file upload + send flow per docs/specs/2026-04-19-ui-design/files-inline.md §Upload dialog. Visibility is owned by a session-scoped UploadQueue context; the composer's existing FileShareButton now flips queue.open instead of running its own FileReader → upload → send pipeline. Extracted so future drag-overlay (T10) and paste-to-upload (T12) handlers can enqueue into the same queue without duplicating the read / upload / status surface. v1 ships binary uploading / done / failed status — iroh-blobs has no incremental progress hook yet, so the spec's progress bar is deferred until that lands. Picker, per-file rows, footer (cancel all / attach to message), 25 MB cap, and ARIA labels all match the spec. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
UploadDialog T8 ships with picker + per-file rows + footer per spec §Upload dialog. ARIA-label criterion partially advances: dialog role + cancel-upload labels land here; voice-note + drag-overlay labels remain for T6 / T10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review feedback on PR #638: - `spawn_upload` swaps `cb.forget()` for `cb.into_js_value()` so the one-shot FileReader closure is GC-able once the reader drops, instead of leaking the wasm closure on every upload. - `use_upload_queue` now logs a warning when the fallback fires, so a future mount-order regression (paperclip flips queue.open on a queue the dialog never reads) shows up in production logs instead of as a silent UX dead end. - `UploadQueue::cancel_all` doc comment clarifies it does not abort in-flight upload futures (iroh-blobs has no cancel hook today; the user-visible "file isn't sent" effect is preserved because the row is gone before the future resolves). - `on_attach` carries a comment explaining the deliberate snapshot of `channel.get_untracked()` at click time. - Adds two wasm-pack browser tests (`phase_3b_upload_dialog`): visibility tracks `queue.open`, and the confirm button toggles disabled / enabled as entries flip to `Done(_)`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the deferred T8 from
docs/specs/2026-04-19-ui-design/files-inline.md§Upload dialog.UploadQueue(newcrates/web/src/upload_state.rs) — session-scoped Leptos context shared between the composer attach button, the dialog itself, and any future drag/paste handler that enqueues files. Holds anopen: RwSignal<bool>plus per-entry rows with their own status signals (Uploading/Done(BlobHash)/Failed(String)).<UploadDialog>(newcrates/web/src/components/upload_dialog.rs) — modal sheet on--bg-1with picker row, per-file rows, and footer (cancel all/attach to message). Multi-file pick via a hidden<input type="file" multiple>. The confirm action iteratesDoneentries and posts aFileMessageevent per file in the active channel, then clears the queue.<FileShareButton>rewritten — drops the inline FileReader → upload → send pipeline; now just flipsqueue.open.set(true). The legacyparse_inline_filereader stays for back-compat rendering of pre-3b inline-file messages.app.rs— providesUploadQueue::new()at the app shell layer and mounts<UploadDialog channel=current_channel />adjacent to the composer..upload-dialog__*using foundation tokens (--bg-1,--line,--shadow-2,--moss-1,--ink-0/1/2).Out of scope (deferred)
iroh-blobs::upload_attachmentresolves only on completion; no incremental progress hook exists yet. The spec's progress bar drops in once that lands; v1 ships binaryuploading/✓/✗ {error}status.UploadQueuecontext provided here.Test plan
just check— fmt + clippy + native tests + WASM check, zero warnings.txtfiles → rows show uploading → done → clickattach to message→ file cards land in chatcancel all(or scrim click) clears + closes dialog🤖 Generated with Claude Code