Update Template copy & paste (#1533)

* Split original clipboard functions out

* Add version check for templates

* Fix regression in use template undo steps
This commit is contained in:
filtered
2024-11-14 09:04:31 +11:00
committed by GitHub
parent b9224464c0
commit 82d00a1bcf
4 changed files with 141 additions and 118 deletions

View File

@@ -9,6 +9,10 @@ import { useNodeDefStore } from '@/stores/nodeDefStore'
import { ComfyLink, ComfyNode, ComfyWorkflowJSON } from '@/types/comfyWorkflow'
import { useToastStore } from '@/stores/toastStore'
import { ComfyExtension } from '@/types/comfy'
import {
deserialiseAndCreate,
serialise
} from '@/extensions/core/vintageClipboard'
type GroupNodeWorkflowData = {
external: ComfyLink[]
@@ -1480,120 +1484,6 @@ function manageGroupNodes() {
new ManageGroupDialog(app).show()
}
/**
* Serialises an array of nodes using a modified version of the old Litegraph copy (& paste) function
* @param nodes All nodes to be serialised
* @param graph The graph we are working in
* @returns A serialised string of all nodes, and their connections
* @deprecated Format not in use anywhere else.
*/
function serialise(nodes: LGraphNode[], graph: LGraph): string {
const serialisable = {
nodes: [],
links: []
}
let index = 0
const cloneable: LGraphNode[] = []
for (const node of nodes) {
if (node.clonable === false) continue
node._relative_id = index++
cloneable.push(node)
}
// Clone the node
for (const node of cloneable) {
const cloned = node.clone()
if (!cloned) {
console.warn('node type not found: ' + node.type)
continue
}
serialisable.nodes.push(cloned.serialize())
if (!node.inputs?.length) continue
// For inputs only, gather link details of every connection
for (const input of node.inputs) {
if (!input || input.link == null) continue
const link = graph.links.get(input.link)
if (!link) continue
const outNode = graph.getNodeById(link.origin_id)
if (!outNode) continue
// Special format for old Litegraph copy & paste only
serialisable.links.push([
outNode._relative_id,
link.origin_slot,
node._relative_id,
link.target_slot,
outNode.id
])
}
}
return JSON.stringify(serialisable)
}
/**
* Deserialises nodes and links using a modified version of the old Litegraph (copy &) paste function
* @param data The serialised nodes and links to create
* @param canvas The canvas to create the serialised items in
*/
function deserialiseAndCreate(data: string, canvas: LGraphCanvas): void {
if (!data) return
const { graph, graph_mouse } = canvas
graph.beforeChange()
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]
}
// 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()
}
const id = 'Comfy.GroupNode'
let globalDefs
const ext: ComfyExtension = {

View File

@@ -5,6 +5,7 @@ import { ComfyDialog, $el } from '../../scripts/ui'
import { GroupNodeConfig, GroupNodeHandler } from './groupNode'
import { LGraphCanvas } from '@comfyorg/litegraph'
import { useToastStore } from '@/stores/toastStore'
import { deserialiseAndCreate } from '@/extensions/core/vintageClipboard'
// Adds the ability to save and add multiple nodes as a template
// To save:
@@ -414,8 +415,14 @@ app.registerExtension({
clipboardAction(async () => {
const data = JSON.parse(t.data)
await GroupNodeConfig.registerFromWorkflow(data.groupNodes, {})
localStorage.setItem('litegrapheditor_clipboard', t.data)
app.canvas.pasteFromClipboard()
// Check for old clipboard format
if (!data.reroutes) {
deserialiseAndCreate(t.data, app.canvas)
} else {
localStorage.setItem('litegrapheditor_clipboard', t.data)
app.canvas.pasteFromClipboard()
}
})
}
}

View File

@@ -0,0 +1,119 @@
// @ts-strict-ignore
import type { LGraph, LGraphCanvas, LGraphNode } from '@comfyorg/litegraph'
import { LiteGraph } from '@comfyorg/litegraph'
/**
* Serialises an array of nodes using a modified version of the old Litegraph copy (& paste) function
* @param nodes All nodes to be serialised
* @param graph The graph we are working in
* @returns A serialised string of all nodes, and their connections
* @deprecated Format not in use anywhere else.
*/
export function serialise(nodes: LGraphNode[], graph: LGraph): string {
const serialisable = {
nodes: [],
links: []
}
let index = 0
const cloneable: LGraphNode[] = []
for (const node of nodes) {
if (node.clonable === false) continue
node._relative_id = index++
cloneable.push(node)
}
// Clone the node
for (const node of cloneable) {
const cloned = node.clone()
if (!cloned) {
console.warn('node type not found: ' + node.type)
continue
}
serialisable.nodes.push(cloned.serialize())
if (!node.inputs?.length) continue
// For inputs only, gather link details of every connection
for (const input of node.inputs) {
if (!input || input.link == null) continue
const link = graph.links.get(input.link)
if (!link) continue
const outNode = graph.getNodeById(link.origin_id)
if (!outNode) continue
// Special format for old Litegraph copy & paste only
serialisable.links.push([
outNode._relative_id,
link.origin_slot,
node._relative_id,
link.target_slot,
outNode.id
])
}
}
return JSON.stringify(serialisable)
}
/**
* Deserialises nodes and links using a modified version of the old Litegraph (copy &) paste function
* @param data The serialised nodes and links to create
* @param canvas The canvas to create the serialised items in
*/
export function deserialiseAndCreate(data: string, canvas: LGraphCanvas): void {
if (!data) return
const { graph, graph_mouse } = canvas
canvas.emitBeforeChange()
graph.beforeChange()
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]
}
// 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

@@ -64,6 +64,7 @@ import { shallowReactive } from 'vue'
import { type IBaseWidget } from '@comfyorg/litegraph/dist/types/widgets'
import { workflowService } from '@/services/workflowService'
import { useWidgetStore } from '@/stores/widgetStore'
import { deserialiseAndCreate } from '@/extensions/core/vintageClipboard'
export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview'
@@ -2123,8 +2124,14 @@ export class ComfyApp {
continue
}
localStorage.setItem('litegrapheditor_clipboard', template.data)
app.canvas.pasteFromClipboard()
// Check for old clipboard format
const data = JSON.parse(template.data)
if (!data.reroutes) {
deserialiseAndCreate(template.data, app.canvas)
} else {
localStorage.setItem('litegrapheditor_clipboard', template.data)
app.canvas.pasteFromClipboard()
}
// Move mouse position down to paste the next template below