mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
fix(web): hide filesystem directory sentinels
This commit is contained in:
parent
f607068a99
commit
d0f3676d88
2 changed files with 17 additions and 22 deletions
|
|
@ -205,14 +205,15 @@ describe("binary and decoding helpers", () => {
|
|||
});
|
||||
|
||||
describe("buildTreeInputs", () => {
|
||||
test("emits placeholders for directories so they appear in the tree", () => {
|
||||
test("emits native directory paths without user-visible placeholders", () => {
|
||||
const entries: SandboxFileEntry[] = [
|
||||
{ name: "src", is_dir: true },
|
||||
{ name: "package.json", is_dir: false, size: 200 },
|
||||
];
|
||||
const inputs = buildTreeInputs(entries);
|
||||
expect(inputs.paths).toContain("src/");
|
||||
expect(inputs.paths).toContain("package.json");
|
||||
expect(inputs.paths.some((path) => path.startsWith("src/"))).toBe(true);
|
||||
expect(inputs.paths).not.toContain("src/__fabro_dir__");
|
||||
expect(inputs.directories.has("src")).toBe(true);
|
||||
expect(inputs.fileEntries.get("package.json")?.size).toBe(200);
|
||||
});
|
||||
|
|
@ -225,9 +226,8 @@ describe("classifySelection", () => {
|
|||
];
|
||||
const inputs = buildTreeInputs(entries);
|
||||
|
||||
test("recognizes a placeholder selection as a directory", () => {
|
||||
const placeholder = inputs.paths.find((path) => path.startsWith("src/"))!;
|
||||
expect(classifySelection(placeholder, inputs.fileEntries, inputs.directories)).toEqual({
|
||||
test("recognizes a native directory path selection as a directory", () => {
|
||||
expect(classifySelection("src/", inputs.fileEntries, inputs.directories)).toEqual({
|
||||
kind: "dir",
|
||||
relativePath: "src",
|
||||
});
|
||||
|
|
@ -363,11 +363,11 @@ describe("FilesystemPanel render", () => {
|
|||
};
|
||||
renderPanel();
|
||||
expect(lastFilesArgs?.path).toBe("/");
|
||||
const placeholder = filesystemPanelModule.buildTreeInputs(
|
||||
const directoryPath = filesystemPanelModule.buildTreeInputs(
|
||||
filesState.data!.data,
|
||||
).paths.find((path) => path.startsWith("src/"))!;
|
||||
).paths.find((path) => path === "src/")!;
|
||||
act(() => {
|
||||
lastTreeOptions?.onSelectionChange?.([placeholder]);
|
||||
lastTreeOptions?.onSelectionChange?.([directoryPath]);
|
||||
});
|
||||
expect(lastFilesArgs?.path).toBe("/src");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -142,9 +142,8 @@ interface BuiltTreeInputs {
|
|||
|
||||
// The list endpoint returns flat names like `foo` (depth=1) or `foo/bar.ts`
|
||||
// (depth=2). We feed those names to @pierre/trees as relative paths. Every
|
||||
// directory gets a synthetic placeholder child so empty directories still
|
||||
// appear; the placeholders are filtered out before selection.
|
||||
const DIRECTORY_PLACEHOLDER = "__fabro_dir__";
|
||||
// directories are represented with the tree library's canonical trailing-slash
|
||||
// form so empty directories appear without synthetic child rows.
|
||||
|
||||
export function buildTreeInputs(entries: readonly SandboxFileEntry[]): BuiltTreeInputs {
|
||||
const paths: string[] = [];
|
||||
|
|
@ -154,7 +153,7 @@ export function buildTreeInputs(entries: readonly SandboxFileEntry[]): BuiltTree
|
|||
for (const entry of entries) {
|
||||
if (entry.is_dir) {
|
||||
directories.add(entry.name);
|
||||
paths.push(`${entry.name}/${DIRECTORY_PLACEHOLDER}`);
|
||||
paths.push(`${entry.name}/`);
|
||||
} else {
|
||||
fileEntries.set(entry.name, entry);
|
||||
paths.push(entry.name);
|
||||
|
|
@ -164,8 +163,8 @@ export function buildTreeInputs(entries: readonly SandboxFileEntry[]): BuiltTree
|
|||
return { paths, fileEntries, directories };
|
||||
}
|
||||
|
||||
function isPlaceholderPath(path: string): boolean {
|
||||
return path.endsWith(`/${DIRECTORY_PLACEHOLDER}`) || path === DIRECTORY_PLACEHOLDER;
|
||||
function normalizeDirectorySelection(path: string): string {
|
||||
return path.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
export function classifySelection(
|
||||
|
|
@ -173,19 +172,15 @@ export function classifySelection(
|
|||
fileEntries: Map<string, SandboxFileEntry>,
|
||||
directories: Set<string>,
|
||||
): { kind: "file"; entry: SandboxFileEntry } | { kind: "dir"; relativePath: string } | null {
|
||||
if (isPlaceholderPath(selectedPath)) {
|
||||
const relPath = selectedPath.substring(0, selectedPath.length - DIRECTORY_PLACEHOLDER.length - 1);
|
||||
if (relPath) return { kind: "dir", relativePath: relPath };
|
||||
return null;
|
||||
}
|
||||
const fileEntry = fileEntries.get(selectedPath);
|
||||
if (fileEntry) return { kind: "file", entry: fileEntry };
|
||||
if (directories.has(selectedPath)) {
|
||||
return { kind: "dir", relativePath: selectedPath };
|
||||
const directoryPath = normalizeDirectorySelection(selectedPath);
|
||||
if (directories.has(directoryPath)) {
|
||||
return { kind: "dir", relativePath: directoryPath };
|
||||
}
|
||||
// Intermediate directory implied by a nested path (depth>1). Treat selection
|
||||
// as navigation into that subdir.
|
||||
return { kind: "dir", relativePath: selectedPath };
|
||||
return { kind: "dir", relativePath: directoryPath };
|
||||
}
|
||||
|
||||
interface PreviewState {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue