From 5a5f7cb5cd02e3bfed25a485fb3df67bbf11235f Mon Sep 17 00:00:00 2001 From: Frank Noirot Date: Fri, 21 Jun 2024 11:49:45 -0400 Subject: [PATCH] Franknoirot/limit model loading (#139) * Update guidance on local token in README * Make items fetched per page a named const, add one for fetch ahead page count * Refactor GenerationList to fetch only a few pages ahead and fetch more when scroll is near the bottom * Add a Playwright test to verify this behavior * Follow Svelte warning and put the initial fetch in an onMount handler * Update persistence key so we reset localStorage for people --- README.md | 2 +- src/components/GenerationList.svelte | 107 +++++++++++++++++++-------- src/lib/consts.ts | 11 ++- src/lib/endpoints.ts | 3 +- src/lib/stores.ts | 5 +- tests/e2e.playwright.ts | 14 ++++ 6 files changed, 106 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index dda5cc0..1d36528 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This repository is an open-source example of how to quickly get up and running w ## Developing 1. Generate a dev API token from https://dev.zoo.dev -2. Set the `VITE_TOKEN` environment variable in `./.env.development` to the generated dev API token +2. Set the `VITE_TOKEN` environment variable in `./.env.development.local` to the generated dev API token 3. Install yarn 4. Install dependencies with `yarn global add vite` and `yarn install` 5. Run the dev server with `yarn dev -- --open` diff --git a/src/components/GenerationList.svelte b/src/components/GenerationList.svelte index 99de7e5..c09a88d 100644 --- a/src/components/GenerationList.svelte +++ b/src/components/GenerationList.svelte @@ -1,33 +1,51 @@ -
- {#if Object.keys($generations).length > 0} +
+ {#if error} +

{error}

+ {:else if Object.keys($generations).length > 0} {#each Object.entries($generations).toSorted(sortTimeBuckets) as [category, items]}

{category}

@@ -74,19 +112,24 @@
{/each} - {/if} - {#if isFetching} -

0 ? ' pt-8 border-t' : '')} - > - Fetching your creations - -

- {:else if Object.keys($generations).length === 0} + {#await fetchPromise} +

0 ? ' pt-8 border-t' : '')} + > + Fetching your creations + +

+ {:then} + {#if $nextPageTokens[$nextPageTokens.length - 1] === null} +

+ You've reached the end of your creations 🎉 +

+ {/if} + {/await} + {:else}

You'll see your creations here once you submit your first prompt

{/if} - {#if error} -

{error}

- {/if}
diff --git a/src/lib/consts.ts b/src/lib/consts.ts index 2f35ccf..75734c0 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -1,6 +1,6 @@ import { msSinceStartOfDay, msSinceStartOfMonth, msSinceAWeekAgo, msSinceStartOfYear } from './time' -export const PERSIST_KEY_VERSION = '2023-01-09' +export const PERSIST_KEY_VERSION = '2024-06-21' export const PERSIST_KEY_GENERATIONS = 'TEXT_TO_CAD_GENERATIONS' export const PERSIST_KEY_UNREAD = 'TEXT_TO_CAD_UNREAD' @@ -41,3 +41,12 @@ export const TIME_BUCKETS = [ test: (then: Date, now: Date) => now.getTime() - then.getTime() < msSinceStartOfYear(now) } ] as const + +/** + * The number of pages to fetch ahead of the current page + */ +export const PAGES_AHEAD_TO_FETCH = 5 +/** + * The number of items to fetch per request + */ +export const ITEMS_PER_PAGE = 5 diff --git a/src/lib/endpoints.ts b/src/lib/endpoints.ts index 42481ce..a4813ab 100644 --- a/src/lib/endpoints.ts +++ b/src/lib/endpoints.ts @@ -1,4 +1,5 @@ import type { Models } from '@kittycad/lib' +import { ITEMS_PER_PAGE } from './consts' export type CADFormat = Models['FileExportFormat_type'] @@ -23,7 +24,7 @@ export const endpoints = { `${import.meta.env.VITE_API_BASE_URL}/file/conversion/gltf/${output_format}`, feedback: (id: string, feedback: Models['TextToCad_type']['feedback']) => `${import.meta.env.VITE_API_BASE_URL}/user/text-to-cad/${id}?feedback=${feedback}`, - list: ({ limit = 5, page_token }: ListParams) => + list: ({ limit = ITEMS_PER_PAGE, page_token }: ListParams) => `${import.meta.env.VITE_API_BASE_URL}/user/text-to-cad?no_models=true&limit=${limit}${ page_token ? `&page_token=${page_token}` : '' }`, diff --git a/src/lib/stores.ts b/src/lib/stores.ts index ea9dd14..0c9cade 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -55,7 +55,10 @@ export const generations = derived([combinedGenerations], ([$combinedGenerations return groupBy($combinedGenerations, ({ created_at }) => bucketByTime(created_at)) }) -export const nextPageToken = writable(undefined) +const NEXT_PAGE_TOKENS_KEY = 'nextPageTokens' +export const nextPageTokensInitial = fromLocalStorage(NEXT_PAGE_TOKENS_KEY, []) +export const nextPageTokens = writable(nextPageTokensInitial) +toLocalStorage(nextPageTokens, NEXT_PAGE_TOKENS_KEY) type UserSettings = { autoRotateModels: boolean diff --git a/tests/e2e.playwright.ts b/tests/e2e.playwright.ts index 6a0cbd0..0d39599 100644 --- a/tests/e2e.playwright.ts +++ b/tests/e2e.playwright.ts @@ -1,3 +1,4 @@ +import { ITEMS_PER_PAGE, PAGES_AHEAD_TO_FETCH } from '../src/lib/consts' import { expect, test } from '@playwright/test' test('Redirects to the dashboard from home when logged-in', async ({ page }) => { @@ -24,3 +25,16 @@ test('Prompt input is visible and usable on mobile', async ({ page }) => { await expect(page.locator('textarea')).toBeInViewport() await expect(page.locator('textarea')).toBeFocused() }) + +test('Sidebar only loads set number of pages of results initially', async ({ page }) => { + // Go to the home page + await page.goto('https://localhost:3000') + + // Assert that we are now on the dashboard + await page.waitForURL('**/dashboard', { waitUntil: 'networkidle' }) + + // Assert that only 5 pages of results are loaded initially + await expect(page.getByTestId('generation-list').getByRole('link')).toHaveCount( + PAGES_AHEAD_TO_FETCH * ITEMS_PER_PAGE + ) +})