Compare commits
1 Commits
update-fix
...
export-gen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6a98e3286 |
@@ -18,10 +18,3 @@ TEST_COMFYUI_DIR=/home/ComfyUI
|
||||
|
||||
# Whether to enable minification of the frontend code.
|
||||
ENABLE_MINIFY=true
|
||||
|
||||
# Whether to disable proxying the `/templates` route. If true, allows you to
|
||||
# serve templates from the ComfyUI_frontend/public/templates folder (for
|
||||
# locally testing changes to templates). When false or nonexistent, the
|
||||
# templates are served via the normal method from the server's python site
|
||||
# packages.
|
||||
DISABLE_TEMPLATES_PROXY=false
|
||||
|
||||
37
.github/copilot-instructions.md
vendored
@@ -1,37 +0,0 @@
|
||||
Use the Vue 3 Composition API instead of the Options API when writing Vue components. An exception is when overriding or extending a PrimeVue component for compatibility, you may use the Options API.
|
||||
|
||||
Use setup() function for component logic
|
||||
|
||||
Utilize ref and reactive for reactive state
|
||||
|
||||
Implement computed properties with computed()
|
||||
|
||||
Use watch and watchEffect for side effects
|
||||
|
||||
Implement lifecycle hooks with onMounted, onUpdated, etc.
|
||||
|
||||
Utilize provide/inject for dependency injection
|
||||
|
||||
Use vue 3.5 style of default prop declaration.
|
||||
|
||||
Use Tailwind CSS for styling
|
||||
|
||||
Leverage VueUse functions for performance-enhancing styles
|
||||
|
||||
Use lodash for utility functions
|
||||
|
||||
Use TypeScript for type safety
|
||||
|
||||
Implement proper props and emits definitions
|
||||
|
||||
Utilize Vue 3's Teleport component when needed
|
||||
|
||||
Use Suspense for async components
|
||||
|
||||
Implement proper error handling
|
||||
|
||||
Follow Vue 3 style guide and naming conventions
|
||||
|
||||
Use Vite for fast development and building
|
||||
|
||||
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json.
|
||||
2
.github/workflows/release.yaml
vendored
@@ -29,9 +29,9 @@ jobs:
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
|
||||
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
|
||||
USE_PROD_CONFIG: 'true'
|
||||
run: |
|
||||
npm ci
|
||||
npm run fetch-templates
|
||||
npm run build
|
||||
npm run zipdist
|
||||
- name: Upload dist artifact
|
||||
|
||||
3
.github/workflows/test-ui.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
with:
|
||||
repository: 'Comfy-Org/ComfyUI_devtools'
|
||||
path: 'ComfyUI/custom_nodes/ComfyUI_devtools'
|
||||
ref: '9d2421fd3208a310e4d0f71fca2ea0c985759c33'
|
||||
ref: '49c8220be49120dbaff85f32813d854d6dff2d05'
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -39,6 +39,7 @@ jobs:
|
||||
- name: Build ComfyUI_frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run fetch-templates
|
||||
npm run build
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
|
||||
2
.github/workflows/update-electron-types.yaml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.PR_GH_TOKEN }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: '[chore] Update electron-types to ${{ steps.get-version.outputs.NEW_VERSION }}'
|
||||
title: '[chore] Update electron-types to ${{ steps.get-version.outputs.NEW_VERSION }}'
|
||||
body: |
|
||||
|
||||
3
.gitignore
vendored
@@ -55,6 +55,3 @@ dist.zip
|
||||
|
||||
# Temporary repository directory
|
||||
templates_repo/
|
||||
|
||||
# Vite’s timestamped config modules
|
||||
vite.config.mts.timestamp-*.mjs
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
const { defineConfig } = require('@lobehub/i18n-cli');
|
||||
|
||||
module.exports = defineConfig({
|
||||
modelName: 'gpt-4.1',
|
||||
modelName: 'gpt-4',
|
||||
splitToken: 1024,
|
||||
entry: 'src/locales/en',
|
||||
entryLocale: 'en',
|
||||
output: 'src/locales',
|
||||
outputLocales: ['zh', 'ru', 'ja', 'ko', 'fr', 'es'],
|
||||
reference: `Special names to keep untranslated: flux, photomaker, clip, vae, cfg, stable audio, stable cascade, stable zero, controlnet, lora, HiDream.
|
||||
reference: `Special names to keep untranslated: flux, photomaker, clip, vae, cfg, stable audio, stable cascade, stable zero, controlnet, lora.
|
||||
'latent' is the short form of 'latent space'.
|
||||
'mask' is in the context of image processing.
|
||||
`
|
||||
|
||||
20
README.md
@@ -510,20 +510,6 @@ The selection toolbox will display the command button when items are selected:
|
||||
|
||||
</details>
|
||||
|
||||
## Contributing
|
||||
|
||||
We're building this frontend together and would love your help — no matter how you'd like to pitch in! You don't need to write code to make a difference.
|
||||
|
||||
Here are some ways to get involved:
|
||||
|
||||
- **Pull Requests:** Add features, fix bugs, or improve code health. Browse [issues](https://github.com/Comfy-Org/ComfyUI_frontend/issues) for inspiration.
|
||||
- **Vote on Features:** Give a 👍 to the feature requests you care about to help us prioritize.
|
||||
- **Verify Bugs:** Try reproducing reported issues and share your results (even if the bug doesn't occur!).
|
||||
- **Community Support:** Hop into our [Discord](https://www.comfy.org/discord) to answer questions or get help.
|
||||
- **Share & Advocate:** Tell your friends, tweet about us, or share tips to support the project.
|
||||
|
||||
Have another idea? Drop into Discord or open an issue, and let's chat!
|
||||
|
||||
## Development
|
||||
|
||||
### Tech Stack
|
||||
@@ -571,12 +557,6 @@ After you start the dev server, you should see following logs:
|
||||
Make sure your desktop machine and touch device are on the same network. On your touch device,
|
||||
navigate to `http://<server_ip>:5173` (e.g. `http://192.168.2.20:5173` here), to access the ComfyUI frontend.
|
||||
|
||||
### Recommended Code Editor Configuration
|
||||
|
||||
This project includes `.vscode/launch.json.default` and `.vscode/settings.json.default` files with recommended launch and workspace settings for editors that use the `.vscode` directory (e.g., VS Code, Cursor, etc.).
|
||||
|
||||
We’ve also included a list of recommended extensions in `.vscode/extensions.json`. Your editor should detect this file and show a human friendly list in the Extensions panel, linking each entry to its marketplace page.
|
||||
|
||||
### Unit Test
|
||||
|
||||
- `npm i` to install all dependencies
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"8": {
|
||||
"inputs": {
|
||||
"image": "animated_web.webp"
|
||||
},
|
||||
"class_type": "DevToolsLoadAnimatedImageTest",
|
||||
"_meta": {
|
||||
"title": "Load Animated Image"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"id": "3f1fcbf9-f9de-4935-8fad-401813f61b13",
|
||||
"revision": 0,
|
||||
"last_node_id": 10,
|
||||
"last_link_id": 4,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveAnimatedWEBP",
|
||||
"pos": [336, 104],
|
||||
"size": [210, 368],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": ["ComfyUI", 6, true, 80, "default"]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "DevToolsLoadAnimatedImageTest",
|
||||
"pos": [64, 104],
|
||||
"size": [210, 316],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [4]
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DevToolsLoadAnimatedImageTest"
|
||||
},
|
||||
"widgets_values": ["animated_web.webp", "image"]
|
||||
}
|
||||
],
|
||||
"links": [[4, 10, 0, 9, 0, "IMAGE"]],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"frontendVersion": "1.17.0"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 75 KiB |
@@ -270,7 +270,6 @@ export class ComfyPage {
|
||||
localStorage.clear()
|
||||
sessionStorage.clear()
|
||||
localStorage.setItem('Comfy.userId', id)
|
||||
localStorage.setItem('api-nodes-news-seen', 'true')
|
||||
}, this.id)
|
||||
}
|
||||
await this.goto()
|
||||
@@ -464,129 +463,87 @@ export class ComfyPage {
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
async dragAndDropExternalResource(
|
||||
async dragAndDropFile(
|
||||
fileName: string,
|
||||
options: {
|
||||
fileName?: string
|
||||
url?: string
|
||||
dropPosition?: Position
|
||||
} = {}
|
||||
) {
|
||||
const { dropPosition = { x: 100, y: 100 }, fileName, url } = options
|
||||
const { dropPosition = { x: 100, y: 100 } } = options
|
||||
|
||||
if (!fileName && !url)
|
||||
throw new Error('Must provide either fileName or url')
|
||||
const filePath = this.assetPath(fileName)
|
||||
|
||||
const evaluateParams: {
|
||||
dropPosition: Position
|
||||
fileName?: string
|
||||
fileType?: string
|
||||
buffer?: Uint8Array | number[]
|
||||
url?: string
|
||||
} = { dropPosition }
|
||||
// Read the file content
|
||||
const buffer = fs.readFileSync(filePath)
|
||||
|
||||
// Dropping a file from the filesystem
|
||||
if (fileName) {
|
||||
const filePath = this.assetPath(fileName)
|
||||
const buffer = fs.readFileSync(filePath)
|
||||
|
||||
const getFileType = (fileName: string) => {
|
||||
if (fileName.endsWith('.png')) return 'image/png'
|
||||
if (fileName.endsWith('.svg')) return 'image/svg+xml'
|
||||
if (fileName.endsWith('.webp')) return 'image/webp'
|
||||
if (fileName.endsWith('.webm')) return 'video/webm'
|
||||
if (fileName.endsWith('.json')) return 'application/json'
|
||||
if (fileName.endsWith('.glb')) return 'model/gltf-binary'
|
||||
return 'application/octet-stream'
|
||||
}
|
||||
|
||||
evaluateParams.fileName = fileName
|
||||
evaluateParams.fileType = getFileType(fileName)
|
||||
evaluateParams.buffer = [...new Uint8Array(buffer)]
|
||||
// Get file type
|
||||
const getFileType = (fileName: string) => {
|
||||
if (fileName.endsWith('.png')) return 'image/png'
|
||||
if (fileName.endsWith('.webp')) return 'image/webp'
|
||||
if (fileName.endsWith('.webm')) return 'video/webm'
|
||||
if (fileName.endsWith('.json')) return 'application/json'
|
||||
if (fileName.endsWith('.glb')) return 'model/gltf-binary'
|
||||
return 'application/octet-stream'
|
||||
}
|
||||
|
||||
// Dropping a URL (e.g., dropping image across browser tabs in Firefox)
|
||||
if (url) evaluateParams.url = url
|
||||
const fileType = getFileType(fileName)
|
||||
|
||||
// Execute the drag and drop in the browser
|
||||
await this.page.evaluate(async (params) => {
|
||||
const dataTransfer = new DataTransfer()
|
||||
|
||||
// Add file if provided
|
||||
if (params.buffer && params.fileName && params.fileType) {
|
||||
const file = new File(
|
||||
[new Uint8Array(params.buffer)],
|
||||
params.fileName,
|
||||
{
|
||||
type: params.fileType
|
||||
}
|
||||
)
|
||||
await this.page.evaluate(
|
||||
async ({ buffer, fileName, fileType, dropPosition }) => {
|
||||
const file = new File([new Uint8Array(buffer)], fileName, {
|
||||
type: fileType
|
||||
})
|
||||
const dataTransfer = new DataTransfer()
|
||||
dataTransfer.items.add(file)
|
||||
}
|
||||
|
||||
// Add URL data if provided
|
||||
if (params.url) {
|
||||
dataTransfer.setData('text/uri-list', params.url)
|
||||
dataTransfer.setData('text/x-moz-url', params.url)
|
||||
}
|
||||
const targetElement = document.elementFromPoint(
|
||||
dropPosition.x,
|
||||
dropPosition.y
|
||||
)
|
||||
|
||||
const targetElement = document.elementFromPoint(
|
||||
params.dropPosition.x,
|
||||
params.dropPosition.y
|
||||
)
|
||||
|
||||
if (!targetElement) {
|
||||
console.error('No element found at drop position:', params.dropPosition)
|
||||
return { success: false, error: 'No element at position' }
|
||||
}
|
||||
|
||||
const eventOptions = {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
dataTransfer,
|
||||
clientX: params.dropPosition.x,
|
||||
clientY: params.dropPosition.y
|
||||
}
|
||||
|
||||
const dragOverEvent = new DragEvent('dragover', eventOptions)
|
||||
const dropEvent = new DragEvent('drop', eventOptions)
|
||||
|
||||
Object.defineProperty(dropEvent, 'preventDefault', {
|
||||
value: () => {},
|
||||
writable: false
|
||||
})
|
||||
|
||||
Object.defineProperty(dropEvent, 'stopPropagation', {
|
||||
value: () => {},
|
||||
writable: false
|
||||
})
|
||||
|
||||
targetElement.dispatchEvent(dragOverEvent)
|
||||
targetElement.dispatchEvent(dropEvent)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
targetInfo: {
|
||||
tagName: targetElement.tagName,
|
||||
id: targetElement.id,
|
||||
classList: Array.from(targetElement.classList)
|
||||
if (!targetElement) {
|
||||
console.error('No element found at drop position:', dropPosition)
|
||||
return { success: false, error: 'No element at position' }
|
||||
}
|
||||
}
|
||||
}, evaluateParams)
|
||||
|
||||
const eventOptions = {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
dataTransfer,
|
||||
clientX: dropPosition.x,
|
||||
clientY: dropPosition.y
|
||||
}
|
||||
|
||||
const dragOverEvent = new DragEvent('dragover', eventOptions)
|
||||
const dropEvent = new DragEvent('drop', eventOptions)
|
||||
|
||||
Object.defineProperty(dropEvent, 'preventDefault', {
|
||||
value: () => {},
|
||||
writable: false
|
||||
})
|
||||
Object.defineProperty(dropEvent, 'stopPropagation', {
|
||||
value: () => {},
|
||||
writable: false
|
||||
})
|
||||
|
||||
targetElement.dispatchEvent(dragOverEvent)
|
||||
targetElement.dispatchEvent(dropEvent)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
targetInfo: {
|
||||
tagName: targetElement.tagName,
|
||||
id: targetElement.id,
|
||||
classList: Array.from(targetElement.classList)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ buffer: [...new Uint8Array(buffer)], fileName, fileType, dropPosition }
|
||||
)
|
||||
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
async dragAndDropFile(
|
||||
fileName: string,
|
||||
options: { dropPosition?: Position } = {}
|
||||
) {
|
||||
return this.dragAndDropExternalResource({ fileName, ...options })
|
||||
}
|
||||
|
||||
async dragAndDropURL(url: string, options: { dropPosition?: Position } = {}) {
|
||||
return this.dragAndDropExternalResource({ url, ...options })
|
||||
}
|
||||
|
||||
async dragNode2() {
|
||||
await this.dragAndDrop({ x: 622, y: 400 }, { x: 622, y: 300 })
|
||||
await this.nextFrame()
|
||||
@@ -925,16 +882,10 @@ export class ComfyPage {
|
||||
return window['app'].canvas.ds.convertOffsetToCanvas(pos)
|
||||
}, pos)
|
||||
}
|
||||
|
||||
/** Get number of DOM widgets on the canvas. */
|
||||
async getDOMWidgetCount() {
|
||||
return await this.page.locator('.dom-widget').count()
|
||||
}
|
||||
|
||||
async getNodeRefById(id: NodeId) {
|
||||
return new NodeReference(id, this)
|
||||
}
|
||||
async getNodes(): Promise<LGraphNode[]> {
|
||||
async getNodes() {
|
||||
return await this.page.evaluate(() => {
|
||||
return window['app'].graph.nodes
|
||||
})
|
||||
|
||||
@@ -48,7 +48,6 @@ const customColorPalettes: Record<string, Palette> = {
|
||||
WIDGET_OUTLINE_COLOR: '#333',
|
||||
WIDGET_TEXT_COLOR: '#a3a3a8',
|
||||
WIDGET_SECONDARY_TEXT_COLOR: '#97979c',
|
||||
WIDGET_DISABLED_TEXT_COLOR: '#646464',
|
||||
LINK_COLOR: '#9A9',
|
||||
EVENT_LINK_COLOR: '#A86',
|
||||
CONNECTING_LINK_COLOR: '#AFA'
|
||||
@@ -112,7 +111,6 @@ const customColorPalettes: Record<string, Palette> = {
|
||||
WIDGET_OUTLINE_COLOR: '#333',
|
||||
WIDGET_TEXT_COLOR: '#a3a3a8',
|
||||
WIDGET_SECONDARY_TEXT_COLOR: '#97979c',
|
||||
WIDGET_DISABLED_TEXT_COLOR: '#646464',
|
||||
LINK_COLOR: '#9A9',
|
||||
EVENT_LINK_COLOR: '#A86',
|
||||
CONNECTING_LINK_COLOR: '#AFA'
|
||||
|
||||
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
@@ -341,30 +341,3 @@ test.describe('Error dialog', () => {
|
||||
await expect(errorDialog).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Signin dialog', () => {
|
||||
test('Paste content to signin dialog should not paste node on canvas', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const nodeNum = (await comfyPage.getNodes()).length
|
||||
await comfyPage.clickEmptyLatentNode()
|
||||
await comfyPage.ctrlC()
|
||||
|
||||
const textBox = comfyPage.widgetTextBox
|
||||
await textBox.click()
|
||||
await textBox.fill('test_password')
|
||||
await textBox.press('Control+a')
|
||||
await textBox.press('Control+c')
|
||||
|
||||
await comfyPage.page.evaluate(() => {
|
||||
window['app'].extensionManager.dialog.showSignInDialog()
|
||||
})
|
||||
|
||||
const input = comfyPage.page.locator('#comfy-org-sign-in-password')
|
||||
await input.waitFor({ state: 'visible' })
|
||||
await input.press('Control+v')
|
||||
await expect(input).toHaveValue('test_password')
|
||||
|
||||
expect(await comfyPage.getNodes()).toHaveLength(nodeNum)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,27 +24,4 @@ test.describe('DOM Widget', () => {
|
||||
await expect(firstMultiline).not.toBeVisible()
|
||||
await expect(lastMultiline).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('Position update when entering focus mode', async ({ comfyPage }) => {
|
||||
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
|
||||
await comfyPage.executeCommand('Workspace.ToggleFocusMode')
|
||||
await comfyPage.nextFrame()
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('focus-mode-on.png')
|
||||
})
|
||||
|
||||
// No DOM widget should be created by creation of interim LGraphNode objects.
|
||||
test('Copy node with DOM widget by dragging + alt', async ({ comfyPage }) => {
|
||||
const initialCount = await comfyPage.getDOMWidgetCount()
|
||||
|
||||
// TextEncodeNode1
|
||||
await comfyPage.page.mouse.move(618, 191)
|
||||
await comfyPage.page.keyboard.down('Alt')
|
||||
await comfyPage.page.mouse.down()
|
||||
await comfyPage.page.mouse.move(100, 100)
|
||||
await comfyPage.page.mouse.up()
|
||||
await comfyPage.page.keyboard.up('Alt')
|
||||
|
||||
const finalCount = await comfyPage.getDOMWidgetCount()
|
||||
expect(finalCount).toBe(initialCount + 1)
|
||||
})
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
@@ -3,41 +3,17 @@ import { expect } from '@playwright/test'
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
|
||||
test.describe('Load Workflow in Media', () => {
|
||||
const fileNames = [
|
||||
;[
|
||||
'workflow.webp',
|
||||
'edited_workflow.webp',
|
||||
'no_workflow.webp',
|
||||
'large_workflow.webp',
|
||||
'workflow.webm',
|
||||
// Skipped due to 3d widget unstable visual result.
|
||||
// 3d widget shows grid after fully loaded.
|
||||
// 'workflow.glb',
|
||||
'workflow.mp4',
|
||||
'workflow.mov',
|
||||
'workflow.m4v',
|
||||
'workflow.svg'
|
||||
]
|
||||
fileNames.forEach(async (fileName) => {
|
||||
test(`Load workflow in ${fileName} (drop from filesystem)`, async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
'workflow.glb'
|
||||
].forEach(async (fileName) => {
|
||||
test(`Load workflow in ${fileName}`, async ({ comfyPage }) => {
|
||||
await comfyPage.dragAndDropFile(fileName)
|
||||
await expect(comfyPage.canvas).toHaveScreenshot(`${fileName}.png`)
|
||||
})
|
||||
})
|
||||
|
||||
const urls = [
|
||||
'https://comfyanonymous.github.io/ComfyUI_examples/hidream/hidream_dev_example.png'
|
||||
]
|
||||
urls.forEach(async (url) => {
|
||||
test(`Load workflow from URL ${url} (drop from different browser tabs)`, async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.dragAndDropURL(url)
|
||||
const readableName = url.split('/').pop()
|
||||
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||
`dropped_workflow_url_${readableName}.png`
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
@@ -92,20 +92,4 @@ test.describe('Node badge color', () => {
|
||||
'node-badge-unknown-color-palette.png'
|
||||
)
|
||||
})
|
||||
|
||||
test('Can show node badge with light color palette', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.setSetting(
|
||||
'Comfy.NodeBadge.NodeIdBadgeMode',
|
||||
NodeBadgeMode.ShowAll
|
||||
)
|
||||
await comfyPage.setSetting('Comfy.ColorPalette', 'light')
|
||||
await comfyPage.nextFrame()
|
||||
// Click empty space to trigger canvas re-render.
|
||||
await comfyPage.clickEmptySpace()
|
||||
await expect(comfyPage.canvas).toHaveScreenshot(
|
||||
'node-badge-light-color-palette.png'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||