Skip to content

VideoPress: show a deleting progress state in the dashboard library#49558

Open
vianasw wants to merge 3 commits into
trunkfrom
update/videopress-delete-media-progress-indicator
Open

VideoPress: show a deleting progress state in the dashboard library#49558
vianasw wants to merge 3 commits into
trunkfrom
update/videopress-delete-media-progress-indicator

Conversation

@vianasw

@vianasw vianasw commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Fixes VIDP-251 (CFT feedback item VP09, reported in #49485)

Proposed changes

Deleting media from the modernized VideoPress dashboard gave no feedback until the listing refetched, so the action felt frozen — especially noticeable because the backend also removes the remote VideoPress copy, which takes a while.

  • Row-level "Deleting…" state in both layouts. A new 'deleting' upload status rides the same in-flight channel as 'promoting': the grid shows a "Deleting…" overlay with an indeterminate progress bar on each affected card, the table shows a "Deleting…" pill next to the title. Rows mid-delete are non-interactive (no title link, no thumbnail click-through, no eligible row actions), so a slow delete can't be double-fired or raced by an edit.
  • No flash-back before removal. The delete mutation invalidates the library cache on settle and returns the invalidation promise, so the overlay is only cleared after the refetched listing has actually dropped the rows.
  • Parallel bulk deletes. Bulk deletions now run via Promise.allSettled instead of a sequential await loop — directly addressing the "slow" half of the complaint. Partial failures reject with a DeleteVideosError carrying the failed ids: the error notice reports a precise count ("Failed to delete 1 video."), failed rows return to their normal interactive state and stay selected, successful ones disappear.
  • Resilient lifecycle handling. Cleanup runs off the mutateAsync promise rather than mutate-level callbacks, which TanStack silently drops when another mutation starts on the same observer (overlapping deletes) or the component unmounts mid-flight. The cache invalidation excludes per-item queries so the details page no longer refetches the id it just deleted (a guaranteed 404 + retry that would stall navigation).
  • Details page feedback. The video details screen shows a persistent "Deleting video…" snackbar while the delete is in flight, guards against double-fire, and skips the post-delete navigation to Library if the user has already navigated away.

Known cosmetic limitation: if every selectable row is mid-delete, DataViews briefly collapses the bulk-selection checkbox column until the rows are removed. Transient and harmless.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No.

Testing instructions

Requires the modernized VideoPress dashboard (add_filter( 'rsm_jetpack_ui_modernization_videopress', '__return_true' );) and a site with VideoPress videos.

  • Go to Jetpack → VideoPress → Library (grid layout).
  • Open a video's actions menu (⋯) and choose Delete. The card should immediately show a "Deleting…" overlay with a progress bar; its actions button should become disabled. When the deletion completes, the row disappears and a "1 video deleted." snackbar appears — the overlay never flashes back to a normal card first.
  • Switch to the table layout, select several videos and use the bulk Delete action. Each affected row should show a "Deleting…" pill next to its title; deletions run in parallel.
  • To verify the failure path, make a deletion fail (e.g. block the DELETE /wp/v2/media/{id} request in devtools). The failed row should return to its normal interactive state, stay selected, and an error notice with the failed count should appear.
  • Open a video's details page, use ⋯ → Delete video. A "Deleting video…" snackbar should appear immediately and stay until the delete settles, then you're navigated back to the Library with a success notice.

Screenshots (captured on a local site with mocked media responses; the delete request is stalled 8s to make the in-flight state visible)

Grid — before Grid — deleting
grid before grid deleting
Table — deleting Table — delete failed (row restored + precise error)
table deleting table failed

Unit tests: cd projects/packages/videopress && pnpm test (covers parallel deletion + partial-failure contract, the deleting render states in both layouts, action eligibility while deleting, and the cache-invalidation predicate).

🤖 Generated with Claude Code

Deleting media from the modernized VideoPress dashboard gave no
feedback until the listing refetched, so the action felt frozen
(CFT item VP09).

- Add a 'deleting' upload status that rides the same in-flight
  channel as 'promoting': rows get a "Deleting…" overlay with an
  indeterminate progress bar in the grid layout and a "Deleting…"
  pill in the table layout, and stay non-interactive (no title
  link, no thumbnail button, no eligible row actions) until the
  refetched listing removes them.
- Run bulk deletions in parallel (Promise.allSettled) instead of
  sequentially, and reject with a DeleteVideosError carrying the
  failed ids so partial failures report a precise count and keep
  the surviving rows selected.
- Invalidate the library cache on settle and await the refetch
  before clearing the overlay so rows never flash back to their
  normal state ahead of removal; scope the invalidation away from
  item queries so the details page doesn't refetch the id it just
  deleted.
- React via the mutateAsync promise instead of mutate-level
  callbacks, which TanStack drops when another mutation starts on
  the same observer or the component unmounts mid-flight.
- Details page: show a persistent "Deleting video…" snackbar while
  the delete is in flight, guard against double-fire, and skip the
  post-delete navigation if the user already left the page.

Fixes VIDP-251.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vianasw vianasw added the [Status] Needs Review This PR is ready for review. label Jun 11, 2026
@vianasw vianasw self-assigned this Jun 11, 2026
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the update/videopress-delete-media-progress-indicator branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack update/videopress-delete-media-progress-indicator

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

@vianasw

vianasw commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Notes from the review (verified non-blocking): the mutateAsync promise-chain lifecycle, the onSettled-awaited cache invalidation, the partial-failure restore behavior, and the StrictMode-safe isMountedRef pattern were all double-checked against the TanStack Query v5 source and confirmed correct.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@jp-launch-control

jp-launch-control Bot commented Jun 11, 2026

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 4 files.

File Coverage Δ% Δ Uncovered
projects/packages/videopress/src/dashboard/components/library/fields.tsx 24/44 (54.55%) 2.16% 0 💚
projects/packages/videopress/src/dashboard/hooks/use-delete-video.ts 18/18 (100.00%) 0.00% 0 💚
projects/packages/videopress/src/dashboard/hooks/use-library.ts 46/58 (79.31%) 0.36% 0 💚
projects/packages/videopress/src/dashboard/components/library/actions.ts 8/27 (29.63%) 29.63% -9 💚

1 file is newly checked for coverage.

File Coverage
projects/packages/videopress/src/dashboard/test-utils/library-item.ts 1/1 (100.00%) 💚

Full summary · PHP report · JS report

vianasw and others added 2 commits June 11, 2026 17:27
Cleanup pass over the previous commit, no behavior changes:

- Hoist the duplicated LibraryItem test fixture into
  test-utils/library-item.ts and reuse it in both library test suites.
- Merge the promoting/deleting thumbnail overlays into one block (they
  differed only in the label).
- Replace the settle notices' remove-then-create dance with same-id
  replacement (the notices store drops an existing notice with the
  same id on create).
- Flip isVideoPressIdle from a status blocklist to an allowlist on
  'idle', matching the other render sites, so future statuses are
  excluded from row actions by default.
- Flatten the value-threaded .then/.catch/.then chain in deleteItems
  into async/await with a linear cleanup tail; hoist the requested-ids
  Set out of the selection filter.
- Drop the no-op size guard around the renderedItems overlay map.
- Share the item-query key segment between use-video and the delete
  hook's invalidation predicate instead of re-encoding 'item' at each
  site.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
From a recall-mode review pass over the branch:

- Drop deleted ids' item-detail queries from the cache on settle.
  Invalidating doesn't help (the refetch 404s and stale data is
  retained), so a cached entry let a back-navigation render a ghost
  editor for a deleted video.
- Key the details page's in-progress notice by video id so two
  overlapping deletes (start one, navigate away mid-flight, delete
  another) can't replace each other's notices.
- Disable Save on the details page while a delete is in flight so a
  slow delete can't be raced by a meta update.
- Announce library deletes to screen readers: the row overlay/pill is
  purely visual, so surface an in-progress notice (replaced in place
  by the settle notice) matching the details-page pattern.
- Finish the LIBRARY_ITEM_QUERY_SEGMENT migration in
  use-update-video-meta and use-update-video-poster, which still
  hardcoded 'item'.
- Changelog type fixed → added (new UI state + behavior change, not a
  bug fix).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@CGastrell CGastrell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed both commits (initial implementation + the bdff83a cleanup pass). The deleting-progress flow is carefully designed and well-tested.

Verified against source:

  • Cache invalidation predicate correctly excludes item-detail queries (LIBRARY_ITEM_QUERY_SEGMENT), avoiding the 404+retry stall on the details page; mutateAsync + onSettled returning the invalidation promise keeps the "Deleting…" overlay until the refetched listing actually drops the rows — no flash-back.
  • Parallel Promise.allSettled + DeleteVideosError partial-failure contract is sound: failed rows restore to interactive and stay selected, successful ones disappear.
  • Non-interactivity while deleting is enforced at every render site (action eligibility, title link, thumbnail button).
  • Same-id notice replacement on the details page is correct — @wordpress/notices drops the existing same-id notice on create, so the explicitDismiss snackbar is cleanly replaced (no orphan).

The cleanup commit is a strict improvement (flattened async/await, merged overlay block, shared query-key constant, hoisted test fixture, allowlist-on-idle eligibility) with no regressions.

LGTM 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants