@itwin/tree-widget-react 4.0.0-alpha.5 → 4.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +2 -1
  3. package/lib/esm/tree-widget-react/TreeWidget.js +1 -1
  4. package/lib/esm/tree-widget-react/TreeWidget.js.map +1 -1
  5. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
  6. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  7. package/lib/esm/tree-widget-react/components/tree-header/ErrorState.js +1 -1
  8. package/lib/esm/tree-widget-react/components/tree-header/ErrorState.js.map +1 -1
  9. package/lib/esm/tree-widget-react/components/tree-header/SearchBox.d.ts +1 -0
  10. package/lib/esm/tree-widget-react/components/tree-header/SearchBox.js +3 -2
  11. package/lib/esm/tree-widget-react/components/tree-header/SearchBox.js.map +1 -1
  12. package/lib/esm/tree-widget-react/components/tree-header/SelectableTree.css +2 -1
  13. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
  14. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +3 -2
  15. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  16. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +9 -2
  17. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +53 -7
  18. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  19. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  20. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js +1 -1
  21. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  22. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +30 -3
  23. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +588 -170
  24. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  25. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +15 -4
  26. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +149 -56
  27. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  28. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +30 -15
  29. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +192 -38
  30. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  31. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeNode.d.ts +18 -3
  32. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeNode.js +30 -3
  33. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeNode.js.map +1 -1
  34. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.d.ts +24 -0
  35. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.js +785 -0
  36. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.js.map +1 -0
  37. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/FilteredTree.d.ts +39 -0
  38. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/FilteredTree.js +221 -0
  39. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/FilteredTree.js.map +1 -0
  40. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +5 -17
  41. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +5 -62
  42. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  43. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.d.ts +2 -0
  44. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js +4 -2
  45. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  46. package/lib/esm/tree-widget-react/components/trees/common/UseNodeHighlighting.d.ts +1 -0
  47. package/lib/esm/tree-widget-react/components/trees/common/UseNodeHighlighting.js +2 -1
  48. package/lib/esm/tree-widget-react/components/trees/common/UseNodeHighlighting.js.map +1 -1
  49. package/lib/esm/tree-widget-react/components/trees/common/UseTelemetryContext.d.ts +1 -0
  50. package/lib/esm/tree-widget-react/components/trees/common/UseTelemetryContext.js +2 -1
  51. package/lib/esm/tree-widget-react/components/trees/common/UseTelemetryContext.js.map +1 -1
  52. package/lib/esm/tree-widget-react/components/trees/common/Utils.d.ts +33 -23
  53. package/lib/esm/tree-widget-react/components/trees/common/Utils.js +60 -47
  54. package/lib/esm/tree-widget-react/components/trees/common/Utils.js.map +1 -1
  55. package/lib/esm/tree-widget-react/components/trees/common/components/BaseTreeRenderer.js +3 -3
  56. package/lib/esm/tree-widget-react/components/trees/common/components/BaseTreeRenderer.js.map +1 -1
  57. package/lib/esm/tree-widget-react/components/trees/common/components/Delayed.d.ts +1 -0
  58. package/lib/esm/tree-widget-react/components/trees/common/components/Delayed.js +1 -0
  59. package/lib/esm/tree-widget-react/components/trees/common/components/Delayed.js.map +1 -1
  60. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.css +1 -0
  61. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.d.ts +1 -0
  62. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js +4 -3
  63. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  64. package/lib/esm/tree-widget-react/components/trees/{categories-tree/internal/ClassNameDefinitions.js → common/components/SkeletonTree.css} +12 -7
  65. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.d.ts +4 -0
  66. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.js +16 -0
  67. package/lib/esm/tree-widget-react/components/trees/common/components/SkeletonTree.js.map +1 -0
  68. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.css +11 -0
  69. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.d.ts +1 -0
  70. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js +8 -7
  71. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  72. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.js +3 -3
  73. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.js.map +1 -1
  74. package/lib/esm/tree-widget-react/components/trees/common/components/UseVisibilityButtonHandler.d.ts +1 -0
  75. package/lib/esm/tree-widget-react/components/trees/common/components/UseVisibilityButtonHandler.js +1 -0
  76. package/lib/esm/tree-widget-react/components/trees/common/components/UseVisibilityButtonHandler.js.map +1 -1
  77. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js +1 -1
  78. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  79. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  80. package/lib/esm/tree-widget-react/components/trees/common/internal/AlwaysAndNeverDrawnElementInfo.d.ts +44 -0
  81. package/lib/esm/tree-widget-react/components/trees/{models-tree → common}/internal/AlwaysAndNeverDrawnElementInfo.js +81 -31
  82. package/lib/esm/tree-widget-react/components/trees/common/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -0
  83. package/lib/esm/tree-widget-react/components/trees/common/internal/ClassNameDefinitions.d.ts +33 -0
  84. package/lib/esm/tree-widget-react/components/trees/common/internal/ClassNameDefinitions.js +37 -0
  85. package/lib/esm/tree-widget-react/components/trees/common/internal/ClassNameDefinitions.js.map +1 -0
  86. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.d.ts +16 -0
  87. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js +72 -0
  88. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js.map +1 -0
  89. package/lib/esm/tree-widget-react/components/trees/common/{Rxjs.d.ts → internal/Rxjs.d.ts} +9 -2
  90. package/lib/esm/tree-widget-react/components/trees/common/{Rxjs.js → internal/Rxjs.js} +9 -2
  91. package/lib/esm/tree-widget-react/components/trees/common/internal/Rxjs.js.map +1 -0
  92. package/lib/esm/tree-widget-react/components/trees/common/{Tooltip.d.ts → internal/Tooltip.d.ts} +5 -1
  93. package/lib/esm/tree-widget-react/components/trees/common/{Tooltip.js → internal/Tooltip.js} +7 -1
  94. package/lib/esm/tree-widget-react/components/trees/common/internal/Tooltip.js.map +1 -0
  95. package/lib/esm/tree-widget-react/components/trees/common/internal/Types.d.ts +14 -0
  96. package/lib/esm/tree-widget-react/components/trees/common/internal/Types.js +6 -0
  97. package/lib/esm/tree-widget-react/components/trees/common/internal/Types.js.map +1 -0
  98. package/lib/esm/tree-widget-react/components/trees/common/internal/UseActiveViewport.js.map +1 -0
  99. package/lib/esm/tree-widget-react/components/trees/common/{UseHierarchiesLocalization.d.ts → internal/UseHierarchiesLocalization.d.ts} +1 -0
  100. package/lib/esm/tree-widget-react/components/trees/common/{UseHierarchiesLocalization.js → internal/UseHierarchiesLocalization.js} +6 -2
  101. package/lib/esm/tree-widget-react/components/trees/common/internal/UseHierarchiesLocalization.js.map +1 -0
  102. package/lib/esm/tree-widget-react/components/trees/common/{UseHierarchyFiltering.d.ts → internal/UseHierarchyFiltering.d.ts} +1 -0
  103. package/lib/esm/tree-widget-react/components/trees/common/{UseHierarchyFiltering.js → internal/UseHierarchyFiltering.js} +4 -3
  104. package/lib/esm/tree-widget-react/components/trees/common/internal/UseHierarchyFiltering.js.map +1 -0
  105. package/lib/esm/tree-widget-react/components/trees/common/{UseIModelChangeListener.d.ts → internal/UseIModelChangeListener.d.ts} +1 -0
  106. package/lib/esm/tree-widget-react/components/trees/common/{UseIModelChangeListener.js → internal/UseIModelChangeListener.js} +1 -0
  107. package/lib/esm/tree-widget-react/components/trees/common/internal/UseIModelChangeListener.js.map +1 -0
  108. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +47 -0
  109. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +101 -0
  110. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
  111. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityChangeEventListener.d.ts +20 -0
  112. package/lib/esm/tree-widget-react/components/trees/{models-tree → common}/internal/VisibilityChangeEventListener.js +17 -9
  113. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityChangeEventListener.js.map +1 -0
  114. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.d.ts +82 -0
  115. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js +234 -0
  116. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js.map +1 -0
  117. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.d.ts +7 -2
  118. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +24 -18
  119. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  120. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.d.ts +1 -1
  121. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js.map +1 -1
  122. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +1 -0
  123. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +1 -0
  124. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  125. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +9 -2
  126. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +44 -34
  127. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  128. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.d.ts +1 -1
  129. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.js.map +1 -1
  130. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +13 -0
  131. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +39 -38
  132. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  133. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +5 -5
  134. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +25 -24
  135. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  136. package/lib/esm/tree-widget-react/components/trees/index.d.ts +4 -2
  137. package/lib/esm/tree-widget-react/components/trees/index.js +4 -2
  138. package/lib/esm/tree-widget-react/components/trees/index.js.map +1 -1
  139. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +2 -2
  140. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js +2 -2
  141. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  142. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +15 -11
  143. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  144. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.d.ts +1 -1
  145. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js +1 -1
  146. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  147. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +7 -2
  148. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +73 -70
  149. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  150. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.d.ts +5 -1
  151. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +73 -49
  152. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  153. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -9
  154. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +4 -6
  155. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  156. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +4 -5
  157. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +54 -104
  158. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  159. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +0 -26
  160. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +75 -291
  161. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  162. package/lib/public/locales/en/TreeWidget.json +55 -6
  163. package/package.json +17 -18
  164. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +0 -37
  165. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +0 -214
  166. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +0 -1
  167. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/ClassNameDefinitions.d.ts +0 -7
  168. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/ClassNameDefinitions.js.map +0 -1
  169. package/lib/esm/tree-widget-react/components/trees/common/Rxjs.js.map +0 -1
  170. package/lib/esm/tree-widget-react/components/trees/common/Tooltip.js.map +0 -1
  171. package/lib/esm/tree-widget-react/components/trees/common/UseActiveViewport.js.map +0 -1
  172. package/lib/esm/tree-widget-react/components/trees/common/UseFiltering.d.ts +0 -11
  173. package/lib/esm/tree-widget-react/components/trees/common/UseFiltering.js +0 -24
  174. package/lib/esm/tree-widget-react/components/trees/common/UseFiltering.js.map +0 -1
  175. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchiesLocalization.js.map +0 -1
  176. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyFiltering.js.map +0 -1
  177. package/lib/esm/tree-widget-react/components/trees/common/UseIModelChangeListener.js.map +0 -1
  178. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +0 -7
  179. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +0 -21
  180. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +0 -1
  181. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +0 -29
  182. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +0 -1
  183. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/VisibilityChangeEventListener.d.ts +0 -12
  184. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/VisibilityChangeEventListener.js.map +0 -1
  185. /package/lib/esm/tree-widget-react/components/trees/common/{UseActiveViewport.d.ts → internal/UseActiveViewport.d.ts} +0 -0
  186. /package/lib/esm/tree-widget-react/components/trees/common/{UseActiveViewport.js → internal/UseActiveViewport.js} +0 -0
@@ -2,23 +2,64 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { defer, EMPTY, from, lastValueFrom, map, mergeMap, toArray } from "rxjs";
6
- import { createNodesQueryClauseFactory, createPredicateBasedHierarchyDefinition } from "@itwin/presentation-hierarchies";
5
+ import { bufferCount, defer, firstValueFrom, from, lastValueFrom, map, merge, mergeMap, of, reduce, toArray } from "rxjs";
6
+ import { assert } from "@itwin/core-bentley";
7
+ import { createNodesQueryClauseFactory, createPredicateBasedHierarchyDefinition, ProcessedHierarchyNode } from "@itwin/presentation-hierarchies";
7
8
  import { createBisInstanceLabelSelectClauseFactory, ECSql } from "@itwin/presentation-shared";
9
+ import { DEFINITION_CONTAINER_CLASS_NAME, INFORMATION_PARTITION_ELEMENT_CLASS_NAME, MODEL_CLASS_NAME, SUB_CATEGORY_CLASS_NAME, SUB_MODELED_ELEMENT_CLASS_NAME, } from "../common/internal/ClassNameDefinitions.js";
10
+ import { createIdsSelector, getClassesByView, getDistinctMapValues, parseIdsSelectorResult, releaseMainThreadOnItemsCount } from "../common/internal/Utils.js";
8
11
  import { FilterLimitExceededError } from "../common/TreeErrors.js";
9
- import { getClassesByView } from "./internal/CategoriesTreeIdsCache.js";
10
- import { DEFINITION_CONTAINER_CLASS, DEFINITION_ELEMENT_CLASS, SUB_CATEGORY_CLASS } from "./internal/ClassNameDefinitions.js";
11
12
  const MAX_FILTERING_INSTANCE_KEY_COUNT = 100;
13
+ /** @internal */
14
+ export const defaultHierarchyConfiguration = {
15
+ hideSubCategories: false,
16
+ showElements: false,
17
+ };
18
+ /** @internal */
12
19
  export class CategoriesTreeDefinition {
13
20
  constructor(props) {
14
21
  this._iModelAccess = props.imodelAccess;
15
- this._viewType = props.viewType;
16
22
  this._idsCache = props.idsCache;
17
23
  this._nodeLabelSelectClauseFactory = createBisInstanceLabelSelectClauseFactory({ classHierarchyInspector: props.imodelAccess });
18
24
  this._selectQueryFactory = createNodesQueryClauseFactory({
19
25
  imodelAccess: props.imodelAccess,
20
26
  instanceLabelSelectClauseFactory: this._nodeLabelSelectClauseFactory,
21
27
  });
28
+ this._hierarchyConfig = props.hierarchyConfig;
29
+ const { categoryClass, elementClass, modelClass } = getClassesByView(props.viewType);
30
+ this._categoryClass = categoryClass;
31
+ this._categoryElementClass = elementClass;
32
+ this._categoryModelClass = modelClass;
33
+ }
34
+ async postProcessNode(node) {
35
+ if (ProcessedHierarchyNode.isGroupingNode(node)) {
36
+ const modelElementsMap = new Map();
37
+ node.children.forEach((child) => {
38
+ let modelEntry = modelElementsMap.get(child.extendedData?.modelId);
39
+ if (!modelEntry) {
40
+ modelEntry = new Set();
41
+ modelElementsMap.set(child.extendedData?.modelId, modelEntry);
42
+ }
43
+ assert(child.key.type === "instances");
44
+ for (const { id } of child.key.instanceKeys) {
45
+ modelEntry.add(id);
46
+ }
47
+ });
48
+ return {
49
+ ...node,
50
+ label: node.label,
51
+ extendedData: {
52
+ ...node.extendedData,
53
+ // add `categoryId` from the first grouped element
54
+ categoryId: node.children[0].extendedData?.categoryId,
55
+ modelElementsMap,
56
+ // `imageId` is assigned to instance nodes at query time, but grouping ones need to
57
+ // be handled during post-processing
58
+ imageId: "icon-ec-class",
59
+ },
60
+ };
61
+ }
62
+ return node;
22
63
  }
23
64
  async getHierarchyDefinition() {
24
65
  this._impl ??= (async () => {
@@ -26,20 +67,37 @@ export class CategoriesTreeDefinition {
26
67
  return createPredicateBasedHierarchyDefinition({
27
68
  classHierarchyInspector: this._iModelAccess,
28
69
  hierarchy: {
29
- rootNodes: async (requestProps) => this.createDefinitionContainersAndCategoriesQuery({ ...requestProps, viewType: this._viewType }),
70
+ rootNodes: async (requestProps) => this.createDefinitionContainersAndCategoriesQuery(requestProps),
30
71
  childNodes: [
31
- {
32
- parentInstancesNodePredicate: "BisCore.Category",
33
- definitions: async (requestProps) => this.createSubcategoryQuery(requestProps),
34
- },
72
+ ...(this._hierarchyConfig.showElements
73
+ ? [
74
+ {
75
+ parentInstancesNodePredicate: this._categoryElementClass,
76
+ definitions: async (requestProps) => this.createElementChildrenQuery(requestProps),
77
+ },
78
+ {
79
+ parentInstancesNodePredicate: SUB_MODELED_ELEMENT_CLASS_NAME,
80
+ definitions: async (requestProps) => this.createISubModeledElementChildrenQuery(requestProps),
81
+ },
82
+ {
83
+ parentInstancesNodePredicate: this._categoryModelClass,
84
+ definitions: async (requestProps) => this.createGeometricModel3dChildrenQuery(requestProps),
85
+ },
86
+ ]
87
+ : []),
88
+ ...(this._hierarchyConfig.hideSubCategories && !this._hierarchyConfig.showElements
89
+ ? []
90
+ : [
91
+ {
92
+ parentInstancesNodePredicate: this._categoryClass,
93
+ definitions: async (requestProps) => this.createCategoryChildrenQuery(requestProps),
94
+ },
95
+ ]),
35
96
  ...(isDefinitionContainerSupported
36
97
  ? [
37
98
  {
38
- parentInstancesNodePredicate: DEFINITION_CONTAINER_CLASS,
39
- definitions: async (requestProps) => this.createDefinitionContainersAndCategoriesQuery({
40
- ...requestProps,
41
- viewType: this._viewType,
42
- }),
99
+ parentInstancesNodePredicate: DEFINITION_CONTAINER_CLASS_NAME,
100
+ definitions: async (requestProps) => this.createDefinitionContainersAndCategoriesQuery(requestProps),
43
101
  },
44
102
  ]
45
103
  : []),
@@ -52,116 +110,215 @@ export class CategoriesTreeDefinition {
52
110
  async defineHierarchyLevel(props) {
53
111
  return (await this.getHierarchyDefinition()).defineHierarchyLevel(props);
54
112
  }
113
+ async createISubModeledElementChildrenQuery({ parentNodeInstanceIds: elementIds, }) {
114
+ // note: we do not apply hierarchy level filtering on this hierarchy level, because it's always
115
+ // hidden - the filter will get applied on the child hierarchy levels
116
+ return [
117
+ {
118
+ fullClassName: this._categoryModelClass,
119
+ query: {
120
+ ecsql: `
121
+ SELECT
122
+ ${await this._selectQueryFactory.createSelectClause({
123
+ ecClassId: { selector: "this.ECClassId" },
124
+ ecInstanceId: { selector: "this.ECInstanceId" },
125
+ nodeLabel: "",
126
+ hideNodeInHierarchy: true,
127
+ hasChildren: true,
128
+ extendedData: {
129
+ isModel: true,
130
+ },
131
+ })}
132
+ FROM ${this._categoryModelClass} this
133
+ WHERE
134
+ this.ModeledElement.Id IN (${elementIds.map(() => "?").join(",")})
135
+ AND NOT this.IsPrivate
136
+ AND this.ECInstanceId IN (SELECT Model.Id FROM ${this._categoryElementClass})
137
+ `,
138
+ bindings: [...elementIds.map((id) => ({ type: "id", value: id }))],
139
+ },
140
+ },
141
+ ];
142
+ }
143
+ async createGeometricModel3dChildrenQuery({ parentNodeInstanceIds: modelIds, instanceFilter, }) {
144
+ const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
145
+ filter: instanceFilter,
146
+ contentClass: { fullName: this._categoryClass, alias: "this" },
147
+ });
148
+ return [
149
+ {
150
+ fullClassName: this._categoryClass,
151
+ query: {
152
+ ecsql: `
153
+ SELECT
154
+ ${await this._selectQueryFactory.createSelectClause({
155
+ ecClassId: { selector: "this.ECClassId" },
156
+ ecInstanceId: { selector: "this.ECInstanceId" },
157
+ nodeLabel: {
158
+ selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
159
+ classAlias: "this",
160
+ className: this._categoryClass,
161
+ }),
162
+ },
163
+ grouping: { byLabel: { action: "merge", groupId: "category" } },
164
+ hasChildren: true,
165
+ extendedData: {
166
+ imageId: "icon-layers",
167
+ isCategory: true,
168
+ modelIds: { selector: createIdsSelector(modelIds) },
169
+ isCategoryOfSubModel: true,
170
+ },
171
+ supportsFiltering: true,
172
+ })}
173
+ FROM ${instanceFilterClauses.from} this
174
+ ${instanceFilterClauses.joins}
175
+ WHERE
176
+ EXISTS (
177
+ SELECT 1
178
+ FROM ${this._categoryElementClass} element
179
+ WHERE
180
+ element.Model.Id IN (${modelIds.join(",")})
181
+ AND element.Category.Id = +this.ECInstanceId
182
+ AND element.Parent.Id IS NULL
183
+ )
184
+ ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
185
+ `,
186
+ },
187
+ },
188
+ ];
189
+ }
55
190
  async createDefinitionContainersAndCategoriesQuery(props) {
56
- const { parentNodeInstanceIds, instanceFilter, viewType } = props;
191
+ const { parentNodeInstanceIds, instanceFilter } = props;
57
192
  const { definitionContainers, categories } = parentNodeInstanceIds === undefined
58
193
  ? await this._idsCache.getRootDefinitionContainersAndCategories()
59
194
  : await this._idsCache.getDirectChildDefinitionContainersAndCategories(parentNodeInstanceIds);
60
- if (categories.length === 0 && definitionContainers.length === 0) {
61
- return [];
195
+ const hierarchyDefinition = new Array();
196
+ if (categories.length > 0) {
197
+ hierarchyDefinition.push(...(await this.createCategoriesQuery({ categories, instanceFilter })));
62
198
  }
63
- const categoriesWithSingleChild = new Array();
64
- const categoriesWithMultipleChildren = new Array();
65
- categories.forEach((category) => {
66
- if (category.childCount > 1) {
67
- categoriesWithMultipleChildren.push(category.id);
68
- }
69
- else {
70
- categoriesWithSingleChild.push(category.id);
71
- }
72
- });
73
- const dataToDetermineHasChildren = categoriesWithSingleChild.length > categoriesWithMultipleChildren.length
74
- ? { ids: categoriesWithMultipleChildren, ifTrue: 1, ifFalse: 0 }
75
- : { ids: categoriesWithSingleChild, ifTrue: 0, ifFalse: 1 };
76
- const { categoryClass } = getClassesByView(viewType);
77
- const [categoriesInstanceFilterClauses, definitionContainersInstanceFilterClauses] = await Promise.all([categoryClass, ...(definitionContainers.length > 0 ? [DEFINITION_CONTAINER_CLASS] : [])].map(async (className) => this._selectQueryFactory.createFilterClauses({
199
+ if (definitionContainers.length > 0) {
200
+ hierarchyDefinition.push(...(await this.createDefinitionContainersQuery({ definitionContainerIds: definitionContainers, instanceFilter })));
201
+ }
202
+ return hierarchyDefinition;
203
+ }
204
+ async createDefinitionContainersQuery({ definitionContainerIds, instanceFilter, }) {
205
+ const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
78
206
  filter: instanceFilter,
79
- contentClass: { fullName: className, alias: "this" },
80
- })));
81
- const definitionContainersQuery = definitionContainers.length > 0
82
- ? `
83
- SELECT
84
- ${await this._selectQueryFactory.createSelectClause({
85
- ecClassId: { selector: ECSql.createRawPropertyValueSelector("this", "ECClassId") },
86
- ecInstanceId: { selector: "this.ECInstanceId" },
87
- nodeLabel: {
88
- selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
89
- classAlias: "this",
90
- className: DEFINITION_CONTAINER_CLASS,
91
- }),
92
- },
93
- extendedData: {
94
- isDefinitionContainer: true,
95
- imageId: "icon-definition-container",
96
- },
97
- hasChildren: true,
98
- supportsFiltering: true,
99
- })}
100
- FROM
101
- ${definitionContainersInstanceFilterClauses.from} this
102
- ${definitionContainersInstanceFilterClauses.joins}
103
- WHERE
104
- this.ECInstanceId IN (${definitionContainers.join(", ")})
105
- ${definitionContainersInstanceFilterClauses.where ? `AND ${definitionContainersInstanceFilterClauses.where}` : ""}
106
- `
107
- : undefined;
108
- const categoriesQuery = categories.length > 0
109
- ? `
110
- SELECT
207
+ contentClass: { fullName: DEFINITION_CONTAINER_CLASS_NAME, alias: "this" },
208
+ });
209
+ return [
210
+ {
211
+ fullClassName: DEFINITION_CONTAINER_CLASS_NAME,
212
+ query: {
213
+ ecsql: `
214
+ SELECT
111
215
  ${await this._selectQueryFactory.createSelectClause({
112
- ecClassId: { selector: ECSql.createRawPropertyValueSelector("this", "ECClassId") },
113
- ecInstanceId: { selector: "this.ECInstanceId" },
114
- nodeLabel: {
115
- selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
116
- classAlias: "this",
117
- className: categoryClass,
118
- }),
119
- },
120
- ...(dataToDetermineHasChildren.ids.length > 0
121
- ? {
122
- hasChildren: {
123
- selector: `
124
- IIF(this.ECInstanceId IN (${dataToDetermineHasChildren.ids.join(",")}),
125
- ${dataToDetermineHasChildren.ifTrue},
126
- ${dataToDetermineHasChildren.ifFalse}
127
- )
128
- `,
216
+ ecClassId: { selector: ECSql.createRawPropertyValueSelector("this", "ECClassId") },
217
+ ecInstanceId: { selector: "this.ECInstanceId" },
218
+ nodeLabel: {
219
+ selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
220
+ classAlias: "this",
221
+ className: DEFINITION_CONTAINER_CLASS_NAME,
222
+ }),
129
223
  },
130
- }
131
- : { hasChildren: !!dataToDetermineHasChildren.ifFalse }),
132
- extendedData: {
133
- description: { selector: "this.Description" },
134
- isCategory: true,
135
- imageId: "icon-layers",
136
- },
137
- supportsFiltering: true,
138
- })}
224
+ extendedData: {
225
+ isDefinitionContainer: true,
226
+ imageId: "icon-definition-container",
227
+ },
228
+ hasChildren: true,
229
+ supportsFiltering: true,
230
+ })}
139
231
  FROM
140
- ${categoriesInstanceFilterClauses.from} this
141
- ${categoriesInstanceFilterClauses.joins}
232
+ ${instanceFilterClauses.from} this
233
+ ${instanceFilterClauses.joins}
142
234
  WHERE
143
- this.ECInstanceId IN (${categories.map((category) => category.id).join(", ")})
144
- ${categoriesInstanceFilterClauses.where ? `AND ${categoriesInstanceFilterClauses.where}` : ""}
145
- `
146
- : undefined;
147
- const queries = [categoriesQuery, definitionContainersQuery].filter((query) => query !== undefined);
235
+ this.ECInstanceId IN (${definitionContainerIds.join(", ")})
236
+ ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
237
+ `,
238
+ },
239
+ },
240
+ ];
241
+ }
242
+ async createCategoriesQuery({ categories, instanceFilter, }) {
243
+ const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
244
+ filter: instanceFilter,
245
+ contentClass: { fullName: this._categoryClass, alias: "this" },
246
+ });
247
+ const categoriesWithMultipleSubCategories = categories
248
+ .filter((categoryInfo) => categoryInfo.subCategoryChildCount > 1)
249
+ .map((categoryInfo) => categoryInfo.id);
250
+ const hasChildrenSelector = () => {
251
+ const conditions = new Array();
252
+ if (!this._hierarchyConfig.hideSubCategories && categoriesWithMultipleSubCategories.length > 0) {
253
+ conditions.push(`this.ECInstanceId IN (${categoriesWithMultipleSubCategories.join(",")})`);
254
+ }
255
+ if (this._hierarchyConfig.showElements) {
256
+ conditions.push(`
257
+ this.ECInstanceId IN (
258
+ SELECT e.Category.Id
259
+ FROM ${this._categoryElementClass} e
260
+ WHERE
261
+ e.Parent.Id IS NULL
262
+ AND e.ECInstanceId NOT IN (SELECT m.ECInstanceId FROM ${this._categoryModelClass} m)
263
+ )`);
264
+ }
265
+ return conditions.length > 0
266
+ ? {
267
+ selector: `IIF(${conditions.join(" OR ")}, 1, 0)`,
268
+ }
269
+ : false;
270
+ };
148
271
  return [
149
272
  {
150
- fullClassName: DEFINITION_ELEMENT_CLASS,
273
+ fullClassName: this._categoryClass,
151
274
  query: {
152
- ecsql: queries.join(" UNION ALL "),
275
+ ecsql: `
276
+ SELECT
277
+ ${await this._selectQueryFactory.createSelectClause({
278
+ ecClassId: { selector: ECSql.createRawPropertyValueSelector("this", "ECClassId") },
279
+ ecInstanceId: { selector: "this.ECInstanceId" },
280
+ nodeLabel: {
281
+ selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
282
+ classAlias: "this",
283
+ className: this._categoryClass,
284
+ }),
285
+ },
286
+ hasChildren: hasChildrenSelector(),
287
+ extendedData: {
288
+ description: { selector: "this.Description" },
289
+ isCategory: true,
290
+ imageId: "icon-layers",
291
+ hasSubCategories: categoriesWithMultipleSubCategories.length > 0
292
+ ? { selector: `IIF(this.ECInstanceId IN (${categoriesWithMultipleSubCategories.join(",")}), true, false) ` }
293
+ : false,
294
+ },
295
+ supportsFiltering: true,
296
+ })}
297
+ FROM
298
+ ${instanceFilterClauses.from} this
299
+ ${instanceFilterClauses.joins}
300
+ WHERE
301
+ this.ECInstanceId IN (${categories.map((category) => category.id).join(", ")})
302
+ ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
303
+ `,
153
304
  },
154
305
  },
155
306
  ];
156
307
  }
157
- async createSubcategoryQuery({ parentNodeInstanceIds: elementIds, instanceFilter, }) {
308
+ async createCategoryChildrenQuery(props) {
309
+ return (await Promise.all([
310
+ ...(!this._hierarchyConfig.hideSubCategories && props.parentNode.extendedData?.hasSubCategories ? [this.createSubCategoriesQuery(props)] : []),
311
+ ...(this._hierarchyConfig.showElements ? [this.createCategoryElementsQuery(props)] : []),
312
+ ])).reduce((acc, levelDefinition) => acc.concat(levelDefinition), new Array());
313
+ }
314
+ async createSubCategoriesQuery({ parentNodeInstanceIds: categoryIds, instanceFilter, }) {
158
315
  const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
159
316
  filter: instanceFilter,
160
- contentClass: { fullName: SUB_CATEGORY_CLASS, alias: "this" },
317
+ contentClass: { fullName: SUB_CATEGORY_CLASS_NAME, alias: "this" },
161
318
  });
162
319
  return [
163
320
  {
164
- fullClassName: SUB_CATEGORY_CLASS,
321
+ fullClassName: SUB_CATEGORY_CLASS_NAME,
165
322
  query: {
166
323
  ecsql: `
167
324
  SELECT
@@ -171,7 +328,7 @@ export class CategoriesTreeDefinition {
171
328
  nodeLabel: {
172
329
  selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
173
330
  classAlias: "this",
174
- className: SUB_CATEGORY_CLASS,
331
+ className: SUB_CATEGORY_CLASS_NAME,
175
332
  }),
176
333
  },
177
334
  extendedData: {
@@ -184,30 +341,149 @@ export class CategoriesTreeDefinition {
184
341
  FROM ${instanceFilterClauses.from} this
185
342
  ${instanceFilterClauses.joins}
186
343
  WHERE
187
- NOT this.IsPrivate AND this.Parent.Id IN (${elementIds.map(() => "?").join(",")})
344
+ NOT this.IsPrivate AND this.Parent.Id IN (${categoryIds.join(",")})
345
+ ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
346
+ `,
347
+ },
348
+ },
349
+ ];
350
+ }
351
+ async createCategoryElementsQuery({ parentNodeInstanceIds: categoryIds, instanceFilter, parentNode, }) {
352
+ const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
353
+ filter: instanceFilter,
354
+ contentClass: { fullName: this._categoryElementClass, alias: "this" },
355
+ });
356
+ const modelIds = parentNode.extendedData?.isCategoryOfSubModel
357
+ ? parseIdsSelectorResult(parentNode.extendedData?.modelIds)
358
+ : [...getDistinctMapValues(await this._idsCache.getCategoriesElementModels(categoryIds))];
359
+ if (modelIds.length === 0) {
360
+ return [];
361
+ }
362
+ const modeledElements = await firstValueFrom(from(modelIds).pipe(mergeMap(async (modelId) => this._idsCache.getCategoriesModeledElements(modelId, categoryIds)), reduce((acc, foundModeledElements) => {
363
+ return acc.concat(foundModeledElements);
364
+ }, new Array())));
365
+ return [
366
+ {
367
+ fullClassName: this._categoryElementClass,
368
+ query: {
369
+ ecsql: `
370
+ SELECT
371
+ ${await this._selectQueryFactory.createSelectClause({
372
+ ecClassId: { selector: "this.ECClassId" },
373
+ ecInstanceId: { selector: "this.ECInstanceId" },
374
+ nodeLabel: {
375
+ selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
376
+ classAlias: "this",
377
+ className: this._categoryElementClass,
378
+ }),
379
+ },
380
+ hasChildren: {
381
+ selector: `
382
+ IIF(
383
+ ${modeledElements.length ? `this.ECInstanceId IN (${modeledElements.join(",")})` : `FALSE`},
384
+ 1,
385
+ IFNULL((
386
+ SELECT 1
387
+ FROM ${this._categoryElementClass} ce
388
+ WHERE ce.Parent.Id = this.ECInstanceId
389
+ LIMIT 1
390
+ ), 0)
391
+ )
392
+ `,
393
+ },
394
+ grouping: {
395
+ byClass: true,
396
+ },
397
+ extendedData: {
398
+ modelId: { selector: "IdToHex(this.Model.Id)" },
399
+ categoryId: { selector: "IdToHex(this.Category.Id)" },
400
+ imageId: "icon-item",
401
+ isElement: true,
402
+ },
403
+ supportsFiltering: true,
404
+ })}
405
+ FROM ${instanceFilterClauses.from} this
406
+ ${parentNode.extendedData?.isCategoryOfSubModel ? "" : `JOIN ${INFORMATION_PARTITION_ELEMENT_CLASS_NAME} ipe ON ipe.ECInstanceId = this.Model.Id`}
407
+ ${instanceFilterClauses.joins}
408
+ WHERE
409
+ this.Category.Id IN (${categoryIds.join(",")})
410
+ AND this.Model.Id IN (${modelIds.join(",")})
411
+ AND this.Parent.Id IS NULL
412
+ ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
413
+ `,
414
+ },
415
+ },
416
+ ];
417
+ }
418
+ async createElementChildrenQuery({ parentNodeInstanceIds: elementIds, instanceFilter, }) {
419
+ const instanceFilterClauses = await this._selectQueryFactory.createFilterClauses({
420
+ filter: instanceFilter,
421
+ contentClass: { fullName: this._categoryElementClass, alias: "this" },
422
+ });
423
+ return [
424
+ {
425
+ fullClassName: this._categoryElementClass,
426
+ query: {
427
+ ecsql: `
428
+ SELECT
429
+ ${await this._selectQueryFactory.createSelectClause({
430
+ ecClassId: { selector: "this.ECClassId" },
431
+ ecInstanceId: { selector: "this.ECInstanceId" },
432
+ nodeLabel: {
433
+ selector: await this._nodeLabelSelectClauseFactory.createSelectClause({
434
+ classAlias: "this",
435
+ className: this._categoryElementClass,
436
+ }),
437
+ },
438
+ hasChildren: {
439
+ selector: `
440
+ IFNULL((
441
+ SELECT 1
442
+ FROM ${this._categoryElementClass} ce
443
+ JOIN ${MODEL_CLASS_NAME} m ON ce.Model.Id = m.ECInstanceId
444
+ WHERE ce.Parent.Id = this.ECInstanceId OR (ce.Model.Id = this.ECInstanceId AND m.IsPrivate = false)
445
+ LIMIT 1
446
+ ), 0)
447
+ `,
448
+ },
449
+ grouping: {
450
+ byClass: true,
451
+ },
452
+ extendedData: {
453
+ modelId: { selector: "IdToHex(this.Model.Id)" },
454
+ categoryId: { selector: "IdToHex(this.Category.Id)" },
455
+ imageId: "icon-item",
456
+ isElement: true,
457
+ },
458
+ supportsFiltering: true,
459
+ })}
460
+ FROM ${instanceFilterClauses.from} this
461
+ ${instanceFilterClauses.joins}
462
+ WHERE
463
+ this.Parent.Id IN (${elementIds.join(",")})
188
464
  ${instanceFilterClauses.where ? `AND ${instanceFilterClauses.where}` : ""}
189
465
  `,
190
- bindings: elementIds.map((id) => ({ type: "id", value: id })),
191
466
  },
192
467
  },
193
468
  ];
194
469
  }
195
470
  static async createInstanceKeyPaths(props) {
196
471
  const labelsFactory = createBisInstanceLabelSelectClauseFactory({ classHierarchyInspector: props.imodelAccess });
197
- return createInstanceKeyPathsFromInstanceLabel({ ...props, labelsFactory, cache: props.idsCache });
472
+ return createInstanceKeyPathsFromInstanceLabel({ ...props, labelsFactory });
198
473
  }
199
474
  }
200
475
  async function createInstanceKeyPathsFromInstanceLabel(props) {
201
- const { definitionContainers, categories } = await props.cache.getAllDefinitionContainersAndCategories();
476
+ const { definitionContainers, categories } = await props.idsCache.getAllDefinitionContainersAndCategories();
202
477
  if (categories.length === 0) {
203
478
  return [];
204
479
  }
205
- const { categoryClass } = getClassesByView(props.viewType);
480
+ const { categoryClass, elementClass } = getClassesByView(props.viewType);
206
481
  const adjustedLabel = props.label.replace(/[%_\\]/g, "\\$&");
207
482
  const CATEGORIES_WITH_LABELS_CTE = "CategoriesWithLabels";
483
+ const ELEMENTS_WITH_LABELS_CTE = "ElementsWithLabels";
208
484
  const SUBCATEGORIES_WITH_LABELS_CTE = "SubCategoriesWithLabels";
209
485
  const DEFINITION_CONTAINERS_WITH_LABELS_CTE = "DefinitionContainersWithLabels";
210
- const [categoryLabelSelectClause, subCategoryLabelSelectClause, definitionContainerLabelSelectClause] = await Promise.all([categoryClass, SUB_CATEGORY_CLASS, ...(definitionContainers.length > 0 ? [DEFINITION_CONTAINER_CLASS] : [])].map(async (className) => props.labelsFactory.createSelectClause({ classAlias: "this", className })));
486
+ const [categoryLabelSelectClause, subCategoryLabelSelectClause, elementLabelSelectClause, definitionContainerLabelSelectClause] = await Promise.all([categoryClass, SUB_CATEGORY_CLASS_NAME, elementClass, ...(definitionContainers.length > 0 ? [DEFINITION_CONTAINER_CLASS_NAME] : [])].map(async (className) => props.labelsFactory.createSelectClause({ classAlias: "this", className })));
211
487
  return lastValueFrom(defer(() => {
212
488
  const ctes = [
213
489
  `${CATEGORIES_WITH_LABELS_CTE}(ClassName, ECInstanceId, ChildCount, DisplayLabel) AS (
@@ -218,23 +494,44 @@ async function createInstanceKeyPathsFromInstanceLabel(props) {
218
494
  ${categoryLabelSelectClause}
219
495
  FROM
220
496
  ${categoryClass} this
221
- JOIN ${SUB_CATEGORY_CLASS} sc ON sc.Parent.Id = this.ECInstanceId
497
+ JOIN ${SUB_CATEGORY_CLASS_NAME} sc ON sc.Parent.Id = this.ECInstanceId
222
498
  WHERE
223
499
  this.ECInstanceId IN (${categories.join(", ")})
224
500
  GROUP BY this.ECInstanceId
225
501
  )`,
226
- `${SUBCATEGORIES_WITH_LABELS_CTE}(ClassName, ECInstanceId, ParentId, DisplayLabel) AS (
227
- SELECT
228
- 'sc',
229
- this.ECInstanceId,
230
- this.Parent.Id,
231
- ${subCategoryLabelSelectClause}
232
- FROM
233
- ${SUB_CATEGORY_CLASS} this
234
- WHERE
235
- NOT this.IsPrivate
236
- AND this.Parent.Id IN (${categories.join(", ")})
237
- )`,
502
+ ...(props.hierarchyConfig.showElements
503
+ ? [
504
+ `${ELEMENTS_WITH_LABELS_CTE}(ClassName, ECInstanceId, ParentId, DisplayLabel) AS (
505
+ SELECT
506
+ 'e',
507
+ this.ECInstanceId,
508
+ this.Parent.Id,
509
+ ${elementLabelSelectClause}
510
+ FROM
511
+ ${elementClass} this
512
+ JOIN ${MODEL_CLASS_NAME} m ON this.Model.Id = m.ECInstanceId
513
+ WHERE
514
+ NOT m.IsPrivate
515
+ AND this.Category.Id IN (${categories.join(", ")})
516
+ )`,
517
+ ]
518
+ : []),
519
+ ...(props.hierarchyConfig.hideSubCategories
520
+ ? []
521
+ : [
522
+ `${SUBCATEGORIES_WITH_LABELS_CTE}(ClassName, ECInstanceId, ParentId, DisplayLabel) AS (
523
+ SELECT
524
+ 'sc',
525
+ this.ECInstanceId,
526
+ this.Parent.Id,
527
+ ${subCategoryLabelSelectClause}
528
+ FROM
529
+ ${SUB_CATEGORY_CLASS_NAME} this
530
+ WHERE
531
+ NOT this.IsPrivate
532
+ AND this.Parent.Id IN (${categories.join(", ")})
533
+ )`,
534
+ ]),
238
535
  ...(definitionContainers.length > 0
239
536
  ? [
240
537
  `${DEFINITION_CONTAINERS_WITH_LABELS_CTE}(ClassName, ECInstanceId, DisplayLabel) AS (
@@ -243,7 +540,7 @@ async function createInstanceKeyPathsFromInstanceLabel(props) {
243
540
  this.ECInstanceId,
244
541
  ${definitionContainerLabelSelectClause}
245
542
  FROM
246
- ${DEFINITION_CONTAINER_CLASS} this
543
+ ${DEFINITION_CONTAINER_CLASS_NAME} this
247
544
  WHERE
248
545
  this.ECInstanceId IN (${definitionContainers.join(", ")})
249
546
  )`,
@@ -252,69 +549,190 @@ async function createInstanceKeyPathsFromInstanceLabel(props) {
252
549
  ];
253
550
  const ecsql = `
254
551
  SELECT * FROM (
255
- SELECT
256
- sc.ClassName AS ClassName,
257
- sc.ECInstanceId AS ECInstanceId
258
- FROM
259
- ${CATEGORIES_WITH_LABELS_CTE} c
260
- JOIN ${SUBCATEGORIES_WITH_LABELS_CTE} sc ON sc.ParentId = c.ECInstanceId
261
- WHERE
262
- c.ChildCount > 1
263
- AND sc.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
264
-
265
- UNION ALL
266
-
267
- SELECT
268
- c.ClassName AS ClassName,
269
- c.ECInstanceId AS ECInstanceId
270
- FROM
271
- ${CATEGORIES_WITH_LABELS_CTE} c
272
- WHERE
273
- c.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
274
-
275
- ${definitionContainers.length > 0
552
+ SELECT
553
+ c.ClassName AS ClassName,
554
+ c.ECInstanceId AS ECInstanceId
555
+ FROM
556
+ ${CATEGORIES_WITH_LABELS_CTE} c
557
+ WHERE
558
+ c.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
559
+ ${props.hierarchyConfig.showElements
276
560
  ? `
277
- UNION ALL
278
- SELECT
279
- dc.ClassName AS ClassName,
280
- dc.ECInstanceId AS ECInstanceId
281
- FROM
282
- ${DEFINITION_CONTAINERS_WITH_LABELS_CTE} dc
283
- WHERE
284
- dc.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
285
- `
561
+ UNION ALL
562
+ SELECT
563
+ e.ClassName AS ClassName,
564
+ e.ECInstanceId AS ECInstanceId
565
+ FROM
566
+ ${ELEMENTS_WITH_LABELS_CTE} e
567
+ WHERE
568
+ e.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
569
+ `
570
+ : ""}
571
+ ${props.hierarchyConfig.hideSubCategories
572
+ ? ""
573
+ : `
574
+ UNION ALL
575
+ SELECT
576
+ sc.ClassName AS ClassName,
577
+ sc.ECInstanceId AS ECInstanceId
578
+ FROM
579
+ ${CATEGORIES_WITH_LABELS_CTE} c
580
+ JOIN ${SUBCATEGORIES_WITH_LABELS_CTE} sc ON sc.ParentId = c.ECInstanceId
581
+ WHERE
582
+ c.ChildCount > 1
583
+ AND sc.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
584
+ `}
585
+ ${definitionContainers.length > 0
586
+ ? `
587
+ UNION ALL
588
+ SELECT
589
+ dc.ClassName AS ClassName,
590
+ dc.ECInstanceId AS ECInstanceId
591
+ FROM
592
+ ${DEFINITION_CONTAINERS_WITH_LABELS_CTE} dc
593
+ WHERE
594
+ dc.DisplayLabel LIKE '%' || ? || '%' ESCAPE '\\'
595
+ `
286
596
  : ""}
287
597
  )
288
598
  ${props.limit === undefined ? `LIMIT ${MAX_FILTERING_INSTANCE_KEY_COUNT + 1}` : props.limit !== "unbounded" ? `LIMIT ${props.limit}` : ""}
289
599
  `;
290
600
  const bindings = [
291
601
  { type: "string", value: adjustedLabel },
292
- { type: "string", value: adjustedLabel },
602
+ ...(props.hierarchyConfig.showElements ? [{ type: "string", value: adjustedLabel }] : []),
603
+ ...(props.hierarchyConfig.hideSubCategories ? [] : [{ type: "string", value: adjustedLabel }]),
293
604
  ...(definitionContainers.length > 0 ? [{ type: "string", value: adjustedLabel }] : []),
294
605
  ];
295
606
  return props.imodelAccess.createQueryReader({ ctes, ecsql, bindings }, { restartToken: "tree-widget/categories-tree/filter-by-label-query", limit: props.limit });
296
- }).pipe(map((row) => ({
297
- className: row.ClassName === "c" ? categoryClass : row.ClassName === "sc" ? SUB_CATEGORY_CLASS : DEFINITION_CONTAINER_CLASS,
298
- id: row.ECInstanceId,
299
- })), toArray(), mergeMap((targetItems) => createInstanceKeyPathsFromTargetItems({ ...props, targetItems })), toArray()));
607
+ }).pipe(map((row) => {
608
+ let className;
609
+ switch (row.ClassName) {
610
+ case "c":
611
+ className = categoryClass;
612
+ break;
613
+ case "sc":
614
+ className = SUB_CATEGORY_CLASS_NAME;
615
+ break;
616
+ case "e":
617
+ className = elementClass;
618
+ break;
619
+ default:
620
+ className = DEFINITION_CONTAINER_CLASS_NAME;
621
+ break;
622
+ }
623
+ return {
624
+ className,
625
+ id: row.ECInstanceId,
626
+ };
627
+ }), toArray(), mergeMap((targetItems) => createInstanceKeyPathsFromTargetItems({ ...props, targetItems })), toArray()));
300
628
  }
301
- function createInstanceKeyPathsFromTargetItems(props) {
302
- const { limit, targetItems, viewType, idsCache } = props;
629
+ function createInstanceKeyPathsFromTargetItems({ targetItems, imodelAccess, viewType, hierarchyConfig, idsCache, limit, }) {
303
630
  if (limit !== "unbounded" && targetItems.length > (limit ?? MAX_FILTERING_INSTANCE_KEY_COUNT)) {
304
631
  throw new FilterLimitExceededError(limit ?? MAX_FILTERING_INSTANCE_KEY_COUNT);
305
632
  }
306
- if (targetItems.length === 0) {
307
- return EMPTY;
308
- }
309
633
  const { categoryClass } = getClassesByView(viewType);
310
- return from(targetItems).pipe(mergeMap(async (targetItem) => {
311
- if (targetItem.className === SUB_CATEGORY_CLASS) {
312
- return { path: await idsCache.getInstanceKeyPaths({ subCategoryId: targetItem.id }), options: { autoExpand: true } };
634
+ return from(targetItems).pipe(releaseMainThreadOnItemsCount(2000), reduce((acc, { id, className }) => {
635
+ if (className === categoryClass) {
636
+ acc.categoryIds.push(id);
637
+ return acc;
638
+ }
639
+ if (className === DEFINITION_CONTAINER_CLASS_NAME) {
640
+ acc.definitionContainerIds.push(id);
641
+ return acc;
642
+ }
643
+ if (className === SUB_CATEGORY_CLASS_NAME) {
644
+ if (hierarchyConfig.hideSubCategories) {
645
+ return acc;
646
+ }
647
+ acc.subCategoryIds.push(id);
648
+ return acc;
313
649
  }
314
- if (targetItem.className === categoryClass) {
315
- return { path: await idsCache.getInstanceKeyPaths({ categoryId: targetItem.id }), options: { autoExpand: true } };
650
+ if (!hierarchyConfig.showElements) {
651
+ return acc;
316
652
  }
317
- return { path: await idsCache.getInstanceKeyPaths({ definitionContainerId: targetItem.id }), options: { autoExpand: true } };
653
+ acc.elementIds.push(id);
654
+ return acc;
655
+ }, {
656
+ definitionContainerIds: new Array(),
657
+ categoryIds: new Array(),
658
+ subCategoryIds: new Array(),
659
+ elementIds: new Array(),
660
+ }), mergeMap((ids) => {
661
+ const elementsLength = ids.elementIds.length;
662
+ return merge(from(ids.definitionContainerIds).pipe(mergeMap(async (id) => ({ path: await idsCache.getInstanceKeyPaths({ definitionContainerId: id }), options: { autoExpand: true } }))), from(ids.categoryIds).pipe(mergeMap(async (id) => ({ path: await idsCache.getInstanceKeyPaths({ categoryId: id }), options: { autoExpand: true } }))), from(ids.subCategoryIds).pipe(mergeMap(async (id) => ({ path: await idsCache.getInstanceKeyPaths({ subCategoryId: id }), options: { autoExpand: true } }))), from(ids.elementIds).pipe(bufferCount(Math.ceil(elementsLength / Math.ceil(elementsLength / 5000))), releaseMainThreadOnItemsCount(1), mergeMap((block) => createGeometricElementInstanceKeyPaths(imodelAccess, idsCache, hierarchyConfig, viewType, block), 10)));
318
663
  }));
319
664
  }
665
+ function createGeometricElementInstanceKeyPaths(imodelAccess, idsCache, hierarchyConfig, viewType, targetItems) {
666
+ const separator = ";";
667
+ const { categoryClass, elementClass, modelClass } = getClassesByView(viewType);
668
+ if (targetItems.length === 0 || !hierarchyConfig.showElements) {
669
+ return of([]);
670
+ }
671
+ return defer(() => {
672
+ const ctes = [
673
+ `CategoriesElementsHierarchy(ECInstanceId, ParentId, ModelId, Path) AS (
674
+ SELECT
675
+ e.ECInstanceId,
676
+ e.Parent.Id,
677
+ e.Model.Id,
678
+ IIF(e.Parent.Id IS NULL,
679
+ 'm${separator}' || CAST(IdToHex([m].[ECInstanceId]) AS TEXT) || '${separator}c${separator}' || CAST(IdToHex([c].[ECInstanceId]) AS TEXT) || '${separator}e${separator}' || CAST(IdToHex([e].[ECInstanceId]) AS TEXT),
680
+ 'e${separator}' || CAST(IdToHex([e].[ECInstanceId]) AS TEXT)
681
+ )
682
+ FROM ${elementClass} e
683
+ LEFT JOIN ${modelClass} m ON (e.Parent.Id IS NULL AND m.ECInstanceId = e.Model.Id)
684
+ LEFT JOIN ${categoryClass} c ON (e.Parent.Id IS NULL AND c.ECInstanceId = e.Category.Id)
685
+ WHERE e.ECInstanceId IN (${targetItems.join(",")})
686
+
687
+ UNION ALL
688
+
689
+ SELECT
690
+ pe.ECInstanceId,
691
+ pe.Parent.Id,
692
+ pe.Model.Id,
693
+ IIF(pe.Parent.Id IS NULL,
694
+ 'm${separator}' || CAST(IdToHex([m].[ECInstanceId]) AS TEXT) || '${separator}c${separator}' || CAST(IdToHex([c].[ECInstanceId]) AS TEXT) || '${separator}e${separator}' || CAST(IdToHex([pe].[ECInstanceId]) AS TEXT) || '${separator}' || ce.Path,
695
+ 'e${separator}' || CAST(IdToHex([pe].[ECInstanceId]) AS TEXT) || '${separator}' || ce.Path
696
+ )
697
+ FROM CategoriesElementsHierarchy ce
698
+ JOIN ${elementClass} pe ON (pe.ECInstanceId = ce.ParentId OR pe.ECInstanceId = ce.ModelId AND ce.ParentId IS NULL)
699
+ LEFT JOIN ${modelClass} m ON (pe.Parent.Id IS NULL AND m.ECInstanceId = pe.Model.Id)
700
+ LEFT JOIN ${categoryClass} c ON (pe.Parent.Id IS NULL AND c.ECInstanceId = pe.Category.Id)
701
+ )`,
702
+ ];
703
+ const ecsql = `
704
+ SELECT mce.Path
705
+ FROM CategoriesElementsHierarchy mce
706
+ WHERE mce.ParentId IS NULL
707
+ `;
708
+ return imodelAccess.createQueryReader({ ctes, ecsql }, { rowFormat: "Indexes", limit: "unbounded", restartToken: "tree-widget/categories-tree/elements-filter-paths-query" });
709
+ }).pipe(releaseMainThreadOnItemsCount(300), map((row) => parseQueryRow(row, separator, elementClass, categoryClass, modelClass)), mergeMap(async (elementHierarchyPath) => {
710
+ const pathToCategory = await idsCache.getInstanceKeyPaths({ categoryId: elementHierarchyPath[0].id });
711
+ pathToCategory.pop(); // category is already included in the element hierarchy path
712
+ const path = [...pathToCategory, ...elementHierarchyPath];
713
+ return { path, options: { autoExpand: true } };
714
+ }));
715
+ }
716
+ function parseQueryRow(row, separator, elementClassName, categoryClassName, modelClassName) {
717
+ const rowElements = row[0].split(separator);
718
+ const path = new Array();
719
+ for (let i = 0; i < rowElements.length; i += 2) {
720
+ switch (rowElements[i]) {
721
+ case "e":
722
+ path.push({ className: elementClassName, id: rowElements[i + 1] });
723
+ break;
724
+ case "c":
725
+ path.push({ className: categoryClassName, id: rowElements[i + 1] });
726
+ break;
727
+ case "m":
728
+ // Ignore first model since it isn't in hierarchy
729
+ if (i === 0) {
730
+ break;
731
+ }
732
+ path.push({ className: modelClassName, id: rowElements[i + 1] });
733
+ break;
734
+ }
735
+ }
736
+ return path;
737
+ }
320
738
  //# sourceMappingURL=CategoriesTreeDefinition.js.map