From 5869c305aa1863f1a2fb73144d1b507fefdad4b1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Apr 2026 16:25:03 +0000 Subject: [PATCH] fix(bulk-delete): snapshot targets and bail on first failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit executeDeleteCompleted and executeDeleteCompletedSubtasks iterated over the reactive completedTasks/completedSubtasks lists with no error handling: the array shrinks with every successful delete, skipping subsequent entries, and a failed delete silently left a half-deleted state. Snapshot the target list up front and abort as soon as a delete returns false — matching the subtask-cascade path. --- apps/tauri/src/lib/components/TaskDetailView.svelte | 7 ++++++- apps/tauri/src/lib/screens/TasksScreen.svelte | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/tauri/src/lib/components/TaskDetailView.svelte b/apps/tauri/src/lib/components/TaskDetailView.svelte index 39c8571..c5e0a32 100644 --- a/apps/tauri/src/lib/components/TaskDetailView.svelte +++ b/apps/tauri/src/lib/components/TaskDetailView.svelte @@ -120,7 +120,12 @@ async function executeDeleteCompletedSubtasks() { confirmDeleteCompleted = false; showSubtaskMenu = false; - for (const s of completedSubtasks) await app.deleteTask(s.id); + // Snapshot — completedSubtasks is reactive and shrinks as we delete. + // Bail on first failure so we don't silently leave a partial delete. + const targets = [...completedSubtasks]; + for (const s of targets) { + if (!(await app.deleteTask(s.id))) return; + } } function handleSubtaskMenuClickOutside(e: MouseEvent) { diff --git a/apps/tauri/src/lib/screens/TasksScreen.svelte b/apps/tauri/src/lib/screens/TasksScreen.svelte index c068cae..362bcdc 100644 --- a/apps/tauri/src/lib/screens/TasksScreen.svelte +++ b/apps/tauri/src/lib/screens/TasksScreen.svelte @@ -100,7 +100,12 @@ async function executeDeleteCompleted() { confirmDeleteCompleted = false; - for (var t of app.completedTasks) await app.deleteTask(t.id); + // Snapshot targets first — deletes mutate app.completedTasks reactively. + // Bail on first failure so we don't silently leave a partial delete. + const targets = [...app.completedTasks]; + for (const t of targets) { + if (!(await app.deleteTask(t.id))) return; + } } function promptDeleteList() {