fix(bulk-delete): snapshot targets and bail on first failure

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.
This commit is contained in:
Claude 2026-04-17 16:25:03 +00:00
parent d213e523ec
commit 5869c305aa
No known key found for this signature in database
2 changed files with 12 additions and 2 deletions

View file

@ -120,7 +120,12 @@
async function executeDeleteCompletedSubtasks() { async function executeDeleteCompletedSubtasks() {
confirmDeleteCompleted = false; confirmDeleteCompleted = false;
showSubtaskMenu = 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) { function handleSubtaskMenuClickOutside(e: MouseEvent) {

View file

@ -100,7 +100,12 @@
async function executeDeleteCompleted() { async function executeDeleteCompleted() {
confirmDeleteCompleted = false; 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() { function promptDeleteList() {