fix(desktop): bound file picker to project

This commit is contained in:
LukeParkerDev 2026-06-07 18:09:44 +10:00
parent cd8866ecb0
commit e5c671fcfa
3 changed files with 24 additions and 2 deletions

View file

@ -15,6 +15,7 @@ import {
nextSuggestionIndex,
nextTreeScrollTop,
pickerFileSearchQuery,
pickerAbsoluteInput,
pickerMode,
preloadTreeDirectories,
} from "./directory-tree"
@ -107,7 +108,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
}
async function navigate(path: string) {
const value = cleanInput(path)
const value = policy.navigation(pickerAbsoluteInput(cleanInput(path), home()))
if (!value) return
const token = ++navigation
setLoading(true)

View file

@ -52,11 +52,14 @@ test("centralizes file and directory selection policy", () => {
expect(file.selection("/repo/src", "index.ts")).toBe("src/index.ts")
expect(file.selection("/repo", "src/")).toBeUndefined()
expect(file.result("/repo", "src/index.ts")).toBe("src/index.ts")
expect(file.selection("/tmp", "example.txt")).toBe("/tmp/example.txt")
expect(file.selection("/tmp", "example.txt")).toBeUndefined()
expect(file.navigation("/repo/src")).toBe("/repo/src")
expect(file.navigation("/tmp")).toBeUndefined()
const directory = pickerMode("directory")
expect(directory.includeFiles).toBeFalse()
expect(directory.selection("/repo", "src/")).toBe("/repo/src")
expect(directory.navigation("/tmp")).toBe("/tmp")
expect(directory.result("/repo", "")).toBe("/repo")
expect(directory.result("/repo", "", false)).toBeUndefined()
})

View file

@ -29,10 +29,14 @@ export function pickerMode(mode: "directory" | "file", base?: string) {
entries(parent: string, nodes: ReadonlyArray<{ name: string; type: "file" | "directory" }>) {
return treeEntries(parent, nodes)
},
navigation(path: string) {
return treePathWithin(base, path) ? path : undefined
},
result(root: string, selected: string) {
return selected || undefined
},
selection(root: string, path: string) {
if (!treePathWithin(base, root)) return
return selectedTreePath(root, path, "file", base)
},
}
@ -46,6 +50,9 @@ export function pickerMode(mode: "directory" | "file", base?: string) {
nodes.filter((node) => node.type === "directory"),
)
},
navigation(path: string) {
return path
},
result(root: string, selected: string, valid = true) {
if (!valid) return
return selected || root || undefined
@ -64,6 +71,17 @@ export function pickerFileSearchQuery(root: string, input: string, home: string)
return value
}
export function pickerAbsoluteInput(input: string, home: string) {
return input.replace(/\\/g, "/").replace(/^~(?=\/|$)/, home).replace(/\/+$/, "") || "/"
}
export function treePathWithin(base: string | undefined, path: string) {
if (!base) return false
const root = absoluteTreePath(base, "").toLowerCase()
const target = absoluteTreePath(path, "").toLowerCase()
return target === root || target.startsWith(root + "/")
}
export function preloadTreeDirectories(
parent: string,
nodes: ReadonlyArray<{ name: string; type: "file" | "directory" }>,