fix(web): every change to the task list builds a new array
Ticking a task off never removed its row. The optimistic update ran, the
request went out, the server answered 200 — and the view did not move.
The same applied to a change arriving over the websocket, which is how
somebody else's edit was supposed to show up. It had never worked.
The common factor was tasks[i] = value. push and whole-array assignment
both reached the views; index assignment did not. Rather than depend on
which mutations the reactivity happens to see through, every write now
goes through app.replace() or app.upsert(), which build a new array. The
lists are at most a few hundred rows and the copy is not worth a moment's
thought next to the class of bug it removes.
upsert exists because the same task arrives twice: once as the response
to the request that created it, and once over the socket, which publishes
to the whole project including whoever did it. Either can land first, and
appending both puts two rows with one id into a keyed {#each} — not a
duplicated row but a thrown error that stops the view rendering.
complete, reopen and update were three copies of the same twenty lines;
they are now one private helper.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Kristian Wind
co-authored by
Claude Opus 5
parent
68d82a1cb6
commit
fc4dba8549
@@ -51,30 +51,29 @@
|
||||
draggingId = null;
|
||||
if (!id || !canEdit) return;
|
||||
|
||||
const task = app.tasks.find((t) => t.id === id);
|
||||
const task = app.get(id);
|
||||
if (!task || (task.section_id ?? '') === sectionId) return;
|
||||
|
||||
// Optimistic: the card is in the new column before the request goes out,
|
||||
// because a card that snaps back for 200ms reads as a failed drop.
|
||||
const previous = { ...task };
|
||||
const index = app.tasks.findIndex((t) => t.id === id);
|
||||
app.tasks[index] = { ...task, section_id: sectionId };
|
||||
app.replace(id, { ...task, section_id: sectionId });
|
||||
|
||||
try {
|
||||
// Dropped at the end of the column: the task after it is nothing, and
|
||||
// the one before it is whatever was last there.
|
||||
const existing = tasksIn(sectionId).filter((t) => t.id !== id);
|
||||
const after = existing.at(-1);
|
||||
const updated = await api.moveTask(id, {
|
||||
project_id: project.id,
|
||||
section_id: sectionId,
|
||||
after_id: after?.id ?? ''
|
||||
});
|
||||
const i = app.tasks.findIndex((t) => t.id === id);
|
||||
if (i >= 0) app.tasks[i] = updated;
|
||||
} catch (e) {
|
||||
const i = app.tasks.findIndex((t) => t.id === id);
|
||||
if (i >= 0) app.tasks[i] = previous;
|
||||
app.replace(
|
||||
id,
|
||||
await api.moveTask(id, {
|
||||
project_id: project.id,
|
||||
section_id: sectionId,
|
||||
after_id: after?.id ?? ''
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
app.replace(id, previous);
|
||||
app.toast('Kunne ikke flytte opgaven.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user