Media: Show determinate GIF conversion progress in the upload snackbar - #80329
Media: Show determinate GIF conversion progress in the upload snackbar#80329adamsilverstein wants to merge 12 commits into
Conversation
The conversion loop knows the exact frame count up front, so per-frame progress is precise. Add an onProgress callback to convertGifToVideo(), throttled to whole-percent increments, and dispatch the previously unused updateItemProgress action from transcodeGifItem. A new getProgressById selector resolves progress for an attachment, matching sideload companions via additionalData.post. See #80325.
Replace the indeterminate spinner overlay with a determinate ProgressBar while a long-running client-side operation reports progress for the block's attachment, so authors converting long animated GIFs can see how far along the conversion is. See #80325.
Fast conversions can emit ~100 whole-percent reports in a couple of seconds. Each dispatch synchronously re-renders every upload-store consumer in the editor, which saturates the main thread and starves painting - the progress bar was in the DOM but never drawn. Allow at most one dispatch per 250ms (the final report always goes through). Verified in the editor: the bar now paints and advances visibly during conversion. See #80325.
|
Size Change: +504 B (+0.01%) Total Size: 7.75 MB 📦 View Changed
|
|
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. |
|
Flaky tests detected in 2970d39. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/29788532163
|
…o add/gif-conversion-progress
The default ProgressBar is a 1.5px hairline in theme foreground color, nearly invisible over noisy GIF frames or dark video posters. Thicken it and give it media-relative contrast: white indicator on a dark translucent track, with a light outline and drop shadow so the track extent stays visible over dark media.
…o add/gif-conversion-progress
…rogress # Conflicts: # packages/upload-media/src/store/private-actions.ts # packages/upload-media/src/store/test/private-actions.js # packages/upload-media/src/store/utils/video-conversion.ts # packages/video-conversion/CHANGELOG.md # packages/video-conversion/README.md # packages/video-conversion/src/index.ts # packages/video-conversion/src/video-conversion-worker.ts
|
Thanks for the PR, and the tireless work. I responded on something related on the upload hang discussion, which is to say: we are entering some complexity territory with some of this work that may be worth visioning out before going too far into details. The details are critical, but they need to all connect, somehow. For me in this case, the topic is less showing progress while converting GIFs, but rather: how do we show process for processing media in general, and how do we do that in a way that scales not only from the block, but eventually, to the media library itself—because presumably you should be able to upload and process a GIF there too. I share that mostly as apprehension with going too fast on this area too soon. I know @fcoveram has had a lot of thoughts around the media library, and those thoughts should likely extend here as well. For example I outline a loose idea of showing an "upload tray" that can both surface retry options and give status information for enqueued processing actions that are bulk-added. My instinct would go the same way with this. That means I'd also show any progressbars inside such a tray, rather than on the block itself. E.g. what would it look like if you uploaded dancing-megaman, a 26x26px piece of pixel art? The progressbar would not be visible. For that reason, I'd keep the image must fading in and out, if possible with a blurred version of itself as a backdrop, and have the actual progressbar happen in the aforementioned tray. But that's a vague vision that needs a bit more clarity before committing. So looking at the issue which is valid: can we still use UploadProgressSnackbar, but make it determinate? If we have to, we can replace the Spinner inside with ProgressBar, which should be possible to make determinate. What do you think? |
Generally I like this direction, maybe even show "Processing" or some similar verb instead of uploading during this phase.
I've been experimenting with leveraging the client side media code in the classic media screen (including GIF -> Video support): |
… block Per review feedback, keep the block canvas treatment as-is (a progress bar overlaid on the block would be invisible on small images) and make the upload progress snackbar determinate instead: while the GIF-to-video conversion reports progress, the spinner is replaced with a ProgressBar and the label switches from Uploading to Processing. Remove the now-unused getProgressById selector; consumers read per-item progress directly off the queue items returned by getItems().
|
@jasmussen - I tried moving the progress indicator to the snackbar in 2970d39: the block canvas is untouched now (the image keeps its existing fade), and Since progress now lives on the upload queue item itself (readable via Screenshots
|
|
Honestly that looks pretty good at a glance! Did you make the actual progressbar hairline thicker? It's intentionally 1.5px which is small but visible and elegant. If it's unchanged, IMO, this could work. I still think there's a larger vision we can unpack at a later time. |
The height is set explicitly in https://github.com/WordPress/gutenberg/pull/80329/changes#diff-96ffb1246440442d4d45343faaa6ee39c03d36f5757ee78124ad42a94e2abe51R28, I will try removing that height style to capture a screenshot of what it looks like without that. |
|
Height removed:
I think thats about 2px vs 4 px? How does that look @jasmussen? |
The 1.5px hairline is an intentional part of the component's design and reads fine on the snackbar, so drop the 4px height override and keep only the width and foreground-color adjustments.
|
That looks perfect. In general for all our reused componentry, the less CSS we can add on top of it, the better, so it all looks the same across every instance! Nice. |
|
Thanks for the reviews and approval @jasmussen. I'll leave this open a bit longer to get a code review as well, and I think we can land this before the next Beta. |
|
I like the idea of a progress bar and when it displays I quite like the look of it, too. The main issue I've run into in testing is just that for the majority of smaller GIFs I upload the conversion stage is so quick it effectively looks like a flicker, rather than a good bit of visual feedback. I.e. in the following, the progress bar only shows for a frame or two: 2026-07-23.14.17.24.mp4This is probably more of a design question, but if I'm wondering if we should stick with either the spinner or the progress bar, and not switch from spinner to progress bar to spinner? I imagine the blocker to using a progress bar overall is that we then sort of need to bake in the overall progress across the entire upload sequence rather than just the GIF processing stage? |
Came to do some manual testing and I can't see the progress bar at all. I think I'm doing something wrong. I understand there's an upper limit, but I tried:
GIFs, and all only show the upload snackbar, no progress indicator. Kapture.2026-07-23.at.14.31.58.mp4To confirm, I'm using latest Chrome running this branch freshly built. (also checked playground) Here's one of the GIFs I'm using (5.7MB)
|
Ha its too fast now!
@ramonjd Can you confirm the companion video is generated for you (you can watch for it sideloading in the network panel, check your uploads folder or check if you have an option to transform the gif to a video). Note that videos with transparency are not converted. @andrewserong can you also confirm you are getting the conversion working? |
Yep, the videos are being converted to video for me, it's just that the processing stage for some of these test GIFs is so quick. As such, I'd probably suggest we take a look at this PR for 7.2 rather than 7.1 and see if we can have the progress bar contain the whole upload progress between conversion + file uploads etc, rather than switching between spinner + progress bar and back again. One nuance there is that the server-side / non-client-side path will probably never be able to have an accurate progress bar since we don't have the same level of insights into what the real progress will be, so I imagine there'll still be a case where we want to sometimes show progress bar and sometimes a spinner. What do you reckon? Does this change feel like a must have for 7.1? |
Thanks for the help. I used a different gif from https://commons.wikimedia.org/wiki/Category:Animated_GIF_files_between_50_MP_and_100_MP and now I can reproduce what @andrewserong is experience. mp4 is being generated fine 👍🏻 This is a 15MB GIF: Kapture.2026-07-24.at.13.02.49.mp4 |
Nope. For sure lets punt to 7.2. I'm curious if you throttle your CPU (in the performance tab) can you get the progress bar to display? I think the optimization PRs just made it really efficient so maybe we don't even need this. |
|
If we decide to enable Animated GIF sub-sizes, the processing time increases dramatically so we may want to show progress... but the indicator may be more of a "processing image X of Y" string vs a bar. |
Yeah, funnily enough CPU throttling (even by 20x) doesn't make much of a difference to the duration of when the progress bar is showing for me 🤷
Gotcha, yeah, sounds like a good thing to review all together when we pick up that work for 7.2 👍 |
Interesting... I'll give it another test! |






What?
Fixes #80325.
Shows determinate progress in the editor's upload progress snackbar while an animated GIF is being converted to a video: the snackbar's spinner is replaced with a determinate
ProgressBarand the label switches from "Uploading" to "Processing". The block canvas is untouched - the image keeps its existing fade treatment.Follows the direction in this review comment: an earlier iteration overlaid the progress bar on the Image block itself, which doesn't scale to small images and puts per-item processing UI on the block rather than in the shared upload surface.
Why?
Converting a long animated GIF to a video (#76942, #80072) can take tens of seconds: every frame is decoded and re-encoded via WebCodecs. #80260 fixed the outright hang, but during a legitimately long conversion the author only sees an indeterminate spinner with no indication of how far along the conversion is or whether it is making progress at all.
Exact progress is available for free: the conversion loop reads the total frame count up front (
ImageDecodertrack.frameCount) and processes frames one at a time, soframesDone / frameCountis precise. Encoder backpressure happens inside the same loop, so the frame index tracks wall-clock progress closely.How?
Data layer:
convertGifToVideo()in@wordpress/video-conversionaccepts an optionalonProgresscallback reporting a 0–1 fraction. It is throttled to whole-percent increments so a thousand-frame GIF doesn't flood the worker message channel. The worker RPC layer (comctx) proxies top-level function arguments across the worker boundary, so the callback passes straight through.transcodeGifItem()in@wordpress/upload-mediadispatches the previously dormantupdateItemProgress()action from that callback. (QueueItem.progress, theUPDATE_PROGRESSreducer case, andgetItemProgress()already existed with no producers or consumers.) Dispatches are additionally time-gated to one per 250ms: without this, a fast conversion emits ~100 reports in a couple of seconds and each dispatch synchronously re-renders every upload-store consumer in the editor, saturating the main thread so the browser never paints the bar. The final report always goes through.getItems()selector; no new store API is added.UI:
UploadProgressSnackbarlooks for a queue item reporting progress below 100 (the conversion runs on a sideload companion item, so the full queue is scanned rather than just the originals it counts). While one exists, the notice icon slot renders a determinateProgressBar(from@wordpress/components) instead of theSpinner, and the label reads "Processing — file.gif" (with the usual "x of y" form for batches).--wp-components-color-foregroundcustom property, 4px tall, 48px wide) and the notice text is indented to clear the wider icon slot.Out of scope: network upload progress for the resulting video file (
apiFetchdoesn't expose upload progress; for long GIFs the conversion phase dominates).Testing Instructions
The states can also be reviewed in Storybook:
Editor/UploadProgressSnackbar.Unit tests:
Note: there is no e2e assertion for the transient Processing state because conversion of the small e2e GIF fixtures completes in well under a second, which would make the assertion flaky. The data flow (worker progress reports, throttling, snackbar states) is covered by unit tests.
Screenshots
(Updated screenshot of the snackbar's Processing state incoming.)