Skip to content

Commit f6309c6

Browse files
committed
Fix persistence
1 parent 4345c6c commit f6309c6

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
5+
import type { QueryClient } from '@tanstack/react-query'
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
7+
import { taskKeys } from '@/hooks/queries/tasks'
8+
import { handleTaskStatusEvent } from '@/hooks/use-task-events'
9+
10+
describe('handleTaskStatusEvent', () => {
11+
const queryClient = {
12+
invalidateQueries: vi.fn().mockResolvedValue(undefined),
13+
} satisfies Pick<QueryClient, 'invalidateQueries'>
14+
15+
beforeEach(() => {
16+
vi.clearAllMocks()
17+
})
18+
19+
it('invalidates the task list and completed chat detail', () => {
20+
handleTaskStatusEvent(
21+
queryClient,
22+
JSON.stringify({
23+
chatId: 'chat-1',
24+
type: 'completed',
25+
timestamp: Date.now(),
26+
})
27+
)
28+
29+
expect(queryClient.invalidateQueries).toHaveBeenCalledTimes(2)
30+
expect(queryClient.invalidateQueries).toHaveBeenNthCalledWith(1, {
31+
queryKey: taskKeys.lists(),
32+
})
33+
expect(queryClient.invalidateQueries).toHaveBeenNthCalledWith(2, {
34+
queryKey: taskKeys.detail('chat-1'),
35+
})
36+
})
37+
38+
it('keeps list invalidation only for non-completed task events', () => {
39+
handleTaskStatusEvent(
40+
queryClient,
41+
JSON.stringify({
42+
chatId: 'chat-1',
43+
type: 'started',
44+
timestamp: Date.now(),
45+
})
46+
)
47+
48+
expect(queryClient.invalidateQueries).toHaveBeenCalledTimes(1)
49+
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
50+
queryKey: taskKeys.lists(),
51+
})
52+
})
53+
54+
it('preserves list invalidation when task event payload is invalid', () => {
55+
handleTaskStatusEvent(queryClient, '{')
56+
57+
expect(queryClient.invalidateQueries).toHaveBeenCalledTimes(1)
58+
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
59+
queryKey: taskKeys.lists(),
60+
})
61+
})
62+
})

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

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,60 @@
11
import { useEffect } from 'react'
22
import { createLogger } from '@sim/logger'
3+
import type { QueryClient } from '@tanstack/react-query'
34
import { useQueryClient } from '@tanstack/react-query'
45
import { taskKeys } from '@/hooks/queries/tasks'
56

67
const logger = createLogger('TaskEvents')
78

9+
interface TaskStatusEventPayload {
10+
chatId?: string
11+
type?: 'started' | 'completed' | 'created' | 'deleted' | 'renamed'
12+
}
13+
14+
function parseTaskStatusEventPayload(data: unknown): TaskStatusEventPayload | null {
15+
let parsed = data
16+
17+
if (typeof parsed === 'string') {
18+
try {
19+
parsed = JSON.parse(parsed)
20+
} catch {
21+
return null
22+
}
23+
}
24+
25+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
26+
return null
27+
}
28+
29+
const record = parsed as Record<string, unknown>
30+
31+
return {
32+
...(typeof record.chatId === 'string' ? { chatId: record.chatId } : {}),
33+
...(typeof record.type === 'string'
34+
? { type: record.type as TaskStatusEventPayload['type'] }
35+
: {}),
36+
}
37+
}
38+
39+
export function handleTaskStatusEvent(
40+
queryClient: Pick<QueryClient, 'invalidateQueries'>,
41+
data: unknown
42+
): void {
43+
queryClient.invalidateQueries({ queryKey: taskKeys.lists() })
44+
45+
const payload = parseTaskStatusEventPayload(data)
46+
if (!payload) {
47+
logger.warn('Received invalid task_status payload')
48+
return
49+
}
50+
51+
if (payload.type === 'completed' && payload.chatId) {
52+
queryClient.invalidateQueries({ queryKey: taskKeys.detail(payload.chatId) })
53+
}
54+
}
55+
856
/**
9-
* Subscribes to task status SSE events and invalidates the task list on changes.
57+
* Subscribes to task status SSE events and invalidates task caches on changes.
1058
*/
1159
export function useTaskEvents(workspaceId: string | undefined) {
1260
const queryClient = useQueryClient()
@@ -18,8 +66,8 @@ export function useTaskEvents(workspaceId: string | undefined) {
1866
`/api/mothership/events?workspaceId=${encodeURIComponent(workspaceId)}`
1967
)
2068

21-
eventSource.addEventListener('task_status', () => {
22-
queryClient.invalidateQueries({ queryKey: taskKeys.lists() })
69+
eventSource.addEventListener('task_status', (event) => {
70+
handleTaskStatusEvent(queryClient, event instanceof MessageEvent ? event.data : undefined)
2371
})
2472

2573
eventSource.onerror = () => {

0 commit comments

Comments
 (0)