Compare commits

...

15 Commits

Author SHA1 Message Date
Chenlei Hu
227db065f3 1.4.0 (#1562) 2024-11-15 21:18:29 -05:00
Chenlei Hu
b4352bcd8d Fix node search box filter test (#1561) 2024-11-15 21:18:19 -05:00
Chenlei Hu
39bab9d9e2 Disable flaky group node test (#1560) 2024-11-15 20:55:18 -05:00
Chenlei Hu
c71644f02f Use tailwind class in NodeSearchBox (#1559) 2024-11-15 20:46:04 -05:00
filtered
6aad7ee8b6 Allow remote dev to be switched on/off (#1558)
* Allow remote dev to be switched on/off

* nit - Docs
2024-11-15 19:26:41 -05:00
Chenlei Hu
2b96d831fc Fix install location path picker (#1557) 2024-11-15 18:55:58 -05:00
filtered
dde0291add Fix change tracker count desync on error (#1555)
* Add TS types

* Ensure changeTracker works after exceptions

Wraps all code between before/after change calls in try/finally blocks
2024-11-15 16:03:21 -05:00
filtered
8af016ffc1 Fix husky pre-commit for winnt clients [skip ci] (#1551) 2024-11-15 09:45:39 -05:00
Chenlei Hu
82b4547d7d Remove canvas border rendering (#1549)
* Remove canvas border rendering

* Update test expectations [skip ci]

---------

Co-authored-by: github-actions <github-actions@github.com>
2024-11-15 09:24:51 -05:00
Chenlei Hu
791a25637f Revert "Fix husky pre-commit & type check only staged" (#1550)
* Revert "Fix husky pre-commit & type check only staged (#1361)"

This reverts commit 795e932b8f.

* Update package.json
2024-11-15 09:19:24 -05:00
filtered
b922aa5c7c Add option to disable ctrl + shift + zoom (#1545)
* Add option to disable ctrl + shift + zoom

Minor change to default behaviour: zoom no longer triggers if alt key is also down.

* Update coreSettings.ts

Next release will be 1.4.0 to leave room for patches in 1.3 stable after today's main repo sync.

---------

Co-authored-by: Chenlei Hu <huchenlei@proton.me>
2024-11-15 09:10:09 -05:00
Chenlei Hu
cbaebbc9c2 chore: update litegraph to 0.8.27 (#1542) 2024-11-15 09:06:33 -05:00
Chenlei Hu
86b2e1aa6c Add electron adapter extension (#1538) 2024-11-14 19:57:09 -05:00
Chenlei Hu
61c5f05126 1.3.44 (#1541) 2024-11-14 19:56:46 -05:00
Chenlei Hu
dde9c3dad5 Fix tree explorer y-axis padding (#1540)
* Fix tree explorer y-axis padding

* nit
2024-11-14 17:15:57 -05:00
28 changed files with 279 additions and 135 deletions

View File

@@ -6,6 +6,11 @@ PLAYWRIGHT_TEST_URL=http://localhost:5173
# Note: localhost:8188 does not work.
DEV_SERVER_COMFYUI_URL=http://127.0.0.1:8188
# Allow dev server access from remote IP addresses.
# If true, the vite dev server will listen on all addresses, including LAN
# and public addresses.
VITE_REMOTE_DEV=false
# The target ComfyUI checkout directory to deploy the frontend code to.
# The dist directory will be copied to {DEPLOY_COMFYUI_DIR}/custom_web_versions/main/dev
# Add `--front-end-root {DEPLOY_COMFYUI_DIR}/custom_web_versions/main/dev`

View File

@@ -3,3 +3,4 @@ if [[ "$OS" == "Windows_NT" ]]; then
else
npx lint-staged
fi
npm run typecheck

View File

@@ -431,6 +431,8 @@ core extensions will be loaded.
#### Access dev server on touch devices
Enable remote access to the dev server by setting `VITE_REMOTE_DEV` in `.env` to `true`.
After you start the dev server, you should see following logs:
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -43,7 +43,7 @@ export class ComfyNodeSearchBox {
}
get filterButton() {
return this.page.locator('.comfy-vue-node-search-container ._filter-button')
return this.page.locator('.comfy-vue-node-search-container .filter-button')
}
async fillAndSelectFirstNode(

View File

@@ -77,8 +77,13 @@ test.describe('Group Node', () => {
.click()
})
})
test('Can be added to canvas using search', async ({ comfyPage }) => {
// The 500ms fixed delay on the search results is causing flakiness
// Potential solution: add a spinner state when the search is in progress,
// and observe that state from the test. Blocker: the PrimeVue AutoComplete
// does not have a v-model on the query, so we cannot observe the raw
// query update, and thus cannot set the spinning state between the raw query
// update and the debounced search update.
test.skip('Can be added to canvas using search', async ({ comfyPage }) => {
const groupNodeName = 'DefautWorkflowGroupNode'
await comfyPage.convertAllNodesToGroupNode(groupNodeName)
await comfyPage.doubleClickCanvas()

26
package-lock.json generated
View File

@@ -1,16 +1,16 @@
{
"name": "comfyui-frontend",
"version": "1.3.43",
"version": "1.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "comfyui-frontend",
"version": "1.3.43",
"version": "1.4.0",
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
"@comfyorg/comfyui-electron-types": "^0.2.16",
"@comfyorg/litegraph": "^0.8.26",
"@comfyorg/litegraph": "^0.8.27",
"@primevue/themes": "^4.0.5",
"@vueuse/core": "^11.0.0",
"@xterm/addon-fit": "^0.10.0",
@@ -63,7 +63,6 @@
"tailwindcss": "^3.4.4",
"ts-jest": "^29.1.4",
"ts-node": "^10.9.2",
"tsc-files": "^1.1.4",
"tsx": "^4.15.6",
"typescript": "^5.4.5",
"typescript-eslint": "^8.0.0",
@@ -1922,9 +1921,9 @@
"license": "GPL-3.0-only"
},
"node_modules/@comfyorg/litegraph": {
"version": "0.8.26",
"resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.26.tgz",
"integrity": "sha512-q0Vcd5usphR5nghfyFksVx+VM+eSB1MyX8Ne304KFDnr214KQMA6DAjrEQJlGBUUCybLiOtPCvd3dxPecEQiSQ==",
"version": "0.8.27",
"resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.27.tgz",
"integrity": "sha512-EMQ3jsny+3gUQL4+vSVwJAFxrLq4IpuyjCvAiErLY4wLZZu2Mi+7cELmhrNS0MajhZqfN1M0GPmdcBRwSWbarw==",
"license": "MIT"
},
"node_modules/@cspotcode/source-map-support": {
@@ -12170,19 +12169,6 @@
}
}
},
"node_modules/tsc-files": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/tsc-files/-/tsc-files-1.1.4.tgz",
"integrity": "sha512-RePsRsOLru3BPpnf237y1Xe1oCGta8rmSYzM76kYo5tLGsv5R2r3s64yapYorGTPuuLyfS9NVbh9ydzmvNie2w==",
"dev": true,
"license": "MIT",
"bin": {
"tsc-files": "cli.js"
},
"peerDependencies": {
"typescript": ">=3"
}
},
"node_modules/tsconfig": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz",

View File

@@ -1,7 +1,7 @@
{
"name": "comfyui-frontend",
"private": true,
"version": "1.3.43",
"version": "1.4.0",
"type": "module",
"scripts": {
"dev": "vite",
@@ -58,7 +58,6 @@
"tailwindcss": "^3.4.4",
"ts-jest": "^29.1.4",
"ts-node": "^10.9.2",
"tsc-files": "^1.1.4",
"tsx": "^4.15.6",
"typescript": "^5.4.5",
"typescript-eslint": "^8.0.0",
@@ -73,7 +72,7 @@
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
"@comfyorg/comfyui-electron-types": "^0.2.16",
"@comfyorg/litegraph": "^0.8.26",
"@comfyorg/litegraph": "^0.8.27",
"@primevue/themes": "^4.0.5",
"@vueuse/core": "^11.0.0",
"@xterm/addon-fit": "^0.10.0",
@@ -94,7 +93,8 @@
"zod-validation-error": "^3.3.0"
},
"lint-staged": {
"./**/*.{js,ts,tsx,vue}": "prettier --write",
"**/*.ts": "tsc-files --noEmit"
"./**/*.{js,ts,tsx,vue}": [
"prettier --write"
]
}
}

View File

@@ -1,6 +1,6 @@
<template>
<Tree
class="tree-explorer p-2 2xl:p-4"
class="tree-explorer py-0 px-2 2xl:px-4"
:class="props.class"
v-model:expandedKeys="expandedKeys"
v-model:selectionKeys="selectionKeys"

View File

@@ -262,6 +262,7 @@ onMounted(async () => {
ChangeTracker.init(comfyApp)
await comfyApp.setup(canvasRef.value)
canvasStore.canvas = comfyApp.canvas
canvasStore.canvas.render_canvas_border = false
workspaceStore.spinner = false
window['app'] = comfyApp

View File

@@ -87,10 +87,10 @@ onMounted(async () => {
installPath.value = paths.defaultInstallPath
})
const validatePath = async () => {
const validatePath = async (path: string) => {
try {
pathError.value = ''
const validation = await electron.validateInstallPath(installPath.value)
const validation = await electron.validateInstallPath(path)
if (!validation.isValid) {
pathError.value = validation.error
@@ -105,7 +105,7 @@ const browsePath = async () => {
const result = await electron.showDirectoryPicker()
if (result) {
installPath.value = result
await validatePath()
await validatePath(result)
}
} catch (error) {
pathError.value = t('install.failedToSelectDirectory')

View File

@@ -1,6 +1,11 @@
<template>
<div class="comfy-vue-node-search-container">
<div class="comfy-vue-node-preview-container" v-if="enableNodePreview">
<div
class="comfy-vue-node-search-container flex justify-center items-center w-full min-w-96 pointer-events-auto"
>
<div
class="comfy-vue-node-preview-container absolute left-[-350px] top-[50px]"
v-if="enableNodePreview"
>
<NodePreview
:nodeDef="hoveredSuggestion"
:key="hoveredSuggestion?.name || ''"
@@ -11,10 +16,10 @@
<Button
icon="pi pi-filter"
severity="secondary"
class="_filter-button"
class="filter-button z-10"
@click="nodeSearchFilterVisible = true"
/>
<Dialog v-model:visible="nodeSearchFilterVisible" class="_dialog">
<Dialog v-model:visible="nodeSearchFilterVisible" class="min-w-96">
<template #header>
<h3>Add node filter condition</h3>
</template>
@@ -25,7 +30,7 @@
<AutoCompletePlus
:model-value="props.filters"
class="comfy-vue-node-search-box"
class="comfy-vue-node-search-box z-10 flex-grow"
scrollHeight="40vh"
:placeholder="placeholder"
:input-id="inputId"
@@ -148,31 +153,3 @@ const setHoverSuggestion = (index: number) => {
hoveredSuggestion.value = value
}
</script>
<style scoped>
.comfy-vue-node-search-container {
@apply flex justify-center items-center w-full min-w-96;
}
.comfy-vue-node-search-container * {
pointer-events: auto;
}
.comfy-vue-node-preview-container {
position: absolute;
left: -350px;
top: 50px;
}
.comfy-vue-node-search-box {
@apply z-10 flex-grow;
}
._filter-button {
z-index: 10;
}
._dialog {
@apply min-w-96;
}
</style>

View File

@@ -31,7 +31,7 @@
<ElectronDownloadItems v-if="isElectron()" />
<TreeExplorer
class="model-lib-tree-explorer py-0"
class="model-lib-tree-explorer"
:roots="renderedRoot.children"
v-model:expandedKeys="expandedKeys"
>

View File

@@ -48,7 +48,7 @@
class="m-2"
/>
<TreeExplorer
class="node-lib-tree-explorer py-0"
class="node-lib-tree-explorer"
:roots="renderedRoot.children"
v-model:expandedKeys="expandedKeys"
>

View File

@@ -1,6 +1,6 @@
<template>
<TreeExplorer
class="node-lib-bookmark-tree-explorer py-0"
class="node-lib-bookmark-tree-explorer"
ref="treeExplorerRef"
:roots="renderedBookmarkedRoot.children"
:expandedKeys="expandedKeys"

View File

@@ -0,0 +1,138 @@
import { app } from '@/scripts/app'
import { electronAPI as getElectronAPI, isElectron } from '@/utils/envUtil'
;(async () => {
if (!isElectron()) return
const electronAPI = getElectronAPI()
const desktopAppVersion = await electronAPI.getElectronVersion()
app.registerExtension({
name: 'Comfy.ElectronAdapter',
settings: [
{
id: 'Comfy-Desktop.AutoUpdate',
category: ['Comfy-Desktop', 'General', 'AutoUpdate'],
name: 'Automatically check for updates',
type: 'boolean',
defaultValue: true,
onChange(newValue, oldValue) {
if (oldValue !== undefined && newValue !== oldValue) {
electronAPI.restartApp(
'Restart ComfyUI to apply changes.',
1500 // add delay to allow changes to take effect before restarting.
)
}
}
}
],
commands: [
{
id: 'Comfy-Desktop.Folders.OpenLogsFolder',
label: 'Open Logs Folder',
icon: 'pi pi-folder-open',
function() {
electronAPI.openLogsFolder()
}
},
{
id: 'Comfy-Desktop.Folders.OpenModelsFolder',
label: 'Open Models Folder',
icon: 'pi pi-folder-open',
function() {
electronAPI.openModelsFolder()
}
},
{
id: 'Comfy-Desktop.Folders.OpenOutputsFolder',
label: 'Open Outputs Folder',
icon: 'pi pi-folder-open',
function() {
electronAPI.openOutputsFolder()
}
},
{
id: 'Comfy-Desktop.Folders.OpenInputsFolder',
label: 'Open Inputs Folder',
icon: 'pi pi-folder-open',
function() {
electronAPI.openInputsFolder()
}
},
{
id: 'Comfy-Desktop.Folders.OpenCustomNodesFolder',
label: 'Open Custom Nodes Folder',
icon: 'pi pi-folder-open',
function() {
electronAPI.openCustomNodesFolder()
}
},
{
id: 'Comfy-Desktop.Folders.OpenModelConfig',
label: 'Open extra_model_paths.yaml',
icon: 'pi pi-file',
function() {
electronAPI.openModelConfig()
}
},
{
id: 'Comfy-Desktop.OpenDevTools',
label: 'Open DevTools',
icon: 'pi pi-code',
function() {
electronAPI.openDevTools()
}
},
{
id: 'Comfy-Desktop.OpenFeedbackPage',
label: 'Feedback',
icon: 'pi pi-envelope',
function() {
window.open('https://forum.comfy.org/c/v1-feedback/', '_blank')
}
},
{
id: 'Comfy-Desktop.Reinstall',
label: 'Reinstall',
icon: 'pi pi-refresh',
function() {
// TODO(huchenlei): Add a confirmation dialog.
electronAPI.reinstall()
}
}
],
menuCommands: [
{
path: ['Help'],
commands: ['Comfy-Desktop.OpenFeedbackPage']
},
{
path: ['Help'],
commands: ['Comfy-Desktop.OpenDevTools']
},
{
path: ['Help', 'Open Folder'],
commands: [
'Comfy-Desktop.Folders.OpenLogsFolder',
'Comfy-Desktop.Folders.OpenModelsFolder',
'Comfy-Desktop.Folders.OpenOutputsFolder',
'Comfy-Desktop.Folders.OpenInputsFolder',
'Comfy-Desktop.Folders.OpenCustomNodesFolder',
'Comfy-Desktop.Folders.OpenModelConfig'
]
},
{
path: ['Help'],
commands: ['Comfy-Desktop.Reinstall']
}
],
aboutPageBadges: [
{
label: 'ComfyUI_Desktop ' + desktopAppVersion,
url: 'https://github.com/Comfy-Org/electron',
icon: 'pi pi-github'
}
]
})
})()

View File

@@ -13,6 +13,7 @@ import {
deserialiseAndCreate,
serialise
} from '@/extensions/core/vintageClipboard'
import type { ComfyNodeDef } from '@/types/apiTypes'
type GroupNodeWorkflowData = {
external: ComfyLink[]
@@ -56,7 +57,7 @@ const Workflow = {
class GroupNodeBuilder {
nodes: LGraphNode[]
nodeData: any
nodeData: GroupNodeWorkflowData
constructor(nodes: LGraphNode[]) {
this.nodes = nodes
@@ -175,7 +176,7 @@ export class GroupNodeConfig {
primitiveToWidget: {}
nodeInputs: {}
outputVisibility: any[]
nodeDef: any
nodeDef: ComfyNodeDef
inputs: any[]
linksFrom: {}
linksTo: {}
@@ -204,6 +205,7 @@ export class GroupNodeConfig {
output: [],
output_name: [],
output_is_list: [],
// @ts-expect-error Unused, doesn't exist
output_is_hidden: [],
name: source + SEPARATOR + this.name,
display_name: this.name,
@@ -695,11 +697,11 @@ export class GroupNodeConfig {
}
export class GroupNodeHandler {
node
node: LGraphNode
groupData
innerNodes: any
constructor(node) {
constructor(node: LGraphNode) {
this.node = node
this.groupData = node.constructor?.nodeData?.[GROUP]
@@ -774,6 +776,7 @@ export class GroupNodeHandler {
this.node.updateLink = (link) => {
// Replace the group node reference with the internal node
// @ts-expect-error Can this be removed? Or replaced with: LLink.create(link.asSerialisable())
link = { ...link }
const output = this.groupData.newToOldOutputMap[link.origin_slot]
let innerNode = this.innerNodes[output.node.index]
@@ -965,17 +968,20 @@ export class GroupNodeHandler {
app.canvas.emitBeforeChange()
const { newNodes, selectedIds } = addInnerNodes()
reconnectInputs(selectedIds)
reconnectOutputs(selectedIds)
app.graph.remove(this.node)
try {
const { newNodes, selectedIds } = addInnerNodes()
reconnectInputs(selectedIds)
reconnectOutputs(selectedIds)
app.graph.remove(this.node)
app.canvas.emitAfterChange()
return newNodes
return newNodes
} finally {
app.canvas.emitAfterChange()
}
}
const getExtraMenuOptions = this.node.getExtraMenuOptions
// @ts-expect-error Should pass patched return value getExtraMenuOptions
this.node.getExtraMenuOptions = function (_, options) {
getExtraMenuOptions?.apply(this, arguments)
@@ -988,6 +994,7 @@ export class GroupNodeHandler {
null,
{
content: 'Convert to nodes',
// @ts-expect-error
callback: () => {
return this.convertToNodes()
}
@@ -1148,6 +1155,7 @@ export class GroupNodeHandler {
if (
old.inputName !== 'image' &&
// @ts-expect-error Widget values
!widget.options.values.includes(widget.value)
) {
widget.value = widget.options.values[0]
@@ -1354,6 +1362,7 @@ export class GroupNodeHandler {
if (!originNode) continue // this node is in the group
originNode.connect(
originSlot,
// @ts-expect-error Valid - uses deprecated interface. Required check: if (graph.getNodeById(this.node.id) !== this.node) report()
this.node.id,
this.groupData.oldToNewInputMap[targetId][targetSlot]
)
@@ -1475,7 +1484,7 @@ function ungroupSelectedGroupNodes() {
const nodes = Object.values(app.canvas.selected_nodes ?? {})
for (const node of nodes) {
if (GroupNodeHandler.isGroupNode(node)) {
node['convertToNodes']?.()
node.convertToNodes?.()
}
}
}

View File

@@ -20,3 +20,4 @@ import './uploadImage'
import './webcamCapture'
import './widgetInputs'
import './uploadAudio'
import './electronAdapter'

View File

@@ -69,51 +69,54 @@ export function deserialiseAndCreate(data: string, canvas: LGraphCanvas): void {
const { graph, graph_mouse } = canvas
canvas.emitBeforeChange()
graph.beforeChange()
try {
graph.beforeChange()
const deserialised = JSON.parse(data)
const deserialised = JSON.parse(data)
// Find the top left point of the boundary of all pasted nodes
const topLeft = [Infinity, Infinity]
for (const { pos } of deserialised.nodes) {
if (topLeft[0] > pos[0]) topLeft[0] = pos[0]
if (topLeft[1] > pos[1]) topLeft[1] = pos[1]
// Find the top left point of the boundary of all pasted nodes
const topLeft = [Infinity, Infinity]
for (const { pos } of deserialised.nodes) {
if (topLeft[0] > pos[0]) topLeft[0] = pos[0]
if (topLeft[1] > pos[1]) topLeft[1] = pos[1]
}
// Silent default instead of throw
if (!Number.isFinite(topLeft[0]) || !Number.isFinite(topLeft[1])) {
topLeft[0] = graph_mouse[0]
topLeft[1] = graph_mouse[1]
}
// Create nodes
const nodes: LGraphNode[] = []
for (const info of deserialised.nodes) {
const node = LiteGraph.createNode(info.type)
if (!node) continue
node.configure(info)
// Paste to the bottom right of pointer
node.pos[0] += graph_mouse[0] - topLeft[0]
node.pos[1] += graph_mouse[1] - topLeft[1]
graph.add(node, true)
nodes.push(node)
}
// Create links
for (const info of deserialised.links) {
const relativeId = info[0]
const outNode = relativeId != null ? nodes[relativeId] : undefined
const inNode = nodes[info[2]]
if (outNode && inNode) outNode.connect(info[1], inNode, info[3])
else console.warn('Warning, nodes missing on pasting')
}
canvas.selectNodes(nodes)
graph.afterChange()
} finally {
canvas.emitAfterChange()
}
// Silent default instead of throw
if (!Number.isFinite(topLeft[0]) || !Number.isFinite(topLeft[1])) {
topLeft[0] = graph_mouse[0]
topLeft[1] = graph_mouse[1]
}
// Create nodes
const nodes: LGraphNode[] = []
for (const info of deserialised.nodes) {
const node = LiteGraph.createNode(info.type)
if (!node) continue
node.configure(info)
// Paste to the bottom right of pointer
node.pos[0] += graph_mouse[0] - topLeft[0]
node.pos[1] += graph_mouse[1] - topLeft[1]
graph.add(node, true)
nodes.push(node)
}
// Create links
for (const info of deserialised.links) {
const relativeId = info[0]
const outNode = relativeId != null ? nodes[relativeId] : undefined
const inNode = nodes[info[2]]
if (outNode && inNode) outNode.connect(info[1], inNode, info[3])
else console.warn('Warning, nodes missing on pasting')
}
canvas.selectNodes(nodes)
graph.afterChange()
canvas.emitAfterChange()
}

View File

@@ -1227,7 +1227,8 @@ export class ComfyApp {
const origProcessMouseDown = LGraphCanvas.prototype.processMouseDown
LGraphCanvas.prototype.processMouseDown = function (e) {
// prepare for ctrl+shift drag: zoom start
if (e.ctrlKey && e.shiftKey && e.buttons) {
const useFastZoom = useSettingStore().get('Comfy.Graph.CtrlShiftZoom')
if (useFastZoom && e.ctrlKey && e.shiftKey && !e.altKey && e.buttons) {
self.zoom_drag_start = [e.x, e.y, this.ds.scale]
return
}
@@ -1572,10 +1573,7 @@ export class ComfyApp {
api.addEventListener('execution_start', ({ detail }) => {
this.lastExecutionError = null
this.graph.nodes.forEach((node) => {
// @ts-expect-error
if (node.onExecutionStart)
// @ts-expect-error
node.onExecutionStart()
if (node.onExecutionStart) node.onExecutionStart()
})
})
@@ -2407,8 +2405,8 @@ export class ComfyApp {
}
}
const innerNodes = outerNode['getInnerNodes']
? outerNode['getInnerNodes']()
const innerNodes = outerNode.getInnerNodes
? outerNode.getInnerNodes()
: [outerNode]
for (const node of innerNodes) {
if (node.isVirtualNode) {
@@ -2426,8 +2424,8 @@ export class ComfyApp {
for (const outerNode of graph.computeExecutionOrder(false)) {
const skipNode = outerNode.mode === 2 || outerNode.mode === 4
const innerNodes =
!skipNode && outerNode['getInnerNodes']
? outerNode['getInnerNodes']()
!skipNode && outerNode.getInnerNodes
? outerNode.getInnerNodes()
: [outerNode]
for (const node of innerNodes) {
if (node.isVirtualNode) {
@@ -2893,7 +2891,6 @@ export class ComfyApp {
for (let nodeNum in this.graph.nodes) {
const node = this.graph.nodes[nodeNum]
const def = defs[node.type]
// @ts-expect-error
// Allow primitive nodes to handle refresh
node.refreshComboInNode?.(defs)

View File

@@ -521,5 +521,12 @@ export const CORE_SETTINGS: SettingParams[] = [
name: 'Enable DOM element clipping (enabling may reduce performance)',
type: 'boolean',
defaultValue: true
},
{
id: 'Comfy.Graph.CtrlShiftZoom',
name: 'Enable fast-zoom shortcut (Ctrl + Shift + Drag)',
type: 'boolean',
defaultValue: true,
versionAdded: '1.4.0'
}
]

View File

@@ -1,6 +1,7 @@
import '@comfyorg/litegraph'
import type { ComfyNodeDef } from '@/types/apiTypes'
import type { LLink } from '@comfyorg/litegraph'
import type { NodeId } from './comfyWorkflow'
/**
* ComfyUI extensions of litegraph
@@ -26,8 +27,17 @@ declare module '@comfyorg/litegraph' {
onExecuted?(output: any): void
onNodeCreated?(this: LGraphNode): void
setInnerNodes?(nodes: LGraphNode[]): void
// TODO: Requires several coercion changes to runtime code.
getInnerNodes?() // : LGraphNode[]
convertToNodes?(): LGraphNode[]
recreate?(): Promise<LGraphNode>
refreshComboInNode?(defs: Record<string, ComfyNodeDef>)
applyToGraph?(extraLinks?: LLink[]): void
updateLink?(link: LLink): LLink | null
onExecutionStart?(): unknown
index?: number
runningInternalNodeId?: NodeId
comfyClass?: string

View File

@@ -11,6 +11,8 @@ dotenv.config()
const IS_DEV = process.env.NODE_ENV === 'development'
const SHOULD_MINIFY = process.env.ENABLE_MINIFY === 'true'
// vite dev server will listen on all addresses, including LAN and public addresses
const VITE_REMOTE_DEV = process.env.VITE_REMOTE_DEV === 'true'
interface ShimResult {
code: string
@@ -94,7 +96,7 @@ const DEV_SERVER_COMFYUI_URL = process.env.DEV_SERVER_COMFYUI_URL || 'http://127
export default defineConfig({
base: '',
server: {
host: '0.0.0.0',
host: VITE_REMOTE_DEV ? '0.0.0.0' : undefined,
proxy: {
'/internal': {
target: DEV_SERVER_COMFYUI_URL,