Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/sidebar/tabs/AssetSidebarTemplate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
<slot name="header" />
</div>
</div>
<!-- h-0 to force scrollpanel to grow -->
<ScrollPanel class="h-0 grow">
<!-- min-h-0 to force scrollpanel to grow -->
<ScrollPanel class="min-h-0 grow">
<slot name="body" />
</ScrollPanel>
<div v-if="slots.footer">
Expand Down
44 changes: 29 additions & 15 deletions src/components/sidebar/tabs/AssetsSidebarTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@
<template #body>
<div v-if="displayAssets.length" class="relative size-full">
<VirtualGrid
v-if="displayAssets.length"
v-if="!loading && displayAssets.length"
:items="mediaAssetsWithKey"
:grid-style="{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
padding: '0.5rem',
gap: '0.5rem'
}"
@approach-end="handleApproachEnd"
>
<template #item="{ item }">
<MediaAssetCard
Expand All @@ -66,24 +67,24 @@
/>
</template>
</VirtualGrid>
<div v-else-if="loading">
<div v-else>
<ProgressSpinner
class="absolute left-1/2 w-[50px] -translate-x-1/2"
/>
</div>
<div v-else>
<NoResultsPlaceholder
icon="pi pi-info-circle"
:title="
$t(
activeTab === 'input'
? 'sideToolbar.noImportedFiles'
: 'sideToolbar.noGeneratedFiles'
)
"
:message="$t('sideToolbar.noFilesFoundMessage')"
/>
</div>
</div>
<div v-else>
<NoResultsPlaceholder
icon="pi pi-info-circle"
:title="
$t(
activeTab === 'input'
? 'sideToolbar.noImportedFiles'
: 'sideToolbar.noGeneratedFiles'
)
"
:message="$t('sideToolbar.noFilesFoundMessage')"
/>
</div>
</template>
<template #footer>
Expand Down Expand Up @@ -291,6 +292,7 @@ watch(
activeTab,
() => {
clearSelection()
// Reset pagination state when tab changes
void refreshAssets()
},
{ immediate: true }
Expand Down Expand Up @@ -395,4 +397,16 @@ const handleDeleteSelected = async () => {
await deleteMultipleAssets(selectedAssets)
clearSelection()
}

const handleApproachEnd = async () => {
if (
activeTab.value === 'output' &&
!isInFolderView.value &&
outputAssets.loadMore &&
outputAssets.hasMore?.value &&
!outputAssets.isLoadingMore?.value
) {
await outputAssets.loadMore()
}
}
</script>
15 changes: 15 additions & 0 deletions src/platform/assets/composables/media/IAssetsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,19 @@ export interface IAssetsProvider {
* Refresh the media list (alias for fetchMediaList)
*/
refresh: () => Promise<AssetItem[]>

/**
* Load more items (for pagination)
*/
loadMore?: () => Promise<void>

/**
* Whether there are more items to load
*/
hasMore?: Ref<boolean>

/**
* Whether currently loading more items
*/
isLoadingMore?: Ref<boolean>
}
19 changes: 18 additions & 1 deletion src/platform/assets/composables/media/useAssetsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,28 @@ export function useAssetsApi(directory: 'input' | 'output') {

const refresh = () => fetchMediaList()

const loadMore = async (): Promise<void> => {
if (directory === 'output') {
await assetsStore.loadMoreHistory()
}
}

const hasMore = computed(() => {
return directory === 'output' ? assetsStore.hasMoreHistory : false
})

const isLoadingMore = computed(() => {
return directory === 'output' ? assetsStore.isLoadingMore : false
})

return {
media,
loading,
error,
fetchMediaList,
refresh
refresh,
loadMore,
hasMore,
isLoadingMore
}
}
19 changes: 18 additions & 1 deletion src/platform/assets/composables/media/useInternalFilesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,28 @@ export function useInternalFilesApi(directory: 'input' | 'output') {

const refresh = () => fetchMediaList()

const loadMore = async (): Promise<void> => {
if (directory === 'output') {
await assetsStore.loadMoreHistory()
}
}

const hasMore = computed(() => {
return directory === 'output' ? assetsStore.hasMoreHistory : false
})

const isLoadingMore = computed(() => {
return directory === 'output' ? assetsStore.isLoadingMore : false
})

return {
media,
loading,
error,
fetchMediaList,
refresh
refresh,
loadMore,
hasMore,
isLoadingMore
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ import type {
*/
export async function fetchHistoryV1(
fetchApi: (url: string) => Promise<Response>,
maxItems: number = 200
maxItems: number = 200,
offset?: number
): Promise<HistoryV1Response> {
const res = await fetchApi(`/history?max_items=${maxItems}`)
let url = `/history?max_items=${maxItems}`
if (offset !== undefined) {
url += `&offset=${offset}`
}
const res = await fetchApi(url)
const json: Record<
string,
Omit<HistoryTaskItem, 'taskType'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ import type { HistoryResponseV2 } from '../types/historyV2Types'
*/
export async function fetchHistoryV2(
fetchApi: (url: string) => Promise<Response>,
maxItems: number = 200
maxItems: number = 200,
offset?: number
): Promise<HistoryV1Response> {
const res = await fetchApi(`/history_v2?max_items=${maxItems}`)
let url = `/history_v2?max_items=${maxItems}`
if (offset !== undefined) {
url += `&offset=${offset}`
}
const res = await fetchApi(url)
const rawData: HistoryResponseV2 = await res.json()
const adaptedHistory = mapHistoryV2toHistory(rawData)
return { History: adaptedHistory }
Expand Down
9 changes: 7 additions & 2 deletions src/scripts/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -898,10 +898,15 @@ export class ComfyApi extends EventTarget {
* @returns Prompt history including node outputs
*/
async getHistory(
max_items: number = 200
max_items: number = 200,
options?: { offset?: number }
): Promise<{ History: HistoryTaskItem[] }> {
try {
return await fetchHistory(this.fetchApi.bind(this), max_items)
return await fetchHistory(
this.fetchApi.bind(this),
max_items,
options?.offset
)
} catch (error) {
console.error(error)
return { History: [] }
Expand Down
Loading