Skip to content

Commit

Permalink
Merge pull request #3583 from ingef/fix-search-for-multi-struct-node-…
Browse files Browse the repository at this point in the history
…hierarchy-2

Fix search for multi struct node hierarchy
  • Loading branch information
Kadrian authored Oct 2, 2024
2 parents 23b76fd + c238107 commit 356fa08
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 43 deletions.
55 changes: 37 additions & 18 deletions frontend/src/js/concept-trees/ConceptTreeFolder.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import styled from "@emotion/styled";
import { FC } from "react";
import { useMemo } from "react";

import type { ConceptIdT, ConceptT } from "../api/types";
import { useOpenableConcept } from "../concept-trees-open/useOpenableConcept";

import ConceptTree from "./ConceptTree";
import ConceptTreeNodeTextContainer from "./ConceptTreeNodeTextContainer";
import { getConceptById } from "./globalTreeStoreHelper";
import type { SearchT, TreesT } from "./reducer";
import type { LoadedConcept, SearchT, TreesT } from "./reducer";
import { isNodeInSearchResult } from "./selectors";

const Root = styled("div")`
font-size: ${({ theme }) => theme.font.sm};
`;

interface PropsT {
depth: number;
trees: TreesT;
tree: ConceptT;
conceptId: ConceptIdT;
active?: boolean;
openInitially?: boolean;
search: SearchT;
onLoadTree: (id: string) => void;
}

const sumMatchingEntities = (children: string[], initSum: number) => {
return children.reduce((sum, treeId) => {
const rootConcept = getConceptById(treeId);
Expand All @@ -43,7 +32,22 @@ const sumMatchingEntries = (children: string[], initSum: number) => {
}, initSum);
};

const ConceptTreeFolder: FC<PropsT> = ({
export const getNonFolderChildren = (
trees: TreesT,
node: LoadedConcept,
): string[] => {
if (node.detailsAvailable) return node.children || [];

if (!node.children) return [];

// collect all non-folder children, recursively
return node.children.reduce<ConceptIdT[]>((acc, childId) => {
const child = trees[childId];
return acc.concat(getNonFolderChildren(trees, child));
}, []);
};

const ConceptTreeFolder = ({
trees,
tree,
conceptId,
Expand All @@ -52,17 +56,32 @@ const ConceptTreeFolder: FC<PropsT> = ({
active,
onLoadTree,
openInitially,
}: {
depth: number;
trees: TreesT;
tree: ConceptT;
conceptId: ConceptIdT;
active?: boolean;
openInitially?: boolean;
search: SearchT;
onLoadTree: (id: string) => void;
}) => {
const { open, onToggleOpen } = useOpenableConcept({
conceptId,
openInitially,
});

if (!search.showMismatches) {
const shouldRender = isNodeInSearchResult(conceptId, search, tree.children);
const nonFolderChildren = useMemo(
() =>
tree.detailsAvailable ? tree.children : getNonFolderChildren(trees, tree),
[trees, tree],
);

if (!shouldRender) return null;
}
if (
!search.showMismatches &&
!isNodeInSearchResult(conceptId, search, nonFolderChildren)
)
return null;

const matchingEntries =
!tree.children || !tree.matchingEntries
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/js/concept-trees/ConceptTreeListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useMemo } from "react";
import type { ConceptIdT } from "../api/types";

import ConceptTree from "./ConceptTree";
import ConceptTreeFolder from "./ConceptTreeFolder";
import ConceptTreeFolder, { getNonFolderChildren } from "./ConceptTreeFolder";
import { getConceptById } from "./globalTreeStoreHelper";
import type { SearchT, TreesT } from "./reducer";
import { isNodeInSearchResult } from "./selectors";
Expand All @@ -19,7 +20,13 @@ const ConceptTreeListItem = ({
}) => {
const tree = trees[conceptId];

if (!isNodeInSearchResult(conceptId, search, tree.children)) return null;
const nonFolderChildren = useMemo(
() =>
tree.detailsAvailable ? tree.children : getNonFolderChildren(trees, tree),
[trees, tree],
);

if (!isNodeInSearchResult(conceptId, search, nonFolderChildren)) return null;

const rootConcept = getConceptById(conceptId);

Expand Down
32 changes: 16 additions & 16 deletions frontend/src/js/concept-trees/ConceptTreeNodeTextContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useRef } from "react";
import { useRef } from "react";
import { useDrag } from "react-dnd";

import type { ConceptIdT, ConceptT } from "../api/types";
Expand All @@ -15,19 +15,6 @@ import AdditionalInfoHoverable from "../tooltip/AdditionalInfoHoverable";
import ConceptTreeNodeText from "./ConceptTreeNodeText";
import type { SearchT } from "./reducer";

interface PropsT {
conceptId: ConceptIdT;
node: ConceptT;
root: ConceptT;
open: boolean;
depth: number;
active?: boolean;
onTextClick?: () => void;
createQueryElement?: () => ConceptQueryNodeType;
search: SearchT;
isStructFolder?: boolean;
}

function getResultCount(
search: SearchT,
node: ConceptT,
Expand All @@ -44,7 +31,7 @@ function getResultCount(
: null;
}

const ConceptTreeNodeTextContainer: FC<PropsT> = ({
const ConceptTreeNodeTextContainer = ({
conceptId,
node,
root,
Expand All @@ -55,11 +42,24 @@ const ConceptTreeNodeTextContainer: FC<PropsT> = ({
onTextClick,
isStructFolder,
createQueryElement,
}: {
conceptId: ConceptIdT;
node: ConceptT;
root: ConceptT;
open: boolean;
depth: number;
active?: boolean;
onTextClick?: () => void;
createQueryElement?: () => ConceptQueryNodeType;
search: SearchT;
isStructFolder?: boolean;
}) => {
const ref = useRef<HTMLDivElement | null>(null);

const red = exists(node.matchingEntries) && node.matchingEntries === 0;
const resultCount = getResultCount(search, node, conceptId);
const resultCount = isStructFolder
? null
: getResultCount(search, node, conceptId);
const hasChildren = !!node.children && node.children.length > 0;

const item: DragItemConceptTreeNode = {
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/js/concept-trees/globalTreeStoreHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,8 @@ export const globalSearch = async (trees: TreesT, query: string) => {
// TODO: Refactor the state and keep both root trees as well as concept trees in a single format
// Then simply use that here
const formattedTrees = Object.fromEntries(
Object.keys(trees).map((key) => [key, { [key]: trees[key] }]),
Object.entries(trees).map(([key, value]) => [key, { [key]: value }]),
);

const combinedTrees = Object.assign({}, formattedTrees, window.conceptTrees);

const result = Object.keys(combinedTrees)
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/js/concept-trees/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@ export const findConcepts = (
// Count node as 1 already, if it matches
let sum = isNodeIncluded ? 1 : 0;

for (const child of node.children) {
for (const childId of node.children) {
const result = findConcepts(
trees,
treeId,
child,
trees[treeId][child],
childId,
trees[treeId][childId],
query,
intermediateResult,
);

sum += result[child] || 0;
sum += result[childId] || 0;
}

if (sum !== 0) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/js/concept-trees/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const isChildWithinResults = (children: ConceptIdT[], search: SearchT) => {
export const isNodeInSearchResult = (
id: ConceptIdT,
search: SearchT,
children?: ConceptIdT[],
children?: ConceptIdT[], // actual concept tree ids, not folder ids
) => {
if (!search.result) return true;

Expand Down

0 comments on commit 356fa08

Please sign in to comment.