import React from 'react'; import { Handle, Position } from 'reactflow'; import './OutputNode.css'; const OutputNode = ({ data, isConnectable }) => { const { connectedType, label, result } = data; // Log the props received by the component for debugging console.log(`[OutputNode: ${label}] Received data:`, data); // Function to download the output content const downloadOutput = () => { if (!result) return; let filename = `${label || 'output'}-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}`; let blob, url, content; switch (connectedType) { case 'textbox': case 'markdown': case 'json': // For text/JSON content content = typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result); blob = new Blob([content], { type: 'text/plain' }); filename = `${filename}.txt`; break; case 'image': // For image content - handle if it's a URL let imageUrl = ''; if (typeof result === 'string') { imageUrl = result; } else if (Array.isArray(result) && typeof result[0] === 'string') { imageUrl = result[0]; } else if (typeof result === 'object' && result !== null && result.url) { imageUrl = result.url; } if (imageUrl) { // For a URL, open in a new tab for direct download window.open(imageUrl, '_blank'); return; } return; // Can't download if no URL case 'audio': case 'video': case 'file': // For file content - handle if it's a URL let fileUrl = ''; if (typeof result === 'string') { fileUrl = result; } else if (Array.isArray(result) && typeof result[0] === 'string') { fileUrl = result[0]; } else if (typeof result === 'object' && result !== null && result.url) { fileUrl = result.url; } if (fileUrl) { // For a URL, open in a new tab for direct download window.open(fileUrl, '_blank'); return; } return; // Can't download if no URL default: // Default case - try to stringify any content content = typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result); blob = new Blob([content], { type: 'text/plain' }); filename = `${filename}.txt`; } // Create download link and trigger it if (blob) { url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); // Clean up setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 100); } }; const renderContent = () => { // Use a more robust check for the existence of a result. // Checks for null, undefined. Allows 0, false, and empty strings to be displayed. const hasResult = result !== null && result !== undefined; if (!hasResult) { console.log(`[OutputNode: ${label}] No result found. Rendering placeholder.`); switch (connectedType) { case 'textbox': return

Text output will appear here.

; case 'image': return

Image output will appear here.

; case 'audio': case 'video': case 'file': return

File output will appear here.

; default: return

Connect an output to see the result.

; } } console.log(`[OutputNode: ${label}] Result found. Rendering content for type: ${connectedType}`); // --- Robust Result Rendering --- let content; if (typeof result === 'object' && result !== null) { // If the result is an object or array, display it as a formatted JSON string. // This prevents React from crashing on "Objects are not valid as a React child". content =
{JSON.stringify(result, null, 2)}
; } else { // Otherwise, display the primitive value directly. content =

{String(result)}

; } switch (connectedType) { case 'textbox': case 'markdown': // Handle markdown as text for now case 'json': return
{content}
; case 'image': // Handle results that are strings, objects with a URL, or arrays containing a URL. let imageUrl = ''; if (typeof result === 'string') { imageUrl = result; } else if (Array.isArray(result) && typeof result[0] === 'string') { imageUrl = result[0]; } else if (typeof result === 'object' && result !== null && result.url) { imageUrl = result.url; } return
Generated
; case 'audio': case 'video': case 'file': // Handle results that are strings, objects with a URL, or arrays containing a URL. let fileUrl = ''; if (typeof result === 'string') { fileUrl = result; } else if (Array.isArray(result) && typeof result[0] === 'string') { fileUrl = result[0]; } else if (typeof result === 'object' && result !== null && result.url) { fileUrl = result.url; } return (

File output:

{fileUrl} {connectedType === 'audio' &&
); default: console.log(`[OutputNode: ${label}] Cannot determine how to render type '${connectedType}'. Displaying raw data.`); return
{content}
; } }; // Download button icon (simple SVG) const DownloadIcon = () => ( ); // Get the output type for the handle const getOutputDataType = () => { switch (connectedType) { case 'textbox': case 'markdown': return 'string'; case 'json': return 'object'; case 'image': return 'image'; case 'audio': return 'audio'; case 'video': return 'video'; case 'file': return 'file'; default: return 'any'; } }; return (
{label || 'Output'} {data.status && {data.status}} {data.isSource && → Source}
{renderContent()} {result !== null && result !== undefined && (
)}
); }; export default OutputNode;