feat: auto-follow active document in Auto Run sidebar (#347)#518
feat: auto-follow active document in Auto Run sidebar (#347)#518kianhub wants to merge 7 commits intoRunMaestro:mainfrom
Conversation
Add "Follow active task" checkbox to the Auto Run batch progress banner that auto-selects the currently running document when the batch document index changes. Includes state tracking refs for detecting batch start and document transitions.
…RunMaestro#347) - Add autoFollowEnabled prop to AutoRunProps interface - Guard both focus-stealing useEffects (mode change + document selection) to skip .focus() when autoFollowEnabled && batchRunState.isRunning - Add useEffect that scrolls to first unchecked checkbox in preview mode using scrollIntoView (focus-safe) with 150ms render delay - Pass autoFollowEnabled through RightPanel autoRunSharedProps - Add autoFollowEnabled to React.memo comparison function
…start (RunMaestro#347) When auto-follow is enabled and a batch run starts, automatically: - Switch the Right Bar to the Auto Run tab - Open the right panel if it was closed - Switch to preview mode if currently in edit mode This only triggers on batch START (not on subsequent document transitions), so users can freely switch tabs mid-run without being overridden.
…unMaestro#347) Move auto-follow state, refs, and useEffect from RightPanel.tsx into a dedicated hook for testability. Add 8 test cases covering document auto-selection, tab switching, panel opening, and ref reset behavior.
📝 WalkthroughWalkthroughAdds an opt-in "auto-follow" feature: a new hook detects batch start/document changes and, when enabled, auto-selects the active document, opens/switches the right panel to the Auto Run tab, and coordinates mode/scroll/focus behavior across AutoRun, RightPanel and the UI store. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RightPanel
participant Hook as useAutoRunAutoFollow
participant AutoRun
participant Batch as BatchState
User->>RightPanel: Toggle "Follow active task" on
RightPanel->>Hook: setAutoFollowEnabled(true)
Hook->>Hook: update autoFollowEnabled
Note over Batch,Hook: Batch starts (isRunning -> true)
Batch->>Hook: currentDocumentIndex / isRunning update
Hook->>Hook: detect batch start via refs
alt autoFollowEnabled && batch started
Hook->>RightPanel: setActiveRightTab("autorun")
Hook->>RightPanel: setRightPanelOpen(true)
Hook->>AutoRun: request mode -> "preview"
Hook->>AutoRun: onAutoRunSelectDocument(activeDoc)
AutoRun->>AutoRun: update selectedFile & scroll to first unchecked task
end
Note over Batch,Hook: Document changes while running
Batch->>Hook: currentDocumentIndex changes
alt autoFollowEnabled && doc changed
Hook->>AutoRun: onAutoRunSelectDocument(newActiveDoc)
AutoRun->>AutoRun: update selectedFile
end
Note over Batch,Hook: Batch ends then new batch starts
Batch->>Hook: isRunning false -> refs reset -> isRunning true
Hook->>Hook: re-trigger auto-selection for new batch
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds a "Follow active task" toggle to the Auto Run sidebar that automatically tracks the currently running document during batch runs — selecting the active document, switching to preview mode, opening the right panel, and scrolling to the first unchecked task. The implementation is cleanly extracted into a dedicated Key issues found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant BatchRunnerModal
participant UIStore
participant useAutoRunAutoFollow
participant RightPanel
participant AutoRun
User->>BatchRunnerModal: Check "Follow active task"
Note over BatchRunnerModal: Updates local state only
User->>BatchRunnerModal: Click "Go"
BatchRunnerModal->>UIStore: setAutoFollowEnabled(true)
BatchRunnerModal->>BatchRunnerModal: Start batch run
loop Batch running
BatchRunnerModal-->>useAutoRunAutoFollow: currentSessionBatchState changes
useAutoRunAutoFollow->>UIStore: reads autoFollowEnabled
useAutoRunAutoFollow->>RightPanel: onAutoRunSelectDocument(activeDoc)
useAutoRunAutoFollow->>RightPanel: setActiveRightTab("autorun")
useAutoRunAutoFollow->>RightPanel: setRightPanelOpen(true)
useAutoRunAutoFollow->>RightPanel: onAutoRunModeChange("preview")
RightPanel->>AutoRun: autoFollowEnabled=true prop
AutoRun->>AutoRun: skip focus() calls
AutoRun->>AutoRun: scrollIntoView first unchecked checkbox
end
User->>RightPanel: Toggle "Follow active task" off
RightPanel->>UIStore: setAutoFollowEnabled(false) [immediate]
Note over BatchRunnerModal: Local state still = true (diverged)
User->>BatchRunnerModal: Click "Go" again
BatchRunnerModal->>UIStore: setAutoFollowEnabled(true) [overwrites!]
Last reviewed commit: 4387ecf |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/renderer/hooks/batch/useAutoRunAutoFollow.ts (1)
4-14: UnusedtoggleRightPanelin interface.The
toggleRightPanelproperty is defined inUseAutoRunAutoFollowDepsbut is never used within the hook. OnlysetRightPanelOpenis called (line 60). Consider removingtoggleRightPanelfrom the interface to avoid confusion, or document why it's included for future use.♻️ Suggested fix
export interface UseAutoRunAutoFollowDeps { currentSessionBatchState: BatchRunState | null | undefined; onAutoRunSelectDocument: (filename: string) => void | Promise<void>; selectedFile: string | null; setActiveRightTab: (tab: RightPanelTab) => void; rightPanelOpen: boolean; setRightPanelOpen?: (open: boolean) => void; - toggleRightPanel?: () => void; onAutoRunModeChange?: (mode: 'edit' | 'preview') => void; currentMode?: 'edit' | 'preview'; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/hooks/batch/useAutoRunAutoFollow.ts` around lines 4 - 14, The interface property toggleRightPanel in UseAutoRunAutoFollowDeps is unused in the useAutoRunAutoFollow hook; remove toggleRightPanel from the UseAutoRunAutoFollowDeps interface and any related type references, leaving setRightPanelOpen as the single API used by the hook (update callers that pass toggleRightPanel to stop passing it or map it to setRightPanelOpen), and run type checks to ensure no remaining references to toggleRightPanel remain in the codebase.src/renderer/components/AutoRun.tsx (1)
981-1007: Consider adding a guard for empty preview content.The scroll-to-task effect works well, but if
previewRef.currentexists but has no checkboxes (e.g., document has no tasks), the loop exits harmlessly. However, consider whether scrolling behavior should also be guarded against rapid re-triggers whenlocalContentchanges during the batch.Currently the effect doesn't depend on
localContent, so it won't re-run when content updates mid-task. This may cause the scroll position to become stale if the agent checks off multiple tasks quickly before the nextcurrentTaskIndexupdate. This is a minor edge case and the current approach is reasonable for the initial implementation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/components/AutoRun.tsx` around lines 981 - 1007, The effect should early-return if preview has no checkboxes and should re-run when preview content changes; update the useEffect body to check after previewRef.current is defined that querySelectorAll('input[type="checkbox"]') yields length > 0 and return early if zero, and add the relevant content state (e.g., localContent or whatever holds the preview text) to the dependency array alongside batchRunState, autoFollowEnabled, and mode so the scroll logic in AutoRun (useEffect using previewRef, autoFollowEnabled, batchRunState, mode) retriggers when the preview updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/renderer/components/AutoRun.tsx`:
- Around line 981-1007: The effect should early-return if preview has no
checkboxes and should re-run when preview content changes; update the useEffect
body to check after previewRef.current is defined that
querySelectorAll('input[type="checkbox"]') yields length > 0 and return early if
zero, and add the relevant content state (e.g., localContent or whatever holds
the preview text) to the dependency array alongside batchRunState,
autoFollowEnabled, and mode so the scroll logic in AutoRun (useEffect using
previewRef, autoFollowEnabled, batchRunState, mode) retriggers when the preview
updates.
In `@src/renderer/hooks/batch/useAutoRunAutoFollow.ts`:
- Around line 4-14: The interface property toggleRightPanel in
UseAutoRunAutoFollowDeps is unused in the useAutoRunAutoFollow hook; remove
toggleRightPanel from the UseAutoRunAutoFollowDeps interface and any related
type references, leaving setRightPanelOpen as the single API used by the hook
(update callers that pass toggleRightPanel to stop passing it or map it to
setRightPanelOpen), and run type checks to ensure no remaining references to
toggleRightPanel remain in the codebase.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 55e379b0-8ca4-4ba2-ada8-b5123f9ff42b
📒 Files selected for processing (5)
src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.tssrc/renderer/components/AutoRun.tsxsrc/renderer/components/RightPanel.tsxsrc/renderer/hooks/batch/index.tssrc/renderer/hooks/batch/useAutoRunAutoFollow.ts
…tro#347) - Lift autoFollowEnabled state from local useState to zustand uiStore - Add checkbox in BatchRunnerModal footer, applied on Go - Immediately jump to active task when toggling on during a running batch
…Panel (RunMaestro#347) - Gate auto-select on isRunning to prevent spurious document navigation when toggling auto-follow after a batch ends - Remove unused toggleRightPanel from UseAutoRunAutoFollowDeps interface - Early-return in scroll-to-task effect when preview has no checkboxes
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.ts (1)
68-99: Add one test for enabling auto-follow during an already-running batch.Current tests mostly enable before transition-to-running. A direct assertion for the setter’s immediate path would lock in the new runtime behavior.
Suggested test case
+ it('should immediately jump to active document when enabling during a running batch', () => { + const onAutoRunSelectDocument = vi.fn(); + const setActiveRightTab = vi.fn(); + const setRightPanelOpen = vi.fn(); + const deps = createDeps({ + onAutoRunSelectDocument, + setActiveRightTab, + rightPanelOpen: false, + setRightPanelOpen, + currentMode: 'edit', + currentSessionBatchState: createBatchState({ + isRunning: true, + documents: ['doc-a', 'doc-b'], + currentDocumentIndex: 1, + }), + }); + + const { result } = renderHook((props: UseAutoRunAutoFollowDeps) => useAutoRunAutoFollow(props), { + initialProps: deps, + }); + + act(() => { + result.current.setAutoFollowEnabled(true); + }); + + expect(onAutoRunSelectDocument).toHaveBeenCalledWith('doc-b'); + expect(setActiveRightTab).toHaveBeenCalledWith('autorun'); + expect(setRightPanelOpen).toHaveBeenCalledWith(true); + });Also applies to: 100-135, 170-200, 229-261
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.ts` around lines 68 - 99, Add a test in the useAutoRunAutoFollow suite that verifies enabling auto-follow while a batch is already running triggers immediate selection: render the hook with deps where currentSessionBatchState represents a running batch (use createBatchState with isRunning: true, documents: ['doc-a','doc-b'], currentDocumentIndex: 0) and a spy for onAutoRunSelectDocument, then call result.current.setAutoFollowEnabled(true) and assert onAutoRunSelectDocument was called with 'doc-a'; reference the hook useAutoRunAutoFollow, the setter setAutoFollowEnabled, and the callback onAutoRunSelectDocument so the test exercises the immediate-path behavior when enabling auto-follow mid-run.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderer/components/BatchRunnerModal.tsx`:
- Around line 104-108: The local autoFollowEnabled state in BatchRunnerModal
(variables autoFollowEnabled and setAutoFollowEnabled) is initialized once from
useUIStore (autoFollowFromStore) and can become stale; remove the local state
and read/write directly from the store (useUIStore(autoFollowEnabled) and
setAutoFollowStore) or, if a local editable copy is needed, keep it synced by
adding a useEffect that updates setAutoFollowEnabled whenever
autoFollowFromStore changes and ensure the save handler (the "Go"/save action
that currently reads autoFollowEnabled) calls setAutoFollowStore with the latest
autoFollowFromStore (or the synced local value) instead of blindly persisting
the originally captured local state; update references in the component
(initialization and the save handler) to use the store-backed value or the
effect-synced local copy.
---
Nitpick comments:
In `@src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.ts`:
- Around line 68-99: Add a test in the useAutoRunAutoFollow suite that verifies
enabling auto-follow while a batch is already running triggers immediate
selection: render the hook with deps where currentSessionBatchState represents a
running batch (use createBatchState with isRunning: true, documents:
['doc-a','doc-b'], currentDocumentIndex: 0) and a spy for
onAutoRunSelectDocument, then call result.current.setAutoFollowEnabled(true) and
assert onAutoRunSelectDocument was called with 'doc-a'; reference the hook
useAutoRunAutoFollow, the setter setAutoFollowEnabled, and the callback
onAutoRunSelectDocument so the test exercises the immediate-path behavior when
enabling auto-follow mid-run.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9d2e920b-be39-466e-8c63-f46ddc7ed3d4
📒 Files selected for processing (5)
src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.tssrc/renderer/components/AutoRun.tsxsrc/renderer/components/BatchRunnerModal.tsxsrc/renderer/hooks/batch/useAutoRunAutoFollow.tssrc/renderer/stores/uiStore.ts
|
ready for review, it's working well on my end @pedramamini |
|
fixing new annotations |
- Remove local autoFollowEnabled state in BatchRunnerModal to prevent stale overwrite of store value on Go action - Wrap scroll-to-task setTimeout with requestAnimationFrame for more reliable DOM targeting after React render - Add test for enabling auto-follow during an already-running batch
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderer/components/AutoRun.tsx`:
- Around line 945-954: The effect in AutoRun.tsx re-focuses on the batchRunState
true->false transition because batchRunState?.isRunning is in the dependency
array; remove batchRunState?.isRunning from this effect’s dependencies and
instead read the run state from a ref updated by a separate useEffect so the
focus effect only runs on mode or autoFollowEnabled changes; keep the same guard
(if (autoFollowEnabled && isRunningRef.current) return) and continue to focus
textareaRef or previewRef based on mode.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fb56e78c-95c1-483b-90c0-4a47bf78e5b3
📒 Files selected for processing (3)
src/__tests__/renderer/hooks/useAutoRunAutoFollow.test.tssrc/renderer/components/AutoRun.tsxsrc/renderer/components/BatchRunnerModal.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/renderer/components/BatchRunnerModal.tsx
- src/tests/renderer/hooks/useAutoRunAutoFollow.test.ts
| useEffect(() => { | ||
| // Skip focus when auto-follow is driving changes during a batch run | ||
| if (autoFollowEnabled && batchRunState?.isRunning) return; | ||
|
|
||
| if (mode === 'edit' && textareaRef.current) { | ||
| textareaRef.current.focus(); | ||
| } else if (mode === 'preview' && previewRef.current) { | ||
| previewRef.current.focus(); | ||
| } | ||
| }, [mode]); | ||
| }, [mode, autoFollowEnabled, batchRunState?.isRunning]); |
There was a problem hiding this comment.
Avoid re-focusing the sidebar when the batch stops.
Adding batchRunState?.isRunning to this effect’s dependencies makes it run again on the true -> false transition. With auto-follow enabled, that focuses the preview/editor at batch completion even when mode did not change, which pulls keyboard focus back into Auto Run and breaks the “don’t steal focus” guarantee.
Suggested fix
+ const suppressAutoFocusRef = useRef(false);
+ suppressAutoFocusRef.current = !!autoFollowEnabled && !!batchRunState?.isRunning;
+
// Auto-focus the active element after mode change
useEffect(() => {
- // Skip focus when auto-follow is driving changes during a batch run
- if (autoFollowEnabled && batchRunState?.isRunning) return;
+ // Skip focus when auto-follow is driving changes during a batch run
+ if (suppressAutoFocusRef.current) return;
if (mode === 'edit' && textareaRef.current) {
textareaRef.current.focus();
} else if (mode === 'preview' && previewRef.current) {
previewRef.current.focus();
}
- }, [mode, autoFollowEnabled, batchRunState?.isRunning]);
+ }, [mode]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| // Skip focus when auto-follow is driving changes during a batch run | |
| if (autoFollowEnabled && batchRunState?.isRunning) return; | |
| if (mode === 'edit' && textareaRef.current) { | |
| textareaRef.current.focus(); | |
| } else if (mode === 'preview' && previewRef.current) { | |
| previewRef.current.focus(); | |
| } | |
| }, [mode]); | |
| }, [mode, autoFollowEnabled, batchRunState?.isRunning]); | |
| const suppressAutoFocusRef = useRef(false); | |
| suppressAutoFocusRef.current = !!autoFollowEnabled && !!batchRunState?.isRunning; | |
| // Auto-focus the active element after mode change | |
| useEffect(() => { | |
| // Skip focus when auto-follow is driving changes during a batch run | |
| if (suppressAutoFocusRef.current) return; | |
| if (mode === 'edit' && textareaRef.current) { | |
| textareaRef.current.focus(); | |
| } else if (mode === 'preview' && previewRef.current) { | |
| previewRef.current.focus(); | |
| } | |
| }, [mode]); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderer/components/AutoRun.tsx` around lines 945 - 954, The effect in
AutoRun.tsx re-focuses on the batchRunState true->false transition because
batchRunState?.isRunning is in the dependency array; remove
batchRunState?.isRunning from this effect’s dependencies and instead read the
run state from a ref updated by a separate useEffect so the focus effect only
runs on mode or autoFollowEnabled changes; keep the same guard (if
(autoFollowEnabled && isRunningRef.current) return) and continue to focus
textareaRef or previewRef based on mode.
Summary
Adds a "Follow active task" toggle to the Auto Run batch progress banner. When enabled, the sidebar automatically tracks the currently running document and scrolls to the active task — without stealing focus from the user's workspace.
Closes #347
What Changed
New:
useAutoRunAutoFollowhook (src/renderer/hooks/batch/useAutoRunAutoFollow.ts)Extracted, testable hook that encapsulates all auto-follow logic:
currentDocumentIndexchanges inBatchRunStateonAutoRunSelectDocumentModified:
RightPanel.tsxuseAutoRunAutoFollowhookautoFollowEnabledtoAutoRunvia shared propsModified:
AutoRun.tsxautoFollowEnabledpropuseEffects that call.focus()(on mode change and document selection) are guarded to skip focus — preventing the sidebar from stealing focus from the user's main input or scratchpaduseEffectqueries the preview for the first unchecked checkbox (input[type="checkbox"]:not(:checked)) and scrolls its parentliinto view withscrollIntoView({ behavior: 'smooth', block: 'center' })— this only scrolls the container, never moves DOM focusReact.memocomparison functionNew: Tests (
useAutoRunAutoFollow.test.ts)8 test cases covering:
Design Decisions
scrollIntoViewinstead of manual scroll math.focus()calls withautoFollowEnabled && isRunningrenderHook, keeps RightPanel cleanHow to Test
Files Changed
src/renderer/hooks/batch/useAutoRunAutoFollow.tssrc/renderer/hooks/batch/index.tssrc/renderer/components/RightPanel.tsxsrc/renderer/components/AutoRun.tsxsrc/__tests__/renderer/hooks/useAutoRunAutoFollow.test.tsSummary by CodeRabbit
New Features
Tests