mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-09-14 05:25:23 +00:00
Group nodes (#1776)
* setup ui unit tests * Refactoring, adding connections * Few tweaks * Fix type * Add general test * Refactored and extended test * move to describe * for groups * wip group nodes * Relink nodes Fixed widget values Convert to nodes * Reconnect on convert back * add via node menu + canvas refactor * Add ws event handling * fix using wrong node on widget serialize * allow reroute pipe fix control_after_generate configure * allow multiple images * Add test for converted widgets on missing nodes + fix crash * tidy * mores tests + refactor * throw earlier to get less confusing error * support outputs * more test * add ci action * use lts node * Fix? * Prevent connecting non matching combos * update * accidently removed npm i * Disable logging extension * fix naming allow control_after_generate custom name allow convert from reroutes * group node tests * Add executing info, custom node icon Tidy * internal reroute just works * Fix crash on virtual nodes e.g. note * Save group nodes to templates * Fix template nodes not being stored * Fix aborting convert * tidy * Fix reconnecting output links on convert to group * Fix links on convert to nodes * Handle missing internal nodes * Trigger callback on text change * Apply value on connect * Fix converted widgets not reconnecting * Group node updates - persist internal ids in current session - copy widget values when converting to nodes - fix issue serializing converted inputs * Resolve issue with sanitized node name * Fix internal id * allow outputs to be used internally and externally * order widgets on group node various fixes * fix imageupload widget requiring a specific name * groupnode imageupload test give widget unique name * Fix issue with external node links * Add VAE model * Fix internal node id check * fix potential crash * wip widget input support * more wip group widget inputs * Group node refactor Support for primitives/converted widgets * Fix convert to nodes with internal reroutes * fix applying primitive * Fix control widget values * fix test
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||
import { GroupNodeConfig, GroupNodeHandler } from "./groupNode.js";
|
||||
|
||||
// Adds the ability to save and add multiple nodes as a template
|
||||
// To save:
|
||||
@@ -34,7 +35,7 @@ class ManageTemplates extends ComfyDialog {
|
||||
type: "file",
|
||||
accept: ".json",
|
||||
multiple: true,
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
parent: document.body,
|
||||
onchange: () => this.importAll(),
|
||||
});
|
||||
@@ -109,13 +110,13 @@ class ManageTemplates extends ComfyDialog {
|
||||
return;
|
||||
}
|
||||
|
||||
const json = JSON.stringify({templates: this.templates}, null, 2); // convert the data to a JSON string
|
||||
const blob = new Blob([json], {type: "application/json"});
|
||||
const json = JSON.stringify({ templates: this.templates }, null, 2); // convert the data to a JSON string
|
||||
const blob = new Blob([json], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = $el("a", {
|
||||
href: url,
|
||||
download: "node_templates.json",
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
parent: document.body,
|
||||
});
|
||||
a.click();
|
||||
@@ -291,11 +292,11 @@ app.registerExtension({
|
||||
setup() {
|
||||
const manage = new ManageTemplates();
|
||||
|
||||
const clipboardAction = (cb) => {
|
||||
const clipboardAction = async (cb) => {
|
||||
// We use the clipboard functions but dont want to overwrite the current user clipboard
|
||||
// Restore it after we've run our callback
|
||||
const old = localStorage.getItem("litegrapheditor_clipboard");
|
||||
cb();
|
||||
await cb();
|
||||
localStorage.setItem("litegrapheditor_clipboard", old);
|
||||
};
|
||||
|
||||
@@ -309,13 +310,31 @@ app.registerExtension({
|
||||
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
|
||||
callback: () => {
|
||||
const name = prompt("Enter name");
|
||||
if (!name || !name.trim()) return;
|
||||
if (!name?.trim()) return;
|
||||
|
||||
clipboardAction(() => {
|
||||
app.canvas.copyToClipboard();
|
||||
let data = localStorage.getItem("litegrapheditor_clipboard");
|
||||
data = JSON.parse(data);
|
||||
const nodeIds = Object.keys(app.canvas.selected_nodes);
|
||||
for (let i = 0; i < nodeIds.length; i++) {
|
||||
const node = app.graph.getNodeById(nodeIds[i]);
|
||||
const nodeData = node?.constructor.nodeData;
|
||||
|
||||
let groupData = GroupNodeHandler.getGroupData(node);
|
||||
if (groupData) {
|
||||
groupData = groupData.nodeData;
|
||||
if (!data.groupNodes) {
|
||||
data.groupNodes = {};
|
||||
}
|
||||
data.groupNodes[nodeData.name] = groupData;
|
||||
data.nodes[i].type = nodeData.name;
|
||||
}
|
||||
}
|
||||
|
||||
manage.templates.push({
|
||||
name,
|
||||
data: localStorage.getItem("litegrapheditor_clipboard"),
|
||||
data: JSON.stringify(data),
|
||||
});
|
||||
manage.store();
|
||||
});
|
||||
@@ -323,15 +342,19 @@ app.registerExtension({
|
||||
});
|
||||
|
||||
// Map each template to a menu item
|
||||
const subItems = manage.templates.map((t) => ({
|
||||
content: t.name,
|
||||
callback: () => {
|
||||
clipboardAction(() => {
|
||||
localStorage.setItem("litegrapheditor_clipboard", t.data);
|
||||
app.canvas.pasteFromClipboard();
|
||||
});
|
||||
},
|
||||
}));
|
||||
const subItems = manage.templates.map((t) => {
|
||||
return {
|
||||
content: t.name,
|
||||
callback: () => {
|
||||
clipboardAction(async () => {
|
||||
const data = JSON.parse(t.data);
|
||||
await GroupNodeConfig.registerFromWorkflow(data.groupNodes, {});
|
||||
localStorage.setItem("litegrapheditor_clipboard", t.data);
|
||||
app.canvas.pasteFromClipboard();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
subItems.push(null, {
|
||||
content: "Manage",
|
||||
|
Reference in New Issue
Block a user