fix: clear close dialog debounce timers (#3478)

This commit is contained in:
Neil
2026-05-29 22:41:30 -07:00
committed by GitHub
parent fbed7dd923
commit 620b6ab7e8
+37 -18
View File
@@ -227,6 +227,24 @@ function Terminal(): React.JSX.Element | null {
// so the stray click from the previous dialog is absorbed while a genuine
// new click on the next dialog still works.
const isClosingRef = useRef(false)
const closeDialogDebounceTimersRef = useRef<Set<number>>(new Set())
const releaseCloseDialogGuardAfterDebounce = useCallback(() => {
const timer = window.setTimeout(() => {
closeDialogDebounceTimersRef.current.delete(timer)
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
closeDialogDebounceTimersRef.current.add(timer)
}, [])
useEffect(() => {
const timers = closeDialogDebounceTimersRef.current
return () => {
for (const timer of timers) {
window.clearTimeout(timer)
}
timers.clear()
}
}, [])
// Window close confirmation dialog — shown for local terminals with running
// child processes. SSH terminals detach/persist through the relay lifecycle.
@@ -399,9 +417,7 @@ function Terminal(): React.JSX.Element | null {
(id) => id !== fileId
)
advanceEditorCloseQueue()
setTimeout(() => {
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
releaseCloseDialogGuardAfterDebounce()
return
}
@@ -433,9 +449,7 @@ function Terminal(): React.JSX.Element | null {
(id) => id !== fileId
)
advanceEditorCloseQueue()
setTimeout(() => {
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
releaseCloseDialogGuardAfterDebounce()
return
}
toast.error('Save timed out or failed. Fix errors before closing.')
@@ -450,10 +464,13 @@ function Terminal(): React.JSX.Element | null {
(id) => id !== fileId
)
advanceEditorCloseQueue()
setTimeout(() => {
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
}, [advanceEditorCloseQueue, saveDialogFileId, waitForFileClosed])
releaseCloseDialogGuardAfterDebounce()
}, [
advanceEditorCloseQueue,
releaseCloseDialogGuardAfterDebounce,
saveDialogFileId,
waitForFileClosed
])
const handleSaveDialogDiscard = useCallback(async () => {
if (isClosingRef.current) {
@@ -488,10 +505,14 @@ function Terminal(): React.JSX.Element | null {
(id) => id !== fileId
)
advanceEditorCloseQueue()
setTimeout(() => {
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
}, [advanceEditorCloseQueue, closeFile, markFileDirty, saveDialogFileId])
releaseCloseDialogGuardAfterDebounce()
}, [
advanceEditorCloseQueue,
closeFile,
markFileDirty,
releaseCloseDialogGuardAfterDebounce,
saveDialogFileId
])
const handleSaveDialogCancel = useCallback(() => {
if (isClosingRef.current) {
@@ -501,10 +522,8 @@ function Terminal(): React.JSX.Element | null {
pendingEditorCloseQueueRef.current = []
windowCloseAfterDirtyRef.current = null
setSaveDialogFileId(null)
setTimeout(() => {
isClosingRef.current = false
}, CLOSE_DIALOG_DEBOUNCE_MS)
}, [])
releaseCloseDialogGuardAfterDebounce()
}, [releaseCloseDialogGuardAfterDebounce])
useEffect(() => {
const onRequestEditorClose = (event: Event): void => {