Skip to content

Commit 3aa2b61

Browse files
committed
fix(scheduled-tasks): lock modal dismiss while a save is in flight
Cancel, the header X, Escape, and overlay click all route through one guarded onOpenChange that no-ops while submitting, and the footer Cancel is disabled (cancelDisabled) — so an in-progress create/edit can't be abandoned mid-save and lose its draft. submitting moves up to TaskModal so the guard can read it.
1 parent 3d42b04 commit 3aa2b61

1 file changed

Lines changed: 27 additions & 4 deletions

File tree

  • apps/sim/app/workspace/[workspaceId]/scheduled-tasks/components/task-modal

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/components/task-modal/task-modal.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,25 +131,46 @@ export function TaskModal({
131131
onSubmit,
132132
onRequestDelete,
133133
}: TaskModalProps) {
134+
const [submitting, setSubmitting] = useState(false)
135+
136+
/**
137+
* While a save is in flight, swallow every dismiss path — Cancel, header X,
138+
* Escape, and overlay click all route through this one handler — so an
139+
* in-progress create/edit can't be abandoned and lose its draft. `submitting`
140+
* lives here (not in the unmounted-on-close content) so this guard can see it.
141+
*/
142+
const handleOpenChange = (next: boolean) => {
143+
if (!next && submitting) return
144+
onOpenChange(next)
145+
}
146+
134147
return (
135148
<ChipModal
136149
open={open}
137-
onOpenChange={onOpenChange}
150+
onOpenChange={handleOpenChange}
138151
size='lg'
139152
srTitle={edit ? 'Edit scheduled task' : 'New scheduled task'}
140153
>
141154
<TaskModalContent
142-
onOpenChange={onOpenChange}
155+
onOpenChange={handleOpenChange}
143156
slot={slot}
144157
edit={edit}
145158
prefill={prefill}
146159
onSubmit={onSubmit}
147160
onRequestDelete={onRequestDelete}
161+
submitting={submitting}
162+
setSubmitting={setSubmitting}
148163
/>
149164
</ChipModal>
150165
)
151166
}
152167

168+
interface TaskModalContentProps extends Omit<TaskModalProps, 'open'> {
169+
/** Whether a save is in flight — owned by {@link TaskModal} so the dismiss guard can read it. */
170+
submitting: boolean
171+
setSubmitting: (submitting: boolean) => void
172+
}
173+
153174
/**
154175
* Inner content, mounted only while the dialog is open (the Radix portal
155176
* unmounts closed content). Holding the editor here keeps its mention-data
@@ -162,7 +183,9 @@ function TaskModalContent({
162183
prefill,
163184
onSubmit,
164185
onRequestDelete,
165-
}: Omit<TaskModalProps, 'open'>) {
186+
submitting,
187+
setSubmitting,
188+
}: TaskModalContentProps) {
166189
const { workspaceId } = useParams<{ workspaceId: string }>()
167190
const source = edit ?? prefill
168191
const accountTimezone = useTimezone()
@@ -193,7 +216,6 @@ function TaskModalContent({
193216
const [recurrence, setRecurrence] = useState<Recurrence>(
194217
() => source?.recurrence ?? DEFAULT_RECURRENCE
195218
)
196-
const [submitting, setSubmitting] = useState(false)
197219
const launchEditedRef = useRef(false)
198220

199221
/**
@@ -287,6 +309,7 @@ function TaskModalContent({
287309
</ChipModalPromptBody>
288310
<ChipModalFooter
289311
onCancel={close}
312+
cancelDisabled={submitting}
290313
secondaryActions={secondaryActions}
291314
primaryAction={{
292315
label: submitting ? (edit ? 'Saving...' : 'Scheduling...') : edit ? 'Save' : 'Schedule',

0 commit comments

Comments
 (0)