-
Notifications
You must be signed in to change notification settings - Fork 490
feat: implement progressive pagination for Asset Browser model assets #8212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dc39d79
b6e0ef7
d8da949
b09cc33
20aeac4
a61121e
58ef1a9
c3f0b46
5dd2323
01c5953
bdac181
770fa68
cf237cf
3a4e716
48493e2
cda777c
da869fa
c281278
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import { fromZodError } from 'zod-validation-error' | ||
|
|
||
| import { st } from '@/i18n' | ||
|
|
||
| import { | ||
| assetItemSchema, | ||
| assetResponseSchema, | ||
|
|
@@ -17,6 +18,16 @@ import type { | |
| import { api } from '@/scripts/api' | ||
| import { useModelToNodeStore } from '@/stores/modelToNodeStore' | ||
|
|
||
| export interface PaginationOptions { | ||
| limit?: number | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are they optional?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are defaults set below, and the API itself doesn't require them. |
||
| offset?: number | ||
| } | ||
|
|
||
| interface AssetRequestOptions extends PaginationOptions { | ||
| includeTags: string[] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it could be optional, isnt it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is always set. Not sure if it's required by the API. Once we get the spec synced we'll know that we are aligned with the backend expectations. |
||
| includePublic?: boolean | ||
| } | ||
|
|
||
| /** | ||
| * Maps CivitAI validation error codes to localized error messages | ||
| */ | ||
|
|
@@ -77,9 +88,27 @@ function createAssetService() { | |
| * Handles API response with consistent error handling and Zod validation | ||
| */ | ||
| async function handleAssetRequest( | ||
| url: string, | ||
| options: AssetRequestOptions, | ||
| context: string | ||
| ): Promise<AssetResponse> { | ||
| const { | ||
| includeTags, | ||
| limit = DEFAULT_LIMIT, | ||
| offset, | ||
| includePublic | ||
| } = options | ||
| const queryParams = new URLSearchParams({ | ||
| include_tags: includeTags.join(','), | ||
| limit: limit.toString() | ||
| }) | ||
| if (offset !== undefined && offset > 0) { | ||
| queryParams.set('offset', offset.toString()) | ||
| } | ||
| if (includePublic !== undefined) { | ||
| queryParams.set('include_public', includePublic ? 'true' : 'false') | ||
| } | ||
|
|
||
| const url = `${ASSETS_ENDPOINT}?${queryParams.toString()}` | ||
| const res = await api.fetchApi(url) | ||
| if (!res.ok) { | ||
| throw new Error( | ||
|
|
@@ -101,7 +130,7 @@ function createAssetService() { | |
| */ | ||
| async function getAssetModelFolders(): Promise<ModelFolder[]> { | ||
| const data = await handleAssetRequest( | ||
| `${ASSETS_ENDPOINT}?include_tags=${MODELS_TAG}&limit=${DEFAULT_LIMIT}`, | ||
| { includeTags: [MODELS_TAG] }, | ||
| 'model folders' | ||
| ) | ||
|
|
||
|
|
@@ -130,7 +159,7 @@ function createAssetService() { | |
| */ | ||
| async function getAssetModels(folder: string): Promise<ModelFile[]> { | ||
| const data = await handleAssetRequest( | ||
| `${ASSETS_ENDPOINT}?include_tags=${MODELS_TAG},${folder}&limit=${DEFAULT_LIMIT}`, | ||
| { includeTags: [MODELS_TAG, folder] }, | ||
| `models for ${folder}` | ||
| ) | ||
|
|
||
|
|
@@ -169,9 +198,15 @@ function createAssetService() { | |
| * and fetching all assets with that category tag | ||
| * | ||
| * @param nodeType - The ComfyUI node type (e.g., 'CheckpointLoaderSimple') | ||
| * @param options - Pagination options | ||
| * @param options.limit - Maximum number of assets to return (default: 500) | ||
| * @param options.offset - Number of assets to skip (default: 0) | ||
| * @returns Promise<AssetItem[]> - Full asset objects with preserved metadata | ||
| */ | ||
| async function getAssetsForNodeType(nodeType: string): Promise<AssetItem[]> { | ||
| async function getAssetsForNodeType( | ||
| nodeType: string, | ||
| { limit = DEFAULT_LIMIT, offset = 0 }: PaginationOptions = {} | ||
| ): Promise<AssetItem[]> { | ||
| if (!nodeType || typeof nodeType !== 'string') { | ||
| return [] | ||
| } | ||
|
|
@@ -186,7 +221,7 @@ function createAssetService() { | |
|
|
||
| // Fetch assets for this category using same API pattern as getAssetModels | ||
| const data = await handleAssetRequest( | ||
| `${ASSETS_ENDPOINT}?include_tags=${MODELS_TAG},${category}&limit=${DEFAULT_LIMIT}`, | ||
| { includeTags: [MODELS_TAG, category], limit, offset }, | ||
| `assets for ${nodeType}` | ||
| ) | ||
|
Comment on lines
223
to
226
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. small nit: should we modify handleAssetRequest signature to accept query params instead of doing string templating here?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good and ideally this is type-checked agains the types that are generated from openapi spec!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. openapi spec should be merged sometime today, but i dont think that should block
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call, updated. The interface there is a good target to swap out once we have the spec types. |
||
|
|
||
|
|
@@ -242,23 +277,10 @@ function createAssetService() { | |
| async function getAssetsByTag( | ||
| tag: string, | ||
| includePublic: boolean = true, | ||
| { | ||
| limit = DEFAULT_LIMIT, | ||
| offset = 0 | ||
| }: { limit?: number; offset?: number } = {} | ||
| { limit = DEFAULT_LIMIT, offset = 0 }: PaginationOptions = {} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose we won't have the type generation in time for this PR? related comment above
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not without some form of time travel |
||
| ): Promise<AssetItem[]> { | ||
| const queryParams = new URLSearchParams({ | ||
| include_tags: tag, | ||
| limit: limit.toString(), | ||
| include_public: includePublic ? 'true' : 'false' | ||
| }) | ||
|
|
||
| if (offset > 0) { | ||
| queryParams.set('offset', offset.toString()) | ||
| } | ||
|
|
||
| const data = await handleAssetRequest( | ||
| `${ASSETS_ENDPOINT}?${queryParams.toString()}`, | ||
| { includeTags: [tag], limit, offset, includePublic }, | ||
| `assets for tag ${tag}` | ||
| ) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.