From ef86c716a9f8ca99186abed9ccd3f92d2783678f Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Thu, 30 Jul 2026 14:37:13 -0400 Subject: [PATCH] fix: PATCH only dirty fields from the schedule edit dialog A name-only save submitted the whole form snapshot, silently overwriting prompt/agent edits another tab made while the dialog sat open (the server revision fence reads the current revision, so a stale full-form write passes it). Mirrors the existing cadence dirty-field handling; an untouched form closes without a request, matching the server's refusal of field-less updates. --- .../SidePanel/Schedules/ScheduleDialog.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/client/src/components/SidePanel/Schedules/ScheduleDialog.tsx b/client/src/components/SidePanel/Schedules/ScheduleDialog.tsx index bbc9efc8e5..6c3895c8a2 100644 --- a/client/src/components/SidePanel/Schedules/ScheduleDialog.tsx +++ b/client/src/components/SidePanel/Schedules/ScheduleDialog.tsx @@ -237,14 +237,25 @@ export default function ScheduleDialog({ ? schedule.cadence.daysOfWeek : undefined; const cadence = buildCadence(values, preserveWeeklyDays); + // PATCH only the fields the user actually touched, like the cadence handling + // above: submitting the whole form snapshot silently overwrites fields another + // tab or session edited while this dialog sat open (the server's revision fence + // reads the CURRENT revision, so it cannot catch a stale full-form write). + const payload = { + ...(dirtyFields.name ? { name: values.name.trim() } : {}), + ...(dirtyFields.prompt ? { prompt: values.prompt.trim() } : {}), + ...(dirtyFields.agent_id ? { agent_id: values.agent_id } : {}), + ...(cadenceTouched ? { cadence } : {}), + }; + // Nothing touched: a field-less PATCH is refused server-side (it would rotate + // the schedule's fencing for a request that changes nothing), so just close. + if (Object.keys(payload).length === 0) { + onOpenChange(false); + return; + } updateSchedule.mutate({ id: schedule.id, - payload: { - name: values.name.trim(), - prompt: values.prompt.trim(), - agent_id: values.agent_id, - ...(cadenceTouched ? { cadence } : {}), - }, + payload, }); return; }