@itwin/tree-widget-react 3.15.1 → 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 +14 -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 +4 -13
  59. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +62 -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 +155 -177
  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 +4 -13
  121. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +63 -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 +157 -179
  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
@@ -5,6 +5,8 @@
5
5
  *--------------------------------------------------------------------------------------------*/
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.releaseMainThreadOnItemsCount = releaseMainThreadOnItemsCount;
8
+ exports.getIdsFromChildrenTree = getIdsFromChildrenTree;
9
+ exports.updateChildrenTree = updateChildrenTree;
8
10
  const rxjs_1 = require("rxjs");
9
11
  /**
10
12
  * Checks if all given models are displayed in given viewport.
@@ -21,4 +23,48 @@ function releaseMainThreadOnItemsCount(elementCount) {
21
23
  }), (0, rxjs_1.concatAll)());
22
24
  };
23
25
  }
26
+ /** @internal */
27
+ function getIdsFromChildrenTree({ tree, predicate, }) {
28
+ function getIdsInternal({ childrenTree, depth }) {
29
+ const result = new Set();
30
+ childrenTree.forEach((entry, id) => {
31
+ if (!predicate || predicate({ depth, treeEntry: entry })) {
32
+ result.add(id);
33
+ }
34
+ if (entry.children) {
35
+ const childrenIds = getIdsInternal({ childrenTree: entry.children, depth: depth + 1 });
36
+ childrenIds.forEach((childId) => result.add(childId));
37
+ }
38
+ });
39
+ return result;
40
+ }
41
+ return getIdsInternal({ childrenTree: tree, depth: 0 });
42
+ }
43
+ /**
44
+ * Updates children tree with provided `idsToAdd`:
45
+ * - All Ids are added (if they are not yet added) to children tree in the same order they appear in `idsToAdd` array.
46
+ * - `T` is assigned to each entry using the `additionalPropsGetter` function.
47
+ * @internal
48
+ */
49
+ function updateChildrenTree({ tree, additionalPropsGetter, idsToAdd, }) {
50
+ let currentTree = tree;
51
+ for (let i = 0; i < idsToAdd.length; ++i) {
52
+ const id = idsToAdd[i];
53
+ let entry = currentTree.get(id);
54
+ entry = {
55
+ // Whoever calls this function knows how to assign the `T` to entry.
56
+ ...additionalPropsGetter(id, entry),
57
+ // If children already exists, we reuse it.
58
+ // 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.
59
+ ...(entry?.children || i + 1 < idsToAdd.length ? { children: entry?.children ?? new Map() } : {}),
60
+ };
61
+ // Always update the set with updated entry.
62
+ currentTree.set(id, entry);
63
+ // This will only happen if it's the last id in `idsToAdd` array. In such case loop can be exited.
64
+ if (!entry.children) {
65
+ break;
66
+ }
67
+ currentTree = entry.children;
68
+ }
69
+ }
24
70
  //# 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;;AAUhG,sEAcC;AAtBD,+BAAoE;AAIpE;;;GAGG;AACH,SAAgB,6BAA6B,CAAI,YAAoB;IACnE,OAAO,CAAC,GAAkB,EAAiB,EAAE;QAC3C,OAAO,GAAG,CAAC,IAAI,CACb,IAAA,kBAAW,EAAC,YAAY,CAAC,EACzB,IAAA,gBAAS,EAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,IAAA,SAAE,EAAC,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,IAAA,YAAK,EAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC,CAAC,EACF,IAAA,gBAAS,GAAE,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":"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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 { 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;
@@ -8,7 +8,7 @@ exports.AlwaysAndNeverDrawnElementInfo = exports.SET_CHANGE_DEBOUNCE_TIME = void
8
8
  const rxjs_1 = require("rxjs");
9
9
  const core_bentley_1 = require("@itwin/core-bentley");
10
10
  const presentation_core_interop_1 = require("@itwin/presentation-core-interop");
11
- const Utils_js_1 = require("../../common/Utils.js");
11
+ const Utils_js_1 = require("../Utils.js");
12
12
  /** @internal */
13
13
  exports.SET_CHANGE_DEBOUNCE_TIME = 20;
14
14
  class AlwaysAndNeverDrawnElementInfo {
@@ -17,14 +17,18 @@ class AlwaysAndNeverDrawnElementInfo {
17
17
  #neverDrawn;
18
18
  #disposeSubject = new rxjs_1.Subject();
19
19
  #viewport;
20
+ #componentId;
21
+ #componentName;
20
22
  #suppressors;
21
23
  #suppress = new rxjs_1.Subject();
22
- constructor(viewport) {
24
+ constructor(viewport, componentId) {
23
25
  this.#viewport = viewport;
24
26
  this.#alwaysDrawn = { cacheEntryObs: this.createCacheEntryObservable("always") };
25
27
  this.#neverDrawn = { cacheEntryObs: this.createCacheEntryObservable("never") };
26
28
  this.#suppressors = this.#suppress.pipe((0, rxjs_1.scan)((acc, suppress) => acc + (suppress ? 1 : -1), 0), (0, rxjs_1.startWith)(0), (0, rxjs_1.shareReplay)(1));
27
29
  this.#subscriptions = [this.#alwaysDrawn.cacheEntryObs.subscribe(), this.#neverDrawn.cacheEntryObs.subscribe()];
30
+ this.#componentId = componentId ?? core_bentley_1.Guid.createValue();
31
+ this.#componentName = "AlwaysAndNeverDrawnElementInfo";
28
32
  }
29
33
  suppressChangeEvents() {
30
34
  this.#suppress.next(true);
@@ -32,29 +36,43 @@ class AlwaysAndNeverDrawnElementInfo {
32
36
  resumeChangeEvents() {
33
37
  this.#suppress.next(false);
34
38
  }
35
- getElements({ setType, modelId, categoryIds }) {
39
+ getElementsTree({ setType, modelIds, ...props }) {
36
40
  const cache = setType === "always" ? this.#alwaysDrawn : this.#neverDrawn;
37
- const getElements = categoryIds
38
- ? (entry) => {
39
- const result = new Set();
40
- for (const categoryId of core_bentley_1.Id64.iterable(categoryIds)) {
41
- const elements = entry?.get(modelId)?.get(categoryId);
42
- elements?.forEach((elementId) => result.add(elementId));
43
- }
44
- return result;
41
+ const getElements = (rootTreeNodes) => {
42
+ if (!rootTreeNodes) {
43
+ return new Map();
45
44
  }
46
- : (entry) => {
47
- const modelEntry = entry?.get(modelId);
48
- const elements = new Set();
49
- for (const set of modelEntry?.values() ?? []) {
50
- set.forEach((id) => elements.add(id));
45
+ const pathToElements = [modelIds];
46
+ if ("categoryIds" in props && props.categoryIds) {
47
+ pathToElements.push(props.categoryIds);
48
+ if ("parentElementIdsPath" in props && props.parentElementIdsPath) {
49
+ props.parentElementIdsPath.forEach((parentElementIds) => pathToElements.push(parentElementIds));
51
50
  }
52
- return elements;
53
- };
51
+ }
52
+ return this.getChildrenTree({ currentChildrenTree: rootTreeNodes, pathToElements, currentIdsIndex: 0 });
53
+ };
54
54
  return !cache.latestCacheEntryValue
55
55
  ? cache.cacheEntryObs.pipe((0, rxjs_1.map)(getElements))
56
56
  : this.#suppressors.pipe((0, rxjs_1.take)(1), (0, rxjs_1.mergeMap)((suppressionCount) => suppressionCount > 0 ? (0, rxjs_1.of)(cache.latestCacheEntryValue).pipe((0, rxjs_1.map)(getElements)) : cache.cacheEntryObs.pipe((0, rxjs_1.map)(getElements))));
57
57
  }
58
+ getChildrenTree({ currentChildrenTree, pathToElements, currentIdsIndex, }) {
59
+ if (currentIdsIndex >= pathToElements.length) {
60
+ return currentChildrenTree;
61
+ }
62
+ const result = new Map();
63
+ for (const parentId of core_bentley_1.Id64.iterable(pathToElements[currentIdsIndex])) {
64
+ const entry = currentChildrenTree.get(parentId);
65
+ if (entry?.children) {
66
+ const childrenTreeOfChildren = this.getChildrenTree({
67
+ currentChildrenTree: entry.children,
68
+ pathToElements,
69
+ currentIdsIndex: currentIdsIndex + 1,
70
+ });
71
+ childrenTreeOfChildren.forEach((val, childId) => result.set(childId, val));
72
+ }
73
+ }
74
+ return result;
75
+ }
58
76
  createCacheEntryObservable(setType) {
59
77
  const event = setType === "always" ? this.#viewport.onAlwaysDrawnChanged : this.#viewport.onNeverDrawnChanged;
60
78
  const getIds = setType === "always" ? () => this.#viewport.alwaysDrawn : () => this.#viewport.neverDrawn;
@@ -81,7 +99,7 @@ class AlwaysAndNeverDrawnElementInfo {
81
99
  resetOnRefCountZero: false,
82
100
  }),
83
101
  // Wait until the result is available.
84
- (0, rxjs_1.first)((x) => !!x));
102
+ (0, rxjs_1.first)((x) => !!x, new Map()));
85
103
  return obs;
86
104
  }
87
105
  [Symbol.dispose]() {
@@ -90,16 +108,22 @@ class AlwaysAndNeverDrawnElementInfo {
90
108
  this.#disposeSubject.next();
91
109
  }
92
110
  queryAlwaysOrNeverDrawnElementInfo(set, requestId) {
93
- const elementInfo = set?.size ? this.queryElementInfo([...set], requestId) : rxjs_1.EMPTY;
94
- return elementInfo.pipe((0, rxjs_1.reduce)((state, val) => {
95
- let entry = state.get(val.modelId);
96
- if (!entry) {
97
- entry = new Map();
98
- state.set(val.modelId, entry);
99
- }
100
- (0, Utils_js_1.pushToMap)(entry, val.categoryId, val.elementId);
101
- return state;
102
- }, new Map()));
111
+ const elementInfo = set?.size
112
+ ? (0, rxjs_1.from)(set).pipe((0, rxjs_1.bufferCount)(Math.ceil(set.size / Math.ceil(set.size / 5000))), (0, rxjs_1.mergeMap)((block, index) => this.queryElementInfo(block, `${requestId}-${index}`), 10))
113
+ : rxjs_1.EMPTY;
114
+ return elementInfo.pipe((0, Utils_js_1.releaseMainThreadOnItemsCount)(1000), (0, rxjs_1.reduce)((acc, { categoryId, rootCategoryId, modelId, elementsPath }) => {
115
+ const elementIdInList = elementsPath[elementsPath.length - 1];
116
+ const additionalPropsGetter = (id, additionalProps) => {
117
+ if (id === elementIdInList) {
118
+ // 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.
119
+ return { isInAlwaysOrNeverDrawnSet: true, categoryId };
120
+ }
121
+ // Existing entries can keep their value, if it's a new entry it's not in the list.
122
+ return additionalProps ?? { isInAlwaysOrNeverDrawnSet: false };
123
+ };
124
+ (0, Utils_js_1.updateChildrenTree)({ tree: acc, idsToAdd: [modelId, rootCategoryId, ...elementsPath], additionalPropsGetter });
125
+ return acc;
126
+ }, (() => new Map())()));
103
127
  }
104
128
  queryElementInfo(elementIds, requestId) {
105
129
  return (0, rxjs_1.defer)(() => {
@@ -107,37 +131,42 @@ class AlwaysAndNeverDrawnElementInfo {
107
131
  return executor.createQueryReader({
108
132
  ctes: [
109
133
  `
110
- ElementInfo(elementId, modelId, categoryId, parentId) AS (
134
+ ElementInfo(modelId, rootCategoryId, categoryId, parentId, elementsPath) AS (
111
135
  SELECT
112
- ECInstanceId elementId,
113
136
  Model.Id modelId,
137
+ Category.Id rootCategoryId,
114
138
  Category.Id categoryId,
115
- Parent.Id parentId
139
+ Parent.Id parentId,
140
+ CAST(IdToHex(ECInstanceId) AS TEXT) elementsPath
116
141
  FROM bis.GeometricElement3d
117
142
  WHERE InVirtualSet(?, ECInstanceId)
118
143
 
119
144
  UNION ALL
120
145
 
121
146
  SELECT
122
- e.elementId,
123
- e.modelId,
124
- p.Category.Id categoryId,
125
- p.Parent.Id parentId
147
+ e.modelId modelId,
148
+ p.Category.Id rootCategoryId,
149
+ e.categoryId categoryId,
150
+ p.Parent.Id parentId,
151
+ CAST(IdToHex(p.ECInstanceId) AS TEXT) || ';' || e.elementsPath
126
152
  FROM bis.GeometricElement3d p
127
153
  JOIN ElementInfo e ON p.ECInstanceId = e.parentId
128
154
  )
129
155
  `,
130
156
  ],
131
157
  ecsql: `
132
- SELECT elementId, modelId, categoryId
158
+ SELECT elementsPath elementsPath, modelId modelId, categoryId categoryId, rootCategoryId rootCategoryId
133
159
  FROM ElementInfo
134
160
  WHERE parentId IS NULL
135
161
  `,
136
162
  bindings: [{ type: "idset", value: elementIds }],
137
163
  }, {
138
- restartToken: `ModelsTreeVisibilityHandler/${requestId}`,
164
+ rowFormat: "ECSqlPropertyNames",
165
+ restartToken: `${this.#componentName}/${this.#componentId}/${requestId}`,
139
166
  });
140
- }).pipe((0, rxjs_1.map)((row) => ({ elementId: row.elementId, modelId: row.modelId, categoryId: row.categoryId })));
167
+ }).pipe((0, rxjs_1.map)((row) => {
168
+ return { elementsPath: row.elementsPath.split(";"), modelId: row.modelId, categoryId: row.categoryId, rootCategoryId: row.rootCategoryId };
169
+ }));
141
170
  }
142
171
  }
143
172
  exports.AlwaysAndNeverDrawnElementInfo = AlwaysAndNeverDrawnElementInfo;
@@ -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
@@ -16,10 +16,12 @@ exports.ELEMENT_CLASS_NAME = "BisCore.GeometricElement3d";
16
16
  function createCategoryKey(modelId, categoryId) {
17
17
  return `${modelId}-${categoryId}`;
18
18
  }
19
+ /** @internal */
19
20
  function parseCategoryKey(key) {
20
21
  const [modelId, categoryId] = key.split("-");
21
22
  return { modelId, categoryId };
22
23
  }
24
+ /** @internal */
23
25
  async function createFilteredTree(imodelAccess, filteringPaths) {
24
26
  const root = {
25
27
  children: new Map(),
@@ -58,10 +60,6 @@ async function createFilteredTree(imodelAccess, filteringPaths) {
58
60
  function getVisibilityChangeTargets(root, node) {
59
61
  let lookupParents = [root];
60
62
  const changeTargets = {};
61
- const nodeKey = node.key;
62
- if (!presentation_hierarchies_1.HierarchyNodeKey.isInstances(nodeKey)) {
63
- return changeTargets;
64
- }
65
63
  // find the filtered parent nodes of the `node`
66
64
  for (const parentKey of node.parentKeys) {
67
65
  if (!presentation_hierarchies_1.HierarchyNodeKey.isInstances(parentKey)) {
@@ -69,24 +67,32 @@ function getVisibilityChangeTargets(root, node) {
69
67
  }
70
68
  // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes
71
69
  // and use them when checking for matching node in one level deeper.
72
- const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys);
70
+ const parentNodes = findMatchingFilteredNodes(lookupParents, parentKey.instanceKeys.map((key) => key.id));
73
71
  if (parentNodes.length === 0) {
74
72
  return changeTargets;
75
73
  }
76
74
  lookupParents = parentNodes;
77
75
  }
76
+ const ids = presentation_hierarchies_1.HierarchyNode.isInstancesNode(node) ? node.key.instanceKeys.map(({ id }) => id) : node.groupedInstanceKeys.map(({ id }) => id);
78
77
  // find filtered nodes that match the `node`
79
- const filteredNodes = findMatchingFilteredNodes(lookupParents, nodeKey.instanceKeys);
78
+ const filteredNodes = findMatchingFilteredNodes(lookupParents, ids);
80
79
  if (filteredNodes.length === 0) {
81
80
  return changeTargets;
82
81
  }
83
82
  filteredNodes.forEach((filteredNode) => collectVisibilityChangeTargets(changeTargets, filteredNode));
84
83
  return changeTargets;
85
84
  }
86
- function findMatchingFilteredNodes(lookupParents, keys) {
87
- return lookupParents
88
- .flatMap((lookup) => keys.map((key) => lookup.children?.get(key.id)))
89
- .filter((lookupNode) => lookupNode !== undefined);
85
+ function findMatchingFilteredNodes(lookupParents, ids) {
86
+ return lookupParents.flatMap((lookup) => {
87
+ const childrenArray = Array();
88
+ for (const id of core_bentley_1.Id64.iterable(ids)) {
89
+ const node = lookup.children?.get(id);
90
+ if (node) {
91
+ childrenArray.push(node);
92
+ }
93
+ }
94
+ return childrenArray;
95
+ });
90
96
  }
91
97
  function collectVisibilityChangeTargets(changeTargets, node) {
92
98
  if (node.isFilterTarget) {
@@ -119,11 +125,11 @@ function addTarget(filterTargets, node) {
119
125
  const categoryKey = createCategoryKey(node.modelId, node.categoryId);
120
126
  const elements = (filterTargets.elements ??= new Map()).get(categoryKey);
121
127
  if (elements) {
122
- elements.add(node.id);
123
- return;
128
+ elements.set(node.id, { isFilterTarget: node.isFilterTarget });
129
+ }
130
+ else {
131
+ filterTargets.elements.set(categoryKey, new Map([[node.id, { isFilterTarget: node.isFilterTarget }]]));
124
132
  }
125
- filterTargets.elements.set(categoryKey, new Set([node.id]));
126
- return;
127
133
  }
128
134
  }
129
135
  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":"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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, 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"]}