diff --git a/src/components/__tests__/PromptNode.test.tsx b/src/components/__tests__/PromptNode.test.tsx index b556f7d0..f00b3771 100644 --- a/src/components/__tests__/PromptNode.test.tsx +++ b/src/components/__tests__/PromptNode.test.tsx @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -import { render, screen, fireEvent } from "@testing-library/react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { PromptNode } from "@/components/nodes/PromptNode"; import { ReactFlowProvider } from "@xyflow/react"; @@ -108,6 +108,19 @@ describe("PromptNode", () => { expect(text).toHaveClass("break-words"); }); + it("should keep the selected preview surface draggable while not editing", () => { + render( + + + + ); + + const preview = screen.getByRole("button", { name: "Double-click to edit" }); + expect(preview).toHaveClass("cursor-move"); + expect(preview).not.toHaveClass("nodrag"); + expect(preview).not.toHaveClass("nopan"); + }); + it("should call updateNodeData when typing in textarea and blurring", () => { render( @@ -177,6 +190,26 @@ describe("PromptNode", () => { }); }); + it("should import a markdown file into the prompt node", async () => { + render( + + + + ); + + const input = screen.getByLabelText("Upload text document") as HTMLInputElement; + const file = new File(["# Uploaded\n\n- item"], "brief.md", { type: "text/markdown" }); + fireEvent.change(input, { target: { files: [file] } }); + + await waitFor(() => { + expect(mockUpdateNodeData).toHaveBeenCalledWith("test-prompt-1", { + prompt: "# Uploaded\n\n- item", + documentName: "brief.md", + documentFormat: "markdown", + }); + }); + }); + it("should hide unavailable rich text actions while editing", () => { render( diff --git a/src/components/nodes/PromptNode.tsx b/src/components/nodes/PromptNode.tsx index fc5620e6..3bdb7cdf 100644 --- a/src/components/nodes/PromptNode.tsx +++ b/src/components/nodes/PromptNode.tsx @@ -8,10 +8,12 @@ import { useWorkflowStore } from "@/store/workflowStore"; import { PromptNodeData } from "@/types"; import { useI18n } from "@/i18n"; import { MarkdownEditorModal } from "@/components/modals/MarkdownEditorModal"; +import { readTextDocumentFile } from "@/utils/textDocumentImport"; type PromptNodeType = Node; function getPromptNodeTitle(id: string, data: PromptNodeData, textLabel: string) { + if (data.documentName) return data.documentName; if (data.customTitle) return data.customTitle; if (data.label) return data.label; const match = id.match(/(\d+)$/); @@ -54,6 +56,41 @@ function ExpandIcon() { ); } +function UploadIcon() { + return ( + + + + ); +} + +function renderDocumentPreview(text: string) { + return text.split("\n").map((line, index) => { + const trimmed = line.trim(); + if (!trimmed) return + + {selected && !isEditing && (
+