From ec5bfccc2ea38fbb3aa0e61db6fb451a98efb5e1 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Sun, 7 Jun 2026 21:18:42 -0700 Subject: [PATCH] fix: turn duplicate emulator action into go-to Co-authored-by: Orca --- .../tab-bar/TabBar.context-menu.test.ts | 16 +++++++++----- .../src/components/tab-bar/TabBar.tsx | 21 ++++++++----------- .../tab-group/useTabGroupWorkspaceModel.ts | 6 +++++- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/renderer/src/components/tab-bar/TabBar.context-menu.test.ts b/src/renderer/src/components/tab-bar/TabBar.context-menu.test.ts index ca2e9ba81a4..ae69d914573 100644 --- a/src/renderer/src/components/tab-bar/TabBar.context-menu.test.ts +++ b/src/renderer/src/components/tab-bar/TabBar.context-menu.test.ts @@ -423,7 +423,7 @@ describe('TabBar context menu wiring', () => { expect(menuLabels[3]).toContain('New Browser Tab') }) - it('disables New Mobile Emulator when the workspace already has one', async () => { + it('turns New Mobile Emulator into a go-to action when the workspace already has one', async () => { const onNewSimulatorTab = vi.fn() appStoreSnapshot.unifiedTabsByWorktree = { 'wt-1': [ @@ -449,13 +449,19 @@ describe('TabBar context menu wiring', () => { }) const emulatorItem = findChildrenByType(element, 'DropdownMenuItem').find((item) => - extractText(item.props.children).includes('New Mobile Emulator') + extractText(item.props.children).includes('Go to Mobile Emulator') ) - expect(emulatorItem?.props.disabled).toBe(true) - expect(emulatorItem?.props.onSelect).toBeUndefined() + expect(emulatorItem).toBeTruthy() + if (!emulatorItem) { + throw new Error('Go to Mobile Emulator menu item not rendered') + } + expect(emulatorItem.props.disabled).toBeUndefined() + expect(emulatorItem.props.onSelect).toBeTypeOf('function') + ;(emulatorItem.props.onSelect as () => void)() + expect(onNewSimulatorTab).toHaveBeenCalledTimes(1) const tooltip = findChildrenByType(element, 'TooltipContent').find((item) => - extractText(item.props.children).includes('An emulator already exists in this workspace.') + extractText(item.props.children).includes('Open the existing emulator tab.') ) expect(tooltip).toBeTruthy() }) diff --git a/src/renderer/src/components/tab-bar/TabBar.tsx b/src/renderer/src/components/tab-bar/TabBar.tsx index 854063c70d4..228a91bce46 100644 --- a/src/renderer/src/components/tab-bar/TabBar.tsx +++ b/src/renderer/src/components/tab-bar/TabBar.tsx @@ -63,7 +63,6 @@ type GitStatusEntries = ReturnType['gitStatusByWork const EMPTY_GIT_STATUS_ENTRIES: GitStatusEntries = [] const EMPTY_AGENT_CMD_OVERRIDES: Partial> = {} const EMPTY_UNIFIED_TABS: readonly Tab[] = [] -const EMULATOR_EXISTS_TOOLTIP = 'An emulator already exists in this workspace.' type TabBarProps = { tabs: (TerminalTab & { unifiedTabId?: string })[] @@ -498,19 +497,17 @@ function TabBarInner({ workspaceHasSimulatorTab ? ( - - - - New Mobile Emulator - {newSimulatorShortcut} - - + + + Go to Mobile Emulator + {newSimulatorShortcut} + - {EMULATOR_EXISTS_TOOLTIP} + Open the existing emulator tab. ) : ( diff --git a/src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts b/src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts index 5e799adb34f..d251dec9475 100644 --- a/src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts +++ b/src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts @@ -26,6 +26,7 @@ import { import { closeTerminalTab } from '../terminal/terminal-tab-actions' import { openTabBarEntry, type TabCreateEntryArgs } from '../tab-bar/tab-create-entry-action' import { openMobileEmulatorTab } from '@/lib/open-mobile-emulator-tab' +import { ensureSimulatorTab, getSimulatorTabForWorktree } from '@/lib/ensure-simulator-tab' export function recordTerminalTabGroupSplit(createdTerminal: TerminalTab | null | undefined): void { if (!createdTerminal) { @@ -577,8 +578,11 @@ export function useTabGroupWorkspaceModel({ }, newSimulatorTab: worktreeState.mobileEmulatorEnabled ? () => { + if (getSimulatorTabForWorktree(worktreeId)) { + void ensureSimulatorTab(worktreeId, { surfacePane: true }) + return + } // Why: mobile simulators are most useful beside the current tab group. - // Re-open is guarded as a no-op once a worktree emulator tab exists. void openMobileEmulatorTab(worktreeId, { placement: 'rightSplit', targetGroupId: groupId