From daa6e69baf8256e09bfaebe6b4164c9c2b2e3fe7 Mon Sep 17 00:00:00 2001 From: Nathan Sarrazin Date: Thu, 7 Nov 2024 09:16:20 +0000 Subject: [PATCH 1/3] wip --- src/lib/components/InfiniteScroll.svelte | 30 +++++++++++++++++++++ src/lib/components/NavMenu.svelte | 34 ++++++++++++++++++++++++ src/routes/+layout.server.ts | 31 +++++++++------------ src/routes/api/conversations/+server.ts | 13 ++++++--- 4 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 src/lib/components/InfiniteScroll.svelte diff --git a/src/lib/components/InfiniteScroll.svelte b/src/lib/components/InfiniteScroll.svelte new file mode 100644 index 00000000000..c8ecba24b62 --- /dev/null +++ b/src/lib/components/InfiniteScroll.svelte @@ -0,0 +1,30 @@ + + +
+
+
+
+
diff --git a/src/lib/components/NavMenu.svelte b/src/lib/components/NavMenu.svelte index c69f07bcd5e..99cd1ccf4b0 100644 --- a/src/lib/components/NavMenu.svelte +++ b/src/lib/components/NavMenu.svelte @@ -10,11 +10,20 @@ import type { ConvSidebar } from "$lib/types/ConvSidebar"; import type { Model } from "$lib/types/Model"; import { page } from "$app/stores"; + import InfiniteScroll from "./InfiniteScroll.svelte"; + import type { Conversation } from "$lib/types/Conversation"; + import { tick } from "svelte"; export let conversations: Promise; export let canLogin: boolean; export let user: LayoutData["user"]; + $: p = 0; + + let hasMore = true; + + let scrollContainer: HTMLDivElement; + function handleNewChatClick() { isAborted.set(true); } @@ -44,6 +53,27 @@ } as const; const nModels: number = $page.data.models.filter((el: Model) => !el.unlisted).length; + + async function handleVisible() { + p++; + const newConvs = await fetch(`${base}/api/conversations?p=${p}`) + .then((res) => res.json()) + .then((convs) => + convs.map( + (conv: Pick) => ({ + ...conv, + updatedAt: new Date(conv.updatedAt), + }) + ) + ) + .catch(() => []); + + if (newConvs.length === 0) { + hasMore = false; + } + + conversations = Promise.resolve([...(await conversations), ...newConvs]); + }
@@ -63,6 +93,7 @@
{#await groupedConversations} @@ -90,6 +121,9 @@ {/each}
{/await} + {#if hasMore} + + {/if}
{ +export const load: LayoutServerLoad = async ({ locals, depends, fetch }) => { depends(UrlDependency.ConversationList); const settings = await collections.settings.findOne(authCondition(locals)); @@ -56,24 +56,17 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => { const conversations = nConversations === 0 ? Promise.resolve([]) - : collections.conversations - .find(authCondition(locals)) - .sort({ updatedAt: -1 }) - .project< - Pick< - Conversation, - "title" | "model" | "_id" | "updatedAt" | "createdAt" | "assistantId" - > - >({ - title: 1, - model: 1, - _id: 1, - updatedAt: 1, - createdAt: 1, - assistantId: 1, - }) - .limit(300) - .toArray(); + : fetch(`${env.APP_BASE}/api/conversations`) + .then((res) => res.json()) + .then( + ( + convs: Pick[] + ) => + convs.map((conv) => ({ + ...conv, + updatedAt: new Date(conv.updatedAt), + })) + ); const userAssistants = settings?.assistants?.map((assistantId) => assistantId.toString()) ?? []; const userAssistantsSet = new Set(userAssistants); diff --git a/src/routes/api/conversations/+server.ts b/src/routes/api/conversations/+server.ts index 1b5ca26aa98..3daecf38546 100644 --- a/src/routes/api/conversations/+server.ts +++ b/src/routes/api/conversations/+server.ts @@ -3,7 +3,7 @@ import { models } from "$lib/server/models"; import { authCondition } from "$lib/server/auth"; import type { Conversation } from "$lib/types/Conversation"; -const NUM_PER_PAGE = 300; +const NUM_PER_PAGE = 40; export async function GET({ locals, url }) { const p = parseInt(url.searchParams.get("p") ?? "0"); @@ -24,15 +24,20 @@ export async function GET({ locals, url }) { .limit(NUM_PER_PAGE) .toArray(); + if (convs.length === 0) { + return Response.json([]); + } + const res = convs.map((conv) => ({ - id: conv._id, + _id: conv._id, + id: conv._id, // legacy param iOS title: conv.title, updatedAt: conv.updatedAt, - modelId: conv.model, + model: conv.model, + modelId: conv.model, // legacy param iOS assistantId: conv.assistantId, modelTools: models.find((m) => m.id == conv.model)?.tools ?? false, })); - return Response.json(res); } else { return Response.json({ message: "Must have session cookie" }, { status: 401 }); From 9f54959c7d7dfbbd3ee87f0338fc3e3466057430 Mon Sep 17 00:00:00 2001 From: Nathan Sarrazin Date: Thu, 7 Nov 2024 19:41:51 +0000 Subject: [PATCH 2/3] wip: infinite scrolling continues --- src/lib/components/InfiniteScroll.svelte | 19 ++++++++++++++++++- src/lib/components/NavMenu.svelte | 9 ++++----- src/routes/api/conversations/+server.ts | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/lib/components/InfiniteScroll.svelte b/src/lib/components/InfiniteScroll.svelte index c8ecba24b62..a517bb1a2b6 100644 --- a/src/lib/components/InfiniteScroll.svelte +++ b/src/lib/components/InfiniteScroll.svelte @@ -5,12 +5,26 @@ const dispatch = createEventDispatcher(); let loader: HTMLDivElement; let observer: IntersectionObserver; + let intervalId: ReturnType | undefined; onMount(() => { observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { - dispatch("visible"); + // Clear any existing interval + if (intervalId) { + clearInterval(intervalId); + } + // Start new interval that dispatches every 250ms + intervalId = setInterval(() => { + dispatch("visible"); + }, 250); + } else { + // Clear interval when not intersecting + if (intervalId) { + clearInterval(intervalId); + intervalId = undefined; + } } }); }); @@ -19,6 +33,9 @@ return () => { observer.disconnect(); + if (intervalId) { + clearInterval(intervalId); + } }; }); diff --git a/src/lib/components/NavMenu.svelte b/src/lib/components/NavMenu.svelte index 99cd1ccf4b0..f767272c6e3 100644 --- a/src/lib/components/NavMenu.svelte +++ b/src/lib/components/NavMenu.svelte @@ -12,13 +12,12 @@ import { page } from "$app/stores"; import InfiniteScroll from "./InfiniteScroll.svelte"; import type { Conversation } from "$lib/types/Conversation"; - import { tick } from "svelte"; export let conversations: Promise; export let canLogin: boolean; export let user: LayoutData["user"]; - $: p = 0; + export let p = 0; let hasMore = true; @@ -120,10 +119,10 @@ {/if} {/each}
+ {#if hasMore} + + {/if} {/await} - {#if hasMore} - - {/if}
Date: Fri, 22 Nov 2024 09:18:50 +0000 Subject: [PATCH 3/3] fix: merge regression --- src/lib/components/NavMenu.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/NavMenu.svelte b/src/lib/components/NavMenu.svelte index ff40265d0df..ca6e399f3a9 100644 --- a/src/lib/components/NavMenu.svelte +++ b/src/lib/components/NavMenu.svelte @@ -71,7 +71,7 @@ hasMore = false; } - conversations = Promise.resolve([...(await conversations), ...newConvs]); + conversations = [...conversations, ...newConvs]; }