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:
Johnpaul
2026-01-16 03:12:09 +01:00
parent 00141c47a4
commit 7f0f0305e6
4 changed files with 237 additions and 235 deletions

View File

@@ -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

View File

@@ -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'

View File

@@ -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> {

View File

@@ -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'