diff --git a/src/App.jsx b/src/App.jsx index 662ad40..50482a9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -874,6 +874,68 @@ async function regenerateFromIndex(index, overrideUserText = null) { return chatLibraryHasActiveJob ? ' (syncing)' : ' (needs sync)' }, [chatLibrary, chatLibraryHasActiveJob]) + function getChatLibrarySlugForSession(sessionId) { + if (!sessionId) return null + return chatLibraryBySession[sessionId] || null + } + + function getChatLibraryForSession(sessionId) { + const slug = getChatLibrarySlugForSession(sessionId) + if (!slug) return null + return libraries.find(lib => lib.slug === slug) || null + } + + function isLibrarySyncing(slug) { + if (!slug) return false + return libraryJobs.some(job => job.slug === slug && (job.status === 'queued' || job.status === 'running')) + } + + function setChatLibraryForSession(sessionId, slug) { + if (!sessionId) return + setChatLibraryBySession(prev => { + const next = { ...(prev || {}) } + if (slug) { + next[sessionId] = slug + } else { + delete next[sessionId] + } + return next + }) + } + + function removeLibraryFromChatSelections(slug) { + if (!slug) return + setChatLibraryBySession(prev => { + let changed = false + const next = {} + for (const [sessionId, librarySlug] of Object.entries(prev || {})) { + if (librarySlug === slug) { + changed = true + continue + } + next[sessionId] = librarySlug + } + return changed ? next : prev + }) + } + + useEffect(() => { + if (!isDbPickerOpen) return + + const onPointerDown = (event) => { + if (!dbPickerRef.current?.contains(event.target)) { + setIsDbPickerOpen(false) + } + } + + document.addEventListener('mousedown', onPointerDown) + return () => document.removeEventListener('mousedown', onPointerDown) + }, [isDbPickerOpen]) + + useEffect(() => { + setIsDbPickerOpen(false) + }, [activeSessionId, activeSidebarMode]) + // Persist the scrollTop of the session we are LEAVING (on chat change or when leaving the chat view) useEffect(() => { const leavingSessionId = activeSessionId;