|
@@ -1647,20 +1647,46 @@ function WorkflowEditorInner() {
|
|
|
// viewedNodes while viewing anyway, so this would never be seen then, and
|
|
// viewedNodes while viewing anyway, so this would never be seen then, and
|
|
|
// showing it for an un-kept pin would contradict the point of "kept" -
|
|
// showing it for an un-kept pin would contradict the point of "kept" -
|
|
|
// that the badge means the user asked for this data to stay pinned.
|
|
// that the badge means the user asked for this data to stay pinned.
|
|
|
|
|
+ //
|
|
|
|
|
+ // Also depends on `nodes` itself, unlike a first version of this effect did
|
|
|
|
|
+ // not: reloading the workflow (e.g. the refetch after an autosave) replaces
|
|
|
|
|
+ // `nodes` wholesale with freshly-built, unenriched node objects that carry
|
|
|
|
|
+ // none of this - so without watching `nodes`, a badge already showing could
|
|
|
|
|
+ // silently vanish on the next autosave with nothing to put it back. Depending
|
|
|
|
|
+ // on `nodes` here is only safe because of the "touched" guard below, the
|
|
|
|
|
+ // same pattern the presence/lock effect above uses: `setNodes` is called
|
|
|
|
|
+ // with the *same* array reference when nothing actually differs, so this
|
|
|
|
|
+ // does not feed back into itself the way an earlier version (fixed
|
|
|
|
|
+ // separately) of the pinned-diff recompute did.
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- setNodes((nds) =>
|
|
|
|
|
- nds.map((n) => ({
|
|
|
|
|
- ...n,
|
|
|
|
|
- data: {
|
|
|
|
|
- ...n.data,
|
|
|
|
|
- executionState: effectiveExecutionState.nodeStates[n.id],
|
|
|
|
|
- onExecute: () => executeWorkflow(),
|
|
|
|
|
- onExecuteTrigger: executeTrigger,
|
|
|
|
|
- pinnedStatus: isPinKept ? nodeChangeStatus[n.id] : undefined,
|
|
|
|
|
- hasPinnedData: isPinKept && pinnedNodeData[n.id] !== undefined,
|
|
|
|
|
- },
|
|
|
|
|
- }))
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ setNodes((nds) => {
|
|
|
|
|
+ let touched = false
|
|
|
|
|
+ const next = nds.map((n) => {
|
|
|
|
|
+ const executionState = effectiveExecutionState.nodeStates[n.id]
|
|
|
|
|
+ const pinnedStatus = isPinKept ? nodeChangeStatus[n.id] : undefined
|
|
|
|
|
+ const hasPinnedData = isPinKept && pinnedNodeData[n.id] !== undefined
|
|
|
|
|
+ if (
|
|
|
|
|
+ n.data.executionState === executionState &&
|
|
|
|
|
+ n.data.pinnedStatus === pinnedStatus &&
|
|
|
|
|
+ n.data.hasPinnedData === hasPinnedData
|
|
|
|
|
+ ) {
|
|
|
|
|
+ return n
|
|
|
|
|
+ }
|
|
|
|
|
+ touched = true
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...n,
|
|
|
|
|
+ data: {
|
|
|
|
|
+ ...n.data,
|
|
|
|
|
+ executionState,
|
|
|
|
|
+ onExecute: () => executeWorkflow(),
|
|
|
|
|
+ onExecuteTrigger: executeTrigger,
|
|
|
|
|
+ pinnedStatus,
|
|
|
|
|
+ hasPinnedData,
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ return touched ? next : nds
|
|
|
|
|
+ })
|
|
|
|
|
|
|
|
// Animation only for live execution (not when viewing)
|
|
// Animation only for live execution (not when viewing)
|
|
|
setEdges((eds) =>
|
|
setEdges((eds) =>
|
|
@@ -1669,7 +1695,7 @@ function WorkflowEditorInner() {
|
|
|
animated: executionState.status === 'running',
|
|
animated: executionState.status === 'running',
|
|
|
}))
|
|
}))
|
|
|
)
|
|
)
|
|
|
- }, [effectiveExecutionState.nodeStates, executionState.status, setNodes, setEdges, executeWorkflow, isPinKept, nodeChangeStatus, pinnedNodeData])
|
|
|
|
|
|
|
+ }, [effectiveExecutionState.nodeStates, executionState.status, setNodes, setEdges, executeWorkflow, executeTrigger, isPinKept, nodeChangeStatus, pinnedNodeData, nodes])
|
|
|
|
|
|
|
|
// Update node selection visual
|
|
// Update node selection visual
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|