Track progress during media uploads#75099
Conversation
1fb78d7 to
89e2a02
Compare
45ad7e3 to
7aec886
Compare
|
Size Change: +650 B (+0.01%) Total Size: 7.74 MB 📦 View Changed
ℹ️ View Unchanged
|
f331d44 to
0e5fa33
Compare
0e5fa33 to
333e78d
Compare
|
Flaky tests detected in 530deea. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24095234841
|
Restores the accidentally removed `finalizeItem` action that handles the Finalize operation type, and removes extra trailing newlines that caused prettier errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Move duplicated XHR progress-upload logic from uploadWithProgress and sideloadWithProgress into a shared xhrUpload() helper. This fixes the abort signal event listener never being cleaned up after requests complete, preventing potential memory leaks when AbortControllers are long-lived. Also deduplicates createUploadFormData/createSideloadFormData into a shared buildFormData() with typed wrapper functions.
The interface lacked a string index signature, making it incompatible with Record<string, unknown> when used with Object.entries().
|
Is the intention to display or leverage this progress somewhere or is it more a "because we can" kind of change? |
The check was removed but it prevents unnecessary scaling and sideload operations for images already below the bigImageSizeThreshold, matching WordPress core's wp_create_image_subsizes() behavior.
The tests were removed but the function still exists and has meaningful behavior that should remain tested.
Ensures all '?' characters in the path are converted to '&' when the API root contains a query string, not just the first occurrence.
Removes duplication of the XHR mock class between upload-to-server and sideload-to-server test files.
Verifies that onProgress callbacks from mediaUpload/mediaSideload correctly dispatch updateItemProgress with the item ID and progress value. Also tests edge cases: missing items and unconfigured sideload.
Tests paths with and without leading slashes and verifies the apiRoot trailing slash contract.
Verifies that each file in a multi-file upload receives the same onProgress callback, documenting the current interleaving behavior.
The onProgress callback now receives the file being uploaded as a second argument, allowing callers to distinguish which file's progress is being reported during concurrent multi-file uploads.
Jest was picking up mock-xhr.ts as a test suite and failing because it contains no tests. Moving it to test-utils/ avoids the test file pattern match.
The previous commit moved mock-xhr.ts from test/ to test-utils/, which exposed it to the TypeScript build. Since test-utils/ is not excluded by tsconfig, the jest.fn() calls caused TS2304 errors during CI builds. Moving it back into test/ (which is excluded) fixes the build while keeping the shared helper accessible to both test files.
Jest's testMatch pattern `**/test/*.[jt]s?(x)` matches any .ts file directly inside a test/ directory. Moving mock-xhr.ts to test/helpers/ avoids it being treated as a test suite (which fails because it contains no tests) while still keeping it excluded from the TypeScript production build.
Originally my intention was to visually show progress in #74363. After some experimentation though, we decided to leave progress as spinners (the current approach). Based on that, I can close this PR and the related issue as "Not planned". |
To offer a slight counterpoint, I think being able to show upload progress is a great feature, and it'd be worth revisiting ideas for the UI for it at some point. It's just that in #74363 it was about looking at showing that progress on the image block. If instead we think about progress being shown in other places (i.e. possibly in the footer of the editor skeleton, or in a popover somewhere), then I think it'll still be important for us to be able to do it technically. So I'd be in favour of supporting it, so that we can try out other UI ideas separately. The main use cases I can think of where it'll be really handy are:
What do you think? |
|
The thing is, there is more to the progress bar than just upload progress. There are multiple sideload items, items waiting in queue, vips operations, etc. That makes it difficult to display one true progress bar. |
Indeed. I suppose the challenge here (especially for longer uploads) is how do we display something that's a bit more helpful to indicate that progress really is happening, than an endless spinner. For longer uploads it can be easy to feel like "hang on, is anything happening, or is it stuck?" I'd be keen for us to try out some more ideas for that. As such I've re-opened Images: Implement upload progress UI — Issue #74363 — it could be that it's more of a UI thing than a technical progress thing, but it'd be good to explore. |
What?
Closes #74362
Adds real-time upload progress tracking to the media upload queue. When files are uploaded or sideloaded, progress callbacks now fire with 0-100 percentage updates, enabling UI to display upload progress to users.
Why?
Currently, media uploads provide no feedback on progress — users see only a "loading" state with no indication of how far along an upload is. This is especially frustrating for large files. By switching to XMLHttpRequest for uploads when progress tracking is needed, we can leverage the
upload.onprogressevent to report real-time progress.How?
Core changes
@wordpress/media-utils— XHR-based upload with progress callbacks:upload-to-server.ts: AddeduploadWithProgress()using XHR withonprogresstracking. Falls back toapiFetchwhen noonProgresscallback is provided.sideload-to-server.ts: AddedsideloadWithProgress()with the same XHR approach for sideload operations.upload-media.ts/sideload-media.ts: ThreadonProgresscallback through to the server functions.build-rest-url.ts: Builds full REST API URLs for XHR requests (handles plain permalinks,_localeparam).create-upload-form-data.ts: ConsolidatedFormDatacreation shared by both upload and sideload paths.@wordpress/urldependency for URL building utilities.@wordpress/upload-media— Queue integration:private-actions.ts:uploadItem()andsideloadItem()now passonProgresscallbacks that dispatchupdateItemProgress()to update the store.types.ts: AddedonProgresstoUploadMediaArgsandSideloadMediaArgsinterfaces.Design decisions
onProgressis provided, uploads useXMLHttpRequestfor progress events. Otherwise, the existingapiFetchpath is used, avoiding any behavioral changes for callers that don't need progress.X-WP-NoncefromapiFetch.nonceMiddlewareand enablewithCredentialsfor cookie-based auth, matchingapiFetchbehavior.xhr.abort(), maintaining cancellation support.Testing Instructions
Observing upload progress in the console
To watch upload progress in real time, paste this snippet into the browser's developer console before uploading a file:
Alternatively, you can add a
console.logdirectly in the source. Inpackages/upload-media/src/store/private-actions.ts, find theonProgresscallback insideuploadItem()(~line 782) and add a log: