From b191a60b7f448ef84ddcb6f6de06e5f1fa6aae52 Mon Sep 17 00:00:00 2001 From: Ruud Andriessen Date: Tue, 10 Mar 2026 22:17:00 +0100 Subject: [PATCH] fix(tasks): sync partial task field updates --- src/lib/collections.ts | 29 +++++++++++++++++++++++++---- src/server/functions/tasks.ts | 18 +++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/lib/collections.ts b/src/lib/collections.ts index 32fb011..e56cc71 100644 --- a/src/lib/collections.ts +++ b/src/lib/collections.ts @@ -76,6 +76,22 @@ function txidsToMatch(txids: Array) { return { txid: txids }; } +const taskFieldMap: Record> = { + title: "title", + runnerType: "runner_type", + runnerSessionId: "runner_session_id", + workspacePath: "workspace_path", + error: "error", +}; + +function getTaskUpdateInput(changes: Partial): Record { + return Object.fromEntries( + Object.entries(taskFieldMap) + .filter(([, snakeKey]) => changes[snakeKey] !== undefined) + .map(([camelKey, snakeKey]) => [camelKey, changes[snakeKey]]), + ); +} + function createCollections(baseUrl: string) { const projectsCollection = createCollection( electricCollectionOptions({ @@ -157,12 +173,17 @@ function createCollections(baseUrl: string) { const txids: Array = []; for (const mutation of transaction.mutations) { - const title = mutation.modified.title.trim(); - if (title.length === 0) { - throw new Error("Task title cannot be empty"); + const changes = getTaskUpdateInput(mutation.changes); + if (Object.keys(changes).length === 0) { + continue; } - const { txid } = await updateTask({ data: { taskId: String(mutation.key), title } }); + const { txid } = await updateTask({ + data: { + taskId: String(mutation.key), + ...changes, + }, + }); if (txid !== undefined) { txids.push(txid); } diff --git a/src/server/functions/tasks.ts b/src/server/functions/tasks.ts index 146646d..1770bb0 100644 --- a/src/server/functions/tasks.ts +++ b/src/server/functions/tasks.ts @@ -118,7 +118,11 @@ export const updateTask = createServerFn({ method: "POST" }) .inputValidator( z.object({ taskId: z.string(), - title: z.string(), + title: z.string().optional(), + runnerSessionId: z.string().nullable().optional(), + runnerType: z.string().nullable().optional(), + workspacePath: z.string().nullable().optional(), + error: z.string().nullable().optional(), }), ) .handler(async ({ data: input, context }) => { @@ -134,16 +138,20 @@ export const updateTask = createServerFn({ method: "POST" }) notFound("Task not found"); } - const title = input.title.trim(); - if (title.length === 0) { - badRequest("title is required"); + const { taskId: _, ...fields } = input; + const updates = Object.fromEntries( + Object.entries(fields).filter(([, v]) => v !== undefined), + ) as Partial; + + if (Object.keys(updates).length === 0) { + badRequest("No task fields to update"); } const result = await withTransaction(db, async (tx, txid) => { const updatedAt = Date.now(); await tx .update(schema.tasks) - .set({ title, updatedAt }) + .set({ ...updates, updatedAt }) .where(and(eq(schema.tasks.id, input.taskId), eq(schema.tasks.organizationId, orgId))); const updatedTask = await tx.query.tasks.findFirst({