Preserve paired workspace ownership in terminal drag sources (#26931)

This commit is contained in:
Neil
2026-10-09 17:56:49 -07:00
committed by GitHub
parent e273ec3119
commit dd9cf36581
3 changed files with 54 additions and 7 deletions
@@ -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')
@@ -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<string, string>()
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'
})
}
)
})
@@ -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
)
}