From 2d8f600209c33d045996796ac9903eaaf0b0328b Mon Sep 17 00:00:00 2001 From: Cody Seibert Date: Tue, 9 Dec 2025 08:57:41 -0500 Subject: [PATCH] Add number key toggle for output modal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the output modal is open: - Pressing the same number key closes the modal - Pressing a different number key switches to that feature's output Also adds test utilities for testing number key interactions and fixes the setupMockProjectWithInProgressFeatures utility to properly set __mockFeatures for the mock electron API. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .automaker/feature_list.json | 12 +++-- .../components/views/agent-output-modal.tsx | 26 ++++++++++ app/src/components/views/board-view.tsx | 25 +++++++++ app/tests/utils.ts | 51 +++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/.automaker/feature_list.json b/.automaker/feature_list.json index b8750afd..8efee565 100644 --- a/.automaker/feature_list.json +++ b/.automaker/feature_list.json @@ -32,8 +32,7 @@ "category": "Kanban", "description": "When I edit a card, it's showing an input for the description refactor to also show a text area for description like we do on the add card, add feature card.", "steps": [], - "status": "in_progress", - "startedAt": "2025-12-09T13:48:07.718Z" + "status": "in_progress" }, { "id": "feature-1765287613626-z01cksyg6", @@ -55,5 +54,12 @@ "description": "Can you please add a shortcut for starting a new session?", "steps": [], "status": "verified" + }, + { + "id": "feature-1765288315355-ihrm3jz83", + "category": "Kanban", + "description": "Can you please refactor it so if I were to press one of the number keys on my keyboard when the output modal is open, just go ahead and auto collapse it if it was the same number that I had open. If I were to press a different number on my number key, don't actually close it again.", + "steps": [], + "status": "verified" } -] +] \ No newline at end of file diff --git a/app/src/components/views/agent-output-modal.tsx b/app/src/components/views/agent-output-modal.tsx index bd3157d7..fa56da52 100644 --- a/app/src/components/views/agent-output-modal.tsx +++ b/app/src/components/views/agent-output-modal.tsx @@ -16,6 +16,8 @@ interface AgentOutputModalProps { onClose: () => void; featureDescription: string; featureId: string; + /** Called when a number key (0-9) is pressed while the modal is open */ + onNumberKeyPress?: (key: string) => void; } export function AgentOutputModal({ @@ -23,6 +25,7 @@ export function AgentOutputModal({ onClose, featureDescription, featureId, + onNumberKeyPress, }: AgentOutputModalProps) { const [output, setOutput] = useState(""); const [isLoading, setIsLoading] = useState(true); @@ -169,6 +172,29 @@ export function AgentOutputModal({ autoScrollRef.current = isAtBottom; }; + // Handle number key presses while modal is open + useEffect(() => { + if (!open || !onNumberKeyPress) return; + + const handleKeyDown = (event: KeyboardEvent) => { + // Check if a number key (0-9) was pressed without modifiers + if ( + !event.ctrlKey && + !event.altKey && + !event.metaKey && + /^[0-9]$/.test(event.key) + ) { + event.preventDefault(); + onNumberKeyPress(event.key); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [open, onNumberKeyPress]); + return ( { + // Convert key to index: 1-9 -> 0-8, 0 -> 9 + const index = key === "0" ? 9 : parseInt(key, 10) - 1; + + // Get the feature at that index from in-progress features + const targetFeature = inProgressFeaturesForShortcuts[index]; + + if (!targetFeature) { + // No feature at this index, do nothing + return; + } + + // If pressing the same number key as the currently open feature, close the modal + if (targetFeature.id === outputFeature?.id) { + setShowOutputModal(false); + } + // If pressing a different number key, switch to that feature's output + else { + setOutputFeature(targetFeature); + // Modal stays open, just showing different content + } + }, [inProgressFeaturesForShortcuts, outputFeature?.id]); + const handleForceStopFeature = async (feature: Feature) => { try { await autoMode.stopFeature(feature.id); @@ -1209,6 +1233,7 @@ export function BoardView() { onClose={() => setShowOutputModal(false)} featureDescription={outputFeature?.description || ""} featureId={outputFeature?.id || ""} + onNumberKeyPress={handleOutputModalNumberKeyPress} /> {/* Delete All Verified Dialog */} diff --git a/app/tests/utils.ts b/app/tests/utils.ts index f43a3595..c705c057 100644 --- a/app/tests/utils.ts +++ b/app/tests/utils.ts @@ -894,6 +894,10 @@ export async function setupMockProjectWithInProgressFeatures( }; localStorage.setItem("automaker-storage", JSON.stringify(mockState)); + + // Also store features in a global variable that the mock electron API can use + // This is needed because the board-view loads features from the file system + (window as any).__mockFeatures = mockFeatures; }, options ); @@ -1255,6 +1259,29 @@ export async function pressShortcut(page: Page, key: string): Promise { await page.keyboard.press(key); } +/** + * Count the number of session items in the session list + */ +export async function countSessionItems(page: Page): Promise { + const sessionList = page.locator('[data-testid="session-list"] [data-testid^="session-item-"]'); + return await sessionList.count(); +} + +/** + * Wait for a new session to be created (by checking if a session item appears) + */ +export async function waitForNewSession( + page: Page, + options?: { timeout?: number } +): Promise { + // Wait for any session item to appear + const sessionItem = page.locator('[data-testid^="session-item-"]').first(); + await sessionItem.waitFor({ + timeout: options?.timeout ?? 5000, + state: "visible", + }); +} + /** * Check if a shortcut key indicator is visible for a navigation item */ @@ -1650,3 +1677,27 @@ export async function setupMockProjectWithSkipTestsFeatures( options ); } + +/** + * Press a number key (0-9) on the keyboard + */ +export async function pressNumberKey(page: Page, num: number): Promise { + await page.keyboard.press(num.toString()); +} + +/** + * Get the modal title/description text to verify which feature's output is being shown + */ +export async function getAgentOutputModalDescription(page: Page): Promise { + const modal = page.locator('[data-testid="agent-output-modal"]'); + const description = modal.locator('[id="radix-\\:r.+\\:-description"]').first(); + return await description.textContent().catch(() => null); +} + +/** + * Check the dialog description content in the agent output modal + */ +export async function getOutputModalDescription(page: Page): Promise { + const modalDescription = page.locator('[data-testid="agent-output-modal"] [data-slot="dialog-description"]'); + return await modalDescription.textContent().catch(() => null); +}