diff --git a/src/areas/workflows/nodes/ExtensionNode.tsx b/src/areas/workflows/nodes/ExtensionNode.tsx index a9703290..7a7873b1 100644 --- a/src/areas/workflows/nodes/ExtensionNode.tsx +++ b/src/areas/workflows/nodes/ExtensionNode.tsx @@ -160,11 +160,8 @@ export default function ExtensionNode({ id, data, selected }: { id: string; data const { updateNodeData } = useReactFlow() const running = useWorkflowRunStore((s) => s.activeNodeId === id) - // Refs for handle alignment — support up to 2 inputs - const ioRowRef = useRef(null) - const ioRow2Ref = useRef(null) - const [handleTop, setHandleTop] = useState('50%') - const [handle2Top, setHandle2Top] = useState('50%') + const handleRefs = useRef([]) + const [handleTops, setHandleTops] = useState([]) const { modelExtensions, processExtensions } = useExtensionsStore() const allExtensions = buildAllWorkflowExtensions(modelExtensions, processExtensions) @@ -178,15 +175,14 @@ export default function ExtensionNode({ id, data, selected }: { id: string; data // Align handles with their respective IO rows after mount useLayoutEffect(() => { - if (ioRowRef.current) { - const center = ioRowRef.current.offsetTop + ioRowRef.current.offsetHeight / 2 - setHandleTop(`${center}px`) - } - if (ioRow2Ref.current) { - const center = ioRow2Ref.current.offsetTop + ioRow2Ref.current.offsetHeight / 2 - setHandle2Top(`${center}px`) - } - }, [isMulti]) + setHandleTops(handleRefs.current.map((ref) => { + if (ref) { + const center = ref.offsetTop + ref.offsetHeight / 2 + return `${center}px` + } + return '50%' + })) + }, [isMulti, inputs?.length]) const patchParam = useCallback((key: string, val: number | string) => { const params = { ...data.params, [key]: val } @@ -232,7 +228,7 @@ export default function ExtensionNode({ id, data, selected }: { id: string; data ) : ( // Single-input layout (existing behavior) -
+
{ if (el) handleRefs.current[0] = el }} className="flex items-center justify-between px-3 py-2"> {ext?.input ?? '—'} @@ -250,31 +246,40 @@ export default function ExtensionNode({ id, data, selected }: { id: string; data ) // ── Handles ────────────────────────────────────────────────────────────── - const handlesEl = ( + const handlesEl = isMulti ? ( <> - {/* Primary input handle */} - - {/* Secondary input handle (multi-input only) */} - {isMulti && ( + {inputs.map((inputType, i) => ( + ))} + {!isTerminal && ( + )} - {/* Output handle */} + + ) : ( + <> + {!isTerminal && ( )} diff --git a/src/areas/workflows/workflowRunStore.ts b/src/areas/workflows/workflowRunStore.ts index 1e687193..cb9a02fb 100644 --- a/src/areas/workflows/workflowRunStore.ts +++ b/src/areas/workflows/workflowRunStore.ts @@ -315,6 +315,9 @@ async function executeExtensionNode( const incomingEdges = workflow.edges.filter((e) => e.target === node.id) if (ext?.inputs && ext.inputs.length > 1) { + const inputTypes = ext.inputs + const inputPaths = new Array(inputTypes.length).fill(undefined) + for (const edge of incomingEdges) { const src = resolveSource(edge.source) if (!src) continue @@ -426,6 +429,15 @@ async function executeExtensionNode( const parts = (node.data.extensionId ?? '').split('/') const extId = parts[0] const nid = parts[1] ?? '' + + const processParams: Record = { ...(node.data.params as Record) } + if (nodeInputMeshPath && nodeInputPath) { + // Texture node: mesh is filePath, all images in extra_image_paths + processParams.extra_image_paths = [nodeInputPath, ...extraImagePaths] + } else if (extraImagePaths.length > 0) { + processParams.extra_image_paths = extraImagePaths + } + const result = await window.electron.extensions.runProcess( extId, {