diff --git a/web/src/App.tsx b/web/src/App.tsx index 2240ac2..3de1cff 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -93,6 +93,11 @@ type ActiveRunsState = { chats: Record; searches: Record; }; +type RefreshCollectionsOptions = { + preferredSelection?: SidebarSelection; + reportTransientError?: boolean; + selectFallback?: boolean; +}; function readSidebarSelectionFromUrl(): SidebarSelection | null { if (typeof window === "undefined") return null; @@ -1125,7 +1130,11 @@ export default function App() { resetWorkspaceState(); }; - const refreshCollections = async (preferredSelection?: SidebarSelection, reportTransientError = true) => { + const refreshCollections = async ({ + preferredSelection, + reportTransientError = true, + selectFallback = false, + }: RefreshCollectionsOptions = {}) => { setIsLoadingCollections(true); try { const nextWorkspaceItems = await listWorkspaceItems(); @@ -1146,6 +1155,9 @@ export default function App() { if (hasItem(current)) { return current; } + if (!selectFallback) { + return null; + } const first = nextWorkspaceItems[0]; return first ? { kind: first.type, id: first.id } : null; }); @@ -1242,7 +1254,12 @@ export default function App() { if (!isAuthenticated) return; const preferredSelection = initialRouteSelectionRef.current; initialRouteSelectionRef.current = null; - void Promise.all([refreshCollections(preferredSelection ?? undefined), refreshModels(), refreshChatTools(), refreshActiveRuns()]); + void Promise.all([ + refreshCollections({ preferredSelection: preferredSelection ?? undefined, selectFallback: true }), + refreshModels(), + refreshChatTools(), + refreshActiveRuns(), + ]); }, [isAuthenticated]); useEffect(() => { @@ -1269,8 +1286,8 @@ export default function App() { } setError((current) => (current && isRecoverableStreamDisconnect(new Error(current)) ? null : current)); void refreshActiveRuns(); - void refreshCollections(selectedItemRef.current ?? undefined, false); const currentSelection = selectedItemRef.current; + void refreshCollections({ reportTransientError: false }); if (currentSelection?.kind === "chat") { void refreshChat(currentSelection.id); } else if (currentSelection?.kind === "search") { @@ -1385,10 +1402,18 @@ export default function App() { const selectedKey = selectedItem ? `${selectedItem.kind}:${selectedItem.id}` : null; const transcriptViewKey = draftKind ? `draft:${draftKind}` : selectedKey ?? "empty"; - const selectedChatPendingState = selectedItem?.kind === "chat" ? pendingChatStates[selectedItem.id] ?? null : null; - const selectedSearchRunState = selectedItem?.kind === "search" ? runningSearchStates[selectedItem.id] ?? null : null; - const selectedChatIsActive = selectedItem?.kind === "chat" && (!!selectedChatPendingState || !!activeRuns.chats[selectedItem.id]); - const selectedSearchIsActive = selectedItem?.kind === "search" && (!!selectedSearchRunState || !!activeRuns.searches[selectedItem.id]); + const selectedChatPendingState = + draftKind === null && selectedItem?.kind === "chat" ? pendingChatStates[selectedItem.id] ?? null : null; + const selectedSearchRunState = + draftKind === null && selectedItem?.kind === "search" ? runningSearchStates[selectedItem.id] ?? null : null; + const selectedChatIsActive = + draftKind === null && + selectedItem?.kind === "chat" && + (!!selectedChatPendingState || !!activeRuns.chats[selectedItem.id]); + const selectedSearchIsActive = + draftKind === null && + selectedItem?.kind === "search" && + (!!selectedSearchRunState || !!activeRuns.searches[selectedItem.id]); const isSearchMode = draftKind ? draftKind === "search" : selectedItem?.kind === "search"; const isSearchRunning = !!selectedSearchIsActive; const isSendingActiveChat = draftKind !== "search" && !!selectedChatIsActive; @@ -1495,7 +1520,10 @@ export default function App() { }; }, []); - const messages = selectedChat?.messages ?? []; + const messages = + draftKind === null && selectedItem?.kind === "chat" && selectedChat?.id === selectedItem.id + ? selectedChat.messages + : []; useEffect(() => { if (isSearchMode && pendingAttachments.length) { @@ -1602,6 +1630,7 @@ export default function App() { setError(null); setContextMenu(null); setDraftKind("chat"); + selectedItemRef.current = null; setSelectedItem(null); setSelectedChat(null); setSelectedSearch(null); @@ -1738,6 +1767,7 @@ export default function App() { setError(null); setContextMenu(null); setDraftKind("search"); + selectedItemRef.current = null; setSelectedItem(null); setSelectedChat(null); setSelectedSearch(null); @@ -2065,7 +2095,7 @@ export default function App() { } else { await deleteSearch(target.id); } - await refreshCollections(); + await refreshCollections({ selectFallback: true }); } catch (err) { const message = err instanceof Error ? err.message : String(err); if (message.includes("bearer token")) { @@ -2450,7 +2480,7 @@ export default function App() { backgroundSuspendedChatStreamsRef.current.delete(chatId); const persistedChat = await retryAfterAppResume(() => getChat(chatId)); - await refreshCollections(target, false); + await refreshCollections({ preferredSelection: target, reportTransientError: false }); if (isCurrentSelection(target)) { setSelectedChat(persistedChat); setSelectedSearch(null); @@ -2664,7 +2694,7 @@ export default function App() { } } - await refreshCollections(target); + await refreshCollections({ preferredSelection: target }); return target; }; @@ -2783,7 +2813,7 @@ export default function App() { setSelectedChat(persistedChat); setSelectedSearch(null); } - void refreshCollections(target); + void refreshCollections({ preferredSelection: target }); return; } catch (resumeError) { err = resumeError; @@ -2889,7 +2919,7 @@ export default function App() { { signal: abortController.signal } ); - await refreshCollections(target); + await refreshCollections({ preferredSelection: target }); if (isCurrentSelection(target)) { await refreshSearch(searchId); } @@ -2957,7 +2987,7 @@ export default function App() { messages: [], }); setSelectedSearch(null); - await refreshCollections({ kind: "chat", id: chat.id }); + await refreshCollections({ preferredSelection: { kind: "chat", id: chat.id } }); await refreshChat(chat.id); } catch (err) { const message = err instanceof Error ? err.message : String(err); @@ -3119,7 +3149,7 @@ export default function App() { messages: [], }); setSelectedSearch(null); - await refreshCollections({ kind: "chat", id: chat.id }); + await refreshCollections({ preferredSelection: { kind: "chat", id: chat.id } }); await refreshChat(chat.id); } catch (err) { const message = err instanceof Error ? err.message : String(err);