fileInputRef.current?.click()}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.preventDefault();
+ fileInputRef.current?.click();
+ }
+ }}
onDrop={handleDrop}
onDragOver={handleDragOver}
className="w-full h-full bg-neutral-900/40 flex flex-col items-center justify-center cursor-pointer hover:bg-neutral-900/60 transition-colors"
diff --git a/src/components/nodes/LLMGenerateNode.tsx b/src/components/nodes/LLMGenerateNode.tsx
index 23ef353d..a82d0db7 100644
--- a/src/components/nodes/LLMGenerateNode.tsx
+++ b/src/components/nodes/LLMGenerateNode.tsx
@@ -253,6 +253,9 @@ export function LLMGenerateNode({ id, data, selected }: NodeProps
Generation failed
+ {nodeData.error && (
+ {nodeData.error}
+ )}
) : nodeData.outputText ? (
diff --git a/src/components/nodes/PromptConstructorNode.tsx b/src/components/nodes/PromptConstructorNode.tsx
index 8b8dd34e..0c11737c 100644
--- a/src/components/nodes/PromptConstructorNode.tsx
+++ b/src/components/nodes/PromptConstructorNode.tsx
@@ -1,13 +1,11 @@
"use client";
import { useCallback, useState, useEffect, useMemo, useRef } from "react";
-import { createPortal } from "react-dom";
import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { BaseNode } from "./BaseNode";
import { usePromptAutocomplete } from "@/hooks/usePromptAutocomplete";
import { useWorkflowStore } from "@/store/workflowStore";
import { PromptConstructorNodeData, PromptNodeData, LLMGenerateNodeData, AvailableVariable } from "@/types";
-import { PromptConstructorEditorModal } from "@/components/modals/PromptConstructorEditorModal";
import { parseVarTags } from "@/utils/parseVarTags";
type PromptConstructorNodeType = Node
;
@@ -17,13 +15,10 @@ export function PromptConstructorNode({ id, data, selected }: NodeProps state.updateNodeData);
const edges = useWorkflowStore((state) => state.edges);
const nodes = useWorkflowStore((state) => state.nodes);
- const incrementModalCount = useWorkflowStore((state) => state.incrementModalCount);
- const decrementModalCount = useWorkflowStore((state) => state.decrementModalCount);
// Local state for template to prevent cursor jumping
const [localTemplate, setLocalTemplate] = useState(nodeData.template);
const [isEditing, setIsEditing] = useState(false);
- const [isModalOpenLocal, setIsModalOpenLocal] = useState(false);
const textareaRef = useRef(null);
@@ -158,23 +153,6 @@ export function PromptConstructorNode({ id, data, selected }: NodeProps closeAutocomplete(), 200);
}, [id, localTemplate, nodeData.template, updateNodeData, closeAutocomplete]);
- const handleOpenModal = useCallback(() => {
- setIsModalOpenLocal(true);
- incrementModalCount();
- }, [incrementModalCount]);
-
- const handleCloseModal = useCallback(() => {
- setIsModalOpenLocal(false);
- decrementModalCount();
- }, [decrementModalCount]);
-
- const handleSubmitModal = useCallback(
- (template: string) => {
- updateNodeData(id, { template });
- },
- [id, updateNodeData]
- );
-
return (
<>
-
- {/* Prompt Constructor Editor Modal - rendered via portal to escape React Flow stacking context */}
- {isModalOpenLocal && createPortal(
- ,
- document.body
- )}
>
);
}
diff --git a/src/components/nodes/PromptNode.tsx b/src/components/nodes/PromptNode.tsx
index 44ab34eb..7e63caf0 100644
--- a/src/components/nodes/PromptNode.tsx
+++ b/src/components/nodes/PromptNode.tsx
@@ -6,18 +6,14 @@ import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { BaseNode } from "./BaseNode";
import { useWorkflowStore } from "@/store/workflowStore";
import { PromptNodeData } from "@/types";
-import { PromptEditorModal } from "@/components/modals/PromptEditorModal";
type PromptNodeType = Node;
export function PromptNode({ id, data, selected }: NodeProps) {
const nodeData = data;
const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
- const incrementModalCount = useWorkflowStore((state) => state.incrementModalCount);
- const decrementModalCount = useWorkflowStore((state) => state.decrementModalCount);
const getConnectedInputs = useWorkflowStore((state) => state.getConnectedInputs);
const edges = useWorkflowStore((state) => state.edges);
- const [isModalOpenLocal, setIsModalOpenLocal] = useState(false);
// Local state for prompt to prevent cursor jumping during typing
const [localPrompt, setLocalPrompt] = useState(nodeData.prompt);
@@ -75,23 +71,6 @@ export function PromptNode({ id, data, selected }: NodeProps) {
}
}, [id, localPrompt, nodeData.prompt, updateNodeData]);
- const handleOpenModal = useCallback(() => {
- setIsModalOpenLocal(true);
- incrementModalCount();
- }, [incrementModalCount]);
-
- const handleCloseModal = useCallback(() => {
- setIsModalOpenLocal(false);
- decrementModalCount();
- }, [decrementModalCount]);
-
- const handleSubmitModal = useCallback(
- (prompt: string) => {
- updateNodeData(id, { prompt });
- },
- [id, updateNodeData]
- );
-
const handleSaveVariableName = useCallback(() => {
updateNodeData(id, { variableName: varNameInput || undefined });
setShowVarDialog(false);
@@ -133,11 +112,13 @@ export function PromptNode({ id, data, selected }: NodeProps) {
placeholder={hasIncomingTextConnection ? "Text from connected node (editable)..." : "Describe what to generate..."}
className="nodrag nopan nowheel w-full h-full p-3 text-xs leading-relaxed text-neutral-100 bg-neutral-800 rounded-lg resize-none focus:outline-none placeholder:text-neutral-500"
/>
- {nodeData.variableName && (
-
- @{nodeData.variableName}
-
- )}
+
{/* Text output handle */}
) {
/>
- {/* Prompt Editor Modal - rendered via portal to escape React Flow stacking context */}
- {isModalOpenLocal && createPortal(
- ,
- document.body
- )}
-
{/* Variable Naming Dialog - rendered via portal */}
{showVarDialog && createPortal(
diff --git a/src/components/nodes/SplitGridNode.tsx b/src/components/nodes/SplitGridNode.tsx
index 3f7070e3..a98355ce 100644
--- a/src/components/nodes/SplitGridNode.tsx
+++ b/src/components/nodes/SplitGridNode.tsx
@@ -148,9 +148,9 @@ export function SplitGridNode({ id, data, selected }: NodeProps
Split