import { Button, Input, Textarea, Chip, Select, SelectItem, Checkbox } from "@heroui/react"; import { useEffect, useRef, useState } from "react"; import { useClickAway } from "../../../hooks/use-click-away"; import MarkdownContent from "./markdown-content"; import clsx from "clsx"; import { Label } from "./label"; import dynamic from "next/dynamic"; import { Match } from "./mentions_editor"; import { SparklesIcon, Edit3Icon, XIcon, CheckIcon } from "lucide-react"; import { EntitySelectionContext } from "../../projects/[projectId]/workflow/workflow_editor"; import { useContext } from "react"; const MentionsEditor = dynamic(() => import('./mentions_editor'), { ssr: false }); // Base InputField interface interface BaseInputFieldProps { value: string; onChange: (value: string) => void; label?: string; placeholder?: string; className?: string; validate?: (value: string) => { valid: boolean; errorMessage?: string }; error?: string | null; disabled?: boolean; locked?: boolean; inline?: boolean; showGenerateButton?: { show: boolean; setShow: (show: boolean) => void; }; onMentionNavigate?: (type: 'agent' | 'tool' | 'prompt', name: string) => void; } // Text input specific props interface TextInputFieldProps extends BaseInputFieldProps { type: 'text'; multiline?: boolean; markdown?: boolean; mentions?: boolean; mentionsAtValues?: Match[]; showSaveButton?: boolean; showDiscardButton?: boolean; immediateSave?: boolean; minHeight?: string; } // Select input specific props interface SelectInputFieldProps extends BaseInputFieldProps { type: 'select'; options: { key: string; label: string; disabled?: boolean }[]; selectedKeys?: Set; onSelectionChange: (keys: any) => void; } // Checkbox input specific props interface CheckboxInputFieldProps extends BaseInputFieldProps { type: 'checkbox'; isSelected?: boolean; onValueChange?: (value: boolean) => void; } // Number input specific props interface NumberInputFieldProps extends BaseInputFieldProps { type: 'number'; min?: number; max?: number; step?: number; immediateSave?: boolean; } // Union type for all input field types type InputFieldProps = TextInputFieldProps | SelectInputFieldProps | CheckboxInputFieldProps | NumberInputFieldProps; export function InputField(props: InputFieldProps) { // Handle different input types if (props.type === 'select') { return ; } if (props.type === 'checkbox') { return ; } if (props.type === 'number') { return ; } // Default to text input return ; } // Text Input Field Component function TextInputField({ value, onChange, label, placeholder = "Click to edit...", className = "flex flex-col gap-1 w-full", validate, error, disabled = false, locked = false, inline = false, showGenerateButton, onMentionNavigate, multiline = false, markdown = false, mentions = false, mentionsAtValues = [], showSaveButton = false, showDiscardButton = false, immediateSave = false, minHeight, }: TextInputFieldProps) { const [isEditing, setIsEditing] = useState(false); const [localValue, setLocalValue] = useState(value); const ref = useRef(null); // Use the context directly, will be undefined if not in provider const entitySelection = useContext(EntitySelectionContext); const validationResult = validate?.(localValue); const isValid = !validate || validationResult?.valid; useEffect(() => { setLocalValue(value); }, [value]); useClickAway(ref, () => { if (isEditing) { if (immediateSave) { if (isValid && localValue !== value) { onChange(localValue); } } else { if (isValid && localValue !== value) { onChange(localValue); } else { setLocalValue(value); } } } setIsEditing(false); }); const handleMentionNavigate = onMentionNavigate || ((type, name) => { if (entitySelection) { if (type === 'agent') entitySelection.onSelectAgent(name); else if (type === 'tool') entitySelection.onSelectTool(name); else if (type === 'prompt') entitySelection.onSelectPrompt(name); } }); const handleSave = () => { if (isValid && localValue !== value) { onChange(localValue); } setIsEditing(false); }; const handleDiscard = () => { setLocalValue(value); setIsEditing(false); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (!multiline && e.key === "Enter") { e.preventDefault(); if (immediateSave) { if (isValid && localValue !== value) { onChange(localValue); } } else { handleSave(); } } if (e.key === "Escape") { handleDiscard(); } }; const onValueChange = (newValue: string) => { setLocalValue(newValue); if (immediateSave) { onChange(newValue); } }; // Determine input size based on content length and multiline const getInputSize = () => { if (multiline) { if (localValue.length > 1000) return "lg"; if (localValue.length > 500) return "md"; return "sm"; } return "sm"; }; // Determine if we should show action buttons const hasChanges = localValue !== value; const showActions = hasChanges && (showSaveButton || showDiscardButton); if (isEditing) { return (
{/* Header with label and action buttons */} {(label || showGenerateButton || showActions) && (
{label &&
)} {/* Input field */} {mentions ? (
) : multiline ? (