From cb43b596b9814a6aec570fc7e481fb92df0fb634 Mon Sep 17 00:00:00 2001 From: Waleed Date: Wed, 29 Apr 2026 22:39:59 -0700 Subject: [PATCH] feat(fork): optimistic sidebar entry + Fork | prefix for forked tasks (#4353) * feat(fork): optimistic sidebar entry + rename to 'Fork | Chat Name' Adds the forked task to the sidebar immediately by writing an optimistic entry into the task list cache in onSuccess, before the background refetch arrives. Without this, the sidebar showed no new task until the invalidation refetch completed after navigation. Also moves the Fork prefix to the front of the name ('Fork | Chat Name') so it is immediately scannable in the sidebar. * fix(fork): cancel in-flight queries before optimistic sidebar write --- .../mothership/chats/[chatId]/fork/route.ts | 4 ++-- apps/sim/hooks/queries/tasks.ts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/api/mothership/chats/[chatId]/fork/route.ts b/apps/sim/app/api/mothership/chats/[chatId]/fork/route.ts index 7a33f2326b..e1e4a70c98 100644 --- a/apps/sim/app/api/mothership/chats/[chatId]/fork/route.ts +++ b/apps/sim/app/api/mothership/chats/[chatId]/fork/route.ts @@ -74,8 +74,8 @@ export const POST = withRouteHandler( : [] const newId = generateId() - const baseTitle = (parent.title ?? 'New task').replace(/ \| Fork$/, '') - const title = `${baseTitle} | Fork` + const baseTitle = (parent.title ?? 'New task').replace(/^Fork \| /, '') + const title = `Fork | ${baseTitle}` const now = new Date() const [newChat] = await db diff --git a/apps/sim/hooks/queries/tasks.ts b/apps/sim/hooks/queries/tasks.ts index 100f891c36..e336f6e85d 100644 --- a/apps/sim/hooks/queries/tasks.ts +++ b/apps/sim/hooks/queries/tasks.ts @@ -609,6 +609,25 @@ export function useForkTask(workspaceId?: string) { const queryClient = useQueryClient() return useMutation({ mutationFn: forkChat, + onSuccess: async (data, variables) => { + await queryClient.cancelQueries({ queryKey: taskKeys.list(workspaceId) }) + const existing = queryClient.getQueryData(taskKeys.list(workspaceId)) + if (existing) { + const sourceTask = existing.find((t) => t.id === variables.chatId) + const baseName = (sourceTask?.name ?? 'New task').replace(/^Fork \| /, '') + const optimisticTask: TaskMetadata = { + id: data.id, + name: `Fork | ${baseName}`, + updatedAt: new Date(), + isActive: false, + isUnread: false, + } + queryClient.setQueryData(taskKeys.list(workspaceId), [ + optimisticTask, + ...existing, + ]) + } + }, onSettled: () => { queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) }) },