@itwin/tree-widget-react 3.16.1 → 3.17.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.
- package/CHANGELOG.md +15 -2
- package/lib/cjs/tree-widget-react/components/SelectableTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/TreeSelector.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
- package/lib/cjs/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/tree-header/TreeHeader.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/tree-header/TreeWithHeader.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +13 -0
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +90 -73
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +3 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +21 -8
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +21 -9
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +290 -242
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +2 -0
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +16 -7
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/UseActiveViewport.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
- package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
- package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
- package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +8 -5
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +1 -4
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +1 -4
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +13 -12
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +251 -278
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +47 -35
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react-internal.d.ts +2 -1
- package/lib/cjs/tree-widget-react-internal.js +4 -1
- package/lib/cjs/tree-widget-react-internal.js.map +1 -1
- package/lib/esm/tree-widget-react/components/SelectableTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/TreeSelector.js.map +1 -1
- package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
- package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
- package/lib/esm/tree-widget-react/components/tree-header/TreeHeader.js.map +1 -1
- package/lib/esm/tree-widget-react/components/tree-header/TreeWithHeader.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +13 -0
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +90 -73
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +3 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +22 -9
- package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +21 -9
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +290 -242
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +2 -0
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +16 -7
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/UseActiveViewport.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
- package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
- package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
- package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +9 -6
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +1 -4
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +1 -4
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +13 -12
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +252 -279
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +47 -35
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react-internal.d.ts +2 -1
- package/lib/esm/tree-widget-react-internal.js +2 -1
- package/lib/esm/tree-widget-react-internal.js.map +1 -1
- package/package.json +1 -1
package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
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 { bufferCount, bufferTime, filter,
|
|
5
|
+
import { bufferCount, bufferTime, defer, filter, forkJoin, from, map, mergeAll, mergeMap, reduce, ReplaySubject, shareReplay, Subject, take, toArray, } from "rxjs";
|
|
6
6
|
import { assert, Guid, Id64 } from "@itwin/core-bentley";
|
|
7
7
|
import { IModel } from "@itwin/core-common";
|
|
8
|
-
import { collect } from "../../common/Rxjs.js";
|
|
9
8
|
import { pushToMap } from "../../common/Utils.js";
|
|
10
9
|
/** @internal */
|
|
11
10
|
export class ModelsTreeIdsCache {
|
|
@@ -24,7 +23,7 @@ export class ModelsTreeIdsCache {
|
|
|
24
23
|
constructor(queryExecutor, hierarchyConfig, componentId) {
|
|
25
24
|
this.#hierarchyConfig = hierarchyConfig;
|
|
26
25
|
this.#queryExecutor = queryExecutor;
|
|
27
|
-
this.#categoryElementCounts = new ModelCategoryElementsCountCache(
|
|
26
|
+
this.#categoryElementCounts = new ModelCategoryElementsCountCache((input) => this.queryCategoryElementCounts(input));
|
|
28
27
|
this.#modelKeyPaths = new Map();
|
|
29
28
|
this.#subjectKeyPaths = new Map();
|
|
30
29
|
this.#categoryKeyPaths = new Map();
|
|
@@ -34,78 +33,77 @@ export class ModelsTreeIdsCache {
|
|
|
34
33
|
[Symbol.dispose]() {
|
|
35
34
|
this.#categoryElementCounts[Symbol.dispose]();
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
36
|
+
querySubjects() {
|
|
37
|
+
return defer(() => {
|
|
38
|
+
const subjectsQuery = `
|
|
39
|
+
SELECT
|
|
40
|
+
s.ECInstanceId id,
|
|
41
|
+
s.Parent.Id parentId,
|
|
42
|
+
(
|
|
43
|
+
SELECT m.ECInstanceId
|
|
44
|
+
FROM bis.GeometricModel3d m
|
|
45
|
+
WHERE m.ECInstanceId = HexToId(json_extract(s.JsonProperties, '$.Subject.Model.TargetPartition'))
|
|
46
|
+
AND NOT m.IsPrivate
|
|
47
|
+
AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)
|
|
48
|
+
) targetPartitionId,
|
|
49
|
+
CASE
|
|
50
|
+
WHEN (
|
|
51
|
+
json_extract(s.JsonProperties, '$.Subject.Job.Bridge') IS NOT NULL
|
|
52
|
+
OR json_extract(s.JsonProperties, '$.Subject.Model.Type') = 'Hierarchy'
|
|
53
|
+
) THEN 1
|
|
54
|
+
ELSE 0
|
|
55
|
+
END hideInHierarchy
|
|
56
|
+
FROM bis.Subject s
|
|
57
|
+
`;
|
|
58
|
+
return this.#queryExecutor.createQueryReader({ ecsql: subjectsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/subjects` });
|
|
59
|
+
}).pipe(map((row) => {
|
|
60
|
+
return { id: row.id, parentId: row.parentId, targetPartitionId: row.targetPartitionId, hideInHierarchy: !!row.hideInHierarchy };
|
|
61
|
+
}));
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
queryModels() {
|
|
64
|
+
return defer(() => {
|
|
65
|
+
const modelsQuery = `
|
|
64
66
|
SELECT p.ECInstanceId id, p.Parent.Id parentId
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
FROM bis.InformationPartitionElement p
|
|
68
|
+
INNER JOIN bis.GeometricModel3d m ON m.ModeledElement.Id = p.ECInstanceId
|
|
69
|
+
WHERE
|
|
70
|
+
NOT m.IsPrivate
|
|
71
|
+
${this.#hierarchyConfig.showEmptyModels ? "" : `AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)`}
|
|
72
|
+
`;
|
|
73
|
+
return this.#queryExecutor.createQueryReader({ ecsql: modelsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/models` });
|
|
74
|
+
}).pipe(map((row) => {
|
|
75
|
+
return { id: row.id, parentId: row.parentId };
|
|
76
|
+
}));
|
|
74
77
|
}
|
|
75
|
-
|
|
76
|
-
this.#subjectInfos ??= (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const result = new Map();
|
|
96
|
-
for await (const model of this.queryModels()) {
|
|
97
|
-
pushToMap(result, model.id, model.parentId);
|
|
78
|
+
getSubjectInfos() {
|
|
79
|
+
this.#subjectInfos ??= forkJoin({
|
|
80
|
+
subjectInfos: this.querySubjects().pipe(reduce((acc, subject) => {
|
|
81
|
+
const subjectInfo = {
|
|
82
|
+
parentSubject: subject.parentId,
|
|
83
|
+
hideInHierarchy: subject.hideInHierarchy,
|
|
84
|
+
childSubjects: new Set(),
|
|
85
|
+
childModels: new Set(),
|
|
86
|
+
};
|
|
87
|
+
if (subject.targetPartitionId) {
|
|
88
|
+
subjectInfo.childModels.add(subject.targetPartitionId);
|
|
89
|
+
}
|
|
90
|
+
acc.set(subject.id, subjectInfo);
|
|
91
|
+
return acc;
|
|
92
|
+
}, new Map()), map((subjectInfos) => {
|
|
93
|
+
for (const [subjectId, { parentSubject: parentSubjectId }] of subjectInfos.entries()) {
|
|
94
|
+
if (parentSubjectId) {
|
|
95
|
+
const parentSubjectInfo = subjectInfos.get(parentSubjectId);
|
|
96
|
+
assert(!!parentSubjectInfo);
|
|
97
|
+
parentSubjectInfo.childSubjects.add(subjectId);
|
|
98
98
|
}
|
|
99
|
-
return result;
|
|
100
|
-
})(),
|
|
101
|
-
]);
|
|
102
|
-
for (const [subjectId, { parentSubject: parentSubjectId }] of subjectInfos.entries()) {
|
|
103
|
-
if (parentSubjectId) {
|
|
104
|
-
const parentSubjectInfo = subjectInfos.get(parentSubjectId);
|
|
105
|
-
assert(!!parentSubjectInfo);
|
|
106
|
-
parentSubjectInfo.childSubjects.add(subjectId);
|
|
107
99
|
}
|
|
108
|
-
|
|
100
|
+
return subjectInfos;
|
|
101
|
+
})),
|
|
102
|
+
targetPartitionSubjects: this.queryModels().pipe(reduce((acc, model) => {
|
|
103
|
+
pushToMap(acc, model.id, model.parentId);
|
|
104
|
+
return acc;
|
|
105
|
+
}, new Map())),
|
|
106
|
+
}).pipe(map(({ subjectInfos, targetPartitionSubjects }) => {
|
|
109
107
|
for (const [partitionId, subjectIds] of targetPartitionSubjects) {
|
|
110
108
|
subjectIds.forEach((subjectId) => {
|
|
111
109
|
const subjectInfo = subjectInfos.get(subjectId);
|
|
@@ -114,13 +112,12 @@ export class ModelsTreeIdsCache {
|
|
|
114
112
|
});
|
|
115
113
|
}
|
|
116
114
|
return subjectInfos;
|
|
117
|
-
})();
|
|
115
|
+
}), shareReplay());
|
|
118
116
|
return this.#subjectInfos;
|
|
119
117
|
}
|
|
120
118
|
/** Returns ECInstanceIDs of Subjects that either have direct Model or at least one child Subject with a Model. */
|
|
121
|
-
|
|
122
|
-
this.#parentSubjectIds ??= (
|
|
123
|
-
const subjectInfos = await this.getSubjectInfos();
|
|
119
|
+
getParentSubjectIds() {
|
|
120
|
+
this.#parentSubjectIds ??= this.getSubjectInfos().pipe(map((subjectInfos) => {
|
|
124
121
|
const parentSubjectIds = new Set();
|
|
125
122
|
subjectInfos.forEach((subjectInfo, subjectId) => {
|
|
126
123
|
if (subjectInfo.childModels.size > 0) {
|
|
@@ -133,71 +130,73 @@ export class ModelsTreeIdsCache {
|
|
|
133
130
|
}
|
|
134
131
|
});
|
|
135
132
|
return [...parentSubjectIds];
|
|
136
|
-
})();
|
|
133
|
+
}), shareReplay());
|
|
137
134
|
return this.#parentSubjectIds;
|
|
138
135
|
}
|
|
139
136
|
/**
|
|
140
137
|
* Returns child subjects of the specified parent subjects as they're displayed in the hierarchy - taking into
|
|
141
138
|
* account `hideInHierarchy` flag.
|
|
142
139
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
140
|
+
getChildSubjectIds(parentSubjectIds) {
|
|
141
|
+
return this.getSubjectInfos().pipe(map((subjectInfos) => {
|
|
142
|
+
const childSubjectIds = new Array();
|
|
143
|
+
parentSubjectIds.forEach((subjectId) => {
|
|
144
|
+
forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
|
|
145
|
+
if (!childSubjectInfo.hideInHierarchy) {
|
|
146
|
+
childSubjectIds.push(childSubjectId);
|
|
147
|
+
return "break";
|
|
148
|
+
}
|
|
149
|
+
return "continue";
|
|
150
|
+
});
|
|
153
151
|
});
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
return childSubjectIds;
|
|
153
|
+
}));
|
|
156
154
|
}
|
|
157
155
|
/** Returns ECInstanceIDs of all Models under specific parent Subjects, including their child Subjects, etc. */
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
156
|
+
getSubjectModelIds(subjectIds) {
|
|
157
|
+
return this.getSubjectInfos().pipe(map((subjectInfos) => {
|
|
158
|
+
const subjectStack = [...subjectIds];
|
|
159
|
+
const result = new Array();
|
|
160
|
+
while (true) {
|
|
161
|
+
const subjectId = subjectStack.pop();
|
|
162
|
+
if (subjectId === undefined) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
const subjectInfo = subjectInfos.get(subjectId);
|
|
166
|
+
if (!subjectInfo) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
result.push(...subjectInfo.childModels);
|
|
170
|
+
subjectStack.push(...subjectInfo.childSubjects);
|
|
170
171
|
}
|
|
171
|
-
result
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
return result;
|
|
172
|
+
return result;
|
|
173
|
+
}));
|
|
175
174
|
}
|
|
176
175
|
/** Returns ECInstanceIDs of Models under specific parent Subjects as they are displayed in the hierarchy. */
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
176
|
+
getChildSubjectModelIds(parentSubjectIds) {
|
|
177
|
+
return this.getSubjectInfos().pipe(map((subjectInfos) => {
|
|
178
|
+
const hiddenSubjectIds = new Array();
|
|
179
|
+
parentSubjectIds.forEach((subjectId) => {
|
|
180
|
+
forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
|
|
181
|
+
if (childSubjectInfo.hideInHierarchy) {
|
|
182
|
+
hiddenSubjectIds.push(childSubjectId);
|
|
183
|
+
return "continue";
|
|
184
|
+
}
|
|
185
|
+
return "break";
|
|
186
|
+
});
|
|
187
187
|
});
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
const modelIds = new Array();
|
|
189
|
+
[...parentSubjectIds, ...hiddenSubjectIds].forEach((subjectId) => {
|
|
190
|
+
const subjectInfo = subjectInfos.get(subjectId);
|
|
191
|
+
subjectInfo && modelIds.push(...subjectInfo.childModels);
|
|
192
|
+
});
|
|
193
|
+
return modelIds;
|
|
194
|
+
}));
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
createSubjectInstanceKeysPath(targetSubjectId) {
|
|
197
197
|
let entry = this.#subjectKeyPaths.get(targetSubjectId);
|
|
198
198
|
if (!entry) {
|
|
199
|
-
entry = (
|
|
200
|
-
const subjectInfos = await this.getSubjectInfos();
|
|
199
|
+
entry = this.getSubjectInfos().pipe(map((subjectInfos) => {
|
|
201
200
|
const result = new Array();
|
|
202
201
|
let currParentId = targetSubjectId;
|
|
203
202
|
while (currParentId) {
|
|
@@ -211,128 +210,111 @@ export class ModelsTreeIdsCache {
|
|
|
211
210
|
currParentId = parentInfo?.parentSubject;
|
|
212
211
|
}
|
|
213
212
|
return result.reverse();
|
|
214
|
-
})();
|
|
213
|
+
}), shareReplay());
|
|
215
214
|
this.#subjectKeyPaths.set(targetSubjectId, entry);
|
|
216
215
|
}
|
|
217
216
|
return entry;
|
|
218
217
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
218
|
+
queryModelCategories() {
|
|
219
|
+
return defer(() => {
|
|
220
|
+
const query = `
|
|
221
|
+
SELECT
|
|
222
|
+
this.Model.Id modelId,
|
|
223
|
+
this.Category.Id categoryId,
|
|
224
|
+
m.IsPrivate isModelPrivate,
|
|
225
|
+
MAX(IIF(this.Parent.Id IS NULL, 1, 0)) isRootElementCategory
|
|
226
|
+
FROM BisCore.Model m
|
|
227
|
+
JOIN ${this.#hierarchyConfig.elementClassSpecification} this ON m.ECInstanceId = this.Model.Id
|
|
228
|
+
GROUP BY modelId, categoryId, isModelPrivate
|
|
229
|
+
`;
|
|
230
|
+
return this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/model-categories` });
|
|
231
|
+
}).pipe(map((row) => {
|
|
232
|
+
return { modelId: row.modelId, categoryId: row.categoryId, isModelPrivate: !!row.isModelPrivate, isRootElementCategory: !!row.isRootElementCategory };
|
|
233
|
+
}));
|
|
233
234
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
235
|
+
queryModeledElements() {
|
|
236
|
+
return defer(() => {
|
|
237
|
+
const query = `
|
|
238
|
+
SELECT
|
|
239
|
+
pe.ECInstanceId modeledElementId,
|
|
240
|
+
pe.Category.Id categoryId,
|
|
241
|
+
pe.Model.Id modelId
|
|
242
|
+
FROM BisCore.Model m
|
|
243
|
+
JOIN ${this.#hierarchyConfig.elementClassSpecification} pe ON pe.ECInstanceId = m.ModeledElement.Id
|
|
244
|
+
WHERE
|
|
245
|
+
m.IsPrivate = false
|
|
246
|
+
AND m.ECInstanceId IN (SELECT Model.Id FROM ${this.#hierarchyConfig.elementClassSpecification})
|
|
247
|
+
`;
|
|
248
|
+
return this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/modeled-elements` });
|
|
249
|
+
}).pipe(map((row) => {
|
|
250
|
+
return { modelId: row.modelId, categoryId: row.categoryId, modeledElementId: row.modeledElementId };
|
|
251
|
+
}));
|
|
249
252
|
}
|
|
250
|
-
|
|
251
|
-
this.#modelWithCategoryModeledElements ??= (
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
else {
|
|
260
|
-
entry.add(modeledElementId);
|
|
261
|
-
}
|
|
253
|
+
getModelWithCategoryModeledElements() {
|
|
254
|
+
this.#modelWithCategoryModeledElements ??= this.queryModeledElements().pipe(reduce((acc, { modelId, categoryId, modeledElementId }) => {
|
|
255
|
+
const key = `${modelId}-${categoryId}`;
|
|
256
|
+
const entry = acc.get(key);
|
|
257
|
+
if (entry === undefined) {
|
|
258
|
+
acc.set(key, new Set([modeledElementId]));
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
entry.add(modeledElementId);
|
|
262
262
|
}
|
|
263
|
-
return
|
|
264
|
-
})();
|
|
263
|
+
return acc;
|
|
264
|
+
}, new Map()), shareReplay());
|
|
265
265
|
return this.#modelWithCategoryModeledElements;
|
|
266
266
|
}
|
|
267
|
-
|
|
268
|
-
this.#modelInfos ??= (
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
modelInfos.set(modelId, { categories: new Map([[categoryId, { isRootElementCategory }]]), isModelPrivate });
|
|
278
|
-
}
|
|
267
|
+
getModelInfos() {
|
|
268
|
+
this.#modelInfos ??= this.queryModelCategories().pipe(reduce((acc, { modelId, categoryId, isModelPrivate, isRootElementCategory }) => {
|
|
269
|
+
const entry = acc.get(modelId);
|
|
270
|
+
if (entry) {
|
|
271
|
+
entry.categories.set(categoryId, { isRootElementCategory });
|
|
272
|
+
entry.isModelPrivate = isModelPrivate;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
acc.set(modelId, { categories: new Map([[categoryId, { isRootElementCategory }]]), isModelPrivate });
|
|
279
276
|
}
|
|
280
|
-
return
|
|
281
|
-
})();
|
|
277
|
+
return acc;
|
|
278
|
+
}, new Map()), shareReplay());
|
|
282
279
|
return this.#modelInfos;
|
|
283
280
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
});
|
|
290
|
-
return result;
|
|
281
|
+
getAllCategories() {
|
|
282
|
+
return this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.values()), mergeMap(({ categories }) => categories.keys()), reduce((acc, categoryId) => {
|
|
283
|
+
acc.add(categoryId);
|
|
284
|
+
return acc;
|
|
285
|
+
}, new Set()));
|
|
291
286
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const categories = modelInfos.get(modelId)?.categories.keys();
|
|
295
|
-
return categories ? [...categories] : [];
|
|
287
|
+
getModelCategories(modelId) {
|
|
288
|
+
return this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.get(modelId)?.categories.keys() ?? []), toArray());
|
|
296
289
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
290
|
+
hasSubModel(elementId) {
|
|
291
|
+
return this.getModelInfos().pipe(map((modelInfos) => {
|
|
292
|
+
const modeledElementInfo = modelInfos.get(elementId);
|
|
293
|
+
if (!modeledElementInfo) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
return !modeledElementInfo.isModelPrivate;
|
|
297
|
+
}));
|
|
304
298
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const result = new Array();
|
|
308
|
-
for (const categoryId of Id64.iterable(categoryIds)) {
|
|
299
|
+
getCategoriesModeledElements(modelId, categoryIds) {
|
|
300
|
+
return this.getModelWithCategoryModeledElements().pipe(mergeMap((modelWithCategoryModeledElements) => from(Id64.iterable(categoryIds)).pipe(reduce((acc, categoryId) => {
|
|
309
301
|
const entry = modelWithCategoryModeledElements.get(`${modelId}-${categoryId}`);
|
|
310
302
|
if (entry !== undefined) {
|
|
311
|
-
|
|
303
|
+
acc.push(...entry);
|
|
312
304
|
}
|
|
313
|
-
|
|
314
|
-
|
|
305
|
+
return acc;
|
|
306
|
+
}, new Array()))));
|
|
315
307
|
}
|
|
316
|
-
|
|
308
|
+
createModelInstanceKeyPaths(modelId) {
|
|
317
309
|
let entry = this.#modelKeyPaths.get(modelId);
|
|
318
310
|
if (!entry) {
|
|
319
|
-
entry = (
|
|
320
|
-
const result = new Array();
|
|
321
|
-
const subjectInfos = (await this.getSubjectInfos()).entries();
|
|
322
|
-
for (const [modelSubjectId, subjectInfo] of subjectInfos) {
|
|
323
|
-
if (subjectInfo.childModels.has(modelId)) {
|
|
324
|
-
const subjectPath = await this.createSubjectInstanceKeysPath(modelSubjectId);
|
|
325
|
-
result.push([...subjectPath, { className: "BisCore.GeometricModel3d", id: modelId }]);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return result;
|
|
329
|
-
})();
|
|
311
|
+
entry = this.getSubjectInfos().pipe(mergeMap((subjectInfos) => subjectInfos.entries()), filter(([_, subjectInfo]) => subjectInfo.childModels.has(modelId)), mergeMap(([modelSubjectId]) => this.createSubjectInstanceKeysPath(modelSubjectId).pipe(map((path) => [...path, { className: "BisCore.GeometricModel3d", id: modelId }]))), toArray(), shareReplay());
|
|
330
312
|
this.#modelKeyPaths.set(modelId, entry);
|
|
331
313
|
}
|
|
332
314
|
return entry;
|
|
333
315
|
}
|
|
334
|
-
|
|
335
|
-
return
|
|
316
|
+
queryCategoryElementCounts(input) {
|
|
317
|
+
return from(input).pipe(reduce((acc, { modelId, categoryId }) => {
|
|
336
318
|
const entry = acc.get(modelId);
|
|
337
319
|
if (!entry) {
|
|
338
320
|
acc.set(modelId, new Set([categoryId]));
|
|
@@ -344,73 +326,64 @@ export class ModelsTreeIdsCache {
|
|
|
344
326
|
}, new Map()), mergeMap((modelCategoryMap) => modelCategoryMap.entries()), map(([modelId, categoryIds]) => `Model.Id = ${modelId} AND Category.Id IN (${[...categoryIds].join(", ")})`),
|
|
345
327
|
// we may have thousands of where clauses here, and sending a single query with all of them could take a
|
|
346
328
|
// long time - instead, split it into smaller chunks
|
|
347
|
-
bufferCount(100), mergeMap(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
)
|
|
329
|
+
bufferCount(100), mergeMap((whereClauses) => defer(() => this.#queryExecutor.createQueryReader({
|
|
330
|
+
ctes: [
|
|
331
|
+
`
|
|
332
|
+
CategoryElements(id, modelId, categoryId) AS (
|
|
333
|
+
SELECT ECInstanceId, Model.Id, Category.Id
|
|
334
|
+
FROM ${this.#hierarchyConfig.elementClassSpecification}
|
|
335
|
+
WHERE
|
|
336
|
+
Parent.Id IS NULL
|
|
337
|
+
AND (
|
|
338
|
+
${whereClauses.join(" OR ")}
|
|
339
|
+
)
|
|
359
340
|
|
|
360
|
-
|
|
341
|
+
UNION ALL
|
|
361
342
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
343
|
+
SELECT c.ECInstanceId, p.modelId, p.categoryId
|
|
344
|
+
FROM ${this.#hierarchyConfig.elementClassSpecification} c
|
|
345
|
+
JOIN CategoryElements p ON c.Parent.Id = p.id
|
|
346
|
+
)
|
|
347
|
+
`,
|
|
348
|
+
],
|
|
349
|
+
ecsql: `
|
|
350
|
+
SELECT modelId, categoryId, COUNT(id) elementsCount
|
|
351
|
+
FROM CategoryElements
|
|
352
|
+
GROUP BY modelId, categoryId
|
|
366
353
|
`,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
restartToken: `${this.#componentName}/${this.#componentId}/category-element-counts/${Guid.createValue()}`,
|
|
354
|
+
}, {
|
|
355
|
+
rowFormat: "ECSqlPropertyNames",
|
|
356
|
+
limit: "unbounded",
|
|
357
|
+
restartToken: `${this.#componentName}/${this.#componentId}/category-element-counts/${Guid.createValue()}`,
|
|
358
|
+
}))), reduce(({ acc, createKey }, row) => {
|
|
359
|
+
acc.set(createKey({ modelId: row.modelId, categoryId: row.categoryId }), {
|
|
360
|
+
modelId: row.modelId,
|
|
361
|
+
categoryId: row.categoryId,
|
|
362
|
+
elementsCount: row.elementsCount,
|
|
377
363
|
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
364
|
+
return { acc, createKey };
|
|
365
|
+
}, {
|
|
366
|
+
acc: new Map(),
|
|
367
|
+
createKey: (keyProps) => `${keyProps.modelId}-${keyProps.categoryId}`,
|
|
368
|
+
}), mergeMap(({ acc: result, createKey }) => {
|
|
382
369
|
input.forEach(({ modelId, categoryId }) => {
|
|
383
|
-
if (!result.
|
|
384
|
-
result.
|
|
370
|
+
if (!result.has(createKey({ modelId, categoryId }))) {
|
|
371
|
+
result.set(createKey({ modelId, categoryId }), { categoryId, modelId, elementsCount: 0 });
|
|
385
372
|
}
|
|
386
373
|
});
|
|
387
|
-
return result;
|
|
388
|
-
}),
|
|
374
|
+
return from(result.values());
|
|
375
|
+
}), toArray());
|
|
389
376
|
}
|
|
390
|
-
|
|
377
|
+
getCategoryElementsCount(modelId, categoryId) {
|
|
391
378
|
return this.#categoryElementCounts.getCategoryElementsCount(modelId, categoryId);
|
|
392
379
|
}
|
|
393
|
-
|
|
380
|
+
createCategoryInstanceKeyPaths(categoryId) {
|
|
394
381
|
let entry = this.#categoryKeyPaths.get(categoryId);
|
|
395
382
|
if (!entry) {
|
|
396
|
-
entry = (
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const categoryEntry = modelInfo.categories.get(categoryId);
|
|
401
|
-
if (categoryEntry?.isRootElementCategory) {
|
|
402
|
-
result.add(modelId);
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
const categoryPaths = new Array();
|
|
406
|
-
for (const categoryModelId of [...result]) {
|
|
407
|
-
const modelPaths = await this.createModelInstanceKeyPaths(categoryModelId);
|
|
408
|
-
for (const modelPath of modelPaths) {
|
|
409
|
-
categoryPaths.push([...modelPath, { className: "BisCore.SpatialCategory", id: categoryId }]);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
return categoryPaths;
|
|
413
|
-
})();
|
|
383
|
+
entry = this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.entries()), filter(([_, modelInfo]) => !!modelInfo.categories.get(categoryId)?.isRootElementCategory), mergeMap(([categoryModelId]) => this.createModelInstanceKeyPaths(categoryModelId)), mergeMap((modelPaths) => modelPaths), reduce((acc, modelPath) => {
|
|
384
|
+
acc.push([...modelPath, { className: "BisCore.SpatialCategory", id: categoryId }]);
|
|
385
|
+
return acc;
|
|
386
|
+
}, new Array()), shareReplay());
|
|
414
387
|
this.#categoryKeyPaths.set(categoryId, entry);
|
|
415
388
|
}
|
|
416
389
|
return entry;
|
|
@@ -433,7 +406,7 @@ class ModelCategoryElementsCountCache {
|
|
|
433
406
|
#subscription;
|
|
434
407
|
constructor(loader) {
|
|
435
408
|
this.#subscription = this.#requestsStream
|
|
436
|
-
.pipe(bufferTime(20), filter((requests) => requests.length > 0), mergeMap(
|
|
409
|
+
.pipe(bufferTime(20), filter((requests) => requests.length > 0), mergeMap((requests) => loader(requests)), mergeAll())
|
|
437
410
|
.subscribe({
|
|
438
411
|
next: ({ modelId, categoryId, elementsCount }) => {
|
|
439
412
|
const subject = this.#cache.get(`${modelId}${categoryId}`);
|
|
@@ -445,16 +418,16 @@ class ModelCategoryElementsCountCache {
|
|
|
445
418
|
[Symbol.dispose]() {
|
|
446
419
|
this.#subscription.unsubscribe();
|
|
447
420
|
}
|
|
448
|
-
|
|
421
|
+
getCategoryElementsCount(modelId, categoryId) {
|
|
449
422
|
const cacheKey = `${modelId}${categoryId}`;
|
|
450
423
|
let result = this.#cache.get(cacheKey);
|
|
451
424
|
if (result !== undefined) {
|
|
452
|
-
return
|
|
425
|
+
return from(result).pipe(take(1));
|
|
453
426
|
}
|
|
454
427
|
result = new ReplaySubject(1);
|
|
455
428
|
this.#cache.set(cacheKey, result);
|
|
456
429
|
this.#requestsStream.next({ modelId, categoryId });
|
|
457
|
-
return
|
|
430
|
+
return from(result).pipe(take(1));
|
|
458
431
|
}
|
|
459
432
|
}
|
|
460
433
|
//# sourceMappingURL=ModelsTreeIdsCache.js.map
|