fix(file-tree): propagate path simplification to parents

When all childs of a folder are selected in the tree, the selected path
was only simplifiyng one level. But if the reduction was also making its
own parent "fully selected" it was not correctly reporting only the
parent as selected
This commit is contained in:
Nicolas Meienberger 2026-01-02 15:49:09 +01:00
parent f836e2f9df
commit cd1d65167a
2 changed files with 43 additions and 36 deletions

View file

@ -182,7 +182,8 @@ export const FileTree = memo((props: Props) => {
if (
item.fullPath.startsWith(`${selectedParentPath}/`) &&
!item.fullPath.startsWith(`${path}/`) &&
item.fullPath !== path
item.fullPath !== path &&
!path.startsWith(`${item.fullPath}/`)
) {
newSelection.add(item.fullPath);
}
@ -190,39 +191,45 @@ export const FileTree = memo((props: Props) => {
}
}
const childrenByParent = new Map<string, string[]>();
for (const selectedPath of newSelection) {
const lastSlashIndex = selectedPath.lastIndexOf("/");
if (lastSlashIndex > 0) {
const parentPath = selectedPath.slice(0, lastSlashIndex);
if (!childrenByParent.has(parentPath)) {
childrenByParent.set(parentPath, []);
}
childrenByParent.get(parentPath)?.push(selectedPath);
}
}
// For each parent, check if all its children are selected
for (const [parentPath, selectedChildren] of childrenByParent.entries()) {
// Get all children of this parent from the file list
const allChildren = fileList.filter((item) => {
const itemParentPath = item.fullPath.slice(0, item.fullPath.lastIndexOf("/"));
return itemParentPath === parentPath;
});
// If all children are selected, replace them with the parent
if (allChildren.length > 0 && selectedChildren.length === allChildren.length) {
// Check that we have every child
const allChildrenPaths = new Set(allChildren.map((c) => c.fullPath));
const allChildrenSelected = selectedChildren.every((c) => allChildrenPaths.has(c));
if (allChildrenSelected) {
// Remove all children
for (const childPath of selectedChildren) {
newSelection.delete(childPath);
let changed = true;
while (changed) {
changed = false;
const childrenByParent = new Map<string, string[]>();
for (const selectedPath of newSelection) {
const lastSlashIndex = selectedPath.lastIndexOf("/");
if (lastSlashIndex > 0) {
const parentPath = selectedPath.slice(0, lastSlashIndex);
if (!childrenByParent.has(parentPath)) {
childrenByParent.set(parentPath, []);
}
childrenByParent.get(parentPath)?.push(selectedPath);
}
}
// For each parent, check if all its children are selected
for (const [parentPath, selectedChildren] of childrenByParent.entries()) {
// Get all children of this parent from the file list
const allChildren = fileList.filter((item) => {
const itemParentPath = item.fullPath.slice(0, item.fullPath.lastIndexOf("/"));
return itemParentPath === parentPath;
});
// If all children are selected, replace them with the parent
if (allChildren.length > 0 && selectedChildren.length === allChildren.length) {
// Check that we have every child
const allChildrenPaths = new Set(allChildren.map((c) => c.fullPath));
const allChildrenSelected = selectedChildren.every((c) => allChildrenPaths.has(c));
if (allChildrenSelected) {
// Remove all children
for (const childPath of selectedChildren) {
newSelection.delete(childPath);
}
// Add the parent
newSelection.add(parentPath);
changed = true;
break;
}
// Add the parent
newSelection.add(parentPath);
}
}
}

View file

@ -57,7 +57,7 @@ export const VolumeFileBrowser = ({
if (fileBrowser.isLoading) {
return (
<div className="flex items-center justify-center h-full min-h-[200px]">
<div className="flex items-center justify-center h-full min-h-50">
<p className="text-muted-foreground">Loading files...</p>
</div>
);
@ -65,7 +65,7 @@ export const VolumeFileBrowser = ({
if (error) {
return (
<div className="flex items-center justify-center h-full min-h-[200px]">
<div className="flex items-center justify-center h-full min-h-50">
<p className="text-destructive">Failed to load files: {(error as Error).message}</p>
</div>
);
@ -73,7 +73,7 @@ export const VolumeFileBrowser = ({
if (fileBrowser.isEmpty) {
return (
<div className="flex flex-col items-center justify-center h-full text-center p-8 min-h-[200px]">
<div className="flex flex-col items-center justify-center h-full text-center p-8 min-h-50">
<FolderOpen className="mb-4 h-12 w-12 text-muted-foreground" />
<p className="text-muted-foreground">{emptyMessage}</p>
{emptyDescription && <p className="text-sm text-muted-foreground mt-2">{emptyDescription}</p>}