Fix descendant paths in file explorer multi-drag (#4128)

This commit is contained in:
Neil
2026-05-31 05:20:17 -07:00
committed by GitHub
parent 784c6855b5
commit 7a1baf73cf
2 changed files with 57 additions and 2 deletions
@@ -64,4 +64,24 @@ describe('getWorkspaceFileDragPaths', () => {
})
).toEqual(paths)
})
it('drops selected descendants so moving a folder does not also move its children', () => {
const paths = ['/repo/src', '/repo/src/components/Button.tsx', '/repo/src-extra/index.ts']
expect(
getWorkspaceFileDragPaths({
getData: (type) =>
type === WORKSPACE_FILE_PATHS_MIME ? encodeWorkspaceFilePaths(paths) : ''
})
).toEqual(['/repo/src', '/repo/src-extra/index.ts'])
})
it('drops selected descendants with Windows separators and case', () => {
const paths = ['C:\\Repo\\src', 'c:\\repo\\src\\components\\Button.tsx']
expect(
getWorkspaceFileDragPaths({
getData: (type) =>
type === WORKSPACE_FILE_PATHS_MIME ? encodeWorkspaceFilePaths(paths) : ''
})
).toEqual(['C:\\Repo\\src'])
})
})
+37 -2
View File
@@ -1,3 +1,8 @@
import {
isPathInsideOrEqual,
normalizeRuntimePathForComparison
} from '../../../shared/cross-platform-path'
export const WORKSPACE_FILE_PATH_MIME = 'text/x-orca-file-path'
export const WORKSPACE_FILE_PATHS_MIME = 'text/x-orca-file-paths'
@@ -20,10 +25,40 @@ export function decodeWorkspaceFilePaths(data: string): string[] {
return [data]
}
function getTopLevelWorkspaceFilePaths(paths: readonly string[]): string[] {
const uniquePaths: string[] = []
for (const path of paths) {
if (
path &&
!uniquePaths.some(
(existing) =>
normalizeRuntimePathForComparison(existing) === normalizeRuntimePathForComparison(path)
)
) {
uniquePaths.push(path)
}
}
// Why: moving a selected folder already moves its descendants; issuing
// extra moves for selected children races against paths that no longer exist.
return uniquePaths.filter(
(path) =>
!uniquePaths.some(
(candidateRoot) =>
candidateRoot !== path &&
normalizeRuntimePathForComparison(candidateRoot) !==
normalizeRuntimePathForComparison(path) &&
isPathInsideOrEqual(candidateRoot, path)
)
)
}
export function getWorkspaceFileDragPaths(dataTransfer: Pick<DataTransfer, 'getData'>): string[] {
const multiPathData = dataTransfer.getData(WORKSPACE_FILE_PATHS_MIME)
if (multiPathData) {
return decodeWorkspaceFilePaths(multiPathData)
return getTopLevelWorkspaceFilePaths(decodeWorkspaceFilePaths(multiPathData))
}
return decodeWorkspaceFilePaths(dataTransfer.getData(WORKSPACE_FILE_PATH_MIME))
return getTopLevelWorkspaceFilePaths(
decodeWorkspaceFilePaths(dataTransfer.getData(WORKSPACE_FILE_PATH_MIME))
)
}