From 7b159d98252b6fcfc655c913582a0c6561354ed9 Mon Sep 17 00:00:00 2001 From: mamadoudicko Date: Tue, 12 Sep 2023 16:37:27 +0200 Subject: [PATCH] feat: add polling logic on pending notifications --- .../components/ActionsBar/ActionsBar.tsx | 5 ++- .../ActionsBar/hooks/useActionBar.ts | 1 + .../ActionsBar/hooks/useKnowledgeUploader.ts | 13 +++++- .../[chatId]/hooks/useSelectedChatPage.ts | 45 +++++++++++++++++-- .../utils/getChatNotificationsQueryKey.ts | 2 + .../ChatsList/__tests__/ChatsList.test.tsx | 34 +++++++++----- 6 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 frontend/app/chat/[chatId]/utils/getChatNotificationsQueryKey.ts diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/ActionsBar.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/ActionsBar.tsx index 664d78344a87..f1a49ea086f7 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/ActionsBar.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/ActionsBar.tsx @@ -10,9 +10,12 @@ export const ActionsBar = (): JSX.Element => { shouldDisplayUploadCard, setShouldDisplayUploadCard, hasPendingRequests, + setHasPendingRequests, } = useActionBar(); const { addContent, contents, feedBrain, removeContent } = - useKnowledgeUploader(); + useKnowledgeUploader({ + setHasPendingRequests, + }); const { t } = useTranslation(["chat"]); diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useActionBar.ts b/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useActionBar.ts index c88b2f732d77..a6a6ed254ddb 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useActionBar.ts +++ b/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useActionBar.ts @@ -19,5 +19,6 @@ export const useActionBar = () => { shouldDisplayUploadCard, setShouldDisplayUploadCard, hasPendingRequests, + setHasPendingRequests, }; }; diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useKnowledgeUploader.ts b/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useKnowledgeUploader.ts index b39e04247adf..0c916cb87f31 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useKnowledgeUploader.ts +++ b/frontend/app/chat/[chatId]/components/ActionsBar/hooks/useKnowledgeUploader.ts @@ -13,8 +13,13 @@ import { useToast } from "@/lib/hooks"; import { FeedItemCrawlType, FeedItemType, FeedItemUploadType } from "../types"; +type UseKnowledgeUploaderProps = { + setHasPendingRequests: (hasPendingRequests: boolean) => void; +}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export const useKnowledgeUploader = () => { +export const useKnowledgeUploader = ({ + setHasPendingRequests, +}: UseKnowledgeUploaderProps) => { const [contents, setContents] = useState([]); const { publish } = useToast(); const { uploadFile } = useUploadApi(); @@ -45,6 +50,7 @@ export const useKnowledgeUploader = () => { }; try { + setHasPendingRequests(true); await crawlWebsiteUrl({ brainId, config, @@ -57,6 +63,8 @@ export const useKnowledgeUploader = () => { message: JSON.stringify(error), }), }); + } finally { + setHasPendingRequests(false); } }, [crawlWebsiteUrl, publish, t] @@ -67,6 +75,7 @@ export const useKnowledgeUploader = () => { const formData = new FormData(); formData.append("uploadFile", file); try { + setHasPendingRequests(true); await uploadFile({ brainId, formData, @@ -90,6 +99,8 @@ export const useKnowledgeUploader = () => { text: t("error", { message: e }), }); } + } finally { + setHasPendingRequests(false); } }, [publish, t, uploadFile] diff --git a/frontend/app/chat/[chatId]/hooks/useSelectedChatPage.ts b/frontend/app/chat/[chatId]/hooks/useSelectedChatPage.ts index 055b41cad683..4d17ec9f2b8e 100644 --- a/frontend/app/chat/[chatId]/hooks/useSelectedChatPage.ts +++ b/frontend/app/chat/[chatId]/hooks/useSelectedChatPage.ts @@ -1,20 +1,59 @@ +import { useQuery } from "@tanstack/react-query"; import { useParams } from "next/navigation"; import { useEffect } from "react"; import { useChatApi } from "@/lib/api/chat/useChatApi"; +import { useNotificationApi } from "@/lib/api/notification/useNotificationApi"; import { useChatContext } from "@/lib/context"; +import { getChatNotificationsQueryKey } from "../utils/getChatNotificationsQueryKey"; import { getMessagesFromChatItems } from "../utils/getMessagesFromChatItems"; import { getNotificationsFromChatItems } from "../utils/getNotificationsFromChatItems"; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const useSelectedChatPage = () => { - const { setMessages, setNotifications } = useChatContext(); + const { setMessages, setNotifications, notifications } = useChatContext(); const { getChatItems } = useChatApi(); - + const { getChatNotifications } = useNotificationApi(); const params = useParams(); + const chatId = params?.chatId as string | undefined; + const chatNotificationsQueryKey = getChatNotificationsQueryKey(chatId ?? ""); + const { data: fetchedNotifications = [] } = useQuery({ + queryKey: [chatNotificationsQueryKey], + enabled: notifications.length > 0, + queryFn: () => { + if (chatId === undefined) { + return []; + } + + return getChatNotifications(chatId); + }, + refetchInterval: () => { + if (notifications.length === 0) { + return false; + } + const hasAPendingNotification = notifications.find( + (item) => item.status === "Pending" + ); + + if (hasAPendingNotification) { + //30 seconds + return 30_000; + } + + return false; + }, + }); + + useEffect(() => { + if (fetchedNotifications.length === 0) { + return; + } + setNotifications(fetchedNotifications); + }, [fetchedNotifications]); + useEffect(() => { const fetchHistory = async () => { if (chatId === undefined) { @@ -30,5 +69,5 @@ export const useSelectedChatPage = () => { setNotifications(getNotificationsFromChatItems(chatItems)); }; void fetchHistory(); - }, [chatId, setMessages]); + }, [chatId]); }; diff --git a/frontend/app/chat/[chatId]/utils/getChatNotificationsQueryKey.ts b/frontend/app/chat/[chatId]/utils/getChatNotificationsQueryKey.ts new file mode 100644 index 000000000000..36869479e3ca --- /dev/null +++ b/frontend/app/chat/[chatId]/utils/getChatNotificationsQueryKey.ts @@ -0,0 +1,2 @@ +export const getChatNotificationsQueryKey = (chatId: string): string => + `notifications-${chatId}`; diff --git a/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx b/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx index 03ad6a263494..3e5bd5064727 100644 --- a/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx +++ b/frontend/app/chat/components/ChatsList/__tests__/ChatsList.test.tsx @@ -1,4 +1,5 @@ /* eslint-disable max-lines */ +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { act, fireEvent, render, screen } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; @@ -11,6 +12,7 @@ import * as useChatsListModule from "../hooks/useChatsList"; import { ChatsList } from "../index"; const getChatsMock = vi.fn(() => []); +const queryClient = new QueryClient(); const setOpenMock = vi.fn(); @@ -56,9 +58,11 @@ describe("ChatsList", () => { it("should render correctly", () => { const { getByTestId } = render( - - - + + + + + ); const chatsList = getByTestId("chats-list"); expect(chatsList).toBeDefined(); @@ -72,9 +76,11 @@ describe("ChatsList", () => { it("renders the chats list with correct number of items", () => { render( - - - + + + + + ); const chatItems = screen.getAllByTestId("chats-list-item"); expect(chatItems).toHaveLength(2); @@ -88,9 +94,11 @@ describe("ChatsList", () => { await act(() => render( - - () - + + + () + + ) ); @@ -109,9 +117,11 @@ describe("ChatsList", () => { })); await act(() => render( - - - + + + + + ) );