import { BaseEdge, type Edge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath, useReactFlow } from '@xyflow/react'; import { AlertCircle, Pencil } from 'lucide-react'; import { useCallback, useEffect, useState } from 'react'; import { useWorkflow, useWorkflowOptional } from "@/app/workflow/[workflowId]/contexts/WorkflowContext"; import { useWorkflowStore } from "@/app/workflow/[workflowId]/stores/workflowStore"; import { TextOrAudioInput } from "@/components/flow/TextOrAudioInput"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from '@/components/ui/textarea'; import { cn } from "@/lib/utils"; import { FlowEdge, FlowEdgeData, FlowNode } from '../types'; type CustomEdge = Edge<{ value: number }, 'custom'>; interface EdgeDetailsDialogProps { open: boolean; onOpenChange: (open: boolean) => void; data?: FlowEdgeData; onSave: (value: FlowEdgeData) => void; } const EdgeDetailsDialog = ({ open, onOpenChange, data, onSave }: EdgeDetailsDialogProps) => { const readOnly = useWorkflowOptional()?.readOnly ?? false; const { recordings } = useWorkflow(); const [condition, setCondition] = useState(data?.condition ?? ''); const [label, setLabel] = useState(data?.label ?? ''); const [transitionSpeech, setTransitionSpeech] = useState(data?.transition_speech ?? ''); const [transitionSpeechType, setTransitionSpeechType] = useState<'text' | 'audio'>(data?.transition_speech_type ?? 'text'); const [transitionSpeechRecordingId, setTransitionSpeechRecordingId] = useState(data?.transition_speech_recording_id ?? ''); // Update form state when data changes (e.g., from undo/redo) useEffect(() => { if (open) { setCondition(data?.condition ?? ''); setLabel(data?.label ?? ''); setTransitionSpeech(data?.transition_speech ?? ''); setTransitionSpeechType(data?.transition_speech_type ?? 'text'); setTransitionSpeechRecordingId(data?.transition_speech_recording_id ?? ''); } }, [data, open]); const handleSave = useCallback(() => { onSave({ condition, label, transition_speech: transitionSpeechType === 'text' ? (transitionSpeech || undefined) : undefined, transition_speech_type: transitionSpeechType, transition_speech_recording_id: transitionSpeechType === 'audio' ? (transitionSpeechRecordingId || undefined) : undefined, }); onOpenChange(false); }, [condition, label, transitionSpeech, transitionSpeechType, transitionSpeechRecordingId, onSave, onOpenChange]); // Handle Cmd+S / Ctrl+S keyboard shortcut to save useEffect(() => { if (!open || readOnly) return; const handleKeyDown = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === 's') { e.preventDefault(); e.stopImmediatePropagation(); handleSave(); } }; window.addEventListener('keydown', handleKeyDown, true); return () => window.removeEventListener('keydown', handleKeyDown, true); }, [open, readOnly, handleSave]); return ( Edit Condition {data?.invalid && data.validationMessage && (
{data.validationMessage}
)}
setLabel(e.target.value)} />
{label.length}/64 characters