diff --git a/src/lib/components/chat/Settings/Chats.svelte b/src/lib/components/chat/Settings/Chats.svelte index 2c032d4df..f62e3926e 100644 --- a/src/lib/components/chat/Settings/Chats.svelte +++ b/src/lib/components/chat/Settings/Chats.svelte @@ -12,7 +12,12 @@ getAllUserChats, getChatList } from '$lib/apis/chats'; - import { getImportOrigin, convertOpenAIChats, disablePagination } from '$lib/utils'; + import { + getImportOrigin, + convertOpenAIChats, + disablePagination, + enablePagination + } from '$lib/utils'; import { onMount, getContext } from 'svelte'; import { goto } from '$app/navigation'; import { toast } from 'svelte-sonner'; @@ -61,8 +66,7 @@ await createNewChat(localStorage.token, chat); } } - disablePagination(); - await chats.set(await getChatList(localStorage.token)); + enablePagination(); }; const exportChats = async () => { @@ -77,8 +81,7 @@ await archiveAllChats(localStorage.token).catch((error) => { toast.error(error); }); - disablePagination(); - await chats.set(await getChatList(localStorage.token)); + enablePagination(); }; const deleteAllChatsHandler = async () => { @@ -86,8 +89,8 @@ await deleteAllChats(localStorage.token).catch((error) => { toast.error(error); }); - disablePagination(); - await chats.set(await getChatList(localStorage.token)); + + enablePagination(); }; const toggleSaveChatHistory = async () => { diff --git a/src/lib/components/chat/Tags.svelte b/src/lib/components/chat/Tags.svelte index 19efa2662..a806f2aaa 100644 --- a/src/lib/components/chat/Tags.svelte +++ b/src/lib/components/chat/Tags.svelte @@ -8,12 +8,13 @@ getTagsById, updateChatById } from '$lib/apis/chats'; - import { tags as _tags, chats, pinnedChats, pageSkip, pageLimit, tagView } from '$lib/stores'; + import { tags as _tags, chats, pinnedChats, pageSkip, pageLimit } from '$lib/stores'; import { createEventDispatcher, onMount } from 'svelte'; const dispatch = createEventDispatcher(); import Tags from '../common/Tags.svelte'; + import { enablePagination } from '$lib/utils'; export let chatId = ''; let tags = []; @@ -59,7 +60,7 @@ } } else { // if the tag we deleted is no longer a valid tag, return to main chat list view - tagView.set(false); + enablePagination(); await chats.set( await getChatList(localStorage.token, 0, $pageSkip * $pageLimit || $pageLimit) ); diff --git a/src/lib/components/common/Loader.svelte b/src/lib/components/common/Loader.svelte new file mode 100644 index 000000000..dbe84fd60 --- /dev/null +++ b/src/lib/components/common/Loader.svelte @@ -0,0 +1,30 @@ + + +
+ +
diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 07dac20f0..70360a46d 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -14,13 +14,12 @@ pinnedChats, pageSkip, pageLimit, - scrollPaginationEnabled, - tagView + scrollPaginationEnabled } from '$lib/stores'; import { onMount, getContext, tick } from 'svelte'; const i18n = getContext('i18n'); - import { disablePagination } from '$lib/utils'; + import { disablePagination, enablePagination } from '$lib/utils'; import { updateUserSettings } from '$lib/apis/users'; import { @@ -40,6 +39,7 @@ import ChatItem from './Sidebar/ChatItem.svelte'; import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; import Spinner from '../common/Spinner.svelte'; + import Loader from '../common/Loader.svelte'; const BREAKPOINT = 768; @@ -55,9 +55,10 @@ let showDropdown = false; let filteredChatList = []; - let paginationScrollThreashold = 0.6; - let nextPageLoading = false; - let chatPagniationComplete = false; + + // Pagination variables + let chatListLoading = false; + let allChatsLoaded = false; pageLimit.set(20); @@ -81,6 +82,18 @@ } }); + const loadMoreChats = async () => { + chatListLoading = true; + pageSkip.set($pageSkip + 1); + const newChatList = await getChatList(localStorage.token, $pageSkip * $pageLimit, $pageLimit); + + // once the bottom of the list has been reached (no results) there is no need to continue querying + allChatsLoaded = newChatList.length === 0; + await chats.set([...$chats, ...newChatList]); + + chatListLoading = false; + }; + onMount(async () => { mobile.subscribe((e) => { if ($showSidebar && e) { @@ -151,48 +164,6 @@ window.addEventListener('focus', onFocus); window.addEventListener('blur', onBlur); - // Infinite scroll - const loader = document.getElementById('loader'); - - const observer = new IntersectionObserver( - (entries, observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - loadMoreContent(); - observer.unobserve(loader); // Stop observing until content is loaded - } - }); - }, - { - root: null, // viewport - rootMargin: '0px', - threshold: 1.0 // When 100% of the loader is visible - } - ); - - observer.observe(loader); - const loadMoreContent = async () => { - if (!$scrollPaginationEnabled) return; - if ($tagView) return; - if (nextPageLoading) return; - if (chatPagniationComplete) return; - - nextPageLoading = true; - pageSkip.set($pageSkip + 1); - // extend existing chats - const nextPageChats = await getChatList( - localStorage.token, - $pageSkip * $pageLimit, - $pageLimit - ); - // once the bottom of the list has been reached (no results) there is no need to continue querying - chatPagniationComplete = nextPageChats.length === 0; - await chats.set([...$chats, ...nextPageChats]); - nextPageLoading = false; - - observer.observe(loader); // Start observing again after content is loaded - }; - return () => { window.removeEventListener('keydown', onKeyDown); window.removeEventListener('keyup', onKeyUp); @@ -466,8 +437,8 @@ placeholder={$i18n.t('Search')} bind:value={search} on:focus={async () => { - disablePagination(); // TODO: migrate backend for more scalable search mechanism + disablePagination(); await chats.set(await getChatList(localStorage.token)); // when searching, load all chats enrichChatsWithContent($chats); }} @@ -480,8 +451,8 @@