Browse Source

fix: output node now auto-loads data when connected and adds Run button

- Output Node now automatically triggers execution when a new connection is made
- Added Run button to Output Node header for manual triggering
- Updated regenerateNode to support output node type
- Prevents re-triggering on initial mount or disconnections using edge count tracking

Resolves issue where Output Node would not display data from already-generated upstream nodes unless connected before generation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
handoff-20260429-1057
Shrimbly 5 months ago
committed by shrimbly
parent
commit
5a6c8ee44e
  1. 31
      src/components/nodes/OutputNode.tsx
  2. 5
      src/store/workflowStore.ts

31
src/components/nodes/OutputNode.tsx

@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useState, useMemo } from "react"; import { useCallback, useState, useMemo, useEffect, useRef } from "react";
import { Handle, Position, NodeProps, Node } from "@xyflow/react"; import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { BaseNode } from "./BaseNode"; import { BaseNode } from "./BaseNode";
import { useCommentNavigation } from "@/hooks/useCommentNavigation"; import { useCommentNavigation } from "@/hooks/useCommentNavigation";
@ -14,7 +14,10 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
const nodeData = data; const nodeData = data;
const commentNavigation = useCommentNavigation(id); const commentNavigation = useCommentNavigation(id);
const updateNodeData = useWorkflowStore((state) => state.updateNodeData); const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
const regenerateNode = useWorkflowStore((state) => state.regenerateNode);
const edges = useWorkflowStore((state) => state.edges);
const [showLightbox, setShowLightbox] = useState(false); const [showLightbox, setShowLightbox] = useState(false);
const previousEdgeCountRef = useRef<number>(0);
// Determine if content is audio // Determine if content is audio
const isAudio = useMemo(() => { const isAudio = useMemo(() => {
@ -43,6 +46,31 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
const videoBlobUrl = useVideoBlobUrl(isVideo ? contentSrc ?? null : null); const videoBlobUrl = useVideoBlobUrl(isVideo ? contentSrc ?? null : null);
// Initialize edge count ref on mount
useEffect(() => {
const connectedEdges = edges.filter((edge) => edge.target === id);
previousEdgeCountRef.current = connectedEdges.length;
}, []); // eslint-disable-line react-hooks/exhaustive-deps
// Auto-trigger execution when connected
useEffect(() => {
const connectedEdges = edges.filter((edge) => edge.target === id);
const currentEdgeCount = connectedEdges.length;
// Only trigger if we gained a new connection (not on initial mount or disconnect)
if (currentEdgeCount > previousEdgeCountRef.current) {
// Auto-run when a new connection is made
regenerateNode(id);
}
previousEdgeCountRef.current = currentEdgeCount;
}, [edges, id, regenerateNode]);
// Handle Run button click
const handleRun = useCallback(() => {
regenerateNode(id);
}, [id, regenerateNode]);
const handleDownload = useCallback(async () => { const handleDownload = useCallback(async () => {
if (!contentSrc) return; if (!contentSrc) return;
@ -91,6 +119,7 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
comment={nodeData.comment} comment={nodeData.comment}
onCustomTitleChange={(title) => updateNodeData(id, { customTitle: title || undefined })} onCustomTitleChange={(title) => updateNodeData(id, { customTitle: title || undefined })}
onCommentChange={(comment) => updateNodeData(id, { comment: comment || undefined })} onCommentChange={(comment) => updateNodeData(id, { comment: comment || undefined })}
onRun={handleRun}
selected={selected} selected={selected}
className="min-w-[200px]" className="min-w-[200px]"
commentNavigation={commentNavigation ?? undefined} commentNavigation={commentNavigation ?? undefined}

5
src/store/workflowStore.ts

@ -1167,6 +1167,11 @@ export const useWorkflowStore = create<WorkflowStore>((set, get) => ({
set({ isRunning: false, currentNodeIds: [] }); set({ isRunning: false, currentNodeIds: [] });
await logger.endSession(); await logger.endSession();
return; return;
} else if (node.type === "output") {
await executeOutput(executionCtx);
set({ isRunning: false, currentNodeIds: [] });
await logger.endSession();
return;
} }
// After regeneration, execute directly connected downstream consumer nodes // After regeneration, execute directly connected downstream consumer nodes

Loading…
Cancel
Save