diff --git a/apps/web/src/app/(v2)/chat/[thread_id]/page.tsx b/apps/web/src/app/(v2)/chat/[thread_id]/page.tsx
index 1751df3b..90b6fe3e 100644
--- a/apps/web/src/app/(v2)/chat/[thread_id]/page.tsx
+++ b/apps/web/src/app/(v2)/chat/[thread_id]/page.tsx
@@ -33,7 +33,7 @@ export default function ThreadPage({
process.env.NEXT_PUBLIC_MANAGER_ASSISTANT_ID,
);
// Find the thread by ID
- const thread = threads?.find((t) => t.thread_id === thread_id);
+ const thread = threads.find((t) => t.thread_id === thread_id);
const handleBackToHome = () => {
router.push("/chat");
@@ -44,8 +44,7 @@ export default function ThreadPage({
}
// Convert all threads to display format
- const displayThreads: ThreadDisplayInfo[] =
- threads?.map(threadToDisplayInfo) ?? [];
+ const displayThreads: ThreadDisplayInfo[] = threads.map(threadToDisplayInfo);
const currentDisplayThread = threadToDisplayInfo(thread);
return (
diff --git a/apps/web/src/app/(v2)/chat/page.tsx b/apps/web/src/app/(v2)/chat/page.tsx
index fe08a95b..6bb06c6e 100644
--- a/apps/web/src/app/(v2)/chat/page.tsx
+++ b/apps/web/src/app/(v2)/chat/page.tsx
@@ -14,8 +14,7 @@ export default function ChatPage() {
);
// Convert Thread objects to ThreadDisplayInfo for UI
- const displayThreads: ThreadDisplayInfo[] =
- threads?.map(threadToDisplayInfo) ?? [];
+ const displayThreads: ThreadDisplayInfo[] = threads.map(threadToDisplayInfo);
return (
diff --git a/apps/web/src/app/(v2)/chat/threads/page.tsx b/apps/web/src/app/(v2)/chat/threads/page.tsx
index fefbb930..38bfd127 100644
--- a/apps/web/src/app/(v2)/chat/threads/page.tsx
+++ b/apps/web/src/app/(v2)/chat/threads/page.tsx
@@ -10,22 +10,21 @@ import { useRouter } from "next/navigation";
import { ThreadDisplayInfo, threadToDisplayInfo } from "@/components/v2/types";
import { useThreads } from "@/hooks/useThreads";
import { GraphState } from "@open-swe/shared/open-swe/types";
-import { ThreadCard } from "@/components/v2/thread-card";
+import { ThreadCard, ThreadCardLoading } from "@/components/v2/thread-card";
import { ThemeToggle } from "@/components/theme-toggle";
type FilterStatus = "all" | "running" | "completed" | "failed" | "pending";
export default function AllThreadsPage() {
const router = useRouter();
- const { threads } = useThreads(
+ const { threads, threadsLoading } = useThreads(
process.env.NEXT_PUBLIC_MANAGER_ASSISTANT_ID,
);
const [searchQuery, setSearchQuery] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
// Convert Thread objects to ThreadDisplayInfo for UI
- const displayThreads: ThreadDisplayInfo[] =
- threads?.map(threadToDisplayInfo) ?? [];
+ const displayThreads: ThreadDisplayInfo[] = threads.map(threadToDisplayInfo);
// Filter and search threads
const filteredThreads = displayThreads.filter((thread) => {
@@ -178,7 +177,7 @@ export default function AllThreadsPage() {
)}
- {filteredThreads.length === 0 && (
+ {filteredThreads.length === 0 && !threadsLoading && (
No threads found
@@ -188,6 +187,21 @@ export default function AllThreadsPage() {
)}
+
+ {threadsLoading && threads.length === 0 && (
+
+
+
+ Loading threads...
+
+
+
+ {Array.from({ length: 9 }).map((_, index) => (
+
+ ))}
+
+
+ )}
diff --git a/apps/web/src/hooks/useThreads.tsx b/apps/web/src/hooks/useThreads.tsx
index cc11ef5d..035c0e95 100644
--- a/apps/web/src/hooks/useThreads.tsx
+++ b/apps/web/src/hooks/useThreads.tsx
@@ -6,7 +6,7 @@ export function useThreads>(
assistantId?: string,
) {
const apiUrl: string | undefined = process.env.NEXT_PUBLIC_API_URL ?? "";
- const [threads, setThreads] = useState[] | null>(null);
+ const [threads, setThreads] = useState[]>([]);
const [threadsLoading, setThreadsLoading] = useState(false);
const getThread = useCallback(
@@ -50,7 +50,7 @@ export function useThreads>(
useEffect(() => {
getThreads().then((threads) => {
- setThreads(threads);
+ setThreads(threads ?? []);
});
}, [getThreads]);