fix(site): add optimistic updates for chat archive/unarchive (#22622)

This commit is contained in:
Danielle Maywood
2026-03-04 21:51:33 +00:00
committed by GitHub
parent 93e5d04896
commit 96926cf189
2 changed files with 108 additions and 19 deletions
+98 -10
View File
@@ -16,24 +16,112 @@ export const chat = (chatId: string) => ({
queryFn: () => API.getChat(chatId),
});
export const createChat = (queryClient: QueryClient) => ({
mutationFn: (req: TypesGen.CreateChatRequest) => API.createChat(req),
onSuccess: () => {
void queryClient.invalidateQueries({ queryKey: chatsKey });
},
});
export const archiveChat = (queryClient: QueryClient) => ({
mutationFn: (chatId: string) => API.archiveChat(chatId),
onSuccess: () => {
void queryClient.invalidateQueries({ queryKey: chatsKey });
onMutate: async (chatId: string) => {
await queryClient.cancelQueries({ queryKey: chatsKey });
await queryClient.cancelQueries({ queryKey: chatKey(chatId) });
const previousChats = queryClient.getQueryData<TypesGen.Chat[]>(chatsKey);
const previousChat = queryClient.getQueryData<TypesGen.ChatWithMessages>(
chatKey(chatId),
);
queryClient.setQueryData<TypesGen.Chat[]>(chatsKey, (old) =>
old?.map((chat) =>
chat.id === chatId ? { ...chat, archived: true } : chat,
),
);
if (previousChat) {
queryClient.setQueryData<TypesGen.ChatWithMessages>(chatKey(chatId), {
...previousChat,
chat: { ...previousChat.chat, archived: true },
});
}
return { previousChats, previousChat };
},
onError: (
_error: unknown,
chatId: string,
context:
| {
previousChats?: TypesGen.Chat[];
previousChat?: TypesGen.ChatWithMessages;
}
| undefined,
) => {
if (context?.previousChats) {
queryClient.setQueryData<TypesGen.Chat[]>(
chatsKey,
context.previousChats,
);
}
if (context?.previousChat) {
queryClient.setQueryData<TypesGen.ChatWithMessages>(
chatKey(chatId),
context.previousChat,
);
}
},
onSettled: async (_data: unknown, _error: unknown, chatId: string) => {
await queryClient.invalidateQueries({ queryKey: chatsKey });
await queryClient.invalidateQueries({ queryKey: chatKey(chatId) });
},
});
export const unarchiveChat = (queryClient: QueryClient) => ({
mutationFn: (chatId: string) => API.unarchiveChat(chatId),
onSuccess: async () => {
onMutate: async (chatId: string) => {
await queryClient.cancelQueries({ queryKey: chatsKey });
await queryClient.cancelQueries({ queryKey: chatKey(chatId) });
const previousChats = queryClient.getQueryData<TypesGen.Chat[]>(chatsKey);
const previousChat = queryClient.getQueryData<TypesGen.ChatWithMessages>(
chatKey(chatId),
);
queryClient.setQueryData<TypesGen.Chat[]>(chatsKey, (old) =>
old?.map((chat) =>
chat.id === chatId ? { ...chat, archived: false } : chat,
),
);
if (previousChat) {
queryClient.setQueryData<TypesGen.ChatWithMessages>(chatKey(chatId), {
...previousChat,
chat: { ...previousChat.chat, archived: false },
});
}
return { previousChats, previousChat };
},
onError: (
_error: unknown,
chatId: string,
context:
| {
previousChats?: TypesGen.Chat[];
previousChat?: TypesGen.ChatWithMessages;
}
| undefined,
) => {
if (context?.previousChats) {
queryClient.setQueryData<TypesGen.Chat[]>(
chatsKey,
context.previousChats,
);
}
if (context?.previousChat) {
queryClient.setQueryData<TypesGen.ChatWithMessages>(
chatKey(chatId),
context.previousChat,
);
}
},
onSettled: async (_data: unknown, _error: unknown, chatId: string) => {
await queryClient.invalidateQueries({ queryKey: chatsKey });
await queryClient.invalidateQueries({ queryKey: chatKey(chatId) });
},
});
export const createChat = (queryClient: QueryClient) => ({
mutationFn: (req: TypesGen.CreateChatRequest) => API.createChat(req),
onSuccess: () => {
void queryClient.invalidateQueries({ queryKey: chatsKey });
},
});
+10 -9
View File
@@ -158,14 +158,15 @@ const AgentsPage: FC = () => {
const chatModelsQuery = useQuery(chatModels());
const chatModelConfigsQuery = useQuery(chatModelConfigs());
const createMutation = useMutation(createChat(queryClient));
const archiveChatBase = archiveChat(queryClient);
const archiveAgentMutation = useMutation({
...archiveChat(queryClient),
onSuccess: async (_data, chatId) => {
...archiveChatBase,
onSuccess: (_data, chatId) => {
clearChatErrorReason(chatId);
await queryClient.invalidateQueries({ queryKey: chatKey(chatId) });
toast.success("Agent archived.");
},
onError: (error) => {
onError: (error, chatId, context) => {
archiveChatBase.onError(error, chatId, context);
toast.error(getErrorMessage(error, "Failed to archive agent."));
},
});
@@ -192,17 +193,17 @@ const AgentsPage: FC = () => {
toast.error(getErrorMessage(error, "Failed to archive agent."));
},
});
const unarchiveChatBase = unarchiveChat(queryClient);
const unarchiveAgentMutation = useMutation({
...unarchiveChat(queryClient),
onSuccess: async (_data, chatId) => {
await queryClient.invalidateQueries({ queryKey: chatKey(chatId) });
...unarchiveChatBase,
onSuccess: () => {
toast.success("Agent unarchived.");
},
onError: (error) => {
onError: (error, chatId, context) => {
unarchiveChatBase.onError(error, chatId, context);
toast.error(getErrorMessage(error, "Failed to unarchive agent."));
},
});
const [isConfigureAgentsDialogOpen, setConfigureAgentsDialogOpen] =
useState(false);
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);