@itwin/tree-widget-react 3.15.0 → 3.16.0

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 (126) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/lib/cjs/tree-widget-react/TreeWidget.d.ts +1 -2
  3. package/lib/cjs/tree-widget-react/TreeWidget.js +12 -12
  4. package/lib/cjs/tree-widget-react/TreeWidget.js.map +1 -1
  5. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +2 -3
  6. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +5 -4
  7. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  8. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +4 -7
  9. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +39 -31
  10. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  11. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +6 -2
  12. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  13. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -11
  14. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +45 -36
  15. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  16. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +1 -3
  17. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +30 -30
  18. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  19. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +2 -7
  20. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +8 -21
  21. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  22. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.d.ts +3 -0
  23. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js +7 -7
  24. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js.map +1 -1
  25. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.d.ts +2 -0
  26. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.js +14 -0
  27. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.js.map +1 -0
  28. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +4 -1
  29. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  30. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +4 -6
  31. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +31 -26
  32. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  33. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +1 -1
  34. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +4 -2
  35. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  36. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +1 -5
  37. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +44 -44
  38. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  39. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +3 -6
  40. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +20 -16
  41. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  42. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +3 -1
  43. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  44. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +6 -10
  45. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +107 -64
  46. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  47. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js +18 -8
  48. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  49. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +24 -0
  50. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +46 -0
  51. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  52. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +40 -9
  53. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +68 -39
  54. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  55. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +13 -5
  56. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +20 -14
  57. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  58. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +5 -13
  59. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +70 -60
  60. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  61. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +6 -2
  62. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +189 -197
  63. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  64. package/lib/esm/tree-widget-react/TreeWidget.d.ts +1 -2
  65. package/lib/esm/tree-widget-react/TreeWidget.js +12 -12
  66. package/lib/esm/tree-widget-react/TreeWidget.js.map +1 -1
  67. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +2 -3
  68. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +5 -3
  69. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  70. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +4 -7
  71. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +39 -31
  72. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  73. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +6 -2
  74. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  75. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -11
  76. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +45 -36
  77. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  78. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +1 -3
  79. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +30 -30
  80. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  81. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +2 -7
  82. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +8 -20
  83. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  84. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.d.ts +3 -0
  85. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js +7 -7
  86. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js.map +1 -1
  87. package/lib/esm/tree-widget-react/components/trees/common/useGuid.d.ts +2 -0
  88. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js +11 -0
  89. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js.map +1 -0
  90. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +4 -1
  91. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  92. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +4 -6
  93. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +31 -26
  94. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  95. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +1 -1
  96. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +4 -2
  97. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  98. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +1 -5
  99. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +44 -44
  100. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  101. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +3 -6
  102. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +21 -17
  103. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  104. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +3 -1
  105. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  106. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +6 -10
  107. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +107 -64
  108. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  109. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +18 -8
  110. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  111. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +24 -0
  112. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +44 -0
  113. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  114. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +40 -9
  115. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +70 -41
  116. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  117. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +13 -5
  118. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +22 -16
  119. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  120. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +5 -13
  121. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +71 -61
  122. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  123. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +6 -2
  124. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +192 -200
  125. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  126. package/package.json +8 -8
@@ -1,7 +1,31 @@
1
1
  import type { Observable } from "rxjs";
2
+ import type { Id64Array, Id64String } from "@itwin/core-bentley";
2
3
  /**
3
4
  * Checks if all given models are displayed in given viewport.
4
5
  * @internal
5
6
  */
6
7
  export declare function releaseMainThreadOnItemsCount<T>(elementCount: number): (obs: Observable<T>) => Observable<T>;
8
+ /** @internal */
9
+ export type ChildrenTree<T extends object = {}> = Map<string, T & {
10
+ children?: ChildrenTree<T>;
11
+ }>;
12
+ /** @internal */
13
+ export declare function getIdsFromChildrenTree<T extends object = {}>({ tree, predicate, }: {
14
+ tree: ChildrenTree<T>;
15
+ predicate?: (props: {
16
+ depth: number;
17
+ treeEntry: T;
18
+ }) => boolean;
19
+ }): Set<string>;
20
+ /**
21
+ * Updates children tree with provided `idsToAdd`:
22
+ * - All Ids are added (if they are not yet added) to children tree in the same order they appear in `idsToAdd` array.
23
+ * - `T` is assigned to each entry using the `additionalPropsGetter` function.
24
+ * @internal
25
+ */
26
+ export declare function updateChildrenTree<T extends object = {}>({ tree, additionalPropsGetter, idsToAdd, }: {
27
+ tree: ChildrenTree<T>;
28
+ idsToAdd: Id64Array;
29
+ additionalPropsGetter: (id: Id64String, additionalProps?: T) => T;
30
+ }): void;
7
31
  //# sourceMappingURL=Utils.d.ts.map
@@ -18,4 +18,48 @@ export function releaseMainThreadOnItemsCount(elementCount) {
18
18
  }), concatAll());
19
19
  };
20
20
  }
21
+ /** @internal */
22
+ export function getIdsFromChildrenTree({ tree, predicate, }) {
23
+ function getIdsInternal({ childrenTree, depth }) {
24
+ const result = new Set();
25
+ childrenTree.forEach((entry, id) => {
26
+ if (!predicate || predicate({ depth, treeEntry: entry })) {
27
+ result.add(id);
28
+ }
29
+ if (entry.children) {
30
+ const childrenIds = getIdsInternal({ childrenTree: entry.children, depth: depth + 1 });
31
+ childrenIds.forEach((childId) => result.add(childId));
32
+ }
33
+ });
34
+ return result;
35
+ }
36
+ return getIdsInternal({ childrenTree: tree, depth: 0 });
37
+ }
38
+ /**
39
+ * Updates children tree with provided `idsToAdd`:
40
+ * - All Ids are added (if they are not yet added) to children tree in the same order they appear in `idsToAdd` array.
41
+ * - `T` is assigned to each entry using the `additionalPropsGetter` function.
42
+ * @internal
43
+ */
44
+ export function updateChildrenTree({ tree, additionalPropsGetter, idsToAdd, }) {
45
+ let currentTree = tree;
46
+ for (let i = 0; i < idsToAdd.length; ++i) {
47
+ const id = idsToAdd[i];
48
+ let entry = currentTree.get(id);
49
+ entry = {
50
+ // Whoever calls this function knows how to assign the `T` to entry.
51
+ ...additionalPropsGetter(id, entry),
52
+ // If children already exists, we reuse it.
53
+ // If children do not exist and there are still ids left in the `idsToAdd` array, create a new Map, it will have the next id.
54
+ ...(entry?.children || i + 1 < idsToAdd.length ? { children: entry?.children ?? new Map() } : {}),
55
+ };
56
+ // Always update the set with updated entry.
57
+ currentTree.set(id, entry);
58
+ // This will only happen if it's the last id in `idsToAdd` array. In such case loop can be exited.
59
+ if (!entry.children) {
60
+ break;
61
+ }
62
+ currentTree = entry.children;
63
+ }
64
+ }
21
65
  //# sourceMappingURL=Utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Utils.js","sourceRoot":"","sources":["../../../../../../src/tree-widget-react/components/trees/models-tree/Utils.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAIpE;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAI,YAAoB;IACnE,OAAO,CAAC,GAAkB,EAAiB,EAAE;QAC3C,OAAO,GAAG,CAAC,IAAI,CACb,WAAW,CAAC,YAAY,CAAC,EACzB,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBAC1C,OAAO,GAAG,CAAC;YACb,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,EACF,SAAS,EAAE,CACZ,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { bufferCount, concatAll, concatMap, delay, of } from \"rxjs\";\n\nimport type { Observable } from \"rxjs\";\n\n/**\n * Checks if all given models are displayed in given viewport.\n * @internal\n */\nexport function releaseMainThreadOnItemsCount<T>(elementCount: number) {\n return (obs: Observable<T>): Observable<T> => {\n return obs.pipe(\n bufferCount(elementCount),\n concatMap((buff, i) => {\n const out = of(buff);\n if (i === 0 && buff.length < elementCount) {\n return out;\n }\n return out.pipe(delay(0));\n }),\n concatAll(),\n );\n };\n}\n"]}
1
+ {"version":3,"file":"Utils.js","sourceRoot":"","sources":["../../../../../../src/tree-widget-react/components/trees/models-tree/Utils.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAKpE;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAI,YAAoB;IACnE,OAAO,CAAC,GAAkB,EAAiB,EAAE;QAC3C,OAAO,GAAG,CAAC,IAAI,CACb,WAAW,CAAC,YAAY,CAAC,EACzB,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBAC1C,OAAO,GAAG,CAAC;YACb,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,EACF,SAAS,EAAE,CACZ,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAKD,gBAAgB;AAChB,MAAM,UAAU,sBAAsB,CAAwB,EAC5D,IAAI,EACJ,SAAS,GAIV;IACC,SAAS,cAAc,CAAC,EAAE,YAAY,EAAE,KAAK,EAAoD;QAC/F,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QACjC,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACjC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBACzD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;YACD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,WAAW,GAAG,cAAc,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;gBACvF,WAAW,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,cAAc,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAwB,EACxD,IAAI,EACJ,qBAAqB,EACrB,QAAQ,GAKT;IACC,IAAI,WAAW,GAAoB,IAAI,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,KAAK,GAAG;YACN,oEAAoE;YACpE,GAAG,qBAAqB,CAAC,EAAE,EAAE,KAAK,CAAC;YACnC,2CAA2C;YAC3C,6HAA6H;YAC7H,GAAG,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClG,CAAC;QACF,4CAA4C;QAC5C,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3B,kGAAkG;QAClG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM;QACR,CAAC;QACD,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC/B,CAAC;AACH,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { bufferCount, concatAll, concatMap, delay, of } from \"rxjs\";\n\nimport type { Observable } from \"rxjs\";\nimport type { Id64Array, Id64String } from \"@itwin/core-bentley\";\n\n/**\n * Checks if all given models are displayed in given viewport.\n * @internal\n */\nexport function releaseMainThreadOnItemsCount<T>(elementCount: number) {\n return (obs: Observable<T>): Observable<T> => {\n return obs.pipe(\n bufferCount(elementCount),\n concatMap((buff, i) => {\n const out = of(buff);\n if (i === 0 && buff.length < elementCount) {\n return out;\n }\n return out.pipe(delay(0));\n }),\n concatAll(),\n );\n };\n}\n\n/** @internal */\nexport type ChildrenTree<T extends object = {}> = Map<string, T & { children?: ChildrenTree<T> }>;\n\n/** @internal */\nexport function getIdsFromChildrenTree<T extends object = {}>({\n tree,\n predicate,\n}: {\n tree: ChildrenTree<T>;\n predicate?: (props: { depth: number; treeEntry: T }) => boolean;\n}): Set<string> {\n function getIdsInternal({ childrenTree, depth }: { childrenTree: ChildrenTree<T>; depth: number }): Set<string> {\n const result = new Set<string>();\n childrenTree.forEach((entry, id) => {\n if (!predicate || predicate({ depth, treeEntry: entry })) {\n result.add(id);\n }\n if (entry.children) {\n const childrenIds = getIdsInternal({ childrenTree: entry.children, depth: depth + 1 });\n childrenIds.forEach((childId) => result.add(childId));\n }\n });\n return result;\n }\n return getIdsInternal({ childrenTree: tree, depth: 0 });\n}\n\n/**\n * Updates children tree with provided `idsToAdd`:\n * - All Ids are added (if they are not yet added) to children tree in the same order they appear in `idsToAdd` array.\n * - `T` is assigned to each entry using the `additionalPropsGetter` function.\n * @internal\n */\nexport function updateChildrenTree<T extends object = {}>({\n tree,\n additionalPropsGetter,\n idsToAdd,\n}: {\n tree: ChildrenTree<T>;\n idsToAdd: Id64Array;\n additionalPropsGetter: (id: Id64String, additionalProps?: T) => T;\n}) {\n let currentTree: ChildrenTree<T> = tree;\n for (let i = 0; i < idsToAdd.length; ++i) {\n const id = idsToAdd[i];\n let entry = currentTree.get(id);\n entry = {\n // Whoever calls this function knows how to assign the `T` to entry.\n ...additionalPropsGetter(id, entry),\n // If children already exists, we reuse it.\n // If children do not exist and there are still ids left in the `idsToAdd` array, create a new Map, it will have the next id.\n ...(entry?.children || i + 1 < idsToAdd.length ? { children: entry?.children ?? new Map() } : {}),\n };\n // Always update the set with updated entry.\n currentTree.set(id, entry);\n // This will only happen if it's the last id in `idsToAdd` array. In such case loop can be exited.\n if (!entry.children) {\n break;\n }\n currentTree = entry.children;\n }\n}\n"]}
@@ -1,22 +1,53 @@
1
- import type { Id64Arg, Id64Set, Id64String } from "@itwin/core-bentley";
2
1
  import type { Observable } from "rxjs";
2
+ import type { GuidString, Id64Arg, Id64String } from "@itwin/core-bentley";
3
3
  import type { Viewport } from "@itwin/core-frontend";
4
+ import type { ChildrenTree } from "../Utils.js";
4
5
  /** @internal */
5
6
  export declare const SET_CHANGE_DEBOUNCE_TIME = 20;
6
7
  type SetType = "always" | "never";
7
- /** @internal */
8
- export interface AlwaysOrNeverDrawnElementsQueryProps {
9
- modelId: Id64String;
10
- categoryIds?: Id64Arg;
8
+ interface GetElementsTreeByModelProps {
9
+ /** Only always/never drawn elements that have the specified models will be returned. */
10
+ modelIds: Id64Arg;
11
+ /**
12
+ * The type of set from which tree should be retrieved.
13
+ * `always` - ChildrenTree will be created from `alwaysDrawn` set.
14
+ * `never` - ChildrenTree will be created from `neverDrawn` set.
15
+ */
16
+ setType: SetType;
17
+ }
18
+ interface GetElementsTreeByCategoryProps extends GetElementsTreeByModelProps {
19
+ /**
20
+ * Categories of root elements.
21
+ *
22
+ * Elements are filtered by given categories. Children of those elements are also included, no matter their category.
23
+ */
24
+ categoryIds: Id64Arg;
11
25
  }
26
+ interface GetElementsTreeByElementProps extends GetElementsTreeByCategoryProps {
27
+ /** Path to element for which to get its' child always/never drawn elements. When undefined, models and categories will be used to get the always/never drawn elements. */
28
+ parentElementIdsPath: Array<Id64Arg>;
29
+ }
30
+ /** @internal */
31
+ export type GetElementsTreeProps = GetElementsTreeByModelProps | GetElementsTreeByCategoryProps | GetElementsTreeByElementProps;
32
+ /**
33
+ * - `categoryId` is assigned only to the elements in always/never drawn set.
34
+ * - `isInAlwaysOrNeverDrawnSet` flag determines if key (ECInstanceId) is in always/never set.
35
+ * @internal
36
+ */
37
+ export type MapEntry = {
38
+ isInAlwaysOrNeverDrawnSet: true;
39
+ categoryId: Id64String;
40
+ } | {
41
+ isInAlwaysOrNeverDrawnSet: false;
42
+ };
43
+ type CachedNodesMap = ChildrenTree<MapEntry>;
12
44
  export declare class AlwaysAndNeverDrawnElementInfo implements Disposable {
13
45
  #private;
14
- constructor(viewport: Viewport);
46
+ constructor(viewport: Viewport, componentId?: GuidString);
15
47
  suppressChangeEvents(): void;
16
48
  resumeChangeEvents(): void;
17
- getElements({ setType, modelId, categoryIds }: {
18
- setType: SetType;
19
- } & AlwaysOrNeverDrawnElementsQueryProps): Observable<Id64Set>;
49
+ getElementsTree({ setType, modelIds, ...props }: GetElementsTreeProps): Observable<CachedNodesMap>;
50
+ private getChildrenTree;
20
51
  private createCacheEntryObservable;
21
52
  [Symbol.dispose](): void;
22
53
  private queryAlwaysOrNeverDrawnElementInfo;
@@ -2,10 +2,10 @@
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 { BehaviorSubject, debounceTime, defer, EMPTY, filter, first, fromEventPattern, map, mergeMap, of, reduce, scan, share, shareReplay, startWith, Subject, switchMap, take, takeUntil, tap, } from "rxjs";
6
- import { Id64 } from "@itwin/core-bentley";
5
+ import { BehaviorSubject, bufferCount, debounceTime, defer, EMPTY, filter, first, from, fromEventPattern, map, mergeMap, of, reduce, scan, share, shareReplay, startWith, Subject, switchMap, take, takeUntil, tap, } from "rxjs";
6
+ import { Guid, Id64 } from "@itwin/core-bentley";
7
7
  import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
8
- import { pushToMap } from "../../common/Utils.js";
8
+ import { releaseMainThreadOnItemsCount, updateChildrenTree } from "../Utils.js";
9
9
  /** @internal */
10
10
  export const SET_CHANGE_DEBOUNCE_TIME = 20;
11
11
  export class AlwaysAndNeverDrawnElementInfo {
@@ -14,14 +14,18 @@ export class AlwaysAndNeverDrawnElementInfo {
14
14
  #neverDrawn;
15
15
  #disposeSubject = new Subject();
16
16
  #viewport;
17
+ #componentId;
18
+ #componentName;
17
19
  #suppressors;
18
20
  #suppress = new Subject();
19
- constructor(viewport) {
21
+ constructor(viewport, componentId) {
20
22
  this.#viewport = viewport;
21
23
  this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable("always") };
22
24
  this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable("never") };
23
25
  this.#suppressors = this.#suppress.pipe(scan((acc, suppress) => acc + (suppress ? 1 : -1), 0), startWith(0), shareReplay(1));
24
26
  this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];
27
+ this.#componentId = componentId ?? Guid.createValue();
28
+ this.#componentName = "AlwaysAndNeverDrawnElementInfo";
25
29
  }
26
30
  suppressChangeEvents() {
27
31
  this.#suppress.next(true);
@@ -29,29 +33,43 @@ export class AlwaysAndNeverDrawnElementInfo {
29
33
  resumeChangeEvents() {
30
34
  this.#suppress.next(false);
31
35
  }
32
- getElements({ setType, modelId, categoryIds }) {
36
+ getElementsTree({ setType, modelIds, ...props }) {
33
37
  const cache = setType === "always" ? this.#alwaysDrawn : this.#neverDrawn;
34
- const getElements = categoryIds
35
- ? (entry) => {
36
- const result = new Set();
37
- for (const categoryId of Id64.iterable(categoryIds)) {
38
- const elements = entry?.get(modelId)?.get(categoryId);
39
- elements?.forEach((elementId) => result.add(elementId));
40
- }
41
- return result;
38
+ const getElements = (rootTreeNodes) => {
39
+ if (!rootTreeNodes) {
40
+ return new Map();
42
41
  }
43
- : (entry) => {
44
- const modelEntry = entry?.get(modelId);
45
- const elements = new Set();
46
- for (const set of modelEntry?.values() ?? []) {
47
- set.forEach((id) => elements.add(id));
42
+ const pathToElements = [modelIds];
43
+ if ("categoryIds" in props && props.categoryIds) {
44
+ pathToElements.push(props.categoryIds);
45
+ if ("parentElementIdsPath" in props && props.parentElementIdsPath) {
46
+ props.parentElementIdsPath.forEach((parentElementIds) => pathToElements.push(parentElementIds));
48
47
  }
49
- return elements;
50
- };
48
+ }
49
+ return this.getChildrenTree({ currentChildrenTree: rootTreeNodes, pathToElements, currentIdsIndex: 0 });
50
+ };
51
51
  return !cache.latestCacheEntryValue
52
52
  ? cache.cacheEntryObs.pipe(map(getElements))
53
53
  : this.#suppressors.pipe(take(1), mergeMap((suppressionCount) => suppressionCount > 0 ? of(cache.latestCacheEntryValue).pipe(map(getElements)) : cache.cacheEntryObs.pipe(map(getElements))));
54
54
  }
55
+ getChildrenTree({ currentChildrenTree, pathToElements, currentIdsIndex, }) {
56
+ if (currentIdsIndex >= pathToElements.length) {
57
+ return currentChildrenTree;
58
+ }
59
+ const result = new Map();
60
+ for (const parentId of Id64.iterable(pathToElements[currentIdsIndex])) {
61
+ const entry = currentChildrenTree.get(parentId);
62
+ if (entry?.children) {
63
+ const childrenTreeOfChildren = this.getChildrenTree({
64
+ currentChildrenTree: entry.children,
65
+ pathToElements,
66
+ currentIdsIndex: currentIdsIndex + 1,
67
+ });
68
+ childrenTreeOfChildren.forEach((val, childId) => result.set(childId, val));
69
+ }
70
+ }
71
+ return result;
72
+ }
55
73
  createCacheEntryObservable(setType) {
56
74
  const event = setType === "always" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;
57
75
  const getIds = setType === "always" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;
@@ -78,7 +96,7 @@ export class AlwaysAndNeverDrawnElementInfo {
78
96
  resetOnRefCountZero: false,
79
97
  }),
80
98
  // Wait until the result is available.
81
- first((x) => !!x));
99
+ first((x) => !!x, new Map()));
82
100
  return obs;
83
101
  }
84
102
  [Symbol.dispose]() {
@@ -87,16 +105,22 @@ export class AlwaysAndNeverDrawnElementInfo {
87
105
  this.#disposeSubject.next();
88
106
  }
89
107
  queryAlwaysOrNeverDrawnElementInfo(set, requestId) {
90
- const elementInfo = set?.size ? this.queryElementInfo([...set], requestId) : EMPTY;
91
- return elementInfo.pipe(reduce((state, val) => {
92
- let entry = state.get(val.modelId);
93
- if (!entry) {
94
- entry = new Map();
95
- state.set(val.modelId, entry);
96
- }
97
- pushToMap(entry, val.categoryId, val.elementId);
98
- return state;
99
- }, new Map()));
108
+ const elementInfo = set?.size
109
+ ? from(set).pipe(bufferCount(Math.ceil(set.size / Math.ceil(set.size / 5000))), mergeMap((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10))
110
+ : EMPTY;
111
+ return elementInfo.pipe(releaseMainThreadOnItemsCount(1000), reduce((acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {
112
+ const elementIdInList = elementsPath[elementsPath.length - 1];
113
+ const additionalPropsGetter = (id, additionalProps) => {
114
+ if (id === elementIdInList) {
115
+ // Last element in elementsPath is in always/never drawn set. We want to mark, that it is in the set, and save it's categoryId.
116
+ return { isInAlwaysOrNeverDrawnSet: true, categoryId };
117
+ }
118
+ // Existing entries can keep their value, if it's a new entry it's not in the list.
119
+ return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };
120
+ };
121
+ updateChildrenTree({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });
122
+ return acc;
123
+ }, (() => new Map())()));
100
124
  }
101
125
  queryElementInfo(elementIds, requestId) {
102
126
  return defer(() => {
@@ -104,37 +128,42 @@ export class AlwaysAndNeverDrawnElementInfo {
104
128
  return executor.createQueryReader({
105
129
  ctes: [
106
130
  `
107
- ElementInfo(elementId, modelId, categoryId, parentId) AS (
131
+ ElementInfo(modelId, rootCategoryId, categoryId, parentId, elementsPath) AS (
108
132
  SELECT
109
- ECInstanceId elementId,
110
133
  Model.Id modelId,
134
+ Category.Id rootCategoryId,
111
135
  Category.Id categoryId,
112
- Parent.Id parentId
136
+ Parent.Id parentId,
137
+ CAST(IdToHex(ECInstanceId) AS TEXT) elementsPath
113
138
  FROM bis.GeometricElement3d
114
139
  WHERE InVirtualSet(?, ECInstanceId)
115
140
 
116
141
  UNION ALL
117
142
 
118
143
  SELECT
119
- e.elementId,
120
- e.modelId,
121
- p.Category.Id categoryId,
122
- p.Parent.Id parentId
144
+ e.modelId modelId,
145
+ p.Category.Id rootCategoryId,
146
+ e.categoryId categoryId,
147
+ p.Parent.Id parentId,
148
+ CAST(IdToHex(p.ECInstanceId) AS TEXT) || ';' || e.elementsPath
123
149
  FROM bis.GeometricElement3d p
124
150
  JOIN ElementInfo e ON p.ECInstanceId = e.parentId
125
151
  )
126
152
  `,
127
153
  ],
128
154
  ecsql: `
129
- SELECT elementId, modelId, categoryId
155
+ SELECT elementsPath elementsPath, modelId modelId, categoryId categoryId, rootCategoryId rootCategoryId
130
156
  FROM ElementInfo
131
157
  WHERE parentId IS NULL
132
158
  `,
133
159
  bindings: [{ type: "idset", value: elementIds }],
134
160
  }, {
135
- restartToken: `ModelsTreeVisibilityHandler/${requestId}`,
161
+ rowFormat: "ECSqlPropertyNames",
162
+ restartToken: `${this.#componentName}/${this.#componentId}/${requestId}`,
136
163
  });
137
- }).pipe(map((row) => ({ elementId: row.elementId, modelId: row.modelId, categoryId: row.categoryId })));
164
+ }).pipe(map((row) => {
165
+ return { elementsPath: row.elementsPath.split(";"), modelId: row.modelId, categoryId: row.categoryId, rootCategoryId: row.rootCategoryId };
166
+ }));
138
167
  }
139
168
  }
140
169
  //# sourceMappingURL=AlwaysAndNeverDrawnElementInfo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AlwaysAndNeverDrawnElementInfo.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n BehaviorSubject,\n debounceTime,\n defer,\n EMPTY,\n filter,\n first,\n fromEventPattern,\n map,\n mergeMap,\n of,\n reduce,\n scan,\n share,\n shareReplay,\n startWith,\n Subject,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs\";\nimport { Id64 } from \"@itwin/core-bentley\";\nimport { createECSqlQueryExecutor } from \"@itwin/presentation-core-interop\";\nimport { pushToMap } from \"../../common/Utils.js\";\n\nimport type { Id64Arg, Id64Array, Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { Viewport } from \"@itwin/core-frontend\";\n\n/** @internal */\nexport const SET_CHANGE_DEBOUNCE_TIME = 20;\n\ntype SetType = \"always\" | \"never\";\n\n/** @internal */\nexport interface AlwaysOrNeverDrawnElementsQueryProps {\n modelId: Id64String;\n categoryIds?: Id64Arg;\n}\n\ntype CacheEntry = Map<Id64String, Map<Id64String, Id64Set>>;\n\nexport class AlwaysAndNeverDrawnElementInfo implements Disposable {\n #subscriptions: Subscription[];\n #alwaysDrawn: { cacheEntryObs: Observable<CacheEntry>; latestCacheEntryValue?: CacheEntry };\n #neverDrawn: { cacheEntryObs: Observable<CacheEntry>; latestCacheEntryValue?: CacheEntry };\n #disposeSubject = new Subject<void>();\n readonly #viewport: Viewport;\n\n #suppressors: Observable<number>;\n #suppress = new Subject<boolean>();\n\n constructor(viewport: Viewport) {\n this.#viewport = viewport;\n this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"always\") };\n this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"never\") };\n this.#suppressors = this.#suppress.pipe(\n scan((acc, suppress) => acc + (suppress ? 1 : -1), 0),\n startWith(0),\n shareReplay(1),\n );\n this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];\n }\n\n public suppressChangeEvents() {\n this.#suppress.next(true);\n }\n\n public resumeChangeEvents() {\n this.#suppress.next(false);\n }\n\n public getElements({ setType, modelId, categoryIds }: { setType: SetType } & AlwaysOrNeverDrawnElementsQueryProps): Observable<Id64Set> {\n const cache = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n const getElements = categoryIds\n ? (entry: CacheEntry | undefined) => {\n const result = new Set<Id64String>();\n for (const categoryId of Id64.iterable(categoryIds)) {\n const elements = entry?.get(modelId)?.get(categoryId);\n elements?.forEach((elementId) => result.add(elementId));\n }\n return result;\n }\n : (entry: CacheEntry | undefined) => {\n const modelEntry = entry?.get(modelId);\n const elements = new Set<Id64String>();\n for (const set of modelEntry?.values() ?? []) {\n set.forEach((id) => elements.add(id));\n }\n return elements;\n };\n\n return !cache.latestCacheEntryValue\n ? cache.cacheEntryObs.pipe(map(getElements))\n : this.#suppressors.pipe(\n take(1),\n mergeMap((suppressionCount) =>\n suppressionCount > 0 ? of(cache.latestCacheEntryValue).pipe(map(getElements)) : cache.cacheEntryObs.pipe(map(getElements)),\n ),\n );\n }\n\n private createCacheEntryObservable(setType: SetType): Observable<CacheEntry> {\n const event = setType === \"always\" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;\n const getIds = setType === \"always\" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;\n\n const resultSubject = new BehaviorSubject<CacheEntry | undefined>(undefined);\n\n const obs = fromEventPattern(\n (handler) => event.addListener(handler),\n (handler) => event.removeListener(handler),\n ).pipe(\n // Fire the observable once at the beginning\n startWith(undefined),\n // Reset result subject as soon as a new event is emitted.\n // This will make newly subscribed observers wait for the debounce period to pass\n // instead of consuming the cached value which at this point becomes invalid.\n tap(() => resultSubject.next(undefined)),\n // Check if cache updates are not suppressed.\n switchMap(() =>\n this.#suppressors.pipe(\n filter((suppressors) => suppressors === 0),\n take(1),\n ),\n ),\n debounceTime(SET_CHANGE_DEBOUNCE_TIME),\n // Cancel pending request if dispose() is called.\n takeUntil(this.#disposeSubject),\n // If multiple requests are sent at once, preserve only the result of the newest.\n switchMap(() => this.queryAlwaysOrNeverDrawnElementInfo(getIds(), `${setType}Drawn`)),\n tap((cacheEntry) => {\n const value = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n value.latestCacheEntryValue = cacheEntry;\n }),\n // Share the result by using a subject which always emits the saved result.\n share({\n connector: () => resultSubject,\n resetOnRefCountZero: false,\n }),\n // Wait until the result is available.\n first((x): x is CacheEntry => !!x),\n );\n return obs;\n }\n\n public [Symbol.dispose]() {\n this.#subscriptions.forEach((x) => x.unsubscribe());\n this.#subscriptions = [];\n this.#disposeSubject.next();\n }\n\n private queryAlwaysOrNeverDrawnElementInfo(set: Id64Set | undefined, requestId: string): Observable<CacheEntry> {\n const elementInfo = set?.size ? this.queryElementInfo([...set], requestId) : EMPTY;\n return elementInfo.pipe(\n reduce((state, val) => {\n let entry = state.get(val.modelId);\n if (!entry) {\n entry = new Map();\n state.set(val.modelId, entry);\n }\n pushToMap(entry, val.categoryId, val.elementId);\n return state;\n }, new Map<Id64String, Map<Id64String, Id64Set>>()),\n );\n }\n\n private queryElementInfo(\n elementIds: Id64Array,\n requestId: string,\n ): Observable<{\n elementId: Id64String;\n modelId: Id64String;\n categoryId: Id64String;\n }> {\n return defer(() => {\n const executor = createECSqlQueryExecutor(this.#viewport.iModel);\n return executor.createQueryReader(\n {\n ctes: [\n `\n ElementInfo(elementId, modelId, categoryId, parentId) AS (\n SELECT\n ECInstanceId elementId,\n Model.Id modelId,\n Category.Id categoryId,\n Parent.Id parentId\n FROM bis.GeometricElement3d\n WHERE InVirtualSet(?, ECInstanceId)\n\n UNION ALL\n\n SELECT\n e.elementId,\n e.modelId,\n p.Category.Id categoryId,\n p.Parent.Id parentId\n FROM bis.GeometricElement3d p\n JOIN ElementInfo e ON p.ECInstanceId = e.parentId\n )\n `,\n ],\n ecsql: `\n SELECT elementId, modelId, categoryId\n FROM ElementInfo\n WHERE parentId IS NULL\n `,\n bindings: [{ type: \"idset\", value: elementIds }],\n },\n {\n restartToken: `ModelsTreeVisibilityHandler/${requestId}`,\n },\n );\n }).pipe(map((row) => ({ elementId: row.elementId, modelId: row.modelId, categoryId: row.categoryId })));\n }\n}\n"]}
1
+ {"version":3,"file":"AlwaysAndNeverDrawnElementInfo.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n BehaviorSubject,\n bufferCount,\n debounceTime,\n defer,\n EMPTY,\n filter,\n first,\n from,\n fromEventPattern,\n map,\n mergeMap,\n of,\n reduce,\n scan,\n share,\n shareReplay,\n startWith,\n Subject,\n switchMap,\n take,\n takeUntil,\n tap,\n} from \"rxjs\";\nimport { Guid, Id64 } from \"@itwin/core-bentley\";\nimport { createECSqlQueryExecutor } from \"@itwin/presentation-core-interop\";\nimport { releaseMainThreadOnItemsCount, updateChildrenTree } from \"../Utils.js\";\n\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { GuidString, Id64Arg, Id64Array, Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport type { Viewport } from \"@itwin/core-frontend\";\nimport type { ChildrenTree } from \"../Utils.js\";\n\n/** @internal */\nexport const SET_CHANGE_DEBOUNCE_TIME = 20;\n\ntype SetType = \"always\" | \"never\";\n\ninterface GetElementsTreeByModelProps {\n /** Only always/never drawn elements that have the specified models will be returned. */\n modelIds: Id64Arg;\n /**\n * The type of set from which tree should be retrieved.\n * `always` - ChildrenTree will be created from `alwaysDrawn` set.\n * `never` - ChildrenTree will be created from `neverDrawn` set.\n */\n setType: SetType;\n}\ninterface GetElementsTreeByCategoryProps extends GetElementsTreeByModelProps {\n /**\n * Categories of root elements.\n *\n * Elements are filtered by given categories. Children of those elements are also included, no matter their category.\n */\n categoryIds: Id64Arg;\n}\ninterface GetElementsTreeByElementProps extends GetElementsTreeByCategoryProps {\n /** Path to element for which to get its' child always/never drawn elements. When undefined, models and categories will be used to get the always/never drawn elements. */\n parentElementIdsPath: Array<Id64Arg>;\n}\n\n/** @internal */\nexport type GetElementsTreeProps = GetElementsTreeByModelProps | GetElementsTreeByCategoryProps | GetElementsTreeByElementProps;\n\n/**\n * - `categoryId` is assigned only to the elements in always/never drawn set.\n * - `isInAlwaysOrNeverDrawnSet` flag determines if key (ECInstanceId) is in always/never set.\n * @internal\n */\nexport type MapEntry = { isInAlwaysOrNeverDrawnSet: true; categoryId: Id64String } | { isInAlwaysOrNeverDrawnSet: false };\n\ntype CachedNodesMap = ChildrenTree<MapEntry>;\n\nexport class AlwaysAndNeverDrawnElementInfo implements Disposable {\n #subscriptions: Subscription[];\n #alwaysDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #neverDrawn: { cacheEntryObs: Observable<CachedNodesMap>; latestCacheEntryValue?: CachedNodesMap };\n #disposeSubject = new Subject<void>();\n readonly #viewport: Viewport;\n #componentId: GuidString;\n #componentName: string;\n\n #suppressors: Observable<number>;\n #suppress = new Subject<boolean>();\n\n constructor(viewport: Viewport, componentId?: GuidString) {\n this.#viewport = viewport;\n this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"always\") };\n this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable(\"never\") };\n this.#suppressors = this.#suppress.pipe(\n scan((acc, suppress) => acc + (suppress ? 1 : -1), 0),\n startWith(0),\n shareReplay(1),\n );\n this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];\n this.#componentId = componentId ?? Guid.createValue();\n this.#componentName = \"AlwaysAndNeverDrawnElementInfo\";\n }\n\n public suppressChangeEvents() {\n this.#suppress.next(true);\n }\n\n public resumeChangeEvents() {\n this.#suppress.next(false);\n }\n\n public getElementsTree({ setType, modelIds, ...props }: GetElementsTreeProps): Observable<CachedNodesMap> {\n const cache = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n const getElements = (rootTreeNodes: CachedNodesMap | undefined): CachedNodesMap => {\n if (!rootTreeNodes) {\n return new Map();\n }\n const pathToElements = [modelIds];\n if (\"categoryIds\" in props && props.categoryIds) {\n pathToElements.push(props.categoryIds);\n if (\"parentElementIdsPath\" in props && props.parentElementIdsPath) {\n props.parentElementIdsPath.forEach((parentElementIds) => pathToElements.push(parentElementIds));\n }\n }\n return this.getChildrenTree({ currentChildrenTree: rootTreeNodes, pathToElements, currentIdsIndex: 0 });\n };\n\n return !cache.latestCacheEntryValue\n ? cache.cacheEntryObs.pipe(map(getElements))\n : this.#suppressors.pipe(\n take(1),\n mergeMap((suppressionCount) =>\n suppressionCount > 0 ? of(cache.latestCacheEntryValue).pipe(map(getElements)) : cache.cacheEntryObs.pipe(map(getElements)),\n ),\n );\n }\n\n private getChildrenTree<T extends object>({\n currentChildrenTree,\n pathToElements,\n currentIdsIndex,\n }: {\n currentChildrenTree: ChildrenTree<T>;\n pathToElements: Array<Id64Arg>;\n currentIdsIndex: number;\n }): ChildrenTree<T> {\n if (currentIdsIndex >= pathToElements.length) {\n return currentChildrenTree;\n }\n const result: ChildrenTree<T> = new Map();\n for (const parentId of Id64.iterable(pathToElements[currentIdsIndex])) {\n const entry = currentChildrenTree.get(parentId);\n if (entry?.children) {\n const childrenTreeOfChildren = this.getChildrenTree({\n currentChildrenTree: entry.children,\n pathToElements,\n currentIdsIndex: currentIdsIndex + 1,\n });\n childrenTreeOfChildren.forEach((val, childId) => result.set(childId, val));\n }\n }\n return result;\n }\n\n private createCacheEntryObservable(setType: SetType): Observable<CachedNodesMap> {\n const event = setType === \"always\" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;\n const getIds = setType === \"always\" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;\n\n const resultSubject = new BehaviorSubject<CachedNodesMap | undefined>(undefined);\n\n const obs: Observable<CachedNodesMap> = fromEventPattern(\n (handler) => event.addListener(handler),\n (handler) => event.removeListener(handler),\n ).pipe(\n // Fire the observable once at the beginning\n startWith(undefined),\n // Reset result subject as soon as a new event is emitted.\n // This will make newly subscribed observers wait for the debounce period to pass\n // instead of consuming the cached value which at this point becomes invalid.\n tap(() => resultSubject.next(undefined)),\n // Check if cache updates are not suppressed.\n switchMap(() =>\n this.#suppressors.pipe(\n filter((suppressors) => suppressors === 0),\n take(1),\n ),\n ),\n debounceTime(SET_CHANGE_DEBOUNCE_TIME),\n // Cancel pending request if dispose() is called.\n takeUntil(this.#disposeSubject),\n // If multiple requests are sent at once, preserve only the result of the newest.\n switchMap(() => this.queryAlwaysOrNeverDrawnElementInfo(getIds(), `${setType}Drawn`)),\n tap((cacheEntry) => {\n const value = setType === \"always\" ? this.#alwaysDrawn : this.#neverDrawn;\n value.latestCacheEntryValue = cacheEntry;\n }),\n // Share the result by using a subject which always emits the saved result.\n share({\n connector: () => resultSubject,\n resetOnRefCountZero: false,\n }),\n // Wait until the result is available.\n first((x): x is CachedNodesMap => !!x, new Map()),\n );\n return obs;\n }\n\n public [Symbol.dispose]() {\n this.#subscriptions.forEach((x) => x.unsubscribe());\n this.#subscriptions = [];\n this.#disposeSubject.next();\n }\n\n private queryAlwaysOrNeverDrawnElementInfo(set: Id64Set | undefined, requestId: string): Observable<CachedNodesMap> {\n const elementInfo = set?.size\n ? from(set).pipe(\n bufferCount(Math.ceil(set.size / Math.ceil(set.size / 5000))),\n mergeMap((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10),\n )\n : EMPTY;\n return elementInfo.pipe(\n releaseMainThreadOnItemsCount(1000),\n reduce(\n (acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {\n const elementIdInList = elementsPath[elementsPath.length - 1];\n const additionalPropsGetter = (id: Id64String, additionalProps?: MapEntry): MapEntry => {\n if (id === elementIdInList) {\n // Last element in elementsPath is in always/never drawn set. We want to mark, that it is in the set, and save it's categoryId.\n return { isInAlwaysOrNeverDrawnSet: true, categoryId };\n }\n // Existing entries can keep their value, if it's a new entry it's not in the list.\n return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };\n };\n updateChildrenTree({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });\n return acc;\n },\n ((): CachedNodesMap => new Map())(),\n ),\n );\n }\n\n private queryElementInfo(\n elementIds: Id64Array,\n requestId: string,\n ): Observable<{\n rootCategoryId: Id64String;\n modelId: Id64String;\n categoryId: Id64String;\n elementsPath: Id64Array;\n }> {\n return defer(() => {\n const executor = createECSqlQueryExecutor(this.#viewport.iModel);\n return executor.createQueryReader(\n {\n ctes: [\n `\n ElementInfo(modelId, rootCategoryId, categoryId, parentId, elementsPath) AS (\n SELECT\n Model.Id modelId,\n Category.Id rootCategoryId,\n Category.Id categoryId,\n Parent.Id parentId,\n CAST(IdToHex(ECInstanceId) AS TEXT) elementsPath\n FROM bis.GeometricElement3d\n WHERE InVirtualSet(?, ECInstanceId)\n\n UNION ALL\n\n SELECT\n e.modelId modelId,\n p.Category.Id rootCategoryId,\n e.categoryId categoryId,\n p.Parent.Id parentId,\n CAST(IdToHex(p.ECInstanceId) AS TEXT) || ';' || e.elementsPath\n FROM bis.GeometricElement3d p\n JOIN ElementInfo e ON p.ECInstanceId = e.parentId\n )\n `,\n ],\n ecsql: `\n SELECT elementsPath elementsPath, modelId modelId, categoryId categoryId, rootCategoryId rootCategoryId\n FROM ElementInfo\n WHERE parentId IS NULL\n `,\n bindings: [{ type: \"idset\", value: elementIds }],\n },\n {\n rowFormat: \"ECSqlPropertyNames\",\n restartToken: `${this.#componentName}/${this.#componentId}/${requestId}`,\n },\n );\n }).pipe(\n map((row) => {\n return { elementsPath: row.elementsPath.split(\";\"), modelId: row.modelId, categoryId: row.categoryId, rootCategoryId: row.rootCategoryId };\n }),\n );\n }\n}\n"]}
@@ -1,25 +1,33 @@
1
- import { HierarchyFilteringPath } from "@itwin/presentation-hierarchies";
1
+ import { HierarchyFilteringPath, HierarchyNode } from "@itwin/presentation-hierarchies";
2
2
  import type { Id64String } from "@itwin/core-bentley";
3
- import type { HierarchyNode } from "@itwin/presentation-hierarchies";
3
+ import type { ClassGroupingNodeKey, InstancesNodeKey } from "@itwin/presentation-hierarchies";
4
4
  import type { ECClassHierarchyInspector } from "@itwin/presentation-shared";
5
+ /** @internal */
5
6
  export interface FilteredTree {
6
- getVisibilityChangeTargets(node: HierarchyNode): VisibilityChangeTargets;
7
+ getVisibilityChangeTargets(node: HierarchyNode & {
8
+ key: ClassGroupingNodeKey | InstancesNodeKey;
9
+ }): VisibilityChangeTargets;
7
10
  }
8
11
  export declare const SUBJECT_CLASS_NAME: "BisCore.Subject";
9
12
  export declare const MODEL_CLASS_NAME: "BisCore.GeometricModel3d";
10
13
  export declare const CATEGORY_CLASS_NAME: "BisCore.SpatialCategory";
11
14
  export declare const ELEMENT_CLASS_NAME: "BisCore.GeometricElement3d";
12
15
  type CategoryKey = `${Id64String}-${Id64String}`;
16
+ /** @internal */
13
17
  export declare function parseCategoryKey(key: CategoryKey): {
14
18
  modelId: string;
15
19
  categoryId: string;
16
20
  };
17
- interface VisibilityChangeTargets {
21
+ /** @internal */
22
+ export interface VisibilityChangeTargets {
18
23
  subjects?: Set<Id64String>;
19
24
  models?: Set<Id64String>;
20
25
  categories?: Set<CategoryKey>;
21
- elements?: Map<CategoryKey, Set<Id64String>>;
26
+ elements?: Map<CategoryKey, Map<Id64String, {
27
+ isFilterTarget: boolean;
28
+ }>>;
22
29
  }
30
+ /** @internal */
23
31
  export declare function createFilteredTree(imodelAccess: ECClassHierarchyInspector, filteringPaths: HierarchyFilteringPath[]): Promise<FilteredTree>;
24
32
  export {};
25
33
  //# sourceMappingURL=FilteredTree.d.ts.map
@@ -2,8 +2,8 @@
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 { assert } from "@itwin/core-bentley";
6
- import { HierarchyFilteringPath, HierarchyNodeIdentifier, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
5
+ import { assert, Id64 } from "@itwin/core-bentley";
6
+ import { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
7
7
  export const SUBJECT_CLASS_NAME = "BisCore.Subject";
8
8
  export const MODEL_CLASS_NAME = "BisCore.GeometricModel3d";
9
9
  export const CATEGORY_CLASS_NAME = "BisCore.SpatialCategory";
@@ -11,10 +11,12 @@ export const ELEMENT_CLASS_NAME = "BisCore.GeometricElement3d";
11
11
  function createCategoryKey(modelId, categoryId) {
12
12
  return `${modelId}-${categoryId}`;
13
13
  }
14
+ /** @internal */
14
15
  export function parseCategoryKey(key) {
15
16
  const [modelId, categoryId] = key.split("-");
16
17
  return { modelId, categoryId };
17
18
  }
19
+ /** @internal */
18
20
  export async function createFilteredTree(imodelAccess, filteringPaths) {
19
21
  const root = {
20
22
  children: new Map(),
@@ -53,10 +55,6 @@ export async function createFilteredTree(imodelAccess, filteringPaths) {
53
55
  function getVisibilityChangeTargets(root, node) {
54
56
  let lookupParents = [root];
55
57
  const changeTargets = {};
56
- const nodeKey = node.key;
57
- if (!HierarchyNodeKey.isInstances(nodeKey)) {
58
- return changeTargets;
59
- }
60
58
  // find the filtered parent nodes of the `node`
61
59
  for (const parentKey of node.parentKeys) {
62
60
  if (!HierarchyNodeKey.isInstances(parentKey)) {
@@ -64,24 +62,32 @@ function getVisibilityChangeTargets(root, node) {
64
62
  }
65
63
  // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes
66
64
  // and use them when checking for matching node in one level deeper.
67
- const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);
65
+ const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys.map((key) => key.id));
68
66
  if (parentNodes.length === 0) {
69
67
  return changeTargets;
70
68
  }
71
69
  lookupParents = parentNodes;
72
70
  }
71
+ const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);
73
72
  // find filtered nodes that match the `node`
74
- const filteredNodes = findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);
73
+ const filteredNodes = findMatchingFilteredNodes(lookupParents, ids);
75
74
  if (filteredNodes.length === 0) {
76
75
  return changeTargets;
77
76
  }
78
77
  filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));
79
78
  return changeTargets;
80
79
  }
81
- function findMatchingFilteredNodes(lookupParents, keys) {
82
- return lookupParents
83
- .flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))
84
- .filter((lookupNode) => lookupNode !== undefined);
80
+ function findMatchingFilteredNodes(lookupParents, ids) {
81
+ return lookupParents.flatMap((lookup) => {
82
+ const childrenArray = Array();
83
+ for (const id of Id64.iterable(ids)) {
84
+ const node = lookup.children?.get(id);
85
+ if (node) {
86
+ childrenArray.push(node);
87
+ }
88
+ }
89
+ return childrenArray;
90
+ });
85
91
  }
86
92
  function collectVisibilityChangeTargets(changeTargets, node) {
87
93
  if (node.isFilterTarget) {
@@ -114,11 +120,11 @@ function addTarget(filterTargets, node) {
114
120
  const categoryKey = createCategoryKey(node.modelId, node.categoryId);
115
121
  const elements = (filterTargets.elements ??= new Map()).get(categoryKey);
116
122
  if (elements) {
117
- elements.add(node.id);
118
- return;
123
+ elements.set(node.id, { isFilterTarget: node.isFilterTarget });
124
+ }
125
+ else {
126
+ filterTargets.elements.set(categoryKey, new Map([[node.id, { isFilterTarget: node.isFilterTarget }]]));
119
127
  }
120
- filterTargets.elements.set(categoryKey, new Set([node.id]));
121
- return;
122
128
  }
123
129
  }
124
130
  function createFilteredTreeNode({ type, id, isFilterTarget, parent, }) {
@@ -1 +1 @@
1
- {"version":3,"file":"FilteredTree.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/FilteredTree.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { assert } from \"@itwin/core-bentley\";\nimport { HierarchyFilteringPath, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\n\nimport type { Id64String } from \"@itwin/core-bentley\";\nimport type { HierarchyNode } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector, InstanceKey } from \"@itwin/presentation-shared\";\n\ninterface FilteredTreeRootNode {\n children: Map<Id64String, FilteredTreeNode>;\n}\n\ninterface BaseFilteredTreeNode {\n id: string;\n children?: Map<Id64String, FilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\ninterface GenericFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"subject\" | \"model\";\n}\n\ninterface CategoryFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"category\";\n modelId: Id64String;\n}\n\ninterface ElementFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"element\";\n modelId: Id64String;\n categoryId: Id64String;\n}\n\ntype FilteredTreeNode = GenericFilteredTreeNode | CategoryFilteredTreeNode | ElementFilteredTreeNode;\n\nexport interface FilteredTree {\n getVisibilityChangeTargets(node: HierarchyNode): VisibilityChangeTargets;\n}\n\nexport const SUBJECT_CLASS_NAME = \"BisCore.Subject\" as const;\nexport const MODEL_CLASS_NAME = \"BisCore.GeometricModel3d\" as const;\nexport const CATEGORY_CLASS_NAME = \"BisCore.SpatialCategory\" as const;\nexport const ELEMENT_CLASS_NAME = \"BisCore.GeometricElement3d\" as const;\n\ntype CategoryKey = `${Id64String}-${Id64String}`;\n\nfunction createCategoryKey(modelId: string, categoryId: string): CategoryKey {\n return `${modelId}-${categoryId}`;\n}\n\nexport function parseCategoryKey(key: CategoryKey) {\n const [modelId, categoryId] = key.split(\"-\");\n return { modelId, categoryId };\n}\n\ninterface VisibilityChangeTargets {\n subjects?: Set<Id64String>;\n models?: Set<Id64String>;\n categories?: Set<CategoryKey>;\n elements?: Map<CategoryKey, Set<Id64String>>;\n}\n\nexport async function createFilteredTree(imodelAccess: ECClassHierarchyInspector, filteringPaths: HierarchyFilteringPath[]): Promise<FilteredTree> {\n const root: FilteredTreeRootNode = {\n children: new Map(),\n };\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode | FilteredTreeNode = root;\n for (let i = 0; i < normalizedPath.length; i++) {\n if (\"type\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: FilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n\n const type = await getType(imodelAccess, identifier.className);\n const newNode: FilteredTreeNode = createFilteredTreeNode({\n type,\n id: identifier.id,\n isFilterTarget: i === normalizedPath.length - 1,\n parent: parentNode as FilteredTreeNode,\n });\n (parentNode.children ??= new Map()).set(identifier.id, newNode);\n parentNode = newNode;\n }\n }\n\n return {\n getVisibilityChangeTargets: (node: HierarchyNode) => getVisibilityChangeTargets(root, node),\n };\n}\n\nfunction getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyNode) {\n let lookupParents: Array<{ children?: Map<Id64String, FilteredTreeNode> }> = [root];\n const changeTargets: VisibilityChangeTargets = {};\n\n const nodeKey = node.key;\n if (!HierarchyNodeKey.isInstances(nodeKey)) {\n return changeTargets;\n }\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);\n if (parentNodes.length === 0) {\n return changeTargets;\n }\n lookupParents = parentNodes;\n }\n\n // find filtered nodes that match the `node`\n const filteredNodes = findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);\n if (filteredNodes.length === 0) {\n return changeTargets;\n }\n\n filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));\n return changeTargets;\n}\n\nfunction findMatchingFilteredNodes(lookupParents: Array<{ children?: Map<Id64String, FilteredTreeNode> }>, keys: InstanceKey[]) {\n return lookupParents\n .flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))\n .filter((lookupNode): lookupNode is FilteredTreeNode => lookupNode !== undefined);\n}\n\nfunction collectVisibilityChangeTargets(changeTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n if (node.isFilterTarget) {\n addTarget(changeTargets, node);\n return;\n }\n\n if (node.type === \"element\") {\n // need to add parent ids as filter target will be an element\n addTarget(changeTargets, node);\n }\n\n if (!node.children) {\n return;\n }\n\n for (const child of node.children.values()) {\n collectVisibilityChangeTargets(changeTargets, child);\n }\n}\n\nfunction addTarget(filterTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n switch (node.type) {\n case \"subject\":\n (filterTargets.subjects ??= new Set()).add(node.id);\n return;\n case \"model\":\n (filterTargets.models ??= new Set()).add(node.id);\n return;\n case \"category\":\n (filterTargets.categories ??= new Set()).add(createCategoryKey(node.modelId, node.id));\n return;\n case \"element\":\n const categoryKey = createCategoryKey(node.modelId, node.categoryId);\n const elements = (filterTargets.elements ??= new Map()).get(categoryKey);\n if (elements) {\n elements.add(node.id);\n return;\n }\n filterTargets.elements.set(categoryKey, new Set([node.id]));\n return;\n }\n}\n\nfunction createFilteredTreeNode({\n type,\n id,\n isFilterTarget,\n parent,\n}: {\n type: FilteredTreeNode[\"type\"];\n id: string;\n isFilterTarget: boolean;\n parent: FilteredTreeNode | FilteredTreeRootNode;\n}): FilteredTreeNode {\n if (type === \"subject\" || type === \"model\") {\n return {\n id,\n isFilterTarget,\n type,\n };\n }\n\n if (type === \"category\") {\n assert(\"type\" in parent && parent.type === \"model\");\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"category\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"element\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.categoryId,\n };\n }\n\n throw new Error(\"Invalid parent node type\");\n}\n\nasync function getType(hierarchyChecker: ECClassHierarchyInspector, className: string) {\n if (await hierarchyChecker.classDerivesFrom(className, SUBJECT_CLASS_NAME)) {\n return \"subject\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, MODEL_CLASS_NAME)) {\n return \"model\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, CATEGORY_CLASS_NAME)) {\n return \"category\";\n }\n return \"element\";\n}\n"]}
1
+ {"version":3,"file":"FilteredTree.js","sourceRoot":"","sources":["../../../../../../../src/tree-widget-react/components/trees/models-tree/internal/FilteredTree.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAsCnI,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAA0B,CAAC;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,0BAAmC,CAAC;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG,yBAAkC,CAAC;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,4BAAqC,CAAC;AAIxE,SAAS,iBAAiB,CAAC,OAAe,EAAE,UAAkB;IAC5D,OAAO,GAAG,OAAO,IAAI,UAAU,EAAE,CAAC;AACpC,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,gBAAgB,CAAC,GAAgB;IAC/C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC;AAUD,gBAAgB;AAChB,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,YAAuC,EAAE,cAAwC;IACxH,MAAM,IAAI,GAAyB;QACjC,QAAQ,EAAE,IAAI,GAAG,EAAE;KACpB,CAAC;IAEF,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,cAAc,GAAG,sBAAsB,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QAE5E,IAAI,UAAU,GAA4C,IAAI,CAAC;QAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,MAAM,IAAI,UAAU,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;gBACtD,MAAM;YACR,CAAC;YAED,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,uBAAuB,CAAC,wBAAwB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClE,MAAM;YACR,CAAC;YAED,MAAM,WAAW,GAAiC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC1F,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,GAAG,WAAW,CAAC;gBACzB,SAAS;YACX,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAqB,sBAAsB,CAAC;gBACvD,IAAI;gBACJ,EAAE,EAAE,UAAU,CAAC,EAAE;gBACjB,cAAc,EAAE,CAAC,KAAK,cAAc,CAAC,MAAM,GAAG,CAAC;gBAC/C,MAAM,EAAE,UAA8B;aACvC,CAAC,CAAC;YACH,CAAC,UAAU,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAChE,UAAU,GAAG,OAAO,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO;QACL,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,IAA0B,EAAE,IAAsE;IACpI,IAAI,aAAa,GAAmD,CAAC,IAAI,CAAC,CAAC;IAC3E,MAAM,aAAa,GAA4B,EAAE,CAAC;IAElD,+CAA+C;IAC/C,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACxC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7C,SAAS;QACX,CAAC;QAED,4IAA4I;QAC5I,oEAAoE;QACpE,MAAM,WAAW,GAAG,yBAAyB,CAC3C,aAAa,EACb,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAC5C,CAAC;QACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,aAAa,GAAG,WAAW,CAAC;IAC9B,CAAC;IACD,MAAM,GAAG,GAAG,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3I,4CAA4C;IAC5C,MAAM,aAAa,GAAG,yBAAyB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACpE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,8BAA8B,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;IACrG,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,yBAAyB,CAAC,aAA6D,EAAE,GAAY;IAC5G,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACtC,MAAM,aAAa,GAAG,KAAK,EAAoB,CAAC;QAChD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,IAAI,EAAE,CAAC;gBACT,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,8BAA8B,CAAC,aAAsC,EAAE,IAAsB;IACpG,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,6DAA6D;QAC7D,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,8BAA8B,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,aAAsC,EAAE,IAAsB;IAC/E,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,SAAS;YACZ,CAAC,aAAa,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpD,OAAO;QACT,KAAK,OAAO;YACV,CAAC,aAAa,CAAC,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,KAAK,UAAU;YACb,CAAC,aAAa,CAAC,UAAU,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACvF,OAAO;QACT,KAAK,SAAS;YACZ,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACrE,MAAM,QAAQ,GAAG,CAAC,aAAa,CAAC,QAAQ,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzE,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YACjE,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACzG,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,EAC9B,IAAI,EACJ,EAAE,EACF,cAAc,EACd,MAAM,GAMP;IACC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3C,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;SACL,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,MAAM,CAAC,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACpD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,EAAE;SACnB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACnD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,EAAE;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAClD,OAAO;YACL,EAAE;YACF,cAAc;YACd,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,gBAA2C,EAAE,SAAiB;IACnF,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE,CAAC;QAC3E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,CAAC;QACzE,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,CAAC;QAC5E,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { assert, Id64 } from \"@itwin/core-bentley\";\nimport { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from \"@itwin/presentation-hierarchies\";\n\nimport type { Id64Arg, Id64String } from \"@itwin/core-bentley\";\nimport type { ClassGroupingNodeKey, InstancesNodeKey } from \"@itwin/presentation-hierarchies\";\nimport type { ECClassHierarchyInspector } from \"@itwin/presentation-shared\";\n\ninterface FilteredTreeRootNode {\n children: Map<Id64String, FilteredTreeNode>;\n}\n\ninterface BaseFilteredTreeNode {\n id: string;\n children?: Map<Id64String, FilteredTreeNode>;\n isFilterTarget: boolean;\n}\n\ninterface GenericFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"subject\" | \"model\";\n}\n\ninterface CategoryFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"category\";\n modelId: Id64String;\n}\n\ninterface ElementFilteredTreeNode extends BaseFilteredTreeNode {\n type: \"element\";\n modelId: Id64String;\n categoryId: Id64String;\n}\n\ntype FilteredTreeNode = GenericFilteredTreeNode | CategoryFilteredTreeNode | ElementFilteredTreeNode;\n\n/** @internal */\nexport interface FilteredTree {\n getVisibilityChangeTargets(node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }): VisibilityChangeTargets;\n}\n\nexport const SUBJECT_CLASS_NAME = \"BisCore.Subject\" as const;\nexport const MODEL_CLASS_NAME = \"BisCore.GeometricModel3d\" as const;\nexport const CATEGORY_CLASS_NAME = \"BisCore.SpatialCategory\" as const;\nexport const ELEMENT_CLASS_NAME = \"BisCore.GeometricElement3d\" as const;\n\ntype CategoryKey = `${Id64String}-${Id64String}`;\n\nfunction createCategoryKey(modelId: string, categoryId: string): CategoryKey {\n return `${modelId}-${categoryId}`;\n}\n\n/** @internal */\nexport function parseCategoryKey(key: CategoryKey) {\n const [modelId, categoryId] = key.split(\"-\");\n return { modelId, categoryId };\n}\n\n/** @internal */\nexport interface VisibilityChangeTargets {\n subjects?: Set<Id64String>;\n models?: Set<Id64String>;\n categories?: Set<CategoryKey>;\n elements?: Map<CategoryKey, Map<Id64String, { isFilterTarget: boolean }>>;\n}\n\n/** @internal */\nexport async function createFilteredTree(imodelAccess: ECClassHierarchyInspector, filteringPaths: HierarchyFilteringPath[]): Promise<FilteredTree> {\n const root: FilteredTreeRootNode = {\n children: new Map(),\n };\n\n for (const filteringPath of filteringPaths) {\n const normalizedPath = HierarchyFilteringPath.normalize(filteringPath).path;\n\n let parentNode: FilteredTreeRootNode | FilteredTreeNode = root;\n for (let i = 0; i < normalizedPath.length; i++) {\n if (\"type\" in parentNode && parentNode.isFilterTarget) {\n break;\n }\n\n const identifier = normalizedPath[i];\n if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(identifier)) {\n break;\n }\n\n const currentNode: FilteredTreeNode | undefined = parentNode.children?.get(identifier.id);\n if (currentNode !== undefined) {\n parentNode = currentNode;\n continue;\n }\n\n const type = await getType(imodelAccess, identifier.className);\n const newNode: FilteredTreeNode = createFilteredTreeNode({\n type,\n id: identifier.id,\n isFilterTarget: i === normalizedPath.length - 1,\n parent: parentNode as FilteredTreeNode,\n });\n (parentNode.children ??= new Map()).set(identifier.id, newNode);\n parentNode = newNode;\n }\n }\n\n return {\n getVisibilityChangeTargets: (node) => getVisibilityChangeTargets(root, node),\n };\n}\n\nfunction getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyNode & { key: ClassGroupingNodeKey | InstancesNodeKey }) {\n let lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode> = [root];\n const changeTargets: VisibilityChangeTargets = {};\n\n // find the filtered parent nodes of the `node`\n for (const parentKey of node.parentKeys) {\n if (!HierarchyNodeKey.isInstances(parentKey)) {\n continue;\n }\n\n // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes\n // and use them when checking for matching node in one level deeper.\n const parentNodes = findMatchingFilteredNodes(\n lookupParents,\n parentKey.instanceKeys.map((key) => key.id),\n );\n if (parentNodes.length === 0) {\n return changeTargets;\n }\n lookupParents = parentNodes;\n }\n const ids = HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);\n // find filtered nodes that match the `node`\n const filteredNodes = findMatchingFilteredNodes(lookupParents, ids);\n if (filteredNodes.length === 0) {\n return changeTargets;\n }\n\n filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));\n return changeTargets;\n}\n\nfunction findMatchingFilteredNodes(lookupParents: Array<FilteredTreeRootNode | FilteredTreeNode>, ids: Id64Arg): Array<FilteredTreeNode> {\n return lookupParents.flatMap((lookup) => {\n const childrenArray = Array<FilteredTreeNode>();\n for (const id of Id64.iterable(ids)) {\n const node = lookup.children?.get(id);\n if (node) {\n childrenArray.push(node);\n }\n }\n return childrenArray;\n });\n}\n\nfunction collectVisibilityChangeTargets(changeTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n if (node.isFilterTarget) {\n addTarget(changeTargets, node);\n return;\n }\n\n if (node.type === \"element\") {\n // need to add parent ids as filter target will be an element\n addTarget(changeTargets, node);\n }\n\n if (!node.children) {\n return;\n }\n\n for (const child of node.children.values()) {\n collectVisibilityChangeTargets(changeTargets, child);\n }\n}\n\nfunction addTarget(filterTargets: VisibilityChangeTargets, node: FilteredTreeNode) {\n switch (node.type) {\n case \"subject\":\n (filterTargets.subjects ??= new Set()).add(node.id);\n return;\n case \"model\":\n (filterTargets.models ??= new Set()).add(node.id);\n return;\n case \"category\":\n (filterTargets.categories ??= new Set()).add(createCategoryKey(node.modelId, node.id));\n return;\n case \"element\":\n const categoryKey = createCategoryKey(node.modelId, node.categoryId);\n const elements = (filterTargets.elements ??= new Map()).get(categoryKey);\n if (elements) {\n elements.set(node.id, { isFilterTarget: node.isFilterTarget });\n } else {\n filterTargets.elements.set(categoryKey, new Map([[node.id, { isFilterTarget: node.isFilterTarget }]]));\n }\n }\n}\n\nfunction createFilteredTreeNode({\n type,\n id,\n isFilterTarget,\n parent,\n}: {\n type: FilteredTreeNode[\"type\"];\n id: string;\n isFilterTarget: boolean;\n parent: FilteredTreeNode | FilteredTreeRootNode;\n}): FilteredTreeNode {\n if (type === \"subject\" || type === \"model\") {\n return {\n id,\n isFilterTarget,\n type,\n };\n }\n\n if (type === \"category\") {\n assert(\"type\" in parent && parent.type === \"model\");\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"category\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.id,\n };\n }\n\n if (\"type\" in parent && parent.type === \"element\") {\n return {\n id,\n isFilterTarget,\n type,\n modelId: parent.modelId,\n categoryId: parent.categoryId,\n };\n }\n\n throw new Error(\"Invalid parent node type\");\n}\n\nasync function getType(hierarchyChecker: ECClassHierarchyInspector, className: string) {\n if (await hierarchyChecker.classDerivesFrom(className, SUBJECT_CLASS_NAME)) {\n return \"subject\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, MODEL_CLASS_NAME)) {\n return \"model\";\n }\n if (await hierarchyChecker.classDerivesFrom(className, CATEGORY_CLASS_NAME)) {\n return \"category\";\n }\n return \"element\";\n}\n"]}