Compare commits

...

4 Commits

Author SHA1 Message Date
Alexander Brown
ea11e29f29 Merge branch 'main' into austin/drop-on-top-fe-937 2026-06-12 22:16:18 -07:00
Alexander Brown
d6b312a87f Merge branch 'main' into austin/drop-on-top-fe-937 2026-06-12 15:34:12 -07:00
Austin Mroz
f4ee7008cc Add test 2026-06-04 10:51:17 -07:00
Austin Mroz
c14f182694 Allow drag/drop to topbar 2026-06-04 08:44:07 -07:00
4 changed files with 51 additions and 15 deletions

View File

@@ -8,18 +8,20 @@ import { getMimeType } from '@e2e/fixtures/utils/mimeTypeUtil'
import { assetPath } from '@e2e/fixtures/utils/paths'
import { nextFrame } from '@e2e/fixtures/utils/timing'
type DragDropOptions = {
fileName?: string
filePath?: string
url?: string
dropPosition?: Position
waitForUpload?: boolean
preserveNativePropagation?: boolean
}
export class DragDropHelper {
constructor(private readonly page: Page) {}
async dragAndDropExternalResource(
options: {
fileName?: string
filePath?: string
url?: string
dropPosition?: Position
waitForUpload?: boolean
preserveNativePropagation?: boolean
} = {}
options: DragDropOptions = {}
): Promise<void> {
const {
dropPosition = { x: 100, y: 100 },
@@ -156,24 +158,21 @@ export class DragDropHelper {
async dragAndDropFile(
fileName: string,
options: { dropPosition?: Position; waitForUpload?: boolean } = {}
options: DragDropOptions = {}
): Promise<void> {
return this.dragAndDropExternalResource({ fileName, ...options })
}
async dragAndDropFilePath(
filePath: string,
options: { dropPosition?: Position; waitForUpload?: boolean } = {}
options: DragDropOptions = {}
): Promise<void> {
return this.dragAndDropExternalResource({ filePath, ...options })
}
async dragAndDropURL(
url: string,
options: {
dropPosition?: Position
preserveNativePropagation?: boolean
} = {}
options: DragDropOptions = {}
): Promise<void> {
return this.dragAndDropExternalResource({ url, ...options })
}

View File

@@ -110,5 +110,41 @@ test.describe(
})
})
}
test('Can load from media dropped on topbar', async ({ comfyPage }) => {
// Regretfully, the dragAndDropFile mock uses synthetic events,
// so we need to manually validated that events are prevents
const prevented = await comfyPage.menu.topbar
.getActiveTab()
.evaluate((el) => {
const eventOptions = {
bubbles: true,
cancelable: true,
clientX: 0,
clientY: 0
}
const dragOverEvent = new DragEvent('dragover', eventOptions)
el.dispatchEvent(dragOverEvent)
return dragOverEvent.defaultPrevented
})
expect(prevented).toBe(true)
await test.step('drop media on topbar', async () => {
await comfyPage.dragDrop.dragAndDropFilePath(
metadataFixturePath('with_metadata.png'),
{ dropPosition: { x: 0, y: 0 }, preserveNativePropagation: true }
)
})
await test.step('graph contains only the embedded KSampler', async () => {
await expect.poll(() => comfyPage.nodeOps.getGraphNodesCount()).toBe(1)
const ksamplers = await comfyPage.nodeOps.getNodeRefsByType('KSampler')
expect(
ksamplers,
'exactly one KSampler should have been loaded from the fixture'
).toHaveLength(1)
})
})
}
)

View File

@@ -673,6 +673,7 @@ export class ComfyApp {
this.canvas.setDirty(false, true)
})
useEventListener(document, 'dragover', (e) => e.preventDefault())
// Add handler for dropping onto a specific node
useEventListener(
this.canvasElRef,

View File

@@ -99,7 +99,7 @@ function dragDrop(e: DragEvent) {
</script>
<template>
<MobileDisplay v-if="mobileDisplay" />
<div v-else class="absolute size-full" @dragover.prevent>
<div v-else class="absolute size-full">
<div
class="workflow-tabs-container pointer-events-auto h-(--workflow-tabs-height) w-full border-b border-interface-stroke shadow-interface"
>