History

Fix snapshot sync bypassing recovery coordinator and dead loading state

- Remove refreshActiveSnapshot from unarchiveThread: the EventRouter's recovery coordinator already handles thread.unarchived events via fallbackToSnapshotRecovery, which properly updates latestSequence. Calling syncServerReadModel directly left the coordinator stale, causing already-applied events to be re-processed and potentially corrupting streaming message content via double concatenation. - Fix archived threads loading state: placeholderData always returned EMPTY_ARCHIVED_THREADS on first load, making isPending permanently false and the loading UI unreachable. Now only uses previous query data as placeholder, allowing isPending to be true on first fetch.

Cursor Agent committed 7 months ago

Commit 95dd2b61 parent bbe5e142 files · +2 −13Browse files

Unified · Split

2 files
  1. apps/web/src/hooks/useThreadActions.ts +1 −10
  2. apps/web/src/lib/orchestrationReactQuery.ts +1 −3
apps/web/src/hooks/useThreadActions.ts+1−10
@@ -18,7 +18,6 @@ import { useSettings } from "./useSettings"; · 17 unmodified lines
18 18
19export function useThreadActions() {19export function useThreadActions() {
20 const appSettings = useSettings();20 const appSettings = useSettings();
21 const syncServerReadModel = useStore((store) => store.syncServerReadModel);
22 const clearComposerDraftForThread = useComposerDraftStore((store) => store.clearDraftThread);21 const clearComposerDraftForThread = useComposerDraftStore((store) => store.clearDraftThread);
23 const clearProjectDraftThreadById = useComposerDraftStore(22 const clearProjectDraftThreadById = useComposerDraftStore(
24 (store) => store.clearProjectDraftThreadById,23 (store) => store.clearProjectDraftThreadById,
@@ -33,13 +32,6 @@ export function useThreadActions() { · 8 unmodified lines
33 const queryClient = useQueryClient();32 const queryClient = useQueryClient();
34 const removeWorktreeMutation = useMutation(gitRemoveWorktreeMutationOptions({ queryClient }));33 const removeWorktreeMutation = useMutation(gitRemoveWorktreeMutationOptions({ queryClient }));
35 34
36 const refreshActiveSnapshot = useCallback(async () => {
37 const api = readNativeApi();
38 if (!api) return;
39 const snapshot = await api.orchestration.getActiveSnapshot();
40 syncServerReadModel(snapshot);
41 }, [syncServerReadModel]);
42
43 const archiveThread = useCallback(35 const archiveThread = useCallback(
44 async (threadId: ThreadId) => {36 async (threadId: ThreadId) => {
45 const api = readNativeApi();37 const api = readNativeApi();
@@ -73,10 +65,9 @@ export function useThreadActions() { · 27 unmodified lines
73 commandId: newCommandId(),65 commandId: newCommandId(),
74 threadId,66 threadId,
75 });67 });
76 await refreshActiveSnapshot();
77 void queryClient.invalidateQueries({ queryKey: orchestrationQueryKeys.archivedThreads() });68 void queryClient.invalidateQueries({ queryKey: orchestrationQueryKeys.archivedThreads() });
78 },69 },
79 [queryClient, refreshActiveSnapshot],70 [queryClient],
80 );71 );
81 72
82 const deleteThread = useCallback(73 const deleteThread = useCallback(
apps/web/src/lib/orchestrationReactQuery.ts+1−3
@@ -1,4 +1,3 @@
1import type { OrchestrationListArchivedThreadsResult } from "@t3tools/contracts";
2import { queryOptions } from "@tanstack/react-query";1import { queryOptions } from "@tanstack/react-query";
3import { ensureNativeApi } from "~/nativeApi";2import { ensureNativeApi } from "~/nativeApi";
4 3
@@ -8,7 +7,6 @@ export const orchestrationQueryKeys = { · 3 unmodified lines
8};7};
9 8
10const DEFAULT_ARCHIVED_THREADS_STALE_TIME = 15_000;9const DEFAULT_ARCHIVED_THREADS_STALE_TIME = 15_000;
11const EMPTY_ARCHIVED_THREADS: OrchestrationListArchivedThreadsResult = [];
12 10
13export function archivedThreadsQueryOptions() {11export function archivedThreadsQueryOptions() {
14 return queryOptions({12 return queryOptions({
@@ -18,6 +16,6 @@ export function archivedThreadsQueryOptions() { · 3 unmodified lines
18 return api.orchestration.listArchivedThreads();16 return api.orchestration.listArchivedThreads();
19 },17 },
20 staleTime: DEFAULT_ARCHIVED_THREADS_STALE_TIME,18 staleTime: DEFAULT_ARCHIVED_THREADS_STALE_TIME,
21 placeholderData: (previous) => previous ?? EMPTY_ARCHIVED_THREADS,19 placeholderData: (previous) => previous,
22 });20 });
23}21}