diff --git a/src/renderer/src/components/right-sidebar/ChecksPanel.tsx b/src/renderer/src/components/right-sidebar/ChecksPanel.tsx index b3b75f68921..9b8f77a4a3b 100644 --- a/src/renderer/src/components/right-sidebar/ChecksPanel.tsx +++ b/src/renderer/src/components/right-sidebar/ChecksPanel.tsx @@ -131,6 +131,7 @@ export default function ChecksPanel(): React.JSX.Element { const [titleDraft, setTitleDraft] = useState('') const [titleSaving, setTitleSaving] = useState(false) const titleInputRef = useRef(null) + const titleInputFocusTimerRef = useRef | null>(null) const pollIntervalRef = useRef(30_000) // start at 30s, backs off to 120s const prevChecksRef = useRef('') const conflictSummaryRefreshKeyRef = useRef(null) @@ -160,6 +161,15 @@ export default function ChecksPanel(): React.JSX.Element { const panelContextKeyRef = useRef(panelContextKey) panelContextKeyRef.current = panelContextKey + const clearTitleInputFocusTimer = useCallback((): void => { + if (titleInputFocusTimerRef.current !== null) { + clearTimeout(titleInputFocusTimerRef.current) + titleInputFocusTimerRef.current = null + } + }, []) + + useEffect(() => clearTitleInputFocusTimer, [clearTitleInputFocusTimer]) + // Why: the sidebar no longer uses key={activeWorktreeId} to force a full // remount on worktree switch (that caused an IPC storm on Windows). Reset // branch-specific local state so stale UI from the previous context doesn't @@ -172,6 +182,7 @@ export default function ChecksPanel(): React.JSX.Element { setEditingTitle(false) setTitleDraft('') setTitleSaving(false) + clearTitleInputFocusTimer() setChecks([]) setChecksLoading(false) setComments([]) @@ -1008,16 +1019,22 @@ export default function ChecksPanel(): React.JSX.Element { } setTitleDraft(pr.title) setEditingTitle(true) - setTimeout(() => titleInputRef.current?.focus(), 0) - }, [pr]) + clearTitleInputFocusTimer() + titleInputFocusTimerRef.current = setTimeout(() => { + titleInputFocusTimerRef.current = null + titleInputRef.current?.focus() + }, 0) + }, [clearTitleInputFocusTimer, pr]) const handleCancelEdit = useCallback(() => { + clearTitleInputFocusTimer() setEditingTitle(false) setTitleDraft('') - }, []) + }, [clearTitleInputFocusTimer]) const handleSaveTitle = useCallback(async () => { if (!repo || !pr || !titleDraft.trim() || titleDraft === pr.title) { + clearTitleInputFocusTimer() setEditingTitle(false) return } @@ -1040,10 +1057,20 @@ export default function ChecksPanel(): React.JSX.Element { }) } } finally { + clearTitleInputFocusTimer() setTitleSaving(false) setEditingTitle(false) } - }, [repo, pr, titleDraft, branch, linkedPR, fallbackGitHubPRNumber, fetchPRForBranch]) + }, [ + repo, + pr, + titleDraft, + branch, + linkedPR, + fallbackGitHubPRNumber, + fetchPRForBranch, + clearTitleInputFocusTimer + ]) const handleTitleKeyDown = useCallback( (e: React.KeyboardEvent) => {