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); }