From c238107cb2c1fc9213fb71da8b4ad591dacdd4cf Mon Sep 17 00:00:00 2001 From: Kai Rollmann Date: Wed, 2 Oct 2024 13:49:05 +0200 Subject: [PATCH] Use the same logic for list item and folder, cleanup --- .../js/concept-trees/ConceptTreeFolder.tsx | 55 +++++++++++++------ .../js/concept-trees/ConceptTreeListItem.tsx | 26 +++------ .../ConceptTreeNodeTextContainer.tsx | 32 +++++------ 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/frontend/src/js/concept-trees/ConceptTreeFolder.tsx b/frontend/src/js/concept-trees/ConceptTreeFolder.tsx index 6462d09643..0dd4c3571a 100644 --- a/frontend/src/js/concept-trees/ConceptTreeFolder.tsx +++ b/frontend/src/js/concept-trees/ConceptTreeFolder.tsx @@ -1,5 +1,5 @@ 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"; @@ -7,24 +7,13 @@ 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); @@ -43,7 +32,22 @@ const sumMatchingEntries = (children: string[], initSum: number) => { }, initSum); }; -const ConceptTreeFolder: FC = ({ +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((acc, childId) => { + const child = trees[childId]; + return acc.concat(getNonFolderChildren(trees, child)); + }, []); +}; + +const ConceptTreeFolder = ({ trees, tree, conceptId, @@ -52,17 +56,32 @@ const ConceptTreeFolder: FC = ({ 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 diff --git a/frontend/src/js/concept-trees/ConceptTreeListItem.tsx b/frontend/src/js/concept-trees/ConceptTreeListItem.tsx index ccf9174a8a..31a4d2f8c7 100644 --- a/frontend/src/js/concept-trees/ConceptTreeListItem.tsx +++ b/frontend/src/js/concept-trees/ConceptTreeListItem.tsx @@ -2,23 +2,11 @@ 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 { LoadedConcept, SearchT, TreesT } from "./reducer"; +import type { SearchT, TreesT } from "./reducer"; import { isNodeInSearchResult } from "./selectors"; -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((acc, childId) => { - const child = trees[childId]; - return acc.concat(getNonFolderChildren(trees, child)); - }, []); -}; - const ConceptTreeListItem = ({ trees, conceptId, @@ -32,11 +20,11 @@ const ConceptTreeListItem = ({ }) => { const tree = trees[conceptId]; - const nonFolderChildren = useMemo(() => { - if (tree.detailsAvailable) return tree.children; - - return getNonFolderChildren(trees, tree); - }, [trees, tree]); + const nonFolderChildren = useMemo( + () => + tree.detailsAvailable ? tree.children : getNonFolderChildren(trees, tree), + [trees, tree], + ); if (!isNodeInSearchResult(conceptId, search, nonFolderChildren)) return null; diff --git a/frontend/src/js/concept-trees/ConceptTreeNodeTextContainer.tsx b/frontend/src/js/concept-trees/ConceptTreeNodeTextContainer.tsx index d951846f63..15007c2e03 100644 --- a/frontend/src/js/concept-trees/ConceptTreeNodeTextContainer.tsx +++ b/frontend/src/js/concept-trees/ConceptTreeNodeTextContainer.tsx @@ -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"; @@ -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, @@ -44,7 +31,7 @@ function getResultCount( : null; } -const ConceptTreeNodeTextContainer: FC = ({ +const ConceptTreeNodeTextContainer = ({ conceptId, node, root, @@ -55,11 +42,24 @@ const ConceptTreeNodeTextContainer: FC = ({ 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(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 = {