Skip to content

fix: avoid progress bar oscillation during bulk actions#143

Merged
tfwright merged 1 commit into
mainfrom
fix/bulk-action-progress-flashing
May 11, 2026
Merged

fix: avoid progress bar oscillation during bulk actions#143
tfwright merged 1 commit into
mainfrom
fix/bulk-action-progress-flashing

Conversation

@tfwright
Copy link
Copy Markdown
Owner

@tfwright tfwright commented May 11, 2026

Summary

Two related issues in the bulk action handler on the index page (LiveAdmin.Components.Container.Index):

1. Progress bar oscillation

The handle_event("action", ...) handler wraps each selected record's processing in try/rescue/after, with the after clause broadcasting progress: 1 for the job pid. Because that block sits inside the Enum.each loop over socket.assigns.selected, progress: 1 is broadcast after every record — not once when the batch completes.

The nav jobs LiveView (LiveAdmin.Components.Nav.Jobs) treats any progress >= 1 message as completion: it snaps the bar to 100% and schedules a :remove_job 1500 ms later. Before that fires, the next iteration broadcasts a partial idx / count, which the handler matches by pid and resets the bar back down. Visually that's a progress bar oscillating between full and partial across the duration of the bulk action.

Additionally, the body used Enum.with_index/1 (zero-based), so per-iteration progress was 0/n .. (n-1)/n — the bar could never reach 100% from the body, only from the spurious after.

2. Inaccurate error message

The per-record rescue announces "%{name} encountered an error and stopped" — but the surrounding Enum.each does not stop. The loop continues processing subsequent records after an error, contradicting the message and (more importantly) running an action that has already proven unsafe for the current batch.

Fix

  • Drop the after clause entirely. With Enum.with_index(1) and dividing by a hoisted total, per-iteration progress climbs 1/n .. n/n and reaches 100% naturally on the last record. If the loop halts or the task crashes, the nav jobs LiveView already monitors the task pid and cleans up the entry on :DOWN.
  • Switch Enum.each to Enum.reduce_while, halting with :error when a record raises. The final announcement (complete vs encountered an error and stopped) is chosen based on the reduce result.

Test plan

  • mix format --check-formatted passes
  • mix credo passes
  • mix test test/live_admin/components/container_test.exs — 30/30 pass
  • Manually verify: selecting multiple records and running an action shows a smoothly progressing bar (no flashing between full and partial)
  • Manually verify: when a record's action raises, the loop halts and remaining records are not processed

@tfwright tfwright force-pushed the fix/bulk-action-progress-flashing branch 2 times, most recently from 1470b7b to 154b57f Compare May 11, 2026 23:28
The action handler on the index page wrapped each record in
try/rescue/after, so the `after` clause broadcast progress: 1
after every record — making the active jobs nav flash between
the partial and complete states across iterations. Drop the
after clause and rely on the per-iteration progress broadcast,
indexing from 1 so it reaches 100% naturally on the last record.
On a halted/crashed run, the nav already cleans up via the
:DOWN monitor on the task pid.

Also switch from Enum.each to Enum.reduce_while so the loop
actually halts on a record-level error, matching the
"encountered an error and stopped" message that gets announced.
@tfwright tfwright force-pushed the fix/bulk-action-progress-flashing branch from 154b57f to 95cba7b Compare May 11, 2026 23:29
@tfwright tfwright marked this pull request as ready for review May 11, 2026 23:38
@tfwright tfwright merged commit bb0c3a0 into main May 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant