diff --git a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx index 3fb2aa861..dc53dd505 100644 --- a/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx +++ b/app/(admin)/settings/agent-workflow/agent-workflow-settings-client.tsx @@ -113,6 +113,14 @@ import { Switch } from "@/components/ui/switch"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; import { Separator } from "@/components/ui/separator"; import { SearchableSelect } from "@/components/ui/searchable-select"; import { cn } from "@/lib/utils"; @@ -160,6 +168,7 @@ const WORKFLOW_STEP_DRAG_DATA_TYPE = "application/x-agent-workflow-step"; const WORKFLOW_SETTINGS_DRAFT_STORAGE_KEY = "agent-workflow-settings-draft:v1"; const WORKFLOW_SETTINGS_STALE_DRAFT_STORAGE_KEY = "agent-workflow-settings-stale-draft:v1"; const WORKFLOW_SETTINGS_DRAFT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; +const DELETE_WORKFLOW_STEP_PASSWORD = "123456"; type WorkflowStepDropPosition = "before" | "after" | "inside"; @@ -258,15 +267,26 @@ function scheduleWorkflowIdleTask(callback: () => void, timeoutMs = 2000) { function BufferedInput({ commitDelayMs = 450, onBlur, + onCompositionEnd, + onCompositionStart, + onFocus, onValueCommit, value, ...props }: BufferedInputProps) { const [draftValue, setDraftValue] = useState(value); const committedValueRef = useRef(value); + const draftValueRef = useRef(value); + const isFocusedRef = useRef(false); + const isComposingRef = useRef(false); useEffect(() => { + if (isFocusedRef.current && draftValueRef.current !== committedValueRef.current) { + return; + } + setDraftValue(value); + draftValueRef.current = value; committedValueRef.current = value; }, [value]); @@ -287,7 +307,7 @@ function BufferedInput({ }; useEffect(() => { - if (draftValue === committedValueRef.current) { + if (draftValue === committedValueRef.current || isComposingRef.current) { return; } @@ -302,9 +322,30 @@ function BufferedInput({ setDraftValue(event.target.value)} + onChange={(event) => { + const nextValue = event.target.value; + draftValueRef.current = nextValue; + setDraftValue(nextValue); + }} + onFocus={(event) => { + isFocusedRef.current = true; + onFocus?.(event); + }} + onCompositionStart={(event) => { + isComposingRef.current = true; + onCompositionStart?.(event); + }} + onCompositionEnd={(event) => { + isComposingRef.current = false; + const nextValue = event.currentTarget.value; + draftValueRef.current = nextValue; + setDraftValue(nextValue); + commitValue(nextValue); + onCompositionEnd?.(event); + }} onBlur={(event) => { - commitValue(draftValue, { immediate: true }); + isFocusedRef.current = false; + commitValue(draftValueRef.current, { immediate: true }); onBlur?.(event); }} /> @@ -314,15 +355,26 @@ function BufferedInput({ function BufferedTextarea({ commitDelayMs = 450, onBlur, + onCompositionEnd, + onCompositionStart, + onFocus, onValueCommit, value, ...props }: BufferedTextareaProps) { const [draftValue, setDraftValue] = useState(value); const committedValueRef = useRef(value); + const draftValueRef = useRef(value); + const isFocusedRef = useRef(false); + const isComposingRef = useRef(false); useEffect(() => { + if (isFocusedRef.current && draftValueRef.current !== committedValueRef.current) { + return; + } + setDraftValue(value); + draftValueRef.current = value; committedValueRef.current = value; }, [value]); @@ -343,7 +395,7 @@ function BufferedTextarea({ }; useEffect(() => { - if (draftValue === committedValueRef.current) { + if (draftValue === committedValueRef.current || isComposingRef.current) { return; } @@ -358,9 +410,30 @@ function BufferedTextarea({