Expand folder select for the initial value

This commit is contained in:
WithoutPants 2026-03-23 15:06:01 +11:00
parent bf50679986
commit 07492e045a
2 changed files with 133 additions and 5 deletions

View file

@ -22,3 +22,20 @@ query FindFoldersForQuery(
}
}
}
query FindFolderHierarchyForIDs($ids: [ID!]!) {
findFolders(ids: $ids) {
count
folders {
...SelectFolderData
parent_folders {
...SelectFolderData
# the parent folders will be expanded, so we need the child folders
sub_folders {
...SelectFolderData
}
}
}
}
}

View file

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
FolderDataFragment,
useFindFolderHierarchyForIDsQuery,
useFindFoldersForQueryQuery,
useFindRootFoldersForSelectQuery,
} from "src/core/generated-graphql";
@ -141,7 +142,30 @@ function replaceFolder(folder: IFolder): (f: IFolder) => IFolder {
};
}
function useFolderMap(query: string, skip?: boolean) {
function mergeFolderMaps(base: IFolder[], update: IFolder[]): IFolder[] {
const ret = [...base];
update.forEach((updateFolder) => {
const existingIndex = ret.findIndex((f) => f.id === updateFolder.id);
if (existingIndex === -1) {
// not found, add to the end
ret.push(updateFolder);
} else {
// found, replace
ret[existingIndex] = updateFolder;
}
});
return ret;
}
function useFolderMap(
query: string,
skip?: boolean,
initialSelected?: string[]
) {
const [cachedInitialSelected] = useState<string[]>(initialSelected ?? []);
const { data: rootFoldersResult } = useFindRootFoldersForSelectQuery({
skip,
});
@ -153,11 +177,94 @@ function useFolderMap(query: string, skip?: boolean) {
},
});
const { data: initialSelectedResult } = useFindFolderHierarchyForIDsQuery({
skip: !initialSelected || cachedInitialSelected.length === 0,
variables: {
ids: cachedInitialSelected ?? [],
},
});
const rootFolders: IFolder[] = useMemo(() => {
const ret = rootFoldersResult?.findFolders.folders ?? [];
return ret.map((f) => ({ ...f, expanded: false, children: undefined }));
}, [rootFoldersResult]);
const initialSelectedFolders: IFolder[] = useMemo(() => {
const ret: IFolder[] = [];
(initialSelectedResult?.findFolders.folders ?? []).forEach((folder) => {
if (!folder.parent_folders.length) {
// add root folder if not present
if (!ret.find((f) => f.id === folder.id)) {
ret.push({ ...folder, expanded: true, children: [] });
}
return;
}
let currentParent: IFolder | undefined;
for (let i = folder.parent_folders.length - 1; i >= 0; i--) {
const thisFolder = folder.parent_folders[i];
let existing: IFolder | undefined;
if (i === folder.parent_folders.length - 1) {
// last parent, add the folder as root if not present
existing = ret.find((f) => f.id === thisFolder.id);
if (!existing) {
existing = {
...folder.parent_folders[i],
expanded: true,
children: folder.parent_folders[i].sub_folders.map((f) => ({
...f,
expanded: false,
children: undefined,
})),
};
ret.push(existing);
}
currentParent = existing;
continue;
}
const existingIndex =
currentParent!.children?.findIndex((f) => f.id === thisFolder.id) ??
-1;
if (existingIndex === -1) {
// should be guaranteed
throw new Error(
`Parent folder ${thisFolder.id} not found in children of ${
currentParent!.id
}`
);
}
existing = currentParent!.children![existingIndex];
// replace children
existing = {
...existing,
expanded: true,
children: thisFolder.sub_folders.map((f) => ({
...f,
expanded: false,
children: undefined,
})),
};
currentParent!.children![existingIndex] = existing;
currentParent = existing;
}
});
return ret;
}, [initialSelectedResult]);
const mergedRootFolders = useMemo(() => {
if (query) {
return rootFolders;
}
return mergeFolderMaps(rootFolders, initialSelectedFolders);
}, [rootFolders, initialSelectedFolders, query]);
const queryFolders: IFolder[] = useMemo(() => {
// construct the folder list from the query result
const ret: IFolder[] = [];
@ -229,11 +336,11 @@ function useFolderMap(query: string, skip?: boolean) {
useEffect(() => {
if (!query) {
setFolderMap(rootFolders);
setFolderMap(mergedRootFolders);
} else {
setFolderMap(queryFolders);
}
}, [query, rootFolders, queryFolders]);
}, [query, mergedRootFolders, queryFolders]);
async function onToggleExpanded(folder: IFolder) {
setFolderMap(folderMap.map(toggleExpandedFn(folder)));
@ -472,8 +579,6 @@ export const SidebarFolderFilter: React.FC<
props.onOpen?.();
}
const { folderMap, onToggleExpanded } = useFolderMap(query, skip);
const option = props.criterionOption ?? FolderCriterionOption;
const { filter, setFilter } = props;
@ -494,6 +599,12 @@ export const SidebarFolderFilter: React.FC<
const multipleSelected =
criterion.value.items.length > 1 || criterion.value.excluded.length > 0;
const { folderMap, onToggleExpanded } = useFolderMap(
query,
skip,
criterion.value.items.map((i) => i.id)
);
function onSelect(folder: IFolder) {
// maintain sub-folder select if present
const depth = subDirsSelected ? -1 : 0;