Skip to content

Commit f62d274

Browse files
authored
fix(mothership): stabilize task sidebar ordering on selection (#4309)
1 parent 65e17de commit f62d274

4 files changed

Lines changed: 13 additions & 19 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,7 @@ const SidebarTaskItem = memo(function SidebarTaskItem({
206206
e.preventDefault()
207207
onMultiSelectClick(task.id, true)
208208
} else {
209-
useFolderStore.setState({
210-
selectedTasks: new Set<string>(),
211-
lastSelectedTaskId: task.id,
212-
})
209+
useFolderStore.getState().selectTaskOnly(task.id)
213210
}
214211
}}
215212
onContextMenu={task.id !== 'new' ? (e) => onContextMenu(e, task.id) : undefined}

apps/sim/hooks/queries/tasks.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
1+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
22
import type { PersistedMessage } from '@/lib/copilot/chat/persisted-message'
33
import { normalizeMessage } from '@/lib/copilot/chat/persisted-message'
44
import {
@@ -254,7 +254,6 @@ export function useTasks(workspaceId?: string) {
254254
queryKey: taskKeys.list(workspaceId),
255255
queryFn: ({ signal }) => fetchTasks(workspaceId as string, signal),
256256
enabled: Boolean(workspaceId),
257-
placeholderData: keepPreviousData,
258257
staleTime: 60 * 1000,
259258
})
260259
}
@@ -535,6 +534,10 @@ async function markTaskUnread(chatId: string): Promise<void> {
535534

536535
/**
537536
* Marks a task as read with optimistic update.
537+
*
538+
* The server only updates `lastSeenAt`, never `updatedAt`, so we deliberately
539+
* do not invalidate the list cache — that would trigger a refetch that can
540+
* reorder the sidebar if any unrelated server-side update landed in between.
538541
*/
539542
export function useMarkTaskRead(workspaceId?: string) {
540543
const queryClient = useQueryClient()
@@ -556,14 +559,14 @@ export function useMarkTaskRead(workspaceId?: string) {
556559
queryClient.setQueryData(taskKeys.list(workspaceId), context.previousTasks)
557560
}
558561
},
559-
onSettled: () => {
560-
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
561-
},
562562
})
563563
}
564564

565565
/**
566566
* Marks a task as unread with optimistic update.
567+
*
568+
* Same rationale as `useMarkTaskRead` — no list invalidation, since the server
569+
* only flips `lastSeenAt` and the optimistic update fully reflects the change.
567570
*/
568571
export function useMarkTaskUnread(workspaceId?: string) {
569572
const queryClient = useQueryClient()
@@ -585,8 +588,5 @@ export function useMarkTaskUnread(workspaceId?: string) {
585588
queryClient.setQueryData(taskKeys.list(workspaceId), context.previousTasks)
586589
}
587590
},
588-
onSettled: () => {
589-
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
590-
},
591591
})
592592
}

apps/sim/hooks/use-task-events.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,9 @@ describe('handleTaskStatusEvent', () => {
5050
})
5151
})
5252

53-
it('preserves list invalidation when task event payload is invalid', () => {
53+
it('does not invalidate when task event payload is invalid', () => {
5454
handleTaskStatusEvent(queryClient, 'ws-1', '{')
5555

56-
expect(queryClient.invalidateQueries).toHaveBeenCalledTimes(1)
57-
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
58-
queryKey: taskKeys.list('ws-1'),
59-
})
56+
expect(queryClient.invalidateQueries).not.toHaveBeenCalled()
6057
})
6158
})

apps/sim/hooks/use-task-events.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ export function handleTaskStatusEvent(
4141
workspaceId: string,
4242
data: unknown
4343
): void {
44-
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
45-
4644
const payload = parseTaskStatusEventPayload(data)
4745
if (!payload) {
4846
logger.warn('Received invalid task_status payload')
4947
return
5048
}
49+
50+
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
5151
}
5252

5353
/**

0 commit comments

Comments
 (0)