From 92e03ac4e3c7b19b265f4df881153ccbb43195bb Mon Sep 17 00:00:00 2001 From: "Cody (Radius Red)" Date: Tue, 31 Mar 2026 15:52:46 +0000 Subject: [PATCH] fix(ui): prevent dropdown snap-back when switching env var to Secret Address Greptile review feedback: the plain-value fallback in emit() caused the useEffect sync to re-run toRows(), which mapped the plain binding back to source: "plain", snapping the dropdown back. Fix: add an emittingRef that distinguishes local emit() calls from external value changes (like overlay reset after save). When the change originated from our own emit, skip the re-sync so the transitioning row stays in "secret" mode while the user picks a secret. Co-Authored-By: Paperclip --- ui/src/components/AgentConfigForm.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 7d5c4f45..c3c9bdfa 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -1155,9 +1155,17 @@ function EnvVarEditor({ const [rows, setRows] = useState(() => toRows(value)); const [sealError, setSealError] = useState(null); const valueRef = useRef(value); + const emittingRef = useRef(false); - // Sync when value identity changes (overlay reset after save) + // Sync when value identity changes (overlay reset after save). + // Skip re-sync when the change was triggered by our own emit() to avoid + // reverting local row state (e.g. a secret-transition dropdown choice). useEffect(() => { + if (emittingRef.current) { + emittingRef.current = false; + valueRef.current = value; + return; + } if (value !== valueRef.current) { valueRef.current = value; setRows(toRows(value)); @@ -1173,13 +1181,15 @@ function EnvVarEditor({ if (row.secretId) { rec[k] = { type: "secret_ref", secretId: row.secretId, version: "latest" }; } else { - // Preserve as plain during transition to avoid data loss + // Row is transitioning to secret but user hasn't picked one yet. + // Preserve the plain value so it isn't silently dropped. rec[k] = { type: "plain", value: row.plainValue }; } } else { rec[k] = { type: "plain", value: row.plainValue }; } } + emittingRef.current = true; onChange(Object.keys(rec).length > 0 ? rec : undefined); }