diff --git a/src/renderer/src/components/WorkspaceEmptyAgentList.tsx b/src/renderer/src/components/WorkspaceEmptyAgentList.tsx deleted file mode 100644 index 61acbaadbd2..00000000000 --- a/src/renderer/src/components/WorkspaceEmptyAgentList.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { AgentIcon, getAgentLabel } from '@/lib/agent-catalog' -import { AgentTerminalLaunchButton } from './agent/AgentTerminalLaunchButton' -import { useAgentDetectionTargetForWorktree } from '@/hooks/useAgentDetectionTarget' -import { focusTerminalTabSurface } from '@/lib/focus-terminal-tab-surface' -import { useAppStore } from '@/store' -import { translate } from '@/i18n/i18n' -import { requestNativeChatComposerFocus } from './native-chat/use-native-chat-composer-reveal-focus' -import { useTabAgentMenuLaunch } from './tab-bar/QuickLaunchButton' -import { useNewTabAgentMenuRows } from './tab-bar/use-new-tab-agent-menu-rows' -import { - chatUnavailableLabel, - rowId, - rowLabel, - rowTitle -} from './tab-bar/tab-agent-row-presentation' -import { Button } from './ui/button' - -export function WorkspaceEmptyAgentList({ - worktreeId, - groupId -}: { - worktreeId: string - groupId: string -}): React.JSX.Element { - const target = useAgentDetectionTargetForWorktree(worktreeId) - const model = useNewTabAgentMenuRows(worktreeId, true, target) - const launch = useTabAgentMenuLaunch({ - worktreeId, - groupId, - onFocusTerminal: focusTerminalTabSurface, - onFocusChat: requestNativeChatComposerFocus - }) - const openSettingsPage = useAppStore((state) => state.openSettingsPage) - const openSettingsTarget = useAppStore((state) => state.openSettingsTarget) - const primaryRow = - model.state === 'settled' - ? model.rows.find((row) => row.kind !== 'chat-unavailable') - : undefined - - return ( -
-

- {translate('components.WorkspaceEmptyState.startAgent', 'Start an agent')} -

- {model.state === 'loading' ? ( -

- {translate('auto.components.tab.bar.QuickLaunchButton.agentsLoading', 'Loading agents')} -

- ) : model.rows.length === 0 ? ( -

- {model.detection.needsServerUpdate - ? translate( - 'auto.components.tab.bar.QuickLaunchButton.needsServerUpdate', - 'Update Orca on this server to list this workspace’s agents' - ) - : model.detection.detectionFailed - ? translate( - 'auto.components.tab.bar.QuickLaunchButton.hostUnreachable', - 'Can’t reach this workspace’s host to list its agents' - ) - : model.detection.detectedIds?.length - ? translate( - 'auto.components.tab.bar.QuickLaunchButton.8dea9b5cdf', - 'No enabled agents' - ) - : translate( - 'auto.components.tab.bar.QuickLaunchButton.e518f544b1', - 'No agents detected' - )} -

- ) : ( -
- {model.rows.map((row) => ( -
-
- - {row.kind === 'chat' ? ( - launch({ ...row, kind: 'cli' })} - /> - ) : null} -
- {row.kind === 'chat-unavailable' ? ( -

- {chatUnavailableLabel(row.reason)} -

- ) : null} -
- ))} -
- )} - -
- ) -} diff --git a/src/renderer/src/components/WorkspaceEmptyState.tsx b/src/renderer/src/components/WorkspaceEmptyState.tsx deleted file mode 100644 index 053ad0a2ecf..00000000000 --- a/src/renderer/src/components/WorkspaceEmptyState.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { FileText, Globe, Terminal } from 'lucide-react' -import { useAppStore } from '@/store' -import { translate } from '@/i18n/i18n' -import { getWorkspaceClientCreationActionPolicy } from '@/lib/client-creation-action-policy' -import { showClientCreationActionError } from '@/lib/client-creation-action-error' -import { openDocumentInFloatingWorkspace } from '@/lib/open-document-in-floating-workspace' -import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../shared/constants' -import { WorkspaceEmptyAgentList } from './WorkspaceEmptyAgentList' -import { Button } from './ui/button' - -export function WorkspaceEmptyState({ - worktreeId, - groupId -}: { - worktreeId: string - groupId: string -}): React.JSX.Element { - const newTerminal = useAppStore((state) => state.openNewTerminalTabInActiveWorkspace) - const newBrowser = useAppStore((state) => state.openNewBrowserTabInActiveWorkspace) - const openModal = useAppStore((state) => state.openModal) - const focusGroup = useAppStore((state) => state.focusGroup) - const browserEnabled = useAppStore( - (state) => - getWorkspaceClientCreationActionPolicy(state, worktreeId)['managed-browser'].state === - 'enabled' - ) - const openFile = async (): Promise => { - focusGroup(worktreeId, groupId) - if (worktreeId === FLOATING_TERMINAL_WORKTREE_ID) { - const document = await window.api.app.pickFloatingMarkdownDocument() - if (document) { - openDocumentInFloatingWorkspace(useAppStore.getState().openFile, document, { - targetGroupId: groupId - }) - } - return - } - openModal('quick-open') - } - - return ( -
-
-

- {translate('components.WorkspaceEmptyState.title', 'What would you like to do?')} -

-

- {translate( - 'components.WorkspaceEmptyState.description', - 'No tabs are open here. Start an agent or open a tool to get going.' - )} -

-
- - - {browserEnabled ? ( - - ) : null} -
- -
-
- ) -} diff --git a/src/renderer/src/components/tab-bar/QuickLaunchButton.launch-status.test.tsx b/src/renderer/src/components/tab-bar/QuickLaunchButton.launch-status.test.tsx index c775a5766d2..9352e9b27c6 100644 --- a/src/renderer/src/components/tab-bar/QuickLaunchButton.launch-status.test.tsx +++ b/src/renderer/src/components/tab-bar/QuickLaunchButton.launch-status.test.tsx @@ -33,7 +33,6 @@ vi.mock('@/store', async () => { return { useAppStore } }) vi.mock('@/lib/agent-catalog', () => ({ - getAgentLabel: (agent: string) => (agent === 'codex' ? 'Codex' : 'Claude'), getAgentCatalog: () => [ { id: 'claude', label: 'Claude' }, { id: 'codex', label: 'Codex' } @@ -68,7 +67,6 @@ vi.mock('@/lib/launch-agent-in-new-tab', () => ({ launchAgentInNewTab: launchMoc type DivProps = { disabled?: boolean; title?: string; onSelect?: () => void } import { QuickLaunchAgentMenuItems, ProjectedAgentMenuItems } from './QuickLaunchButton' -import { WorkspaceEmptyAgentList } from '../WorkspaceEmptyAgentList' import { useTabBarCreateMenuController } from './use-tab-bar-create-menu-controller' import * as menuRows from './use-new-tab-agent-menu-rows' import { @@ -78,43 +76,6 @@ import { const WORKTREE_ID = 'worktree-1' -it('offers separate chat and CLI launches on the empty workspace with the same owning host', () => { - const model = vi.spyOn(menuRows, 'useNewTabAgentMenuRows').mockReturnValueOnce({ - state: 'settled', - rows: [{ kind: 'chat', agent: 'codex', executionHostId: 'runtime:server' }], - detection: { - detectedIds: ['codex'], - detectionFailed: false, - needsServerUpdate: false, - isLoading: false, - isRefreshing: false, - refresh: async () => ['codex'] - } - }) - launchMock.mockReset().mockReturnValue({ surface: { kind: 'host-published' } }) - const view = render() - model.mockRestore() - - fireEvent.click(view.getByRole('button', { name: 'Launch Codex in a new terminal' })) - fireEvent.click(view.getByRole('button', { name: 'Start a chat with Codex' })) - - expect(launchMock.mock.calls.map(([args]) => args)).toEqual([ - expect.objectContaining({ - requestedSurface: 'terminal', - selectedExecutionHostId: 'runtime:server', - worktreeId: WORKTREE_ID, - groupId: 'group-1' - }), - expect.objectContaining({ - requestedSurface: 'chat', - selectedExecutionHostId: 'runtime:server', - worktreeId: WORKTREE_ID, - groupId: 'group-1' - }) - ]) - view.unmount() -}) - it('gives static/search no agent actions while loading, retaining settings and generic terminal', () => { const model = vi .spyOn(menuRows, 'useNewTabAgentMenuRows') diff --git a/src/renderer/src/components/tab-group/TabGroupPanel.tsx b/src/renderer/src/components/tab-group/TabGroupPanel.tsx index 1de05feda10..6e623c14482 100644 --- a/src/renderer/src/components/tab-group/TabGroupPanel.tsx +++ b/src/renderer/src/components/tab-group/TabGroupPanel.tsx @@ -3,7 +3,6 @@ import { lazyWithRetry as lazy } from '@/lib/lazy-with-retry' import { useDroppable } from '@dnd-kit/core' import { useAppStore } from '../../store' import TabBar from '../tab-bar/TabBar' -import { WorkspaceEmptyState } from '../WorkspaceEmptyState' import { TabBarQuickCommandsButton } from '../tab-bar/TabBarQuickCommandsButton' import { TabGroupPaneActionsMenu } from './TabGroupPaneActionsMenu' @@ -330,12 +329,6 @@ export default function TabGroupPanel({ className="relative flex-1 min-h-0 overflow-hidden" style={bodyAnchorStyle} > - {isVisible && - !activeTab && - model.groupTabs.length === 0 && - clientHostedRows.length === 0 ? ( - - ) : null} {/* Why: empty anchor so the agent-sessions tour reads as a terminal-area tip, not toolbar chrome. */} {isFocused ? (
{ expect(store.getState().tabsByWorktree['wt-1'] ?? []).toEqual([]) }) - it('creates a terminal in the invoking group’s workspace when another workspace is selected', async () => { - const store = createTestStore() - seedActiveWorkspace(store) - store.setState({ activeWorktreeId: 'another-workspace' }) - - await store.getState().openNewTerminalTabInActiveWorkspace('group-1') - - expect(createWebRuntimeSessionTerminalMock).toHaveBeenCalledWith({ - worktreeId: 'wt-1', - environmentId: 'runtime-1', - targetGroupId: 'group-1', - activate: true - }) - expect(store.getState().tabsByWorktree['another-workspace'] ?? []).toEqual([]) - }) - - it('creates a floating terminal locally while a paired workspace is selected', async () => { - const store = createTestStore() - seedActiveWorkspace(store) - store.setState({ - groupsByWorktree: { - ...store.getState().groupsByWorktree, - [FLOATING_TERMINAL_WORKTREE_ID]: [ - { - id: 'floating-group', - worktreeId: FLOATING_TERMINAL_WORKTREE_ID, - activeTabId: null, - tabOrder: [] - } - ] - } - }) - - await store.getState().openNewTerminalTabInActiveWorkspace('floating-group') - - expect(createWebRuntimeSessionTerminalMock).not.toHaveBeenCalled() - expect(store.getState().tabsByWorktree['wt-1'] ?? []).toEqual([]) - const tabs = store.getState().tabsByWorktree[FLOATING_TERMINAL_WORKTREE_ID] ?? [] - expect(tabs).toHaveLength(1) - expect(store.getState().unifiedTabsByWorktree[FLOATING_TERMINAL_WORKTREE_ID]).toEqual([ - expect.objectContaining({ entityId: tabs[0].id, groupId: 'floating-group' }) - ]) - }) - it('does not create a local folder terminal while paired ownership is unresolved', async () => { const folderId = 'folder-1' const workspaceKey = folderWorkspaceKey(folderId) diff --git a/src/renderer/src/store/terminals/terminal-active-workspace-creation.ts b/src/renderer/src/store/terminals/terminal-active-workspace-creation.ts index ffce04170b0..c1636f3cd70 100644 --- a/src/renderer/src/store/terminals/terminal-active-workspace-creation.ts +++ b/src/renderer/src/store/terminals/terminal-active-workspace-creation.ts @@ -4,7 +4,6 @@ import { focusTerminalTabSurface } from '@/lib/focus-terminal-tab-surface' import { runtimeEnvironmentIdOrLocalUnlessTwin } from '@/lib/worktree-runtime-owner' import { resolveWorktreeOperationRouteResult } from '@/lib/worktree-operation-route' import { isWebClientLocation } from '@/lib/web-client-location' -import { findGroupAndWorktree } from '../slices/tab-group-state' import type { TerminalSlice, TerminalStoreGet, TerminalStoreSet } from './terminal-state' export function createActiveWorkspaceTerminalActions( @@ -14,8 +13,7 @@ export function createActiveWorkspaceTerminalActions( return { openNewTerminalTabInActiveWorkspace: async (groupId) => { const state = get() - const worktreeId = - findGroupAndWorktree(state.groupsByWorktree, groupId)?.worktreeId ?? state.activeWorktreeId + const worktreeId = state.activeWorktreeId if (!worktreeId) { return }