3.6 KiB
id, title, status, assignee, created_date, updated_date, labels, dependencies, references, modified_files, parent_task_id, priority, ordinal
| id | title | status | assignee | created_date | updated_date | labels | dependencies | references | modified_files | parent_task_id | priority | ordinal | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ML-169.10 | Fix: Async optimistic UI for index/list delete streams | To Do | 2026-05-19 11:48 | 2026-05-20 09:41 |
|
|
|
ML-169 | medium | 31000 |
Description
Add optimistic UI for delete operations only where the item is rendered from a LiveView stream on an index/list page. The item should be removed from the stream immediately, while the database delete runs through LiveView-owned async handling so failures can be reported and rolled back.
Problem
Index/list delete handlers currently wait for the database delete before updating the UI. stream_delete is used after the delete succeeds, so the interaction can feel slower than necessary.
This task is intentionally scoped to stream-backed list views only:
- Collection index and wishlist index record streams via
IndexActions.handle_delete/2 - Scrobbled tracks index stream
Show-page deletes are out of scope. CollectionLive.Show and WishlistLive.Show navigate away after delete and do not have a list stream to optimistically update. Their failure and rollback behavior should remain synchronous unless a separate navigation-specific design is created.
Files
lib/music_library_web/live_helpers/index_actions.ex— remove record from:recordsimmediately and start a LiveView async delete operationlib/music_library_web/live/collection_live/index.ex— handle async record delete success/failure for collection indexlib/music_library_web/live/wishlist_live/index.ex— handle async record delete success/failure for wishlist indexlib/music_library_web/live/scrobbled_tracks_live/index.ex— remove track from:tracksimmediately and handle async track delete success/failure
Fix
Use LiveView-owned async handling (start_async/3 plus handle_async/3, or an equivalent pattern that sends results back to the LiveView process). Do not use bare Task.start/1, because it cannot update the socket, reinsert the stream item, or show an error toast.
Expected behavior:
- Fetch the item needed for rollback.
- Immediately call
stream_delete/3on the relevant stream. - Start an async delete operation owned by the LiveView.
- On success, leave the stream as-is and optionally broadcast/refresh any cross-view state the existing design requires.
- On failure or async exit, reinsert the original item into the stream and show a user-facing error toast.
For error text, use the project’s existing user-facing error conventions (ErrorMessages.friendly_message/1 where an error reason is shown).
Acceptance Criteria
- #1 Index/list delete operations remove the item from the relevant stream before waiting for the database delete
- #2 Database delete still executes through LiveView-owned async handling, not bare
Task.start/1 - #3 Async delete failure or exit reinserts the original item into the stream and shows an error toast
- #4 Existing delete confirmation prompts still work correctly
- #5 Show-page delete handlers are not changed as part of this task
- #6 Collection and wishlist index delete behavior remains shared through
IndexActionswhere practical