Compare commits

...

2 Commits

Author SHA1 Message Date
Austin Mroz
42983d79af Add test 2026-06-05 14:24:08 -07:00
Austin Mroz
8df278e186 Indicate in-progress upload with spinner 2026-06-05 11:53:20 -07:00
5 changed files with 58 additions and 2 deletions

View File

@@ -1,3 +1,5 @@
import type { UploadImageResponse } from '@comfyorg/ingest-types'
import {
comfyExpect as expect,
comfyPageFixture as test
@@ -23,4 +25,42 @@ test.describe('Vue Upload Widgets', { tag: '@vue-nodes' }, () => {
)
.toBeGreaterThan(0)
})
test('shows a spinner during upload', async ({ comfyPage }) => {
let releaseUpload: () => void = () => {}
const uploadResponse: UploadImageResponse = { name: 'spinner-test.png' }
await comfyPage.page.route('**/upload/image', async (route) => {
await new Promise<void>((resolve) => {
releaseUpload = resolve
})
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(uploadResponse)
})
})
for (const nodeName of ['Load Image', 'Load Video', 'Load Audio']) {
await test.step(`for ${nodeName}`, async () => {
await comfyPage.menu.topbar.newWorkflowButton.click()
await comfyPage.nextFrame()
await comfyPage.searchBoxV2.addNode(nodeName)
const node = comfyPage.vueNodes.getNodeByTitle(nodeName)
const fileInput = node.locator('input[type="file"]')
const spinner = node.getByRole('status')
await expect(spinner).toBeHidden()
await fileInput.setInputFiles({
name: 'spinner-test.png',
mimeType: 'image/png',
buffer: Buffer.from('test')
})
await expect(spinner).toBeVisible()
releaseUpload()
await expect(spinner).toBeHidden()
})
}
})
})

View File

@@ -154,6 +154,12 @@ function handleIsOpenUpdate(isOpen: boolean) {
void outputMediaAssets.refresh()
}
}
const isUploading = ref(false)
async function updateFiles(files: File[]) {
isUploading.value = true
await handleFilesUpdate(files)
isUploading.value = false
}
</script>
<template>
@@ -175,10 +181,11 @@ function handleIsOpenUpdate(isOpen: boolean) {
:ownership-options
:show-base-model-filter
:base-model-options
:is-uploading
v-bind="combinedProps"
class="w-full"
@update:selected="updateSelectedItems"
@update:files="handleFilesUpdate"
@update:files="updateFiles"
@update:is-open="handleIsOpenUpdate"
/>
</WidgetLayoutField>

View File

@@ -42,6 +42,7 @@ interface Props {
item: FormDropdownItem,
index: number
) => boolean
isUploading?: boolean
searcher?: (
query: string,
items: FormDropdownItem[],
@@ -277,6 +278,7 @@ function handleSearchEnter() {
:uploadable
:disabled
:accept
:is-uploading
@select-click="toggleDropdown"
@file-change="handleFileChange"
/>

View File

@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n'
import { cn } from '@comfyorg/tailwind-utils'
import Loader from '@/components/loader/Loader.vue'
import { WidgetInputBaseClass } from '../../layout'
import type { FormDropdownInputProps } from './types'
@@ -100,7 +101,12 @@ defineExpose({ focus })
)
"
>
<i class="icon-[lucide--folder-search] size-4" aria-hidden="true" />
<Loader v-if="isUploading" size="sm" />
<i
v-else
class="icon-[lucide--folder-search] size-4"
aria-hidden="true"
/>
<input
type="file"
class="absolute inset-0 -z-1 opacity-0"

View File

@@ -39,6 +39,7 @@ export interface FormDropdownInputProps {
uploadable: boolean
disabled: boolean
accept?: string
isUploading?: boolean
}
export interface FormDropdownMenuItemProps {