diff --git a/src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx b/src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx index eefa76cabd3..52f334c3119 100644 --- a/src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx +++ b/src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx @@ -11,7 +11,8 @@ const testState: { executionHostId: ExecutionHostId } = vi.hoisted(() => ({ vi.mock('@/store', () => ({ useAppStore: { getState: () => ({}) } })) vi.mock('@/lib/worktree-runtime-owner', () => ({ - getKnownExecutionHostIdForWorktree: () => testState.executionHostId + getKnownExecutionHostIdForWorktree: () => testState.executionHostId, + getExplicitRuntimeEnvironmentIdForWorktree: () => null })) const { CombinedDiffFileTreeRow } = await import('./combined-diff-file-tree-row') diff --git a/src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts b/src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts index 56fd987a405..2c35e69d939 100644 --- a/src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts +++ b/src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts @@ -5,8 +5,15 @@ import { WORKSPACE_FILE_PATHS_MIME } from '@/lib/workspace-file-drag' import { handleInternalTerminalFileDrop } from './terminal-drop-handler' +import { writeWorkspaceFileDragSourceForWorkspace } from '@/lib/workspace-file-drag-source' +import { toRuntimeExecutionHostId } from '../../../../shared/execution-host' +import type { WorktreeRuntimeOwnerState } from '@/lib/worktree-runtime-owner-state' -const mocks = vi.hoisted(() => ({ write: vi.fn(), error: vi.fn(), activity: vi.fn() })) +const mocks = vi.hoisted(() => { + const state: WorktreeRuntimeOwnerState = {} + return { write: vi.fn(), error: vi.fn(), activity: vi.fn(), state } +}) +vi.mock('@/store', () => ({ useAppStore: { getState: () => mocks.state } })) vi.mock('sonner', () => ({ toast: { error: mocks.error } })) vi.mock('@/lib/connection-context', () => ({ getConnectionId: () => null })) vi.mock('./terminal-drop-worktree-path', () => ({ resolveTerminalDropWorktreePath: () => '/repo' })) @@ -69,6 +76,7 @@ const source = (executionHostId: string, runtimeEnvironmentId?: string) => describe('internal terminal drop source ownership', () => { beforeEach(() => { vi.clearAllMocks() + mocks.state = {} mocks.write.mockResolvedValue({ sentAnyPath: true, targetCurrent: true, pathsWritten: 1 }) }) @@ -120,4 +128,39 @@ describe('internal terminal drop source ownership', () => { expect(focus).toHaveBeenCalledOnce() } ) + + it.each([null, 'paired hub'])( + 'accepts the real workspace producer into its local transport owner: %s', + async (runtimeOwnerEnvironmentId) => { + mocks.state = { + settings: { activeRuntimeEnvironmentId: 'foreign-hub' }, + worktreesByRepo: { + 'repo-a': [ + { + id: 'source-workspace', + repoId: 'repo-a', + hostId: 'local', + ...(runtimeOwnerEnvironmentId ? { runtimeOwnerEnvironmentId } : {}) + } + ] + } + } + const payload = new Map() + writeWorkspaceFileDragSourceForWorkspace( + { setData: (type, value) => payload.set(type, value) }, + 'source-workspace' + ) + const emittedSource = payload.get(WORKSPACE_FILE_DRAG_SOURCE_MIME) + expect(emittedSource).toBeDefined() + const { result } = await drop(emittedSource ?? null, 'local', runtimeOwnerEnvironmentId) + expect(result).toEqual({ status: 'pasted', pathCount: 1 }) + expect(mocks.write).toHaveBeenCalledOnce() + expect(mocks.error).not.toHaveBeenCalled() + expect(JSON.parse(emittedSource ?? '{}')).toMatchObject({ + executionHostId: runtimeOwnerEnvironmentId + ? toRuntimeExecutionHostId(runtimeOwnerEnvironmentId) + : 'local' + }) + } + ) }) diff --git a/src/renderer/src/lib/workspace-file-drag-source.ts b/src/renderer/src/lib/workspace-file-drag-source.ts index 76215ae9a4e..86581a0f352 100644 --- a/src/renderer/src/lib/workspace-file-drag-source.ts +++ b/src/renderer/src/lib/workspace-file-drag-source.ts @@ -3,7 +3,7 @@ import { getKnownExecutionHostIdForWorktree, getExplicitRuntimeEnvironmentIdForWorktree } from './worktree-runtime-owner' -import { parseExecutionHostId } from '../../../shared/execution-host' +import { parseExecutionHostId, toRuntimeExecutionHostId } from '../../../shared/execution-host' import { writeWorkspaceFileDragSourceIfResolved } from './workspace-file-drag' /** Source-control rows list the live workspace, so the owner is resolved now @@ -14,12 +14,15 @@ export function writeWorkspaceFileDragSourceForWorkspace( ): void { const state = useAppStore.getState() const executionHostId = getKnownExecutionHostIdForWorktree(state, workspaceId) + const runtimeEnvironmentId = getExplicitRuntimeEnvironmentIdForWorktree(state, workspaceId) + const sourceExecutionHostId = + executionHostId === 'local' && runtimeEnvironmentId + ? toRuntimeExecutionHostId(runtimeEnvironmentId) + : executionHostId writeWorkspaceFileDragSourceIfResolved( dataTransfer, workspaceId, - executionHostId, - parseExecutionHostId(executionHostId)?.kind === 'ssh' - ? getExplicitRuntimeEnvironmentIdForWorktree(state, workspaceId) - : undefined + sourceExecutionHostId, + parseExecutionHostId(executionHostId)?.kind === 'ssh' ? runtimeEnvironmentId : undefined ) }