@itwin/tree-widget-react 3.0.2 → 3.1.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 (92) hide show
  1. package/CHANGELOG.md +25 -2
  2. package/lib/cjs/components/tree-header/TreeHeader.js +1 -1
  3. package/lib/cjs/components/tree-header/TreeHeader.js.map +1 -1
  4. package/lib/cjs/components/trees/categories-tree/CategoriesTreeButtons.js +3 -3
  5. package/lib/cjs/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  6. package/lib/cjs/components/trees/categories-tree/CategoriesVisibilityHandler.js +2 -1
  7. package/lib/cjs/components/trees/categories-tree/CategoriesVisibilityHandler.js.map +1 -1
  8. package/lib/cjs/components/trees/{models-tree/internal → common}/Tooltip.d.ts +7 -3
  9. package/lib/cjs/components/trees/{models-tree/internal → common}/Tooltip.js +5 -5
  10. package/lib/cjs/components/trees/common/Tooltip.js.map +1 -0
  11. package/lib/cjs/components/trees/common/UseActiveViewport.js.map +1 -1
  12. package/lib/cjs/components/trees/common/UseHierarchyVisibility.js +6 -3
  13. package/lib/cjs/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  14. package/lib/cjs/components/trees/common/Utils.js +1 -1
  15. package/lib/cjs/components/trees/common/Utils.js.map +1 -1
  16. package/lib/cjs/components/trees/common/components/TreeNodeCheckbox.js +5 -5
  17. package/lib/cjs/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  18. package/lib/cjs/components/trees/common/components/TreeRenderer.d.ts +1 -1
  19. package/lib/cjs/components/trees/common/components/TreeRenderer.js +4 -3
  20. package/lib/cjs/components/trees/common/components/TreeRenderer.js.map +1 -1
  21. package/lib/cjs/components/trees/common/components/TreeRenderer.scss +0 -6
  22. package/lib/cjs/components/trees/models-tree/ModelsTreeButtons.js +13 -13
  23. package/lib/cjs/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  24. package/lib/cjs/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  25. package/lib/cjs/components/trees/models-tree/ModelsTreeDefinition.js +1 -1
  26. package/lib/cjs/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  27. package/lib/cjs/components/trees/models-tree/UseModelsTree.d.ts +1 -1
  28. package/lib/cjs/components/trees/models-tree/UseModelsTree.js +23 -12
  29. package/lib/cjs/components/trees/models-tree/UseModelsTree.js.map +1 -1
  30. package/lib/cjs/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +5 -0
  31. package/lib/cjs/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +28 -7
  32. package/lib/cjs/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  33. package/lib/cjs/components/trees/models-tree/internal/FilteredTree.d.ts +25 -0
  34. package/lib/cjs/components/trees/models-tree/internal/FilteredTree.js +178 -0
  35. package/lib/cjs/components/trees/models-tree/internal/FilteredTree.js.map +1 -0
  36. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +2 -1
  37. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeIdsCache.js +55 -23
  38. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  39. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeNode.js +1 -1
  40. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  41. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +8 -8
  42. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +162 -207
  43. package/lib/cjs/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  44. package/lib/cjs/components/trees/models-tree/internal/VisibilityChangeEventListener.d.ts +2 -0
  45. package/lib/cjs/components/trees/models-tree/internal/VisibilityChangeEventListener.js +11 -1
  46. package/lib/cjs/components/trees/models-tree/internal/VisibilityChangeEventListener.js.map +1 -1
  47. package/lib/esm/components/tree-header/TreeHeader.js +1 -1
  48. package/lib/esm/components/tree-header/TreeHeader.js.map +1 -1
  49. package/lib/esm/components/trees/categories-tree/CategoriesTreeButtons.js +3 -3
  50. package/lib/esm/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  51. package/lib/esm/components/trees/categories-tree/CategoriesVisibilityHandler.js +2 -1
  52. package/lib/esm/components/trees/categories-tree/CategoriesVisibilityHandler.js.map +1 -1
  53. package/lib/esm/components/trees/{models-tree/internal → common}/Tooltip.d.ts +7 -3
  54. package/lib/esm/components/trees/{models-tree/internal → common}/Tooltip.js +5 -5
  55. package/lib/esm/components/trees/common/Tooltip.js.map +1 -0
  56. package/lib/esm/components/trees/common/UseActiveViewport.js.map +1 -1
  57. package/lib/esm/components/trees/common/UseHierarchyVisibility.js +7 -4
  58. package/lib/esm/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  59. package/lib/esm/components/trees/common/Utils.js +1 -1
  60. package/lib/esm/components/trees/common/Utils.js.map +1 -1
  61. package/lib/esm/components/trees/common/components/TreeNodeCheckbox.js +6 -6
  62. package/lib/esm/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  63. package/lib/esm/components/trees/common/components/TreeRenderer.d.ts +1 -1
  64. package/lib/esm/components/trees/common/components/TreeRenderer.js +4 -3
  65. package/lib/esm/components/trees/common/components/TreeRenderer.js.map +1 -1
  66. package/lib/esm/components/trees/common/components/TreeRenderer.scss +0 -6
  67. package/lib/esm/components/trees/models-tree/ModelsTreeButtons.js +14 -14
  68. package/lib/esm/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  69. package/lib/esm/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  70. package/lib/esm/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  71. package/lib/esm/components/trees/models-tree/UseModelsTree.d.ts +1 -1
  72. package/lib/esm/components/trees/models-tree/UseModelsTree.js +24 -13
  73. package/lib/esm/components/trees/models-tree/UseModelsTree.js.map +1 -1
  74. package/lib/esm/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +5 -0
  75. package/lib/esm/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +29 -8
  76. package/lib/esm/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  77. package/lib/esm/components/trees/models-tree/internal/FilteredTree.d.ts +25 -0
  78. package/lib/esm/components/trees/models-tree/internal/FilteredTree.js +173 -0
  79. package/lib/esm/components/trees/models-tree/internal/FilteredTree.js.map +1 -0
  80. package/lib/esm/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +2 -1
  81. package/lib/esm/components/trees/models-tree/internal/ModelsTreeIdsCache.js +55 -23
  82. package/lib/esm/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  83. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +8 -8
  84. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +161 -206
  85. package/lib/esm/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  86. package/lib/esm/components/trees/models-tree/internal/VisibilityChangeEventListener.d.ts +2 -0
  87. package/lib/esm/components/trees/models-tree/internal/VisibilityChangeEventListener.js +11 -1
  88. package/lib/esm/components/trees/models-tree/internal/VisibilityChangeEventListener.js.map +1 -1
  89. package/lib/public/locales/en/TreeWidget.json +47 -43
  90. package/package.json +11 -11
  91. package/lib/cjs/components/trees/models-tree/internal/Tooltip.js.map +0 -1
  92. package/lib/esm/components/trees/models-tree/internal/Tooltip.js.map +0 -1
@@ -2,35 +2,18 @@
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 { concat, concatAll, defer, distinct, EMPTY, firstValueFrom, forkJoin, from, map, merge, mergeMap, of, reduce } from "rxjs";
5
+ import { bufferCount, concat, concatAll, concatMap, defer, delay, distinct, EMPTY, filter, firstValueFrom, forkJoin, from, fromEventPattern, map, merge, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeUntil, tap, } from "rxjs";
6
6
  import { assert } from "@itwin/core-bentley";
7
7
  import { PerModelCategoryVisibility } from "@itwin/core-frontend";
8
- import { HierarchyFilteringPath, HierarchyNode, HierarchyNodeIdentifier, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
8
+ import { HierarchyNode, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
9
9
  import { toggleAllCategories } from "../../common/CategoriesVisibilityUtils";
10
10
  import { reduceWhile, toVoidPromise } from "../../common/Rxjs";
11
+ import { createVisibilityStatus } from "../../common/Tooltip";
11
12
  import { createVisibilityHandlerResult } from "../../common/UseHierarchyVisibility";
12
13
  import { AlwaysAndNeverDrawnElementInfo } from "./AlwaysAndNeverDrawnElementInfo";
14
+ import { createFilteredTree, parseCategoryKey } from "./FilteredTree";
13
15
  import { ModelsTreeNode } from "./ModelsTreeNode";
14
- import { createVisibilityStatus } from "./Tooltip";
15
16
  import { createVisibilityChangeEventListener } from "./VisibilityChangeEventListener";
16
- export const SUBJECT_CLASS_NAME = "BisCore.Subject";
17
- export const MODEL_CLASS_NAME = "BisCore.GeometricModel3d";
18
- export const CATEGORY_CLASS_NAME = "BisCore.SpatialCategory";
19
- export const ELEMENT_CLASS_NAME = "BisCore.GeometricElement3d";
20
- function createCategoryKey(modelId, categoryId) {
21
- return `${modelId}-${categoryId}`;
22
- }
23
- function parseCategoryKey(key) {
24
- const [modelId, categoryId] = key.split("-");
25
- return { modelId, categoryId };
26
- }
27
- function createElementKey(modelId, categoryId, elementId) {
28
- return `${modelId}-${categoryId}-${elementId}`;
29
- }
30
- function parseElementKey(key) {
31
- const [modelId, categoryId, elementId] = key.split("-");
32
- return { modelId, categoryId, elementId };
33
- }
34
17
  /**
35
18
  * Creates an instance if `ModelsTreeVisibilityHandler`.
36
19
  * @internal
@@ -41,30 +24,55 @@ export function createModelsTreeVisibilityHandler(props) {
41
24
  class ModelsTreeVisibilityHandlerImpl {
42
25
  constructor(_props) {
43
26
  this._props = _props;
27
+ this._elementChangeQueue = new Subject();
28
+ this._subscriptions = [];
29
+ this._changeRequest = new Subject();
44
30
  this._eventListener = createVisibilityChangeEventListener(_props.viewport);
45
31
  this._alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(_props.viewport);
46
32
  this._idsCache = this._props.idsCache;
33
+ this._filteredTree = _props.filteredPaths ? createFilteredTree(this._props.imodelAccess, _props.filteredPaths) : undefined;
34
+ this._subscriptions.push(this._elementChangeQueue.pipe(concatAll()).subscribe());
47
35
  }
48
36
  // istanbul ignore next
49
37
  get onVisibilityChange() {
50
38
  return this._eventListener.onVisibilityChange;
51
39
  }
52
40
  async getVisibilityStatus(node) {
53
- return firstValueFrom(this.getVisibilityStatusObs(node));
41
+ return firstValueFrom(this.getVisibilityStatusObs(node).pipe(
42
+ // unsubscribe from the observable if the change request for this node is received
43
+ takeUntil(this._changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),
44
+ // unsubscribe if visibility changes
45
+ takeUntil(fromEventPattern((handler) => {
46
+ this._eventListener.onVisibilityChange.addListener(handler);
47
+ }, (handler) => {
48
+ this._eventListener.onVisibilityChange.removeListener(handler);
49
+ }))));
54
50
  }
55
51
  async changeVisibility(node, shouldDisplay) {
56
- return toVoidPromise(this.changeVisibilityObs(node, shouldDisplay));
52
+ // notify about new change request
53
+ this._changeRequest.next({ key: node.key, depth: node.parentKeys.length });
54
+ const changeObservable = this.changeVisibilityObs(node, shouldDisplay).pipe(
55
+ // unsubscribe from the observable if the change request for this node is received
56
+ takeUntil(this._changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))), tap({
57
+ subscribe: () => {
58
+ this._eventListener.suppressChangeEvents();
59
+ this._alwaysAndNeverDrawnElements.suppressChangeEvents();
60
+ },
61
+ finalize: () => {
62
+ this._eventListener.resumeChangeEvents();
63
+ this._alwaysAndNeverDrawnElements.resumeChangeEvents();
64
+ },
65
+ }));
66
+ return toVoidPromise(changeObservable);
57
67
  }
58
68
  dispose() {
59
69
  this._eventListener.dispose();
60
70
  this._alwaysAndNeverDrawnElements.dispose();
71
+ this._subscriptions.forEach((x) => x.unsubscribe());
61
72
  }
62
73
  getVisibilityStatusObs(node) {
63
74
  if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
64
- return this.getFilteredNodeVisibility({
65
- parentKeys: [...node.parentKeys, node.key],
66
- filterPaths: node.filtering.filteredChildrenIdentifierPaths,
67
- });
75
+ return this.getFilteredNodeVisibility({ node });
68
76
  }
69
77
  if (HierarchyNode.isClassGroupingNode(node)) {
70
78
  return this.getClassGroupingNodeDisplayStatus(node);
@@ -74,10 +82,10 @@ class ModelsTreeVisibilityHandlerImpl {
74
82
  }
75
83
  if (ModelsTreeNode.isSubjectNode(node)) {
76
84
  // note: subject nodes may be merged to represent multiple subject instances
77
- return this.getSubjectNodeVisibilityStatus(node.key.instanceKeys.map((key) => key.id));
85
+ return this.getSubjectNodeVisibilityStatus({ subjectIds: node.key.instanceKeys.map((key) => key.id) });
78
86
  }
79
87
  if (ModelsTreeNode.isModelNode(node)) {
80
- return this.getModelVisibilityStatus(node.key.instanceKeys[0].id);
88
+ return this.getModelVisibilityStatus({ modelId: node.key.instanceKeys[0].id });
81
89
  }
82
90
  const modelId = ModelsTreeNode.getModelId(node);
83
91
  if (!modelId) {
@@ -99,25 +107,25 @@ class ModelsTreeVisibilityHandlerImpl {
99
107
  categoryId,
100
108
  });
101
109
  }
102
- getFilteredNodeVisibility({ parentKeys, filterPaths }) {
103
- return from(this.getFilterTargets({ parentKeys, filterPaths })).pipe(mergeMap(({ subjects, models, categories, elements }) => {
110
+ getFilteredNodeVisibility(props) {
111
+ return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ subjects, models, categories, elements }) => {
104
112
  const observables = new Array();
105
113
  if (subjects?.size) {
106
- observables.push(this.getSubjectNodeVisibilityStatus([...subjects]));
114
+ observables.push(this.getSubjectNodeVisibilityStatus({ subjectIds: [...subjects], ignoreTooltip: true }));
107
115
  }
108
116
  if (models?.size) {
109
- observables.push(from(models).pipe(mergeMap((modelId) => this.getModelVisibilityStatus(modelId))));
117
+ observables.push(from(models).pipe(mergeMap((modelId) => this.getModelVisibilityStatus({ modelId, ignoreTooltip: true }))));
110
118
  }
111
119
  if (categories?.size) {
112
120
  observables.push(from(categories).pipe(mergeMap((key) => {
113
121
  const { modelId, categoryId } = parseCategoryKey(key);
114
- return this.getCategoryDisplayStatus({ modelId, categoryId });
122
+ return this.getCategoryDisplayStatus({ modelId, categoryId, ignoreTooltip: true });
115
123
  })));
116
124
  }
117
125
  if (elements?.size) {
118
- observables.push(from(elements).pipe(mergeMap((key) => {
119
- const { modelId, categoryId, elementId } = parseElementKey(key);
120
- return this.getElementDisplayStatus({ modelId, categoryId, elementId });
126
+ observables.push(from(elements).pipe(releaseMainThreadOnItemsCount(50), mergeMap(([categoryKey, elementIds]) => {
127
+ const { modelId, categoryId } = parseCategoryKey(categoryKey);
128
+ return from(elementIds).pipe(releaseMainThreadOnItemsCount(1000), mergeMap((elementId) => this.getElementDisplayStatus({ modelId, categoryId, elementId, ignoreTooltip: true })));
121
129
  })));
122
130
  }
123
131
  return merge(...observables);
@@ -126,65 +134,66 @@ class ModelsTreeVisibilityHandlerImpl {
126
134
  return createVisibilityStatus(x);
127
135
  }));
128
136
  }
129
- getSubjectNodeVisibilityStatus(subjectIds) {
137
+ getSubjectNodeVisibilityStatus({ subjectIds, ignoreTooltip }) {
130
138
  const result = defer(() => {
131
139
  if (!this._props.viewport.view.isSpatialView()) {
132
- return of(createVisibilityStatus("disabled", "subject.nonSpatialView"));
140
+ return of(createVisibilityStatus("disabled", getTooltipOptions("modelsTree.subject.nonSpatialView", ignoreTooltip)));
133
141
  }
134
- return from(this._idsCache.getSubjectModelIds(subjectIds)).pipe(concatAll(), distinct(), mergeMap((modelId) => this.getModelVisibilityStatus(modelId)), map((x) => x.state), getVisibilityStatusFromTreeNodeChildren({
135
- visible: "subject.allModelsVisible",
136
- hidden: "subject.allModelsHidden",
137
- partial: "subject.someModelsHidden",
138
- }));
142
+ return from(this._idsCache.getSubjectModelIds(subjectIds)).pipe(concatAll(), distinct(), mergeMap((modelId) => this.getModelVisibilityStatus({ modelId, ignoreTooltip: true })), map((x) => x.state), getVisibilityStatusFromTreeNodeChildren({
143
+ visible: "modelsTree.subject.allModelsVisible",
144
+ hidden: "modelsTree.subject.allModelsHidden",
145
+ partial: "modelsTree.subject.someModelsHidden",
146
+ }, ignoreTooltip));
139
147
  });
140
148
  return createVisibilityHandlerResult(this, { ids: subjectIds }, result, this._props.overrides?.getSubjectNodeVisibility);
141
149
  }
142
- getModelVisibilityStatus(modelId) {
150
+ getModelVisibilityStatus({ modelId, ignoreTooltip }) {
143
151
  const result = defer(() => {
144
152
  const viewport = this._props.viewport;
145
153
  if (!viewport.view.isSpatialView()) {
146
- return of(createVisibilityStatus("disabled", "model.nonSpatialView"));
154
+ return of(createVisibilityStatus("disabled", getTooltipOptions("modelsTree.model.nonSpatialView", ignoreTooltip)));
147
155
  }
148
156
  if (!viewport.view.viewsModel(modelId)) {
149
- return of(createVisibilityStatus("hidden", "model.hiddenThroughModelSelector"));
157
+ return of(createVisibilityStatus("hidden", getTooltipOptions("modelsTree.model.hiddenThroughModelSelector", ignoreTooltip)));
150
158
  }
151
- return from(this._idsCache.getModelCategories(modelId)).pipe(concatAll(), mergeMap((categoryId) => this.getCategoryDisplayStatus({ modelId, categoryId })), map((x) => x.state), getVisibilityFromTreeNodeChildren, map((visibilityByCategories) => {
159
+ return from(this._idsCache.getModelCategories(modelId)).pipe(concatAll(), mergeMap((categoryId) => this.getCategoryDisplayStatus({ modelId, categoryId, ignoreTooltip: true })), map((x) => x.state), getVisibilityFromTreeNodeChildren, map((visibilityByCategories) => {
152
160
  const state = visibilityByCategories === "empty" ? "visible" : visibilityByCategories;
153
- return createVisibilityStatus(state, state === "partial" ? "model.someCategoriesHidden" : `model.allCategories${state ? "Visible" : "Hidden"}`);
161
+ return createVisibilityStatus(state, getTooltipOptions(state === "partial" ? "modelsTree.model.someCategoriesHidden" : `modelsTree.model.allCategories${state ? "Visible" : "Hidden"}`, ignoreTooltip));
154
162
  }));
155
163
  });
156
164
  return createVisibilityHandlerResult(this, { id: modelId }, result, this._props.overrides?.getModelDisplayStatus);
157
165
  }
158
- getDefaultCategoryVisibilityStatus({ modelId, categoryId }) {
166
+ getDefaultCategoryVisibilityStatus({ modelId, categoryId, ignoreTooltip, }) {
159
167
  const viewport = this._props.viewport;
160
168
  if (!viewport.view.viewsModel(modelId)) {
161
- return createVisibilityStatus("hidden", "category.hiddenThroughModel");
169
+ return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.category.hiddenThroughModel", ignoreTooltip));
162
170
  }
163
171
  switch (this._props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId)) {
164
172
  case PerModelCategoryVisibility.Override.Show:
165
- return createVisibilityStatus("visible", "category.displayedThroughPerModelOverride");
173
+ return createVisibilityStatus("visible", getTooltipOptions("modelsTree.category.displayedThroughPerModelOverride", ignoreTooltip));
166
174
  case PerModelCategoryVisibility.Override.Hide:
167
- return createVisibilityStatus("hidden", "category.hiddenThroughPerModelOverride");
175
+ return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.category.hiddenThroughPerModelOverride", ignoreTooltip));
168
176
  }
169
177
  const isVisible = viewport.view.viewsCategory(categoryId);
170
178
  return isVisible
171
- ? createVisibilityStatus("visible", "category.displayedThroughCategorySelector")
172
- : createVisibilityStatus("hidden", "category.hiddenThroughCategorySelector");
179
+ ? createVisibilityStatus("visible", getTooltipOptions("modelsTree.category.displayedThroughCategorySelector", ignoreTooltip))
180
+ : createVisibilityStatus("hidden", getTooltipOptions("modelsTree.category.hiddenThroughCategorySelector", ignoreTooltip));
173
181
  }
174
- getCategoryDisplayStatus(props) {
182
+ getCategoryDisplayStatus({ ignoreTooltip, ...props }) {
175
183
  const result = defer(() => {
176
184
  if (!this._props.viewport.view.viewsModel(props.modelId)) {
177
- return of(createVisibilityStatus("hidden", "category.hiddenThroughModel"));
185
+ return of(createVisibilityStatus("hidden", getTooltipOptions("modelsTree.category.hiddenThroughModel", ignoreTooltip)));
178
186
  }
179
187
  return this.getVisibilityFromAlwaysAndNeverDrawnElements({
180
188
  queryProps: props,
181
189
  tooltips: {
182
- allElementsInAlwaysDrawnList: "category.allElementsVisible",
183
- allElementsInNeverDrawnList: "category.allElementsHidden",
184
- elementsInBothAlwaysAndNeverDrawn: "category.someElementsAreHidden",
185
- noElementsInExclusiveAlwaysDrawnList: "category.allElementsHidden",
190
+ allElementsInAlwaysDrawnList: "modelsTree.category.allElementsVisible",
191
+ allElementsInNeverDrawnList: "modelsTree.category.allElementsHidden",
192
+ elementsInBothAlwaysAndNeverDrawn: "modelsTree.category.someElementsAreHidden",
193
+ noElementsInExclusiveAlwaysDrawnList: "modelsTree.category.allElementsHidden",
186
194
  },
187
195
  defaultStatus: () => this.getDefaultCategoryVisibilityStatus(props),
196
+ ignoreTooltip,
188
197
  });
189
198
  });
190
199
  return createVisibilityHandlerResult(this, props, result, this._props.overrides?.getCategoryDisplayStatus);
@@ -199,58 +208,54 @@ class ModelsTreeVisibilityHandlerImpl {
199
208
  return this.getVisibilityFromAlwaysAndNeverDrawnElements({
200
209
  elements: elementIds,
201
210
  defaultStatus: () => {
202
- const status = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId });
203
- return createVisibilityStatus(status.state, `groupingNode.${status.state}ThroughCategory`);
211
+ const status = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId, ignoreTooltip: true });
212
+ return createVisibilityStatus(status.state, getTooltipOptions(`modelsTree.groupingNode.${status.state}ThroughCategory`));
204
213
  },
205
214
  tooltips: {
206
- allElementsInAlwaysDrawnList: "groupingNode.allElementsVisible",
207
- allElementsInNeverDrawnList: "groupingNode.allElementsHidden",
208
- elementsInBothAlwaysAndNeverDrawn: "groupingNode.someElementsAreHidden",
209
- noElementsInExclusiveAlwaysDrawnList: "groupingNode.allElementsHidden",
215
+ allElementsInAlwaysDrawnList: "modelsTree.groupingNode.allElementsVisible",
216
+ allElementsInNeverDrawnList: "modelsTree.groupingNode.allElementsHidden",
217
+ elementsInBothAlwaysAndNeverDrawn: "modelsTree.groupingNode.someElementsAreHidden",
218
+ noElementsInExclusiveAlwaysDrawnList: "modelsTree.groupingNode.allElementsHidden",
210
219
  },
211
220
  });
212
221
  });
213
222
  return createVisibilityHandlerResult(this, { node }, result, this._props.overrides?.getElementGroupingNodeDisplayStatus);
214
223
  }
215
- getElementOverriddenVisibility(elementId) {
224
+ getElementOverriddenVisibility(elementId, ignoreTooltip) {
216
225
  const viewport = this._props.viewport;
217
226
  if (viewport.neverDrawn?.has(elementId)) {
218
- return createVisibilityStatus("hidden", "element.hiddenThroughNeverDrawnList");
227
+ return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughNeverDrawnList", ignoreTooltip));
219
228
  }
220
229
  if (viewport.alwaysDrawn?.size) {
221
230
  if (viewport.alwaysDrawn.has(elementId)) {
222
- return createVisibilityStatus("visible", "element.displayedThroughAlwaysDrawnList");
231
+ return createVisibilityStatus("visible", getTooltipOptions("modelsTree.element.displayedThroughAlwaysDrawnList", ignoreTooltip));
223
232
  }
224
233
  if (viewport.isAlwaysDrawnExclusive) {
225
- return createVisibilityStatus("hidden", "element.hiddenDueToOtherElementsExclusivelyAlwaysDrawn");
234
+ return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenDueToOtherElementsExclusivelyAlwaysDrawn", ignoreTooltip));
226
235
  }
227
236
  }
228
237
  return undefined;
229
238
  }
230
- getElementDisplayStatus(props) {
239
+ getElementDisplayStatus({ ignoreTooltip, ...props }) {
231
240
  const result = defer(() => {
232
241
  const viewport = this._props.viewport;
233
242
  const { elementId, modelId, categoryId } = props;
234
243
  if (!viewport.view.viewsModel(modelId)) {
235
- return of(createVisibilityStatus("hidden", "element.hiddenThroughModel"));
244
+ return of(createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughModel", ignoreTooltip)));
236
245
  }
237
- let status = this.getElementOverriddenVisibility(elementId);
246
+ let status = this.getElementOverriddenVisibility(elementId, ignoreTooltip);
238
247
  if (status) {
239
248
  return of(status);
240
249
  }
241
- status = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId });
242
- return of(createVisibilityStatus(status.state, status.state === "visible" ? undefined : "element.hiddenThroughCategory"));
250
+ status = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId, ignoreTooltip: true });
251
+ return of(createVisibilityStatus(status.state, getTooltipOptions(status.state === "visible" ? undefined : "modelsTree.element.hiddenThroughCategory", ignoreTooltip)));
243
252
  });
244
253
  return createVisibilityHandlerResult(this, props, result, this._props.overrides?.getElementDisplayStatus);
245
254
  }
246
255
  /** Changes visibility of the items represented by the tree node. */
247
256
  changeVisibilityObs(node, on) {
248
257
  if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
249
- return this.changeFilteredNodeVisibility({
250
- parentKeys: [...node.parentKeys, node.key],
251
- filterPaths: node.filtering.filteredChildrenIdentifierPaths,
252
- on,
253
- });
258
+ return this.changeFilteredNodeVisibility({ node, on });
254
259
  }
255
260
  if (HierarchyNode.isClassGroupingNode(node)) {
256
261
  return this.changeElementGroupingNodeState(node, on);
@@ -283,62 +288,19 @@ class ModelsTreeVisibilityHandlerImpl {
283
288
  // istanbul ignore next
284
289
  return EMPTY;
285
290
  }
286
- return this.changeElementState({
287
- elementId: node.key.instanceKeys[0].id,
291
+ return this.changeElementsState({
292
+ elementIds: new Set([...node.key.instanceKeys.map(({ id }) => id)]),
288
293
  modelId,
289
294
  categoryId,
290
295
  on,
291
296
  });
292
297
  }
293
- async getFilterTargets({ parentKeys, filterPaths }) {
294
- const filterTargets = {};
295
- function addFilterTarget(targetType, value) {
296
- (filterTargets[targetType] ??= new Set()).add(value);
297
- }
298
- const imodelAccess = this._props.imodelAccess;
299
- // Remove all paths such that there are paths to any of the ancestors of the filter target.
300
- const paths = reduceFilterPaths(filterPaths);
301
- await Promise.all(paths.map(async (path) => {
302
- const target = path[path.length - 1];
303
- if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(target)) {
304
- return;
305
- }
306
- const previousPath = path.slice(0, path.length - 1);
307
- if (await imodelAccess.classDerivesFrom(target.className, SUBJECT_CLASS_NAME)) {
308
- addFilterTarget("subjects", target.id);
309
- return;
310
- }
311
- if (await imodelAccess.classDerivesFrom(target.className, MODEL_CLASS_NAME)) {
312
- addFilterTarget("models", target.id);
313
- return;
314
- }
315
- if (await imodelAccess.classDerivesFrom(target.className, CATEGORY_CLASS_NAME)) {
316
- // eslint-disable-next-line @typescript-eslint/no-shadow
317
- const modelId = await this.findClassIdInFilterPath(previousPath, parentKeys, MODEL_CLASS_NAME);
318
- addFilterTarget("categories", createCategoryKey(modelId, target.id));
319
- return;
320
- }
321
- const [modelId, categoryId] = await Promise.all([
322
- this.findClassIdInFilterPath(previousPath, parentKeys, MODEL_CLASS_NAME),
323
- this.findClassIdInFilterPath(previousPath, parentKeys, CATEGORY_CLASS_NAME),
324
- ]);
325
- addFilterTarget("elements", createElementKey(modelId, categoryId, target.id));
326
- // Add parent elements to the filter targets as well
327
- for (let idx = path.length - 1; idx >= 0; --idx) {
328
- const pathIdentifier = path[idx];
329
- if (!HierarchyNodeIdentifier.isInstanceNodeIdentifier(pathIdentifier)) {
330
- continue;
331
- }
332
- if (!(await imodelAccess.classDerivesFrom(pathIdentifier.className, ELEMENT_CLASS_NAME))) {
333
- break;
334
- }
335
- addFilterTarget("elements", createElementKey(modelId, categoryId, pathIdentifier.id));
336
- }
337
- }));
338
- return filterTargets;
298
+ async getVisibilityChangeTargets({ node }) {
299
+ const filteredTree = await this._filteredTree;
300
+ return filteredTree ? filteredTree.getVisibilityChangeTargets(node) : {};
339
301
  }
340
302
  changeFilteredNodeVisibility({ on, ...props }) {
341
- return from(this.getFilterTargets(props)).pipe(mergeMap(({ subjects, models, categories, elements }) => {
303
+ return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ subjects, models, categories, elements }) => {
342
304
  const observables = new Array();
343
305
  if (subjects?.size) {
344
306
  observables.push(this.changeSubjectNodeState([...subjects], on));
@@ -353,9 +315,9 @@ class ModelsTreeVisibilityHandlerImpl {
353
315
  })));
354
316
  }
355
317
  if (elements?.size) {
356
- observables.push(from(elements).pipe(mergeMap((key) => {
357
- const { modelId, categoryId, elementId } = parseElementKey(key);
358
- return this.changeElementState({ modelId, categoryId, elementId, on });
318
+ observables.push(from(elements).pipe(mergeMap(([categoryKey, elementIds]) => {
319
+ const { modelId, categoryId } = parseCategoryKey(categoryKey);
320
+ return this.changeElementsState({ modelId, categoryId, elementIds, on });
359
321
  })));
360
322
  }
361
323
  return merge(...observables);
@@ -444,9 +406,9 @@ class ModelsTreeVisibilityHandlerImpl {
444
406
  const { modelId, categoryId, elementIds } = info;
445
407
  const viewport = this._props.viewport;
446
408
  return concat(on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
447
- const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId });
409
+ const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId, ignoreTooltip: true });
448
410
  const isDisplayedByDefault = categoryVisibility.state === "visible";
449
- return from(elementIds).pipe(this.changeElementStateNoChildrenOperator({ on, isDisplayedByDefault }));
411
+ return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
450
412
  }));
451
413
  });
452
414
  return createVisibilityHandlerResult(this, { node, on }, result, this._props.overrides?.changeElementGroupingNodeState);
@@ -455,23 +417,49 @@ class ModelsTreeVisibilityHandlerImpl {
455
417
  * Updates visibility of an element and all its child elements by adding them to the always/never drawn list.
456
418
  * @note If element is to be enabled and model is hidden, it will be enabled.
457
419
  */
458
- changeElementState(props) {
420
+ changeElementsState(props) {
459
421
  const result = defer(() => {
460
- const { elementId, on, modelId, categoryId } = props;
422
+ const { elementIds, on, modelId, categoryId } = props;
461
423
  const viewport = this._props.viewport;
462
424
  return concat(props.on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
463
- const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId });
425
+ const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryId, modelId, ignoreTooltip: true });
464
426
  const isDisplayedByDefault = categoryVisibility.state === "visible";
465
- return of(elementId).pipe(this.changeElementStateNoChildrenOperator({ on, isDisplayedByDefault }));
427
+ return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
466
428
  }));
467
429
  });
468
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.changeElementState);
430
+ return createVisibilityHandlerResult(this, props, result, this._props.overrides?.changeElementsState);
431
+ }
432
+ queueElementsVisibilityChange(elementIds, on, visibleByDefault) {
433
+ const finishedSubject = new Subject();
434
+ // observable to track if visibility change is finished/cancelled
435
+ const changeFinished = finishedSubject.pipe(startWith(false), shareReplay(1), filter((finished) => finished));
436
+ const changeObservable = from(elementIds).pipe(
437
+ // check if visibility change is not finished (cancelled) due to change overall change request being cancelled
438
+ takeUntil(changeFinished), this.changeElementStateNoChildrenOperator({ on, isDisplayedByDefault: visibleByDefault }), tap({
439
+ next: () => {
440
+ // notify that visibility change is finished
441
+ finishedSubject.next(true);
442
+ },
443
+ }));
444
+ // queue visibility change. `changeObservable` will be subscribed to when other queue changes are finished
445
+ this._elementChangeQueue.next(changeObservable);
446
+ // return observable that will emit when visibility change is finished
447
+ return changeFinished.pipe(take(1), tap({
448
+ unsubscribe: () => {
449
+ // if this observable is unsubscribed before visibility change is finished, we have to notify that it queued change request is cancelled
450
+ finishedSubject.next(true);
451
+ },
452
+ }), map(() => undefined));
469
453
  }
470
454
  changeElementStateNoChildrenOperator(props) {
471
455
  return (elementIds) => {
472
456
  const { on, isDisplayedByDefault } = props;
473
457
  const isAlwaysDrawnExclusive = this._props.viewport.isAlwaysDrawnExclusive;
474
- return elementIds.pipe(reduce((acc, elementId) => {
458
+ return elementIds.pipe(releaseMainThreadOnItemsCount(500), reduce((acc, elementId) => {
459
+ if (acc.alwaysDrawn === undefined || acc.neverDrawn === undefined) {
460
+ acc.alwaysDrawn = new Set(this._props.viewport.alwaysDrawn || []);
461
+ acc.neverDrawn = new Set(this._props.viewport.neverDrawn || []);
462
+ }
475
463
  if (on) {
476
464
  const wasRemoved = acc.neverDrawn.delete(elementId);
477
465
  acc.changedNeverDrawn ||= wasRemoved;
@@ -494,39 +482,39 @@ class ModelsTreeVisibilityHandlerImpl {
494
482
  }, {
495
483
  changedNeverDrawn: false,
496
484
  changedAlwaysDrawn: false,
497
- neverDrawn: new Set(this._props.viewport.neverDrawn || []),
498
- alwaysDrawn: new Set(this._props.viewport.alwaysDrawn || []),
485
+ neverDrawn: undefined,
486
+ alwaysDrawn: undefined,
499
487
  }), map((state) => {
500
- state.changedNeverDrawn && this._props.viewport.setNeverDrawn(state.neverDrawn);
501
- state.changedAlwaysDrawn && this._props.viewport.setAlwaysDrawn(state.alwaysDrawn, this._props.viewport.isAlwaysDrawnExclusive);
488
+ state.changedNeverDrawn && state.neverDrawn && this._props.viewport.setNeverDrawn(state.neverDrawn);
489
+ state.changedAlwaysDrawn && state.alwaysDrawn && this._props.viewport.setAlwaysDrawn(state.alwaysDrawn, this._props.viewport.isAlwaysDrawnExclusive);
502
490
  }));
503
491
  };
504
492
  }
505
493
  getVisibilityFromAlwaysAndNeverDrawnElementsImpl(props) {
506
- const { alwaysDrawn, neverDrawn, totalCount } = props;
494
+ const { alwaysDrawn, neverDrawn, totalCount, ignoreTooltip } = props;
507
495
  if (neverDrawn?.size === totalCount) {
508
- return createVisibilityStatus("hidden", props.tooltips.allElementsInNeverDrawnList);
496
+ return createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.allElementsInNeverDrawnList, ignoreTooltip));
509
497
  }
510
498
  if (alwaysDrawn?.size === totalCount) {
511
- return createVisibilityStatus("visible", props.tooltips.allElementsInAlwaysDrawnList);
499
+ return createVisibilityStatus("visible", getTooltipOptions(props.tooltips.allElementsInAlwaysDrawnList, ignoreTooltip));
512
500
  }
513
501
  const viewport = this._props.viewport;
514
502
  if (viewport.isAlwaysDrawnExclusive && viewport.alwaysDrawn?.size) {
515
503
  return alwaysDrawn?.size
516
- ? createVisibilityStatus("partial", props.tooltips.elementsInBothAlwaysAndNeverDrawn)
517
- : createVisibilityStatus("hidden", props.tooltips.noElementsInExclusiveAlwaysDrawnList);
504
+ ? createVisibilityStatus("partial", getTooltipOptions(props.tooltips.elementsInBothAlwaysAndNeverDrawn, ignoreTooltip))
505
+ : createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.noElementsInExclusiveAlwaysDrawnList, ignoreTooltip));
518
506
  }
519
507
  const status = props.defaultStatus();
520
508
  if ((status.state === "visible" && neverDrawn?.size) || (status.state === "hidden" && alwaysDrawn?.size)) {
521
- return createVisibilityStatus("partial");
509
+ return createVisibilityStatus("partial", getTooltipOptions(undefined, ignoreTooltip));
522
510
  }
523
511
  return status;
524
512
  }
525
- getVisibilityFromAlwaysAndNeverDrawnElements(props) {
513
+ getVisibilityFromAlwaysAndNeverDrawnElements({ ignoreTooltip, ...props }) {
526
514
  const viewport = this._props.viewport;
527
515
  if (viewport.isAlwaysDrawnExclusive) {
528
516
  if (!viewport?.alwaysDrawn?.size) {
529
- return of(createVisibilityStatus("hidden", props.tooltips.noElementsInExclusiveAlwaysDrawnList));
517
+ return of(createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.noElementsInExclusiveAlwaysDrawnList, ignoreTooltip)));
530
518
  }
531
519
  }
532
520
  else if (!viewport?.neverDrawn?.size && !viewport?.alwaysDrawn?.size) {
@@ -538,6 +526,7 @@ class ModelsTreeVisibilityHandlerImpl {
538
526
  alwaysDrawn: viewport.alwaysDrawn?.size ? setIntersection(props.elements, viewport.alwaysDrawn) : undefined,
539
527
  neverDrawn: viewport.neverDrawn?.size ? setIntersection(props.elements, viewport.neverDrawn) : undefined,
540
528
  totalCount: props.elements.size,
529
+ ignoreTooltip,
541
530
  }));
542
531
  }
543
532
  const { modelId, categoryId } = props.queryProps;
@@ -550,6 +539,7 @@ class ModelsTreeVisibilityHandlerImpl {
550
539
  return this.getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
551
540
  ...props,
552
541
  ...state,
542
+ ignoreTooltip,
553
543
  });
554
544
  }));
555
545
  }
@@ -580,28 +570,6 @@ class ModelsTreeVisibilityHandlerImpl {
580
570
  const elementIds = new Set(node.groupedInstanceKeys.map((key) => key.id));
581
571
  return { modelId, categoryId, elementIds };
582
572
  }
583
- async findClassIdInFilterPath(path, parentKeys, className) {
584
- function* keysToCheck() {
585
- for (let i = path.length - 1; i >= 0; --i) {
586
- const id = path[i];
587
- if (HierarchyNodeIdentifier.isInstanceNodeIdentifier(id)) {
588
- yield id;
589
- }
590
- }
591
- for (let i = parentKeys.length - 1; i >= 0; --i) {
592
- const key = parentKeys[i];
593
- if (HierarchyNodeKey.isInstances(key)) {
594
- yield* key.instanceKeys;
595
- }
596
- }
597
- }
598
- for (const parentKey of keysToCheck()) {
599
- if (await this._props.imodelAccess.classDerivesFrom(parentKey.className, className)) {
600
- return parentKey.id;
601
- }
602
- }
603
- assert(false, () => `Cannot find an instance of ${className} in instance keys: ${JSON.stringify([...keysToCheck()], undefined, 2)}`);
604
- }
605
573
  }
606
574
  function getVisibilityFromTreeNodeChildren(obs) {
607
575
  return obs.pipe(reduceWhile((x) => x.allVisible || x.allHidden, (acc, val) => {
@@ -615,13 +583,13 @@ function getVisibilityFromTreeNodeChildren(obs) {
615
583
  return x.allVisible ? "visible" : x.allHidden ? "hidden" : "partial";
616
584
  }));
617
585
  }
618
- function getVisibilityStatusFromTreeNodeChildren(tooltipMap) {
586
+ function getVisibilityStatusFromTreeNodeChildren(tooltipMap, ignoreTooltip) {
619
587
  return (obs) => {
620
588
  return getVisibilityFromTreeNodeChildren(obs).pipe(map((visibility) => {
621
589
  if (visibility === "empty") {
622
590
  visibility = "visible";
623
591
  }
624
- return createVisibilityStatus(visibility, tooltipMap[visibility]);
592
+ return createVisibilityStatus(visibility, getTooltipOptions(tooltipMap[visibility], ignoreTooltip));
625
593
  }));
626
594
  };
627
595
  }
@@ -635,35 +603,6 @@ function setIntersection(lhs, rhs) {
635
603
  lhs.forEach((x) => rhs.has(x) && result.add(x));
636
604
  return result;
637
605
  }
638
- function reduceFilterPaths(filteringPaths) {
639
- let paths = filteringPaths.map((filteringPath) => HierarchyFilteringPath.normalize(filteringPath).path);
640
- const sorted = [...paths].sort((a, b) => a.length - b.length);
641
- paths = [];
642
- for (const path of sorted) {
643
- if (!arraySortedByLengthContainsPrefix(paths, path)) {
644
- paths.push(path);
645
- }
646
- }
647
- return paths;
648
- }
649
- function arraySortedByLengthContainsPrefix(targetArray, source) {
650
- for (const targetVal of targetArray) {
651
- if (targetVal.length >= source.length) {
652
- break;
653
- }
654
- let isPrefix = true;
655
- for (let i = 0; i < targetVal.length; ++i) {
656
- if (!HierarchyNodeIdentifier.equal(targetVal[i], source[i])) {
657
- isPrefix = false;
658
- break;
659
- }
660
- }
661
- if (isPrefix) {
662
- return true;
663
- }
664
- }
665
- return false;
666
- }
667
606
  /**
668
607
  * Enables display of all given models. Also enables display of all categories and clears always and
669
608
  * never drawn lists in the viewport.
@@ -723,4 +662,20 @@ export async function toggleModels(models, enable, viewport) {
723
662
  export function areAllModelsVisible(models, viewport) {
724
663
  return models.length !== 0 ? models.every((id) => viewport.viewsModel(id)) : false;
725
664
  }
665
+ function releaseMainThreadOnItemsCount(elementCount) {
666
+ return (obs) => {
667
+ return obs.pipe(bufferCount(elementCount), concatMap((buff, i) => {
668
+ const out = of(buff);
669
+ if (i === 0 && buff.length < elementCount) {
670
+ return out;
671
+ }
672
+ return out.pipe(delay(0));
673
+ }), concatAll());
674
+ };
675
+ }
676
+ function getTooltipOptions(key, ignoreTooltip) {
677
+ return {
678
+ useTooltip: ignoreTooltip ? false : key,
679
+ };
680
+ }
726
681
  //# sourceMappingURL=ModelsTreeVisibilityHandler.js.map