|
@@ -36,7 +36,7 @@ import { useExecutionPinStore } from '../stores/executionPinStore'
|
|
|
import type { ExecutionDetail, WorkflowNode as WorkflowNodeType, Connection as WorkflowConnection } from '../api/workflows'
|
|
import type { ExecutionDetail, WorkflowNode as WorkflowNodeType, Connection as WorkflowConnection } from '../api/workflows'
|
|
|
|
|
|
|
|
// Import extracted components
|
|
// Import extracted components
|
|
|
-import { WorkflowNode, NodeExecutionState, IterationResult } from '../components/workflow/WorkflowNode'
|
|
|
|
|
|
|
+import { WorkflowNode, NodeExecutionState, IterationResult, resolveOutputs } from '../components/workflow/WorkflowNode'
|
|
|
import { ExecutionResultsPanel } from '../components/workflow/ExecutionResultsPanel'
|
|
import { ExecutionResultsPanel } from '../components/workflow/ExecutionResultsPanel'
|
|
|
import { NodePickerSidebar } from '../components/workflow/NodePickerSidebar'
|
|
import { NodePickerSidebar } from '../components/workflow/NodePickerSidebar'
|
|
|
import { DeleteConfirmModal } from '../components/workflow/DeleteConfirmModal'
|
|
import { DeleteConfirmModal } from '../components/workflow/DeleteConfirmModal'
|
|
@@ -908,6 +908,8 @@ function WorkflowEditorInner() {
|
|
|
isTrigger: nodeDef?.isTrigger || false,
|
|
isTrigger: nodeDef?.isTrigger || false,
|
|
|
icon: nodeDef?.icon,
|
|
icon: nodeDef?.icon,
|
|
|
outputs,
|
|
outputs,
|
|
|
|
|
+ dynamicOutputs: nodeDef?.dynamicOutputs,
|
|
|
|
|
+ inputs: nodeDef?.inputs,
|
|
|
nodeId: n.id,
|
|
nodeId: n.id,
|
|
|
onExecute: () => {}, // No-op in view mode
|
|
onExecute: () => {}, // No-op in view mode
|
|
|
onExecuteTrigger: () => {}, // No-op in view mode
|
|
onExecuteTrigger: () => {}, // No-op in view mode
|
|
@@ -981,6 +983,8 @@ function WorkflowEditorInner() {
|
|
|
isTrigger: nodeDef?.isTrigger || false,
|
|
isTrigger: nodeDef?.isTrigger || false,
|
|
|
icon: nodeDef?.icon,
|
|
icon: nodeDef?.icon,
|
|
|
outputs,
|
|
outputs,
|
|
|
|
|
+ dynamicOutputs: nodeDef?.dynamicOutputs,
|
|
|
|
|
+ inputs: nodeDef?.inputs,
|
|
|
nodeId: node.id,
|
|
nodeId: node.id,
|
|
|
disabled: node.disabled === true,
|
|
disabled: node.disabled === true,
|
|
|
onExecute: () => executeWorkflow(),
|
|
onExecute: () => executeWorkflow(),
|
|
@@ -1320,6 +1324,8 @@ function WorkflowEditorInner() {
|
|
|
isTrigger: nodeDef.isTrigger,
|
|
isTrigger: nodeDef.isTrigger,
|
|
|
icon: nodeDef.icon,
|
|
icon: nodeDef.icon,
|
|
|
outputs,
|
|
outputs,
|
|
|
|
|
+ dynamicOutputs: nodeDef.dynamicOutputs,
|
|
|
|
|
+ inputs: nodeDef.inputs,
|
|
|
nodeId,
|
|
nodeId,
|
|
|
onExecute: () => executeWorkflow(),
|
|
onExecute: () => executeWorkflow(),
|
|
|
onExecuteTrigger: executeTrigger,
|
|
onExecuteTrigger: executeTrigger,
|
|
@@ -1624,16 +1630,28 @@ function WorkflowEditorInner() {
|
|
|
}
|
|
}
|
|
|
}, [nodes, edges, setNodes])
|
|
}, [nodes, edges, setNodes])
|
|
|
|
|
|
|
|
- // Save node config
|
|
|
|
|
|
|
+ // Save node config. A node whose ports come from its config can lose one when
|
|
|
|
|
+ // a rule is deleted, so any edge left hanging off a vanished port goes too.
|
|
|
const saveNodeConfig = () => {
|
|
const saveNodeConfig = () => {
|
|
|
if (!selectedNodeData) return
|
|
if (!selectedNodeData) return
|
|
|
|
|
+ const nodeId = selectedNodeData.id
|
|
|
|
|
+ const nodeDef = nodeDefsMap[selectedNodeData.type]
|
|
|
|
|
+
|
|
|
setNodes((nds) =>
|
|
setNodes((nds) =>
|
|
|
nds.map((n) =>
|
|
nds.map((n) =>
|
|
|
- n.id === selectedNodeData.id
|
|
|
|
|
- ? { ...n, data: { ...n.data, config: editingConfig } }
|
|
|
|
|
- : n
|
|
|
|
|
|
|
+ n.id === nodeId ? { ...n, data: { ...n.data, config: editingConfig } } : n
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
|
|
|
+
|
|
|
|
|
+ if (nodeDef?.dynamicOutputs) {
|
|
|
|
|
+ const surviving = new Set(
|
|
|
|
|
+ resolveOutputs(nodeDef.outputs, nodeDef.dynamicOutputs, editingConfig).map((o) => o.name)
|
|
|
|
|
+ )
|
|
|
|
|
+ setEdges((eds) =>
|
|
|
|
|
+ eds.filter((e) => e.source !== nodeId || !e.sourceHandle || surviving.has(e.sourceHandle))
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
setHasChanges(true)
|
|
setHasChanges(true)
|
|
|
setShowNodeConfig(false)
|
|
setShowNodeConfig(false)
|
|
|
setSelectedNodeData(null)
|
|
setSelectedNodeData(null)
|