Add number key toggle for output modal

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 <noreply@anthropic.com>
This commit is contained in:
Cody Seibert
2025-12-09 08:57:41 -05:00
parent 9a6e6ea594
commit 2d8f600209
4 changed files with 111 additions and 3 deletions

View File

@@ -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<string>("");
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 (
<Dialog open={open} onOpenChange={onClose}>
<DialogContent

View File

@@ -698,6 +698,30 @@ export function BoardView() {
setShowOutputModal(true);
};
// Handle number key press when output modal is open
const handleOutputModalNumberKeyPress = useCallback((key: string) => {
// 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 */}

View File

@@ -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<void> {
await page.keyboard.press(key);
}
/**
* Count the number of session items in the session list
*/
export async function countSessionItems(page: Page): Promise<number> {
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<void> {
// 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<void> {
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<string | null> {
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<string | null> {
const modalDescription = page.locator('[data-testid="agent-output-modal"] [data-slot="dialog-description"]');
return await modalDescription.textContent().catch(() => null);
}