@itwin/presentation-hierarchies
Version:
A package for creating hierarchies based on data in iTwin.js iModels.
80 lines • 4.79 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { concat, defer, EMPTY, filter, finalize, map, merge, mergeAll, mergeMap, take } from "rxjs";
import { assert } from "@itwin/core-bentley";
import { HierarchyNodeKey } from "../../HierarchyNodeKey.js";
import { createNodeIdentifierForLogging, createOperatorLoggingNamespace, hasChildren, LOGGING_NAMESPACE_INTERNAL, } from "../../internal/Common.js";
import { doLog, log } from "../../internal/LoggingUtils.js";
import { partition } from "../../internal/operators/Partition.js";
import { reduceToMergeMapItem } from "../../internal/operators/ReduceToMergeMap.js";
import { ProcessedHierarchyNode, } from "../IModelHierarchyNode.js";
import { mergeInstanceNodes } from "../Utils.js";
const OPERATOR_NAME = "HideNodesInHierarchy";
/** @internal */
export const LOGGING_NAMESPACE = createOperatorLoggingNamespace(OPERATOR_NAME, LOGGING_NAMESPACE_INTERNAL);
/**
* Creates an operator that hides nodes and instead returns their children if the nodes have a `hideInHierarchy` handling param.
*
* @internal
*/
export function createHideNodesInHierarchyOperator(getNodes, stopOnFirstChild) {
return function (nodes) {
const inputNodes = nodes.pipe(
/* v8 ignore next -- @preserve */
log({ category: LOGGING_NAMESPACE, message: (n) => `in: ${createNodeIdentifierForLogging(n)}` }));
const [withFlag, withoutFlag] = partition(inputNodes, (n) => (ProcessedHierarchyNode.isGeneric(n) || ProcessedHierarchyNode.isInstancesNode(n)) &&
!!n.processingParams?.hideInHierarchy);
// Defer to create a new seed for reduce on every subscribe
const withLoadedChildren = defer(() => withFlag.pipe(
/* v8 ignore next -- @preserve */
log({
category: LOGGING_NAMESPACE,
message: (n) => `${createNodeIdentifierForLogging(n)} needs hide and needs children to be loaded`,
}), filter((node) => node.children !== false), reduceToMergeMapItem((node) => createMergeMapKey(node), (node, mergedNode) => {
if (mergedNode) {
if (ProcessedHierarchyNode.isGeneric(mergedNode)) {
// we don't merge generic nodes, just return the first one
return mergedNode;
}
assert(ProcessedHierarchyNode.isInstancesNode(node));
return mergeInstanceNodes(mergedNode, node);
}
return node;
}),
/* v8 ignore next -- @preserve */
log({ category: LOGGING_NAMESPACE, message: (mm) => `created a merge map of size ${mm.size}` }), mergeMap((mm) => [...mm.values()].map((mergedNode) => defer(() => getNodes(mergedNode)))), mergeAll(), map((n) => n)));
return merge(withoutFlag.pipe(
/* v8 ignore next -- @preserve */
log({
category: LOGGING_NAMESPACE,
message: (n) => `${createNodeIdentifierForLogging(n)} doesn't need hide, return the node`,
})), stopOnFirstChild
? concat(
// a small hack to handle situation when we're here to only check if parent node has children and one of them has `hideIfNoChildren` flag
// with a `hasChildren = true` - we just return the hidden node itself in that case to avoid digging deeper into the hierarchy
inputNodes.pipe(filter(hasChildren),
/* v8 ignore next -- @preserve */
log({
category: LOGGING_NAMESPACE,
message: (n) => `\`stopOnFirstChild = true\` and node ${createNodeIdentifierForLogging(n)} is set to always have nodes - return the hidden node without loading children`,
})), EMPTY.pipe(finalize(() => {
/* v8 ignore next -- @preserve */
doLog({
category: LOGGING_NAMESPACE,
message: () => `\`stopOnFirstChild = true\` but none of the nodes had children determined to \`true\` - do load children`,
});
})), withLoadedChildren).pipe(take(1))
: withLoadedChildren).pipe(
/* v8 ignore next -- @preserve */
log({ category: LOGGING_NAMESPACE, message: (n) => `out: ${createNodeIdentifierForLogging(n)}` }));
};
}
function createMergeMapKey(node) {
if (HierarchyNodeKey.isGeneric(node.key)) {
return `${node.key.source ? `${node.key.source}:` : ""}${node.key.id}`;
}
return node.key.instanceKeys[0].className;
}
//# sourceMappingURL=HideNodesInHierarchy.js.map