diff --git a/friendly-pipe-sandbox.json b/friendly-pipe-sandbox.json deleted file mode 100644 index 508c405..0000000 --- a/friendly-pipe-sandbox.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"7f10e289-6a5d-4520-80ff-f0fded044626","revision":0,"last_node_id":7,"last_link_id":5,"nodes":[{"id":5,"type":"7f36590c-c931-44f4-a37b-ec33ef4051a0","pos":[9625,-2725],"size":[140,26],"flags":{},"order":4,"mode":0,"inputs":[{"name":"pipe","type":"FRIENDLY_PIPE","link":2}],"outputs":[],"properties":{"proxyWidgets":[],"cnr_id":"comfy-core","ver":"0.4.0","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.2"}},"widgets_values":[]},{"id":7,"type":"FriendlyPipeIn","pos":[8950,-2625],"size":[210,150],"flags":{},"order":2,"mode":0,"inputs":[{"label":"in_1","localized_name":"slot_1","name":"slot_1","shape":7,"type":"*","link":3},{"label":"in_2","name":"slot_2","type":"*","link":4}],"outputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","links":[5]}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.2"},"cnr_id":"comfyui-friendly-pipe","ver":"72f0ea3d7f686488045950d1c0bfc4c72b2d677a","Node name for S&R":"FriendlyPipeIn"},"widgets_values":["in_1","in_2"],"slotCount":2,"slotNames":{"1":"in_1","2":"in_2"},"slotTypes":{"1":"FRIENDLY_PIPE","2":"FRIENDLY_PIPE"}},{"id":1,"type":"FriendlyPipeIn","pos":[8650,-2725],"size":[210,150],"flags":{},"order":0,"mode":0,"inputs":[{"label":"in_1_1","localized_name":"slot_1","name":"slot_1","shape":7,"type":"*","link":null},{"label":"in_1_2","name":"slot_2","type":"*","link":null}],"outputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","links":[3]}],"properties":{"cnr_id":"comfyui-friendly-pipe","ver":"72f0ea3d7f686488045950d1c0bfc4c72b2d677a","Node name for S&R":"FriendlyPipeIn","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.2"}},"widgets_values":["in_1_1","in_1_2"],"slotCount":2,"slotNames":{"1":"in_1_1","2":"in_1_2"},"slotTypes":{}},{"id":6,"type":"FriendlyPipeIn","pos":[8650,-2500],"size":[210,150],"flags":{},"order":1,"mode":0,"inputs":[{"label":"in_2_1","localized_name":"slot_1","name":"slot_1","shape":7,"type":"*","link":null},{"label":"in_2_2","name":"slot_2","type":"*","link":null}],"outputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","links":[4]}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.2"},"cnr_id":"comfyui-friendly-pipe","ver":"72f0ea3d7f686488045950d1c0bfc4c72b2d677a","Node name for S&R":"FriendlyPipeIn"},"widgets_values":["in_2_1","in_2_2"],"slotCount":2,"slotNames":{"1":"in_2_1","2":"in_2_2"},"slotTypes":{}},{"id":3,"type":"dddf7678-010f-4040-81b4-1236387d7c23","pos":[9275,-2725],"size":[140,26],"flags":{},"order":3,"mode":0,"inputs":[{"name":"pipe","type":"FRIENDLY_PIPE","link":5}],"outputs":[{"name":"pipe","type":"FRIENDLY_PIPE","links":[2]}],"properties":{"proxyWidgets":[],"cnr_id":"comfy-core","ver":"0.4.0","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.2"}},"widgets_values":[]}],"links":[[2,3,0,5,0,"FRIENDLY_PIPE"],[3,1,0,7,0,"FRIENDLY_PIPE"],[4,6,0,7,1,"FRIENDLY_PIPE"],[5,7,0,3,0,"FRIENDLY_PIPE"]],"groups":[],"definitions":{"subgraphs":[{"id":"dddf7678-010f-4040-81b4-1236387d7c23","version":1,"state":{"lastGroupId":0,"lastNodeId":8,"lastLinkId":9,"lastRerouteId":0},"revision":0,"config":{},"name":"Subgraph 1","inputNode":{"id":-10,"bounding":[9120,-2597,120,60]},"outputNode":{"id":-20,"bounding":[9850,-2600,120,60]},"inputs":[{"id":"8bafb261-0838-48c1-acaf-51aa6443182b","name":"pipe","type":"FRIENDLY_PIPE","linkIds":[1,8],"pos":[9220,-2577]}],"outputs":[{"id":"69e97dba-064c-482b-a6e2-79ed9e663c23","name":"pipe","type":"FRIENDLY_PIPE","linkIds":[9],"pos":[9870,-2580]}],"widgets":[],"nodes":[{"id":6,"type":"FriendlyPipeOut","pos":[9500,-2750],"size":[153.390234375,46],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","link":6}],"outputs":[{"label":"in_1","localized_name":"slot_1","name":"slot_1","type":"*","links":null},{"label":"in_2","name":"slot_2","type":"*","links":null}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}},"cnr_id":"comfyui-friendly-pipe","ver":"292cb622a7776887081a38137a99a43ef5ff2917","Node name for S&R":"FriendlyPipeOut"},"slotCount":2,"slotNames":{"1":"in_1","2":"in_2"},"slotTypes":{}},{"id":2,"type":"FriendlyPipeOut","pos":[9275,-2675],"size":[153.390234375,46],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","link":1}],"outputs":[{"label":"in_1","localized_name":"slot_1","name":"slot_1","type":"*","links":[6]},{"label":"in_2","name":"slot_2","type":"*","links":[7]}],"properties":{"cnr_id":"comfyui-friendly-pipe","ver":"72f0ea3d7f686488045950d1c0bfc4c72b2d677a","Node name for S&R":"FriendlyPipeOut","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}}},"widgets_values":[],"slotCount":2,"slotNames":{"1":"in_1","2":"in_2"},"slotTypes":{}},{"id":7,"type":"FriendlyPipeOut","pos":[9475,-2625],"size":[153.390234375,46],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","link":7}],"outputs":[{"label":"in_1","localized_name":"slot_1","name":"slot_1","type":"*","links":null},{"label":"in_2","name":"slot_2","type":"*","links":null}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}},"cnr_id":"comfyui-friendly-pipe","ver":"292cb622a7776887081a38137a99a43ef5ff2917","Node name for S&R":"FriendlyPipeOut"},"slotCount":2,"slotNames":{"1":"in_1","2":"in_2"},"slotTypes":{}},{"id":8,"type":"FriendlyPipeEdit","pos":[9450,-2500],"size":[210,126],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","link":8},{"label":"slot_1","localized_name":"slot_1","name":"slot_1","shape":7,"type":"*","link":null}],"outputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","links":[9]}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}},"cnr_id":"comfyui-friendly-pipe","ver":"292cb622a7776887081a38137a99a43ef5ff2917","Node name for S&R":"FriendlyPipeEdit"},"widgets_values":["slot_1"],"slotCount":1,"slotNames":{"1":"slot_1"},"slotTypes":{}}],"groups":[],"links":[{"id":1,"origin_id":-10,"origin_slot":0,"target_id":2,"target_slot":0,"type":"FRIENDLY_PIPE"},{"id":6,"origin_id":2,"origin_slot":0,"target_id":6,"target_slot":0,"type":"FRIENDLY_PIPE"},{"id":7,"origin_id":2,"origin_slot":1,"target_id":7,"target_slot":0,"type":"FRIENDLY_PIPE"},{"id":8,"origin_id":-10,"origin_slot":0,"target_id":8,"target_slot":0,"type":"FRIENDLY_PIPE"},{"id":9,"origin_id":8,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"FRIENDLY_PIPE"}],"extra":{"workflowRendererVersion":"LG","ue_links":[]}},{"id":"7f36590c-c931-44f4-a37b-ec33ef4051a0","version":1,"state":{"lastGroupId":0,"lastNodeId":4,"lastLinkId":2,"lastRerouteId":0},"revision":0,"config":{},"name":"Subgraph 2","inputNode":{"id":-10,"bounding":[9345,-2622,120,60]},"outputNode":{"id":-20,"bounding":[9738.390234375,-2622,120,40]},"inputs":[{"id":"e28ac386-50e4-4167-a960-841c1c6aafcd","name":"pipe","type":"FRIENDLY_PIPE","linkIds":[2],"pos":[9445,-2602]}],"outputs":[],"widgets":[],"nodes":[{"id":4,"type":"FriendlyPipeOut","pos":[9525,-2600],"size":[153.390234375,46],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"pipe","name":"pipe","type":"FRIENDLY_PIPE","link":2}],"outputs":[{"label":"edit_2","localized_name":"slot_1","name":"slot_1","type":"*","links":null},{"label":"edit_2","name":"slot_2","type":"*","links":null}],"properties":{"cnr_id":"comfyui-friendly-pipe","ver":"72f0ea3d7f686488045950d1c0bfc4c72b2d677a","Node name for S&R":"FriendlyPipeOut","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}}},"widgets_values":[],"slotCount":2,"slotNames":{"1":"edit_2","2":"edit_2"},"slotTypes":{}}],"groups":[],"links":[{"id":2,"origin_id":-10,"origin_slot":0,"target_id":4,"target_slot":0,"type":"FRIENDLY_PIPE"}],"extra":{"workflowRendererVersion":"LG","ue_links":[]}}]},"config":{},"extra":{"workflowRendererVersion":"LG","ue_links":[]},"version":0.4} \ No newline at end of file diff --git a/friendly_pipe_edit.py b/friendly_pipe_edit.py index a8f6c40..d2f54f2 100644 --- a/friendly_pipe_edit.py +++ b/friendly_pipe_edit.py @@ -4,6 +4,7 @@ class FriendlyPipeEdit: """ A pipe editing node that adds new slots to an existing FRIENDLY_PIPE. Allows extending pipes with additional inputs while preserving existing data. + Also exposes incoming pipe slots as inputs to allow updating their values. """ MAX_SLOTS = 80 @@ -18,9 +19,15 @@ class FriendlyPipeEdit: "hidden": { "slot_count": ("INT", {"default": 1}), "slot_names": ("STRING", {"default": "{}"}), + "incoming_slot_count": ("INT", {"default": 0}), } } + # Define slots for exposed incoming slots (incoming_slot_1, incoming_slot_2, etc.) + # These are created dynamically by the frontend based on incoming pipe + for i in range(1, cls.MAX_SLOTS + 1): + inputs["optional"][f"incoming_slot_{i}"] = (ANY_TYPE, {"forceInput": True}) + # Define additional slots as optional with ANY_TYPE for i in range(1, cls.MAX_SLOTS + 1): inputs["optional"][f"slot_{i}"] = (ANY_TYPE, {"forceInput": True}) @@ -32,7 +39,7 @@ class FriendlyPipeEdit: FUNCTION = "execute" CATEGORY = "utils/pipe" - def execute(self, pipe, slot_count=1, slot_names="{}", **kwargs): + def execute(self, pipe, slot_count=1, slot_names="{}", incoming_slot_count=0, **kwargs): import json # Parse slot names from JSON string @@ -46,13 +53,16 @@ class FriendlyPipeEdit: incoming_names = pipe.get("names", {}) # Calculate actual incoming slot count from the data (more reliable than slot_count field) - incoming_slot_count = 0 + actual_incoming_count = 0 for key in incoming_slots.keys(): int_key = int(key) if isinstance(key, str) else key - incoming_slot_count = max(incoming_slot_count, int_key) + actual_incoming_count = max(actual_incoming_count, int_key) # Also consider the pipe's reported slot_count (for empty slots) - incoming_slot_count = max(incoming_slot_count, pipe.get("slot_count", 0)) + actual_incoming_count = max(actual_incoming_count, pipe.get("slot_count", 0)) + + # Use the frontend-provided incoming_slot_count if it's larger + actual_incoming_count = max(actual_incoming_count, incoming_slot_count) # Create new pipe data combining incoming + new slots pipe_data = { @@ -70,13 +80,19 @@ class FriendlyPipeEdit: int_key = int(key) if isinstance(key, str) else key pipe_data["names"][int_key] = value + # Override incoming slots if exposed inputs are connected + for i in range(1, actual_incoming_count + 1): + incoming_key = f"incoming_slot_{i}" + if incoming_key in kwargs and kwargs[incoming_key] is not None: + pipe_data["slots"][i] = kwargs[incoming_key] + # Find the highest slot we're adding max_new_slot = 0 # Add new slots with offset indices for i in range(1, slot_count + 1): slot_key = f"slot_{i}" - new_index = incoming_slot_count + i + new_index = actual_incoming_count + i if slot_key in kwargs and kwargs[slot_key] is not None: pipe_data["slots"][new_index] = kwargs[slot_key] @@ -89,6 +105,6 @@ class FriendlyPipeEdit: pipe_data["names"][new_index] = names_dict[str(i)] # Calculate final slot count - pipe_data["slot_count"] = incoming_slot_count + max(slot_count, max_new_slot) + pipe_data["slot_count"] = actual_incoming_count + max(slot_count, max_new_slot) return (pipe_data,) diff --git a/js/friendly_pipe.js b/js/friendly_pipe.js index aa2c292..dd8d763 100644 --- a/js/friendly_pipe.js +++ b/js/friendly_pipe.js @@ -1066,6 +1066,9 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { this.incomingSlotTypes = {}; this.incomingSlotSources = {}; + // Track which incoming slots are exposed as inputs + this.exposedIncomingSlots = {}; + // Remove all optional inputs except the first one // Keep the pipe input (index 0) and first slot input (index 1) while (this.inputs && this.inputs.length > 2) { @@ -1087,7 +1090,7 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { const defaultName = "slot_" + node.slotCount; node.slotNames[node.slotCount] = defaultName; - // Add new input slot + // Add new input slot at the end node.addInput("slot_" + node.slotCount, "*"); if (node.inputs && node.inputs.length > 0) { node.inputs[node.inputs.length - 1].label = defaultName; @@ -1107,7 +1110,7 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { // Remove the name widget node.removeSlotNameWidget(node.slotCount); - // Remove the input slot + // Remove the input slot (it's at the end, after exposed incoming slots) node.removeInput(node.inputs.length - 1); delete node.slotNames[node.slotCount]; @@ -1132,8 +1135,8 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { const nameWidget = this.addWidget("text", "Label " + slotNum, defaultName, (value) => { node.slotNames[slotNum] = value; - // Update the input label (offset by 1 for pipe input) - const inputIndex = slotNum; // slotNum maps directly since pipe is at 0 + // Update the input label - account for pipe input and exposed incoming slots + const inputIndex = 1 + node.incomingSlotCount + (slotNum - 1); if (node.inputs && node.inputs[inputIndex]) { node.inputs[inputIndex].label = value; } @@ -1202,6 +1205,8 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { this.incomingSlotNames = {}; this.incomingSlotTypes = {}; this.incomingSlotSources = {}; + // Remove exposed incoming slot inputs + this.updateExposedIncomingSlots(); this.notifyConnectedOutputs(); return; } @@ -1266,9 +1271,76 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { } } + // Update exposed incoming slot inputs + this.updateExposedIncomingSlots(); + this.notifyConnectedOutputs(); }; + // Update the exposed incoming slot inputs based on current incoming pipe slots + nodeType.prototype.updateExposedIncomingSlots = function() { + const node = this; + + // Calculate expected input structure: + // Index 0: pipe input + // Index 1 to incomingSlotCount: exposed incoming slots (named incoming_slot_1, etc.) + // Index incomingSlotCount+1 to end: additional new slots (named slot_1, etc.) + + const expectedExposedCount = this.incomingSlotCount; + const currentExposedCount = Object.keys(this.exposedIncomingSlots || {}).length; + + // First, preserve connections on additional slots by tracking them + const additionalSlotConnections = {}; + const additionalStartIndex = 1 + currentExposedCount; + for (let i = 0; i < this.slotCount; i++) { + const inputIndex = additionalStartIndex + i; + if (this.inputs && this.inputs[inputIndex] && this.inputs[inputIndex].link) { + additionalSlotConnections[i + 1] = this.inputs[inputIndex].link; + } + } + + // Remove all inputs except pipe input (index 0) + while (this.inputs && this.inputs.length > 1) { + this.removeInput(this.inputs.length - 1); + } + + // Add exposed incoming slot inputs + // These have names like "incoming_slot_1" for Python, but display labels from incoming pipe + this.exposedIncomingSlots = {}; + for (let i = 1; i <= expectedExposedCount; i++) { + const displayName = this.incomingSlotNames[i] || ("slot_" + i); + const type = this.incomingSlotTypes[i] || "*"; + // Name must match Python parameter: incoming_slot_N + this.addInput("incoming_slot_" + i, type); + this.exposedIncomingSlots[i] = true; + // Set display label to the incoming slot's name + if (this.inputs[i]) { + this.inputs[i].label = displayName; + this.inputs[i].isExposedIncoming = true; + } + } + + // Re-add additional new slot inputs + // These have names like "slot_1" for Python + for (let i = 1; i <= this.slotCount; i++) { + const displayName = this.slotNames[i] || ("slot_" + i); + // Name must match Python parameter: slot_N + this.addInput("slot_" + i, "*"); + const inputIndex = expectedExposedCount + i; + if (this.inputs[inputIndex]) { + this.inputs[inputIndex].label = displayName; + } + } + + this.updateSize(); + this.setDirtyCanvas(true, true); + }; + + // Get the input index for an additional slot (accounting for exposed incoming slots) + nodeType.prototype.getAdditionalSlotInputIndex = function(slotNum) { + return 1 + this.incomingSlotCount + (slotNum - 1); + }; + // Get total slot count (incoming + our additional slots) nodeType.prototype.getTotalSlotCount = function() { return this.incomingSlotCount + this.slotCount; @@ -1292,31 +1364,6 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { return combined; }; - // Get combined slot types - nodeType.prototype.getCombinedSlotTypes = function() { - // Make sure our slot types are up to date - this.updateSlotTypes(); - - const combined = {}; - - // Copy incoming slot types from upstream pipe - if (this.incomingSlotTypes) { - for (const [key, value] of Object.entries(this.incomingSlotTypes)) { - combined[key] = value; - } - } - - // Add our additional slot types with offset indices - for (let i = 1; i <= this.slotCount; i++) { - const newIndex = this.incomingSlotCount + i; - if (this.slotTypes[i]) { - combined[newIndex] = this.slotTypes[i]; - } - } - - return combined; - }; - // Get combined slot sources (incoming sources + our additional sources with offset indices) nodeType.prototype.getCombinedSlotSources = function() { const combined = {}; @@ -1354,12 +1401,15 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { this.slotTypes = {}; this.slotSources = {}; + // Also track updates to incoming slot types from exposed inputs + this.incomingSlotUpdates = {}; + if (!this.inputs) return; const graph = this.graph || app.graph; - // Start from index 1 to skip the pipe input - for (let i = 1; i < this.inputs.length; i++) { + // Process exposed incoming slot inputs (indices 1 to incomingSlotCount) + for (let i = 1; i <= this.incomingSlotCount; i++) { const input = this.inputs[i]; if (input && input.link) { const link = graph.links instanceof Map ? graph.links.get(input.link) : graph.links?.[input.link]; @@ -1367,7 +1417,37 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { const sourceNode = graph.getNodeById(link.origin_id); if (sourceNode && sourceNode.outputs && sourceNode.outputs[link.origin_slot]) { const outputType = sourceNode.outputs[link.origin_slot].type; - this.slotTypes[i] = outputType; // i corresponds to slot number here + // Track that this incoming slot has an override connection + this.incomingSlotUpdates[i] = { + type: outputType, + sourceNode: sourceNode, + sourceSlot: link.origin_slot + }; + + // If this slot receives a FRIENDLY_PIPE, track its source + if (outputType === "FRIENDLY_PIPE") { + const pipeSource = findOriginalSource(sourceNode, link.origin_slot); + if (pipeSource) { + this.incomingSlotSources[i] = pipeSource; + } + } + } + } + } + } + + // Process additional slot inputs (indices incomingSlotCount+1 to end) + const additionalStartIndex = 1 + this.incomingSlotCount; + for (let i = 1; i <= this.slotCount; i++) { + const inputIndex = additionalStartIndex + (i - 1); + const input = this.inputs[inputIndex]; + if (input && input.link) { + const link = graph.links instanceof Map ? graph.links.get(input.link) : graph.links?.[input.link]; + if (link) { + const sourceNode = graph.getNodeById(link.origin_id); + if (sourceNode && sourceNode.outputs && sourceNode.outputs[link.origin_slot]) { + const outputType = sourceNode.outputs[link.origin_slot].type; + this.slotTypes[i] = outputType; // If this slot receives a FRIENDLY_PIPE, track its source if (outputType === "FRIENDLY_PIPE") { @@ -1382,6 +1462,38 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { } }; + // Get combined slot types (including overrides from exposed incoming slot connections) + nodeType.prototype.getCombinedSlotTypes = function() { + // Make sure our slot types are up to date + this.updateSlotTypes(); + + const combined = {}; + + // Copy incoming slot types from upstream pipe + if (this.incomingSlotTypes) { + for (const [key, value] of Object.entries(this.incomingSlotTypes)) { + combined[key] = value; + } + } + + // Override with types from exposed incoming slot connections + if (this.incomingSlotUpdates) { + for (const [key, update] of Object.entries(this.incomingSlotUpdates)) { + combined[key] = update.type; + } + } + + // Add our additional slot types with offset indices + for (let i = 1; i <= this.slotCount; i++) { + const newIndex = this.incomingSlotCount + i; + if (this.slotTypes[i]) { + combined[newIndex] = this.slotTypes[i]; + } + } + + return combined; + }; + // Handle serialization const origOnSerialize = nodeType.prototype.onSerialize; nodeType.prototype.onSerialize = function(o) { @@ -1391,6 +1503,8 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { o.slotCount = this.slotCount; o.slotNames = this.slotNames; o.slotTypes = this.slotTypes; + o.incomingSlotCount = this.incomingSlotCount; + o.exposedIncomingSlots = this.exposedIncomingSlots; }; // Handle deserialization @@ -1408,6 +1522,12 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { if (o.slotTypes) { this.slotTypes = o.slotTypes; } + if (o.incomingSlotCount !== undefined) { + this.incomingSlotCount = o.incomingSlotCount; + } + if (o.exposedIncomingSlots) { + this.exposedIncomingSlots = o.exposedIncomingSlots; + } if (o.slotCount !== undefined && o.slotCount > 1) { // We already have 1 slot from onNodeCreated @@ -1417,29 +1537,11 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { const name = this.slotNames[i] || ("slot_" + i); this.slotNames[i] = name; - // Add input if needed (offset by 1 for pipe input) - if (!this.inputs || this.inputs.length < i + 1) { - this.addInput("slot_" + i, "*"); - } - if (this.inputs && this.inputs[i]) { - this.inputs[i].label = name; - } - // Add name widget this.addSlotNameWidget(i); } } - // Update all input labels - if (this.inputs) { - for (let i = 1; i < this.inputs.length; i++) { - const slotNum = i; - if (this.slotNames[slotNum]) { - this.inputs[i].label = this.slotNames[slotNum]; - } - } - } - // Update name widget values if (this.widgets) { for (const widget of this.widgets) { @@ -1451,7 +1553,7 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { this.updateSize(); - // Sync with source after configure + // Sync with source after configure - this will rebuild inputs properly setTimeout(() => { this.syncWithSource(); }, 100); @@ -1473,6 +1575,10 @@ function setupFriendlyPipeEdit(nodeType, nodeData, app) { if (slotNamesWidget) { slotNamesWidget.value = JSON.stringify(this.slotNames); } + const incomingSlotCountWidget = this.widgets.find(w => w.name === "incoming_slot_count"); + if (incomingSlotCountWidget) { + incomingSlotCountWidget.value = this.incomingSlotCount; + } } }; }