mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
fix(mothership): stabilize task sidebar ordering on selection (#4309)
This commit is contained in:
@@ -206,10 +206,7 @@ const SidebarTaskItem = memo(function SidebarTaskItem({
|
||||
e.preventDefault()
|
||||
onMultiSelectClick(task.id, true)
|
||||
} else {
|
||||
useFolderStore.setState({
|
||||
selectedTasks: new Set<string>(),
|
||||
lastSelectedTaskId: task.id,
|
||||
})
|
||||
useFolderStore.getState().selectTaskOnly(task.id)
|
||||
}
|
||||
}}
|
||||
onContextMenu={task.id !== 'new' ? (e) => onContextMenu(e, task.id) : undefined}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import type { PersistedMessage } from '@/lib/copilot/chat/persisted-message'
|
||||
import { normalizeMessage } from '@/lib/copilot/chat/persisted-message'
|
||||
import {
|
||||
@@ -254,7 +254,6 @@ export function useTasks(workspaceId?: string) {
|
||||
queryKey: taskKeys.list(workspaceId),
|
||||
queryFn: ({ signal }) => fetchTasks(workspaceId as string, signal),
|
||||
enabled: Boolean(workspaceId),
|
||||
placeholderData: keepPreviousData,
|
||||
staleTime: 60 * 1000,
|
||||
})
|
||||
}
|
||||
@@ -535,6 +534,10 @@ async function markTaskUnread(chatId: string): Promise<void> {
|
||||
|
||||
/**
|
||||
* Marks a task as read with optimistic update.
|
||||
*
|
||||
* The server only updates `lastSeenAt`, never `updatedAt`, so we deliberately
|
||||
* do not invalidate the list cache — that would trigger a refetch that can
|
||||
* reorder the sidebar if any unrelated server-side update landed in between.
|
||||
*/
|
||||
export function useMarkTaskRead(workspaceId?: string) {
|
||||
const queryClient = useQueryClient()
|
||||
@@ -556,14 +559,14 @@ export function useMarkTaskRead(workspaceId?: string) {
|
||||
queryClient.setQueryData(taskKeys.list(workspaceId), context.previousTasks)
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a task as unread with optimistic update.
|
||||
*
|
||||
* Same rationale as `useMarkTaskRead` — no list invalidation, since the server
|
||||
* only flips `lastSeenAt` and the optimistic update fully reflects the change.
|
||||
*/
|
||||
export function useMarkTaskUnread(workspaceId?: string) {
|
||||
const queryClient = useQueryClient()
|
||||
@@ -585,8 +588,5 @@ export function useMarkTaskUnread(workspaceId?: string) {
|
||||
queryClient.setQueryData(taskKeys.list(workspaceId), context.previousTasks)
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,12 +50,9 @@ describe('handleTaskStatusEvent', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves list invalidation when task event payload is invalid', () => {
|
||||
it('does not invalidate when task event payload is invalid', () => {
|
||||
handleTaskStatusEvent(queryClient, 'ws-1', '{')
|
||||
|
||||
expect(queryClient.invalidateQueries).toHaveBeenCalledTimes(1)
|
||||
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
|
||||
queryKey: taskKeys.list('ws-1'),
|
||||
})
|
||||
expect(queryClient.invalidateQueries).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -41,13 +41,13 @@ export function handleTaskStatusEvent(
|
||||
workspaceId: string,
|
||||
data: unknown
|
||||
): void {
|
||||
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
|
||||
|
||||
const payload = parseTaskStatusEventPayload(data)
|
||||
if (!payload) {
|
||||
logger.warn('Received invalid task_status payload')
|
||||
return
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: taskKeys.list(workspaceId) })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user