diff --git a/src/lib/components/InfiniteScroll.svelte b/src/lib/components/InfiniteScroll.svelte new file mode 100644 index 00000000000..a517bb1a2b6 --- /dev/null +++ b/src/lib/components/InfiniteScroll.svelte @@ -0,0 +1,47 @@ + + +
+
+
+
+
diff --git a/src/lib/components/NavMenu.svelte b/src/lib/components/NavMenu.svelte index 146ead0bb71..ca6e399f3a9 100644 --- a/src/lib/components/NavMenu.svelte +++ b/src/lib/components/NavMenu.svelte @@ -10,11 +10,19 @@ 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"; export let conversations: ConvSidebar[]; export let canLogin: boolean; export let user: LayoutData["user"]; + export let p = 0; + + let hasMore = true; + + let scrollContainer: HTMLDivElement; + function handleNewChatClick() { isAborted.set(true); } @@ -44,6 +52,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 = [...conversations, ...newConvs]; + }
@@ -63,6 +92,7 @@
{#await groupedConversations} @@ -89,6 +119,9 @@ {/if} {/each}
+ {#if hasMore} + + {/if} {/await}
{ +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..b8fe48ea223 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 = 5; 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 });