From ea13c7d913a6f746f1f6d69af4757d3bf51dbc73 Mon Sep 17 00:00:00 2001 From: shrimbly Date: Tue, 27 Jan 2026 20:08:56 +1300 Subject: [PATCH] feat(32-02): add Build Workflow button to ChatPanel Add "Build Workflow" button that appears after conversation starts. Button extracts user messages to form a description and passes to parent via callback. Includes loading state support via isBuildingWorkflow prop. Co-Authored-By: Claude Opus 4.5 --- src/components/ChatPanel.tsx | 114 +++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/src/components/ChatPanel.tsx b/src/components/ChatPanel.tsx index 8b34d007..f981837d 100644 --- a/src/components/ChatPanel.tsx +++ b/src/components/ChatPanel.tsx @@ -7,9 +7,11 @@ import { DefaultChatTransport } from "ai"; interface ChatPanelProps { isOpen: boolean; onClose: () => void; + onBuildWorkflow?: (description: string) => Promise; + isBuildingWorkflow?: boolean; } -export function ChatPanel({ isOpen, onClose }: ChatPanelProps) { +export function ChatPanel({ isOpen, onClose, onBuildWorkflow, isBuildingWorkflow = false }: ChatPanelProps) { const messagesEndRef = useRef(null); const [input, setInput] = useState(""); @@ -19,6 +21,34 @@ export function ChatPanel({ isOpen, onClose }: ChatPanelProps) { const isLoading = status === "streaming" || status === "submitted"; + // Extract conversation description from user messages + const getConversationDescription = () => { + const userMessages = messages + .filter((m) => m.role === "user") + .map((m) => { + const textContent = m.parts + ?.filter((part): part is { type: "text"; text: string } => part.type === "text") + .map((part) => part.text) + .join("") || ""; + return textContent; + }) + .filter((text) => text.trim().length > 0); + + return userMessages.join("\n"); + }; + + const handleBuildWorkflow = async () => { + if (!onBuildWorkflow) return; + + const description = getConversationDescription(); + if (!description.trim()) return; + + await onBuildWorkflow(description); + }; + + // Check if conversation has started (has assistant messages) + const hasConversation = messages.some((m) => m.role === "assistant"); + // Auto-scroll to bottom on new messages useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); @@ -97,36 +127,58 @@ export function ChatPanel({ isOpen, onClose }: ChatPanelProps) { {/* Input area */} -
{ - e.preventDefault(); - if (input.trim() && !isLoading) { - sendMessage({ text: input }); - setInput(""); - } - }} - className="p-3 border-t border-neutral-700" - > -
- setInput(e.target.value)} - placeholder="Type a message..." - className="flex-1 bg-neutral-700 border border-neutral-600 rounded-lg px-3 py-2 text-sm text-neutral-200 placeholder-neutral-500 focus:outline-none focus:border-blue-500" - disabled={isLoading} - /> - -
-
+
+
{ + e.preventDefault(); + if (input.trim() && !isLoading) { + sendMessage({ text: input }); + setInput(""); + } + }} + className="p-3" + > +
+ setInput(e.target.value)} + placeholder="Type a message..." + className="flex-1 bg-neutral-700 border border-neutral-600 rounded-lg px-3 py-2 text-sm text-neutral-200 placeholder-neutral-500 focus:outline-none focus:border-blue-500" + disabled={isLoading} + /> + +
+
+ + {/* Build Workflow button */} + {hasConversation && onBuildWorkflow && ( +
+ +
+ )} +
); }