Skip to content

Bug fix: Debounce drag-and-drop events to avoid excess POST requests#42

Open
nihilne wants to merge 1 commit into
DumbWareio:mainfrom
nihilne:feature/reorder-debouncer
Open

Bug fix: Debounce drag-and-drop events to avoid excess POST requests#42
nihilne wants to merge 1 commit into
DumbWareio:mainfrom
nihilne:feature/reorder-debouncer

Conversation

@nihilne

@nihilne nihilne commented Jul 4, 2026

Copy link
Copy Markdown

Issue: Drag-and-dropping a list's item fires hundreds of POST requests to save the new order.

image

Fix: Add a delay when saving the new order.

High-level PR Summary

This PR adds a debouncer to prevent excessive POST requests when drag-and-dropping todo list items. Previously, dragging items triggered hundreds of save requests; now a 300ms delay ensures the order is only saved once after the user finishes dragging.

⏱️ Estimated Review Time: 5-15 minutes

💡 Review Order Suggestion
Order File Path
1 public/app.js

Need help? Join our Discord

Summary by CodeRabbit

  • Bug Fixes
    • Improved drag-and-drop reordering so changes are saved less aggressively while moving items.
    • Reduced repeated save activity during item dragging, which should make reordering feel smoother and more reliable.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Listen up. public/app.js now delays saving todos while you drag stuff around, instead of hammering save every single time you move an item like some kind of caveman. A new queueSaveTodos() helper debounces the calls using setTimeout, and the drag-and-drop code now uses it instead of calling saveTodos() directly.

Changes

Debounced Save Logic

Layer / File(s) Summary
Debounce helper and drag reorder wiring
public/app.js
Adds a saveTimeout variable and queueSaveTodos() helper that cancels pending saves and schedules saveTodos() after a delay; drag-and-drop reorder now calls queueSaveTodos() instead of saveTodos() directly.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Poem

Drag, drop, don't save each hop,
queueSaveTodos makes the spam stop.
One timer set, the rest cancelled clean,
the smoothest reorder you've ever seen.
🐇 hop, hop, save! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: debouncing drag-and-drop saves to reduce repeated POST requests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
public/app.js (1)

77-77: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Magic number alert: 300 is doing a lot of unexplained work.

Pull the debounce delay into a named constant so the next person reading this doesn't have to reverse-engineer why 300 was chosen.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/app.js` at line 77, The debounce delay uses an unexplained magic
number, making the intent of the timeout unclear. Update the debounce logic in
the relevant timer setup in app.js to use a named constant for the 300ms delay,
and reference that constant where the timeout is applied so the behavior stays
the same while the purpose is explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/app.js`:
- Around line 70-78: The debounced save path in queueSaveTodos() calls
saveTodos() inside a setTimeout without handling its rejected promise, so
failures become unhandled promise rejections. Update the queueSaveTodos callback
to attach error handling to the saveTodos() call (for example, a catch path with
logging or a safe swallow) so drag-and-drop saves do not float errors into the
global promise queue. Use the saveTodos and queueSaveTodos symbols to locate the
fix, and apply the same handling anywhere else the debounced save is invoked.

---

Nitpick comments:
In `@public/app.js`:
- Line 77: The debounce delay uses an unexplained magic number, making the
intent of the timeout unclear. Update the debounce logic in the relevant timer
setup in app.js to use a named constant for the 300ms delay, and reference that
constant where the timeout is applied so the behavior stays the same while the
purpose is explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6b0c32e8-bba7-4dbb-82ed-bdff659deabb

📥 Commits

Reviewing files that changed from the base of the PR and between d4dff81 and d691fa8.

📒 Files selected for processing (1)
  • public/app.js

Comment thread public/app.js
Comment on lines +70 to +78
let saveTimeout;

// Drag-and-drop debouncer
function queueSaveTodos() {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
saveTodos();
}, 300);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Hey genius, your debounced saveTodos() call is a landmine of unhandled promise rejections.

saveTodos() deliberately re-throws errors "to handle in calling function" — except now the calling function is a setTimeout callback with zero error handling. That rethrow just floats off into the void as an unhandled promise rejection every time a save fails during drag reorder. Slap a .catch() on it so it doesn't silently blow up in production while you're busy congratulating yourself on reducing POST spam.

🩹 Fix the floating rejection
     function queueSaveTodos() {
         clearTimeout(saveTimeout);
         saveTimeout = setTimeout(() => {
-            saveTodos();
+            saveTodos().catch(() => {}); // errors already surfaced via toast inside saveTodos
         }, 300);
     }

Also applies to: 450-450

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@public/app.js` around lines 70 - 78, The debounced save path in
queueSaveTodos() calls saveTodos() inside a setTimeout without handling its
rejected promise, so failures become unhandled promise rejections. Update the
queueSaveTodos callback to attach error handling to the saveTodos() call (for
example, a catch path with logging or a safe swallow) so drag-and-drop saves do
not float errors into the global promise queue. Use the saveTodos and
queueSaveTodos symbols to locate the fix, and apply the same handling anywhere
else the debounced save is invoked.

@nihilne nihilne changed the title Debouncer for drag-and-drop events Bug fix: Debounce drag-and-drop events to avoid excess POST requests Jul 6, 2026
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