Browse Source

Merge pull request #80 from shrimbly/fix/output-node-auto-load

fix: output node now auto-loads data when connected and adds Run button
handoff-20260429-1057
Willie 5 months ago
committed by GitHub
parent
commit
56d5164379
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      src/components/__tests__/OutputNode.test.tsx
  2. 28
      src/components/nodes/OutputNode.tsx
  3. 5
      src/store/workflowStore.ts

3
src/components/__tests__/OutputNode.test.tsx

@ -39,6 +39,9 @@ describe("OutputNode", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
const state = {
updateNodeData: mockUpdateNodeData,
regenerateNode: vi.fn(),
edges: [],
isRunning: false,
currentNodeIds: [],
groups: {},
nodes: [],

28
src/components/nodes/OutputNode.tsx

@ -1,6 +1,6 @@
"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 { BaseNode } from "./BaseNode";
import { useCommentNavigation } from "@/hooks/useCommentNavigation";
@ -14,7 +14,13 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
const nodeData = data;
const commentNavigation = useCommentNavigation(id);
const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
const regenerateNode = useWorkflowStore((state) => state.regenerateNode);
const connectedEdgeCount = useWorkflowStore(
(state) => state.edges.filter((edge) => edge.target === id).length
);
const isRunning = useWorkflowStore((state) => state.isRunning);
const [showLightbox, setShowLightbox] = useState(false);
const previousEdgeCountRef = useRef<number | null>(null);
// Determine if content is audio
const isAudio = useMemo(() => {
@ -43,6 +49,24 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
const videoBlobUrl = useVideoBlobUrl(isVideo ? contentSrc ?? null : null);
// Auto-trigger execution when a new connection is made
useEffect(() => {
if (previousEdgeCountRef.current === null) {
// First run — just record the baseline, don't trigger
previousEdgeCountRef.current = connectedEdgeCount;
return;
}
if (connectedEdgeCount > previousEdgeCountRef.current) {
regenerateNode(id);
}
previousEdgeCountRef.current = connectedEdgeCount;
}, [connectedEdgeCount, id, regenerateNode]);
// Handle Run button click
const handleRun = useCallback(() => {
regenerateNode(id);
}, [id, regenerateNode]);
const handleDownload = useCallback(async () => {
if (!contentSrc) return;
@ -91,6 +115,8 @@ export function OutputNode({ id, data, selected }: NodeProps<OutputNodeType>) {
comment={nodeData.comment}
onCustomTitleChange={(title) => updateNodeData(id, { customTitle: title || undefined })}
onCommentChange={(comment) => updateNodeData(id, { comment: comment || undefined })}
onRun={handleRun}
isExecuting={isRunning}
selected={selected}
className="min-w-[200px]"
commentNavigation={commentNavigation ?? undefined}

5
src/store/workflowStore.ts

@ -1168,6 +1168,11 @@ const workflowStoreImpl: StateCreator<WorkflowStore> = (set, get) => ({
set({ isRunning: false, currentNodeIds: [] });
await logger.endSession();
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

Loading…
Cancel
Save