ML-169.10: add optimistic delete UI fix task
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
id: ML-169.10
|
||||||
|
title: "Fix: Missing optimistic UI for delete operations"
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: "2026-05-19 11:48"
|
||||||
|
labels:
|
||||||
|
- perf
|
||||||
|
- fix
|
||||||
|
- ux
|
||||||
|
dependencies: []
|
||||||
|
references:
|
||||||
|
- >-
|
||||||
|
backlog/documents/doc-27 -
|
||||||
|
Phase-4-Performance-Audit-Low-Hanging-Fruit-Findings.md
|
||||||
|
modified_files:
|
||||||
|
- lib/music_library_web/live_helpers/index_actions.ex
|
||||||
|
- lib/music_library_web/live/collection_live/show.ex
|
||||||
|
- lib/music_library_web/live/scrobbled_tracks_live/index.ex
|
||||||
|
parent_task_id: ML-169
|
||||||
|
priority: medium
|
||||||
|
ordinal: 31000
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
|
||||||
|
Add optimistic UI for delete operations so the UI removes items immediately without waiting for the database transaction.
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
All delete operations wait for the database transaction to complete before updating the UI. `stream_delete` is already used in some places, but the pattern is inconsistent. CollectionLive.Show deletes don't use `stream_delete` at all (they navigate away).
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `lib/music_library_web/live_helpers/index_actions.ex:94-98` — `handle_delete`
|
||||||
|
- `lib/music_library_web/live/collection_live/show.ex:381-385` — `handle_event("delete")`
|
||||||
|
- `lib/music_library_web/live/scrobbled_tracks_live/index.ex:305-310` — `handle_event("delete")`
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
Adds unnecessary latency to delete operations that could feel instant. While delete failures are rare, the benefit of snappy UI is worth the minimal risk.
|
||||||
|
|
||||||
|
## Fix
|
||||||
|
|
||||||
|
Use `stream_delete` immediately, then perform the DB operation async. If DB fails, re-insert the item and show error toast.
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
def handle_delete(socket, id) do
|
||||||
|
record = Records.get_record!(id)
|
||||||
|
socket = stream_delete(socket, :records, record)
|
||||||
|
Task.start(fn -> Records.delete_record(record) end)
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
|
||||||
|
- [ ] #1 Delete operations remove items from UI immediately (no DB wait)
|
||||||
|
- [ ] #2 Database delete still executes successfully in background
|
||||||
|
- [ ] #3 If DB delete fails, item is re-inserted into stream and error toast shown
|
||||||
|
- [ ] #4 Existing delete confirmation modal still works correctly
|
||||||
|
- [ ] #5 No orphaned UI state after failed delete
|
||||||
|
<!-- AC:END -->
|
||||||
Reference in New Issue
Block a user