diff --git a/apps/web/src/app/(v2)/chat/threads/page.tsx b/apps/web/src/app/(v2)/chat/threads/page.tsx index 77d3e4f4..b632b3f0 100644 --- a/apps/web/src/app/(v2)/chat/threads/page.tsx +++ b/apps/web/src/app/(v2)/chat/threads/page.tsx @@ -29,7 +29,7 @@ type FilterStatus = function AllThreadsPageContent() { const router = useRouter(); - const { currentInstallation } = useGitHubAppProvider(); + const { currentInstallation, installationsLoading } = useGitHubAppProvider(); const { threads, isLoading: threadsLoading } = useThreadsSWR({ assistantId: MANAGER_GRAPH_ID, currentInstallation, @@ -48,40 +48,52 @@ function AllThreadsPageContent() { isLoading: statusLoading, } = useThreadsStatus(threadIds, threads); - const filteredThreads = threadsMetadata.filter((thread: ThreadMetadata) => { - const matchesSearch = - thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || - thread.repository.toLowerCase().includes(searchQuery.toLowerCase()); + const filteredThreads = useMemo(() => { + return threadsMetadata.filter((thread: ThreadMetadata) => { + const matchesSearch = + thread.title.toLowerCase().includes(searchQuery.toLowerCase()) || + thread.repository.toLowerCase().includes(searchQuery.toLowerCase()); - const matchesStatus = - statusFilter === "all" || statusMap[thread.id] === statusFilter; + const matchesStatus = + statusFilter === "all" || statusMap[thread.id] === statusFilter; - return matchesSearch && matchesStatus; - }); + return matchesSearch && matchesStatus; + }); + }, [threadsMetadata, searchQuery, statusFilter, statusMap]); - const groupedThreads = { - running: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "running", - ), - completed: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "completed", - ), - failed: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "failed", - ), - pending: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "pending", - ), - idle: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "idle", - ), - paused: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "paused", - ), - error: filteredThreads.filter( - (thread: ThreadMetadata) => statusMap[thread.id] === "error", - ), - }; + const groupedThreads = useMemo(() => { + return { + running: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "running", + ), + completed: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "completed", + ), + failed: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "failed", + ), + pending: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "pending", + ), + idle: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "idle", + ), + paused: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "paused", + ), + error: filteredThreads.filter( + (thread: ThreadMetadata) => statusMap[thread.id] === "error", + ), + }; + }, [filteredThreads, statusMap]); + + // Show loading state if threads/status/installation requests are loading, and there are no + // threads to display (conditional of the status filter) + const showThreadsLoading = + (threadsLoading || statusLoading || installationsLoading) && + (statusFilter === "all" + ? Object.values(groupedThreads).flat().length === 0 + : filteredThreads.length === 0); return (
@@ -236,21 +248,20 @@ function AllThreadsPageContent() {
)} - {(threadsLoading || statusLoading) && - (!threads || threads.length === 0) && ( -
-
-

- Loading threads... -

-
-
- {Array.from({ length: 9 }).map((_, index) => ( - - ))} -
+ {showThreadsLoading && ( +
+
+

+ Loading threads... +

- )} +
+ {Array.from({ length: 9 }).map((_, index) => ( + + ))} +
+
+ )}