fix(app): allow collapsing the parent folder of a selected file (#500)
The file explorer had a useEffect that re-enforced expansion of every ancestor of `selectedEntryPath` whenever `expandedPaths` changed. As a result, the moment a user collapsed the parent folder of a file they had just opened, the effect re-added that folder to the expanded set and the folder appeared stuck open. Selection and expansion are orthogonal: clicking a file should not dictate that its parent folder stays open forever. There is also no current caller that sets `selectedEntryPath` from outside the tree, so the reveal-on-external-selection use case the effect was designed for is unused. Delete the effect and its two now-dead helpers. If a future "Reveal in Explorer" action is introduced, it can expand ancestors at the call site. Adds an E2E regression test that reproduces the original scenario: expand a folder, open an image, collapse the parent folder, assert children are hidden. Also asserts an unrelated sibling folder still expands after the image is open, guarding against any future regression that makes the bug global.
This commit is contained in:
@@ -195,35 +195,6 @@ export function FileExplorerPane({
|
||||
});
|
||||
}, [hasWorkspaceScope, requestDirectoryListing, workspaceStateKey]);
|
||||
|
||||
// Expand ancestor directories when a file is selected (e.g., from an inline path click)
|
||||
useEffect(() => {
|
||||
if (!selectedEntryPath || !workspaceStateKey) {
|
||||
return;
|
||||
}
|
||||
const parentDir = getParentDirectory(selectedEntryPath);
|
||||
const ancestors = getAncestorDirectories(parentDir);
|
||||
const newPaths = ancestors.filter((path) => !expandedPaths.has(path));
|
||||
if (newPaths.length === 0) {
|
||||
return;
|
||||
}
|
||||
setExpandedPathsForWorkspace(workspaceStateKey, [...Array.from(expandedPaths), ...newPaths]);
|
||||
newPaths.forEach((path) => {
|
||||
if (!directories.has(path)) {
|
||||
void requestDirectoryListing(path, {
|
||||
recordHistory: false,
|
||||
setCurrentPath: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [
|
||||
directories,
|
||||
workspaceStateKey,
|
||||
expandedPaths,
|
||||
requestDirectoryListing,
|
||||
selectedEntryPath,
|
||||
setExpandedPathsForWorkspace,
|
||||
]);
|
||||
|
||||
const handleToggleDirectory = useCallback(
|
||||
(entry: ExplorerEntry) => {
|
||||
if (!workspaceStateKey) {
|
||||
@@ -682,35 +653,6 @@ function buildTreeRows({
|
||||
return rows;
|
||||
}
|
||||
|
||||
function getParentDirectory(path: string): string {
|
||||
const normalized = path.replace(/\/+$/, "");
|
||||
if (!normalized || normalized === ".") {
|
||||
return ".";
|
||||
}
|
||||
const lastSlash = normalized.lastIndexOf("/");
|
||||
if (lastSlash === -1) {
|
||||
return ".";
|
||||
}
|
||||
const dir = normalized.slice(0, lastSlash);
|
||||
return dir.length > 0 ? dir : ".";
|
||||
}
|
||||
|
||||
function getAncestorDirectories(directory: string): string[] {
|
||||
const trimmed = directory.replace(/^\.\/+/, "").replace(/\/+$/, "");
|
||||
if (!trimmed || trimmed === ".") {
|
||||
return ["."];
|
||||
}
|
||||
|
||||
const parts = trimmed.split("/").filter(Boolean);
|
||||
const ancestors: string[] = ["."];
|
||||
let acc = "";
|
||||
for (const part of parts) {
|
||||
acc = acc ? `${acc}/${part}` : part;
|
||||
ancestors.push(acc);
|
||||
}
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
function getErrorRecoveryPath(state: AgentFileExplorerState | undefined): string {
|
||||
if (!state) {
|
||||
return ".";
|
||||
|
||||
Reference in New Issue
Block a user