mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
fix(types): remove all @ts-expect-error from groupNodeManage.ts
- Add GroupNodeConfigEntry interface to LGraph.ts for config typing - Extend GroupNodeWorkflowData with title and widgets_values node props - Type config as Record<number, GroupNodeConfigEntry> instead of unknown - Export new types from litegraph barrel file - Fix all class properties with definite assignment assertions - Type all method parameters (changeTab, changeNode, changeGroup, etc.) - Fix event handlers with proper Event and CustomEvent types - Type storeModification, getEditElement, and build*Page methods - Fix save button callback with proper generic types for node ordering - Add override modifier to show method - Use optional chaining for node.recreate() call
This commit is contained in:
@@ -368,7 +368,7 @@ export class GroupNodeConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNodeDef(
|
getNodeDef(
|
||||||
node: GroupNodeData
|
node: GroupNodeData | GroupNodeWorkflowData['nodes'][number]
|
||||||
): GroupNodeDef | ComfyNodeDef | null | undefined {
|
): GroupNodeDef | ComfyNodeDef | null | undefined {
|
||||||
if (node.type) {
|
if (node.type) {
|
||||||
const def = globalDefs[node.type]
|
const def = globalDefs[node.type]
|
||||||
@@ -386,7 +386,8 @@ export class GroupNodeConfig {
|
|||||||
let type: string | number | null = linksFrom[0]?.[0]?.[5] ?? null
|
let type: string | number | null = linksFrom[0]?.[0]?.[5] ?? null
|
||||||
if (type === 'COMBO') {
|
if (type === 'COMBO') {
|
||||||
// Use the array items
|
// Use the array items
|
||||||
const source = node.outputs?.[0]?.widget?.name
|
const output = node.outputs?.[0] as GroupNodeOutput | undefined
|
||||||
|
const source = output?.widget?.name
|
||||||
const nodeIdx = linksFrom[0]?.[0]?.[2]
|
const nodeIdx = linksFrom[0]?.[0]?.[2]
|
||||||
if (source && nodeIdx != null) {
|
if (source && nodeIdx != null) {
|
||||||
const fromTypeName = this.nodeData.nodes[Number(nodeIdx)]?.type
|
const fromTypeName = this.nodeData.nodes[Number(nodeIdx)]?.type
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { PREFIX, SEPARATOR } from '@/constants/groupNodeConstants'
|
import { PREFIX, SEPARATOR } from '@/constants/groupNodeConstants'
|
||||||
import {
|
import type {
|
||||||
type LGraphNode,
|
GroupNodeConfigEntry,
|
||||||
type LGraphNodeConstructor,
|
GroupNodeWorkflowData,
|
||||||
LiteGraph
|
LGraphNode,
|
||||||
|
LGraphNodeConstructor
|
||||||
} from '@/lib/litegraph/src/litegraph'
|
} from '@/lib/litegraph/src/litegraph'
|
||||||
|
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||||
|
|
||||||
import { type ComfyApp, app } from '../../scripts/app'
|
import { type ComfyApp, app } from '../../scripts/app'
|
||||||
@@ -15,15 +17,17 @@ import './groupNodeManage.css'
|
|||||||
|
|
||||||
const ORDER: symbol = Symbol()
|
const ORDER: symbol = Symbol()
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
function merge(
|
||||||
function merge(target, source) {
|
target: Record<string, unknown>,
|
||||||
|
source: Record<string, unknown>
|
||||||
|
): Record<string, unknown> {
|
||||||
if (typeof target === 'object' && typeof source === 'object') {
|
if (typeof target === 'object' && typeof source === 'object') {
|
||||||
for (const key in source) {
|
for (const key in source) {
|
||||||
const sv = source[key]
|
const sv = source[key]
|
||||||
if (typeof sv === 'object') {
|
if (typeof sv === 'object' && sv !== null) {
|
||||||
let tv = target[key]
|
let tv = target[key] as Record<string, unknown> | undefined
|
||||||
if (!tv) tv = target[key] = {}
|
if (!tv) tv = target[key] = {}
|
||||||
merge(tv, source[key])
|
merge(tv as Record<string, unknown>, sv as Record<string, unknown>)
|
||||||
} else {
|
} else {
|
||||||
target[key] = sv
|
target[key] = sv
|
||||||
}
|
}
|
||||||
@@ -34,8 +38,7 @@ function merge(target, source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
||||||
// @ts-expect-error fixme ts strict error
|
tabs!: Record<
|
||||||
tabs: Record<
|
|
||||||
'Inputs' | 'Outputs' | 'Widgets',
|
'Inputs' | 'Outputs' | 'Widgets',
|
||||||
{ tab: HTMLAnchorElement; page: HTMLElement }
|
{ tab: HTMLAnchorElement; page: HTMLElement }
|
||||||
>
|
>
|
||||||
@@ -52,31 +55,22 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
>
|
>
|
||||||
>
|
>
|
||||||
> = {}
|
> = {}
|
||||||
// @ts-expect-error fixme ts strict error
|
nodeItems!: HTMLLIElement[]
|
||||||
nodeItems: any[]
|
|
||||||
app: ComfyApp
|
app: ComfyApp
|
||||||
// @ts-expect-error fixme ts strict error
|
groupNodeType!: LGraphNodeConstructor<LGraphNode>
|
||||||
groupNodeType: LGraphNodeConstructor<LGraphNode>
|
groupData!: GroupNodeConfig
|
||||||
groupNodeDef: any
|
|
||||||
groupData: any
|
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
innerNodesList!: HTMLUListElement
|
||||||
innerNodesList: HTMLUListElement
|
widgetsPage!: HTMLElement
|
||||||
// @ts-expect-error fixme ts strict error
|
inputsPage!: HTMLElement
|
||||||
widgetsPage: HTMLElement
|
outputsPage!: HTMLElement
|
||||||
// @ts-expect-error fixme ts strict error
|
draggable: DraggableList | undefined
|
||||||
inputsPage: HTMLElement
|
|
||||||
// @ts-expect-error fixme ts strict error
|
|
||||||
outputsPage: HTMLElement
|
|
||||||
draggable: any
|
|
||||||
|
|
||||||
get selectedNodeInnerIndex() {
|
get selectedNodeInnerIndex(): number {
|
||||||
// @ts-expect-error fixme ts strict error
|
return +this.nodeItems[this.selectedNodeIndex!]!.dataset.nodeindex!
|
||||||
return +this.nodeItems[this.selectedNodeIndex].dataset.nodeindex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
constructor(app: ComfyApp) {
|
||||||
constructor(app) {
|
|
||||||
super()
|
super()
|
||||||
this.app = app
|
this.app = app
|
||||||
this.element = $el('dialog.comfy-group-manage', {
|
this.element = $el('dialog.comfy-group-manage', {
|
||||||
@@ -84,19 +78,15 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
}) as HTMLDialogElement
|
}) as HTMLDialogElement
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
changeTab(tab: keyof ManageGroupDialog['tabs']): void {
|
||||||
changeTab(tab) {
|
|
||||||
this.tabs[this.selectedTab].tab.classList.remove('active')
|
this.tabs[this.selectedTab].tab.classList.remove('active')
|
||||||
this.tabs[this.selectedTab].page.classList.remove('active')
|
this.tabs[this.selectedTab].page.classList.remove('active')
|
||||||
// @ts-expect-error fixme ts strict error
|
|
||||||
this.tabs[tab].tab.classList.add('active')
|
this.tabs[tab].tab.classList.add('active')
|
||||||
// @ts-expect-error fixme ts strict error
|
|
||||||
this.tabs[tab].page.classList.add('active')
|
this.tabs[tab].page.classList.add('active')
|
||||||
this.selectedTab = tab
|
this.selectedTab = tab
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
changeNode(index: number, force?: boolean): void {
|
||||||
changeNode(index, force?) {
|
|
||||||
if (!force && this.selectedNodeIndex === index) return
|
if (!force && this.selectedNodeIndex === index) return
|
||||||
|
|
||||||
if (this.selectedNodeIndex != null) {
|
if (this.selectedNodeIndex != null) {
|
||||||
@@ -122,43 +112,41 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
this.groupNodeType = LiteGraph.registered_node_types[
|
this.groupNodeType = LiteGraph.registered_node_types[
|
||||||
`${PREFIX}${SEPARATOR}` + this.selectedGroup
|
`${PREFIX}${SEPARATOR}` + this.selectedGroup
|
||||||
] as unknown as LGraphNodeConstructor<LGraphNode>
|
] as unknown as LGraphNodeConstructor<LGraphNode>
|
||||||
this.groupNodeDef = this.groupNodeType.nodeData
|
this.groupData = GroupNodeHandler.getGroupData(this.groupNodeType)!
|
||||||
this.groupData = GroupNodeHandler.getGroupData(this.groupNodeType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
changeGroup(group: string, reset = true): void {
|
||||||
changeGroup(group, reset = true) {
|
|
||||||
this.selectedGroup = group
|
this.selectedGroup = group
|
||||||
this.getGroupData()
|
this.getGroupData()
|
||||||
|
|
||||||
const nodes = this.groupData.nodeData.nodes
|
const nodes = this.groupData.nodeData.nodes
|
||||||
// @ts-expect-error fixme ts strict error
|
this.nodeItems = nodes.map(
|
||||||
this.nodeItems = nodes.map((n, i) =>
|
(n, i) =>
|
||||||
$el(
|
$el(
|
||||||
'li.draggable-item',
|
'li.draggable-item',
|
||||||
{
|
{
|
||||||
dataset: {
|
dataset: {
|
||||||
nodeindex: n.index + ''
|
nodeindex: n.index + ''
|
||||||
},
|
|
||||||
onclick: () => {
|
|
||||||
this.changeNode(i)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
$el('span.drag-handle'),
|
|
||||||
$el(
|
|
||||||
'div',
|
|
||||||
{
|
|
||||||
textContent: n.title ?? n.type
|
|
||||||
},
|
},
|
||||||
n.title
|
onclick: () => {
|
||||||
? $el('span', {
|
this.changeNode(i)
|
||||||
textContent: n.type
|
}
|
||||||
})
|
},
|
||||||
: []
|
[
|
||||||
)
|
$el('span.drag-handle'),
|
||||||
]
|
$el(
|
||||||
)
|
'div',
|
||||||
|
{
|
||||||
|
textContent: n.title ?? n.type
|
||||||
|
},
|
||||||
|
n.title
|
||||||
|
? $el('span', {
|
||||||
|
textContent: n.type
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
)
|
||||||
|
]
|
||||||
|
) as HTMLLIElement
|
||||||
)
|
)
|
||||||
|
|
||||||
this.innerNodesList.replaceChildren(...this.nodeItems)
|
this.innerNodesList.replaceChildren(...this.nodeItems)
|
||||||
@@ -167,47 +155,46 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
this.selectedNodeIndex = null
|
this.selectedNodeIndex = null
|
||||||
this.changeNode(0)
|
this.changeNode(0)
|
||||||
} else {
|
} else {
|
||||||
const items = this.draggable.getAllItems()
|
const items = this.draggable!.getAllItems()
|
||||||
// @ts-expect-error fixme ts strict error
|
let index = items.findIndex((item: Element) =>
|
||||||
let index = items.findIndex((item) => item.classList.contains('selected'))
|
item.classList.contains('selected')
|
||||||
if (index === -1) index = this.selectedNodeIndex
|
)
|
||||||
|
if (index === -1) index = this.selectedNodeIndex!
|
||||||
this.changeNode(index, true)
|
this.changeNode(index, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ordered = [...nodes]
|
const ordered = [...nodes]
|
||||||
this.draggable?.dispose()
|
this.draggable?.dispose()
|
||||||
this.draggable = new DraggableList(this.innerNodesList, 'li')
|
this.draggable = new DraggableList(this.innerNodesList, 'li')
|
||||||
this.draggable.addEventListener(
|
this.draggable.addEventListener('dragend', (e: Event) => {
|
||||||
'dragend',
|
const { oldPosition, newPosition } = (e as CustomEvent).detail
|
||||||
// @ts-expect-error fixme ts strict error
|
if (oldPosition === newPosition) return
|
||||||
({ detail: { oldPosition, newPosition } }) => {
|
ordered.splice(newPosition, 0, ordered.splice(oldPosition, 1)[0])
|
||||||
if (oldPosition === newPosition) return
|
for (let i = 0; i < ordered.length; i++) {
|
||||||
ordered.splice(newPosition, 0, ordered.splice(oldPosition, 1)[0])
|
this.storeModification({
|
||||||
for (let i = 0; i < ordered.length; i++) {
|
nodeIndex: ordered[i].index,
|
||||||
this.storeModification({
|
section: ORDER,
|
||||||
nodeIndex: ordered[i].index,
|
prop: 'order',
|
||||||
section: ORDER,
|
value: i
|
||||||
prop: 'order',
|
})
|
||||||
value: i
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
storeModification(props: {
|
storeModification(props: {
|
||||||
nodeIndex?: number
|
nodeIndex?: number
|
||||||
section: symbol
|
section: symbol
|
||||||
prop: string
|
prop: string
|
||||||
value: any
|
value: unknown
|
||||||
}) {
|
}) {
|
||||||
const { nodeIndex, section, prop, value } = props
|
const { nodeIndex, section, prop, value } = props
|
||||||
// @ts-expect-error fixme ts strict error
|
const groupKey = this.selectedGroup!
|
||||||
const groupMod = (this.modifications[this.selectedGroup] ??= {})
|
const groupMod = (this.modifications[groupKey] ??= {})
|
||||||
const nodesMod = (groupMod.nodes ??= {})
|
const nodesMod = ((groupMod as Record<string, unknown>).nodes ??=
|
||||||
|
{}) as Record<string, Record<symbol | string, Record<string, unknown>>>
|
||||||
const nodeMod = (nodesMod[nodeIndex ?? this.selectedNodeInnerIndex] ??= {})
|
const nodeMod = (nodesMod[nodeIndex ?? this.selectedNodeInnerIndex] ??= {})
|
||||||
const typeMod = (nodeMod[section] ??= {})
|
const typeMod = (nodeMod[section] ??= {})
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object' && value !== null) {
|
||||||
const objMod = (typeMod[prop] ??= {})
|
const objMod = (typeMod[prop] ??= {})
|
||||||
Object.assign(objMod, value)
|
Object.assign(objMod, value)
|
||||||
} else {
|
} else {
|
||||||
@@ -215,35 +202,45 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
getEditElement(
|
||||||
getEditElement(section, prop, value, placeholder, checked, checkable = true) {
|
section: string,
|
||||||
if (value === placeholder) value = ''
|
prop: string | number,
|
||||||
|
value: unknown,
|
||||||
|
placeholder: string,
|
||||||
|
checked: boolean,
|
||||||
|
checkable = true
|
||||||
|
): HTMLDivElement {
|
||||||
|
let displayValue = value === placeholder ? '' : value
|
||||||
|
|
||||||
const mods =
|
const groupKey = this.selectedGroup!
|
||||||
// @ts-expect-error fixme ts strict error
|
const mods = (
|
||||||
this.modifications[this.selectedGroup]?.nodes?.[
|
this.modifications[groupKey] as Record<string, unknown> | undefined
|
||||||
this.selectedNodeInnerIndex
|
)?.nodes as
|
||||||
]?.[section]?.[prop]
|
| Record<
|
||||||
if (mods) {
|
number,
|
||||||
if (mods.name != null) {
|
Record<string, Record<string, { name?: string; visible?: boolean }>>
|
||||||
value = mods.name
|
>
|
||||||
|
| undefined
|
||||||
|
const modEntry = mods?.[this.selectedNodeInnerIndex]?.[section]?.[prop]
|
||||||
|
if (modEntry) {
|
||||||
|
if (modEntry.name != null) {
|
||||||
|
displayValue = modEntry.name
|
||||||
}
|
}
|
||||||
if (mods.visible != null) {
|
if (modEntry.visible != null) {
|
||||||
checked = mods.visible
|
checked = modEntry.visible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $el('div', [
|
return $el('div', [
|
||||||
$el('input', {
|
$el('input', {
|
||||||
value,
|
value: displayValue as string,
|
||||||
placeholder,
|
placeholder,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
// @ts-expect-error fixme ts strict error
|
onchange: (e: Event) => {
|
||||||
onchange: (e) => {
|
|
||||||
this.storeModification({
|
this.storeModification({
|
||||||
section,
|
section: section as unknown as symbol,
|
||||||
prop,
|
prop: String(prop),
|
||||||
value: { name: e.target.value }
|
value: { name: (e.target as HTMLInputElement).value }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -252,25 +249,23 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked,
|
checked,
|
||||||
disabled: !checkable,
|
disabled: !checkable,
|
||||||
// @ts-expect-error fixme ts strict error
|
onchange: (e: Event) => {
|
||||||
onchange: (e) => {
|
|
||||||
this.storeModification({
|
this.storeModification({
|
||||||
section,
|
section: section as unknown as symbol,
|
||||||
prop,
|
prop: String(prop),
|
||||||
value: { visible: !!e.target.checked }
|
value: { visible: !!(e.target as HTMLInputElement).checked }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
])
|
]) as HTMLDivElement
|
||||||
}
|
}
|
||||||
|
|
||||||
buildWidgetsPage() {
|
buildWidgetsPage() {
|
||||||
const widgets =
|
const widgets =
|
||||||
this.groupData.oldToNewWidgetMap[this.selectedNodeInnerIndex]
|
this.groupData.oldToNewWidgetMap[this.selectedNodeInnerIndex]
|
||||||
const items = Object.keys(widgets ?? {})
|
const items = Object.keys(widgets ?? {})
|
||||||
// @ts-expect-error fixme ts strict error
|
const type = app.rootGraph.extra.groupNodes![this.selectedGroup!]!
|
||||||
const type = app.rootGraph.extra.groupNodes[this.selectedGroup]
|
|
||||||
const config = type.config?.[this.selectedNodeInnerIndex]?.input
|
const config = type.config?.[this.selectedNodeInnerIndex]?.input
|
||||||
this.widgetsPage.replaceChildren(
|
this.widgetsPage.replaceChildren(
|
||||||
...items.map((oldName) => {
|
...items.map((oldName) => {
|
||||||
@@ -289,28 +284,25 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
buildInputsPage() {
|
buildInputsPage() {
|
||||||
const inputs = this.groupData.nodeInputs[this.selectedNodeInnerIndex]
|
const inputs = this.groupData.nodeInputs[this.selectedNodeInnerIndex]
|
||||||
const items = Object.keys(inputs ?? {})
|
const items = Object.keys(inputs ?? {})
|
||||||
// @ts-expect-error fixme ts strict error
|
const type = app.rootGraph.extra.groupNodes![this.selectedGroup!]!
|
||||||
const type = app.rootGraph.extra.groupNodes[this.selectedGroup]
|
|
||||||
const config = type.config?.[this.selectedNodeInnerIndex]?.input
|
const config = type.config?.[this.selectedNodeInnerIndex]?.input
|
||||||
this.inputsPage.replaceChildren(
|
const elements = items
|
||||||
// @ts-expect-error fixme ts strict error
|
.map((oldName) => {
|
||||||
...items
|
const value = inputs[oldName]
|
||||||
.map((oldName) => {
|
if (!value) {
|
||||||
let value = inputs[oldName]
|
return null
|
||||||
if (!value) {
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getEditElement(
|
return this.getEditElement(
|
||||||
'input',
|
'input',
|
||||||
oldName,
|
oldName,
|
||||||
value,
|
value,
|
||||||
oldName,
|
oldName,
|
||||||
config?.[oldName]?.visible !== false
|
config?.[oldName]?.visible !== false
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter((el): el is HTMLDivElement => el !== null)
|
||||||
)
|
this.inputsPage.replaceChildren(...elements)
|
||||||
return !!items.length
|
return !!items.length
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,38 +315,32 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
const groupOutputs =
|
const groupOutputs =
|
||||||
this.groupData.oldToNewOutputMap[this.selectedNodeInnerIndex]
|
this.groupData.oldToNewOutputMap[this.selectedNodeInnerIndex]
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
const type = app.rootGraph.extra.groupNodes![this.selectedGroup!]!
|
||||||
const type = app.rootGraph.extra.groupNodes[this.selectedGroup]
|
|
||||||
const config = type.config?.[this.selectedNodeInnerIndex]?.output
|
const config = type.config?.[this.selectedNodeInnerIndex]?.output
|
||||||
const node = this.groupData.nodeData.nodes[this.selectedNodeInnerIndex]
|
const node = this.groupData.nodeData.nodes[this.selectedNodeInnerIndex]
|
||||||
const checkable = node.type !== 'PrimitiveNode'
|
const checkable = node.type !== 'PrimitiveNode'
|
||||||
this.outputsPage.replaceChildren(
|
const elements = outputs.map((outputType: unknown, slot: number) => {
|
||||||
...outputs
|
const groupOutputIndex = groupOutputs?.[slot]
|
||||||
// @ts-expect-error fixme ts strict error
|
const oldName = innerNodeDef?.output_name?.[slot] ?? String(outputType)
|
||||||
.map((type, slot) => {
|
let value = config?.[slot]?.name
|
||||||
const groupOutputIndex = groupOutputs?.[slot]
|
const visible = config?.[slot]?.visible || groupOutputIndex != null
|
||||||
const oldName = innerNodeDef.output_name?.[slot] ?? type
|
if (!value || value === oldName) {
|
||||||
let value = config?.[slot]?.name
|
value = ''
|
||||||
const visible = config?.[slot]?.visible || groupOutputIndex != null
|
}
|
||||||
if (!value || value === oldName) {
|
return this.getEditElement(
|
||||||
value = ''
|
'output',
|
||||||
}
|
slot,
|
||||||
return this.getEditElement(
|
value,
|
||||||
'output',
|
oldName,
|
||||||
slot,
|
visible,
|
||||||
value,
|
checkable
|
||||||
oldName,
|
)
|
||||||
visible,
|
})
|
||||||
checkable
|
this.outputsPage.replaceChildren(...elements)
|
||||||
)
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
)
|
|
||||||
return !!outputs.length
|
return !!outputs.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
override show(type?: string): void {
|
||||||
show(type?) {
|
|
||||||
const groupNodes = Object.keys(app.rootGraph.extra?.groupNodes ?? {}).sort(
|
const groupNodes = Object.keys(app.rootGraph.extra?.groupNodes ?? {}).sort(
|
||||||
(a, b) => a.localeCompare(b)
|
(a, b) => a.localeCompare(b)
|
||||||
)
|
)
|
||||||
@@ -371,24 +357,27 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
this.outputsPage
|
this.outputsPage
|
||||||
])
|
])
|
||||||
|
|
||||||
this.tabs = [
|
type TabName = 'Inputs' | 'Widgets' | 'Outputs'
|
||||||
|
const tabEntries: [TabName, HTMLElement][] = [
|
||||||
['Inputs', this.inputsPage],
|
['Inputs', this.inputsPage],
|
||||||
['Widgets', this.widgetsPage],
|
['Widgets', this.widgetsPage],
|
||||||
['Outputs', this.outputsPage]
|
['Outputs', this.outputsPage]
|
||||||
// @ts-expect-error fixme ts strict error
|
]
|
||||||
].reduce((p, [name, page]: [string, HTMLElement]) => {
|
this.tabs = tabEntries.reduce(
|
||||||
// @ts-expect-error fixme ts strict error
|
(p, [name, page]) => {
|
||||||
p[name] = {
|
p[name] = {
|
||||||
tab: $el('a', {
|
tab: $el('a', {
|
||||||
onclick: () => {
|
onclick: () => {
|
||||||
this.changeTab(name)
|
this.changeTab(name)
|
||||||
},
|
},
|
||||||
textContent: name
|
textContent: name
|
||||||
}),
|
}) as HTMLAnchorElement,
|
||||||
page
|
page
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}, {}) as any
|
},
|
||||||
|
{} as ManageGroupDialog['tabs']
|
||||||
|
)
|
||||||
|
|
||||||
const outer = $el('div.comfy-group-manage-outer', [
|
const outer = $el('div.comfy-group-manage-outer', [
|
||||||
$el('header', [
|
$el('header', [
|
||||||
@@ -396,9 +385,8 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
$el(
|
$el(
|
||||||
'select',
|
'select',
|
||||||
{
|
{
|
||||||
// @ts-expect-error fixme ts strict error
|
onchange: (e: Event) => {
|
||||||
onchange: (e) => {
|
this.changeGroup((e.target as HTMLSelectElement).value)
|
||||||
this.changeGroup(e.target.value)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
groupNodes.map((g) =>
|
groupNodes.map((g) =>
|
||||||
@@ -439,8 +427,7 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
`Are you sure you want to remove the node: "${this.selectedGroup}"`
|
`Are you sure you want to remove the node: "${this.selectedGroup}"`
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
// @ts-expect-error fixme ts strict error
|
delete app.rootGraph.extra.groupNodes![this.selectedGroup!]
|
||||||
delete app.rootGraph.extra.groupNodes[this.selectedGroup]
|
|
||||||
LiteGraph.unregisterNodeType(
|
LiteGraph.unregisterNodeType(
|
||||||
`${PREFIX}${SEPARATOR}` + this.selectedGroup
|
`${PREFIX}${SEPARATOR}` + this.selectedGroup
|
||||||
)
|
)
|
||||||
@@ -454,97 +441,102 @@ export class ManageGroupDialog extends ComfyDialog<HTMLDialogElement> {
|
|||||||
'button.comfy-btn',
|
'button.comfy-btn',
|
||||||
{
|
{
|
||||||
onclick: async () => {
|
onclick: async () => {
|
||||||
let nodesByType
|
type NodesByType = Record<string, LGraphNode[]>
|
||||||
let recreateNodes = []
|
let nodesByType: NodesByType | undefined
|
||||||
const types = {}
|
const recreateNodes: LGraphNode[] = []
|
||||||
|
const types: Record<string, GroupNodeWorkflowData> = {}
|
||||||
for (const g in this.modifications) {
|
for (const g in this.modifications) {
|
||||||
// @ts-expect-error fixme ts strict error
|
const groupNodeData = app.rootGraph.extra.groupNodes![g]!
|
||||||
const type = app.rootGraph.extra.groupNodes[g]
|
let config = (groupNodeData.config ??= {})
|
||||||
let config = (type.config ??= {})
|
|
||||||
|
|
||||||
let nodeMods = this.modifications[g]?.nodes
|
type NodeMods = Record<
|
||||||
|
string,
|
||||||
|
Record<symbol | string, Record<string, unknown>>
|
||||||
|
>
|
||||||
|
let nodeMods = this.modifications[g]?.nodes as
|
||||||
|
| NodeMods
|
||||||
|
| undefined
|
||||||
if (nodeMods) {
|
if (nodeMods) {
|
||||||
const keys = Object.keys(nodeMods)
|
const keys = Object.keys(nodeMods)
|
||||||
// @ts-expect-error fixme ts strict error
|
if (nodeMods[keys[0]]?.[ORDER]) {
|
||||||
if (nodeMods[keys[0]][ORDER]) {
|
|
||||||
// If any node is reordered, they will all need sequencing
|
// If any node is reordered, they will all need sequencing
|
||||||
const orderedNodes = []
|
const orderedNodes: GroupNodeWorkflowData['nodes'] = []
|
||||||
const orderedMods = {}
|
const orderedMods: NodeMods = {}
|
||||||
const orderedConfig = {}
|
const orderedConfig: Record<number, GroupNodeConfigEntry> =
|
||||||
|
{}
|
||||||
|
|
||||||
for (const n of keys) {
|
for (const n of keys) {
|
||||||
// @ts-expect-error fixme ts strict error
|
const order = (nodeMods[n][ORDER] as { order: number })
|
||||||
const order = nodeMods[n][ORDER].order
|
.order
|
||||||
orderedNodes[order] = type.nodes[+n]
|
orderedNodes[order] = groupNodeData.nodes[+n]
|
||||||
// @ts-expect-error fixme ts strict error
|
|
||||||
orderedMods[order] = nodeMods[n]
|
orderedMods[order] = nodeMods[n]
|
||||||
orderedNodes[order].index = order
|
orderedNodes[order].index = order
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite links
|
// Rewrite links
|
||||||
for (const l of type.links) {
|
for (const l of groupNodeData.links) {
|
||||||
// @ts-expect-error l[0]/l[2] used as node index
|
if (l[0] != null)
|
||||||
if (l[0] != null) l[0] = type.nodes[l[0]].index
|
l[0] = groupNodeData.nodes[l[0] as number].index!
|
||||||
// @ts-expect-error l[0]/l[2] used as node index
|
if (l[2] != null)
|
||||||
if (l[2] != null) l[2] = type.nodes[l[2]].index
|
l[2] = groupNodeData.nodes[l[2] as number].index!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite externals
|
// Rewrite externals
|
||||||
if (type.external) {
|
if (groupNodeData.external) {
|
||||||
for (const ext of type.external) {
|
for (const ext of groupNodeData.external) {
|
||||||
if (ext[0] != null) {
|
if (ext[0] != null) {
|
||||||
// @ts-expect-error ext[0] used as node index
|
ext[0] = groupNodeData.nodes[ext[0] as number].index!
|
||||||
ext[0] = type.nodes[ext[0]].index
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite modifications
|
// Rewrite modifications
|
||||||
for (const id of keys) {
|
for (const id of keys) {
|
||||||
// @ts-expect-error id used as node index
|
if (config[+id]) {
|
||||||
if (config[id]) {
|
orderedConfig[groupNodeData.nodes[+id].index!] =
|
||||||
// @ts-expect-error fixme ts strict error
|
config[+id]
|
||||||
orderedConfig[type.nodes[id].index] = config[id]
|
|
||||||
}
|
}
|
||||||
// @ts-expect-error id used as config key
|
delete config[+id]
|
||||||
delete config[id]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type.nodes = orderedNodes
|
groupNodeData.nodes = orderedNodes
|
||||||
nodeMods = orderedMods
|
nodeMods = orderedMods
|
||||||
type.config = config = orderedConfig
|
groupNodeData.config = config = orderedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
merge(config, nodeMods)
|
merge(
|
||||||
|
config as Record<string, unknown>,
|
||||||
|
nodeMods as Record<string, unknown>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
types[g] = groupNodeData
|
||||||
types[g] = type
|
|
||||||
|
|
||||||
if (!nodesByType) {
|
if (!nodesByType) {
|
||||||
nodesByType = app.rootGraph.nodes.reduce((p, n) => {
|
nodesByType = app.rootGraph.nodes.reduce<NodesByType>(
|
||||||
// @ts-expect-error fixme ts strict error
|
(p, n) => {
|
||||||
p[n.type] ??= []
|
const nodeType = n.type ?? ''
|
||||||
// @ts-expect-error fixme ts strict error
|
p[nodeType] ??= []
|
||||||
p[n.type].push(n)
|
p[nodeType].push(n)
|
||||||
return p
|
return p
|
||||||
}, {})
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error fixme ts strict error
|
const groupTypeNodes = nodesByType[`${PREFIX}${SEPARATOR}` + g]
|
||||||
const nodes = nodesByType[`${PREFIX}${SEPARATOR}` + g]
|
if (groupTypeNodes) recreateNodes.push(...groupTypeNodes)
|
||||||
if (nodes) recreateNodes.push(...nodes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await GroupNodeConfig.registerFromWorkflow(types, [])
|
await GroupNodeConfig.registerFromWorkflow(types, [])
|
||||||
|
|
||||||
for (const node of recreateNodes) {
|
for (const node of recreateNodes) {
|
||||||
node.recreate()
|
node.recreate?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifications = {}
|
this.modifications = {}
|
||||||
this.app.canvas.setDirty(true, true)
|
this.app.canvas.setDirty(true, true)
|
||||||
this.changeGroup(this.selectedGroup, false)
|
this.changeGroup(this.selectedGroup!, false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Save'
|
'Save'
|
||||||
|
|||||||
@@ -102,16 +102,23 @@ export interface LGraphConfig {
|
|||||||
links_ontop?: boolean
|
links_ontop?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupNodeConfigEntry {
|
||||||
|
input?: Record<string, { name?: string; visible?: boolean }>
|
||||||
|
output?: Record<number, { name?: string; visible?: boolean }>
|
||||||
|
}
|
||||||
|
|
||||||
export interface GroupNodeWorkflowData {
|
export interface GroupNodeWorkflowData {
|
||||||
external: (number | string)[][]
|
external: (number | string)[][]
|
||||||
links: SerialisedLLinkArray[]
|
links: SerialisedLLinkArray[]
|
||||||
nodes: {
|
nodes: {
|
||||||
index?: number
|
index?: number
|
||||||
type?: string
|
type?: string
|
||||||
|
title?: string
|
||||||
inputs?: unknown[]
|
inputs?: unknown[]
|
||||||
outputs?: unknown[]
|
outputs?: unknown[]
|
||||||
|
widgets_values?: unknown[]
|
||||||
}[]
|
}[]
|
||||||
config?: Record<number, unknown>
|
config?: Record<number, GroupNodeConfigEntry>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LGraphExtra extends Dictionary<unknown> {
|
export interface LGraphExtra extends Dictionary<unknown> {
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ export type {
|
|||||||
} from './interfaces'
|
} from './interfaces'
|
||||||
export {
|
export {
|
||||||
LGraph,
|
LGraph,
|
||||||
|
type GroupNodeConfigEntry,
|
||||||
|
type GroupNodeWorkflowData,
|
||||||
type LGraphTriggerAction,
|
type LGraphTriggerAction,
|
||||||
type LGraphTriggerParam
|
type LGraphTriggerParam
|
||||||
} from './LGraph'
|
} from './LGraph'
|
||||||
|
|||||||
Reference in New Issue
Block a user