[Tree widget]: parent elements correct visibility on next#1686
Conversation
There was a problem hiding this comment.
Tree-Widget Next benchmark
| Benchmark suite | Current: 778a56b | Previous: 514cc88 | Deviation | Status |
|---|---|---|---|---|
models tree 50k 3D elements search > get search paths |
946 ms |
1236 ms |
-23.46% |
✅ |
models tree 50k 3D elements search > get search paths (P95 of main thread blocks) |
55 ms |
60 ms |
-8.33% |
〰️ |
models tree 50k 3D elements search > load hierarchy from search paths |
94539 ms |
110512 ms |
-14.45% |
✅ |
models tree 50k 3D elements search > load hierarchy from search paths (P95 of main thread blocks) |
26 ms |
37 ms |
-29.73% |
〰️ |
models tree 50k categories > collect nodes |
2486 ms |
2893 ms |
-14.07% |
✅ |
models tree 50k categories > collect nodes (P95 of main thread blocks) |
73 ms |
131 ms |
-44.27% |
✅ |
models tree 50k categories > validate initial visibility |
1838 ms |
2078 ms |
-11.55% |
✅ |
models tree 50k categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k categories > change visibility |
67 ms |
71 ms |
-5.63% |
〰️ |
models tree 50k categories > change visibility (P95 of main thread blocks) |
57 ms |
60 ms |
-5% |
〰️ |
models tree 50k categories > validate changed visibility |
3273 ms |
3685 ms |
-11.18% |
✅ |
models tree 50k categories > validate changed visibility (P95 of main thread blocks) |
23 ms |
22 ms |
4.55% |
〰️ |
models tree 50k 3D elements > collect nodes |
36931 ms |
43988 ms |
-16.04% |
✅ |
models tree 50k 3D elements > collect nodes (P95 of main thread blocks) |
56 ms |
69 ms |
-18.84% |
〰️ |
models tree 50k 3D elements > validate initial visibility |
1512 ms |
2096 ms |
-27.86% |
✅ |
models tree 50k 3D elements > validate initial visibility (P95 of main thread blocks) |
0 ms |
26 ms |
-100% |
〰️ |
models tree 50k 3D elements > change model visibility |
15 ms |
20 ms |
-25% |
〰️ |
models tree 50k 3D elements > change model visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed model visibility |
3122 ms |
2050 ms |
52.29% |
🚨 |
models tree 50k 3D elements > validate changed model visibility (P95 of main thread blocks) |
25 ms |
0 ms |
2500% |
〰️ |
models tree 50k 3D elements > change category node visibility |
411 ms |
517 ms |
-20.50% |
✅ |
models tree 50k 3D elements > change category node visibility (P95 of main thread blocks) |
43 ms |
57 ms |
-24.56% |
〰️ |
models tree 50k 3D elements > validate changed category visibility |
1982 ms |
2053 ms |
-3.46% |
〰️ |
models tree 50k 3D elements > validate changed category visibility (P95 of main thread blocks) |
33 ms |
0 ms |
3300% |
〰️ |
models tree 50k 3D elements > validate per-model category override |
1808 ms |
2019 ms |
-10.45% |
✅ |
models tree 50k 3D elements > validate per-model category override (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > change element visibility |
33 ms |
56 ms |
-41.07% |
〰️ |
models tree 50k 3D elements > change element visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed element visibility |
2244 ms |
2779 ms |
-19.25% |
✅ |
models tree 50k 3D elements > validate changed element visibility (P95 of main thread blocks) |
58 ms |
86 ms |
-32.56% |
〰️ |
models tree 50k 3D child elements with different categories > collect nodes |
37849 ms |
44118 ms |
-14.21% |
✅ |
models tree 50k 3D child elements with different categories > collect nodes (P95 of main thread blocks) |
49 ms |
62 ms |
-20.97% |
〰️ |
models tree 50k 3D child elements with different categories > validate initial visibility |
1544 ms |
1992 ms |
-22.49% |
✅ |
models tree 50k 3D child elements with different categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > change visibility |
50 ms |
52 ms |
-3.85% |
〰️ |
models tree 50k 3D child elements with different categories > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > validate changed visibility |
3821 ms |
2793 ms |
36.81% |
🚨 |
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) |
146 ms |
68 ms |
114.71% |
🚨 |
categories tree 50k subCategories search > get search paths |
1476 ms |
1824 ms |
-19.08% |
✅ |
categories tree 50k subCategories search > get search paths (P95 of main thread blocks) |
31 ms |
42 ms |
-26.19% |
〰️ |
categories tree 50k subCategories search > load hierarchy from search paths |
4303 ms |
5443 ms |
-20.94% |
✅ |
categories tree 50k subCategories search > load hierarchy from search paths (P95 of main thread blocks) |
36 ms |
48 ms |
-25% |
〰️ |
categories tree 50k subCategories > collect nodes |
4699 ms |
5948 ms |
-21.00% |
✅ |
categories tree 50k subCategories > collect nodes (P95 of main thread blocks) |
34 ms |
45 ms |
-24.44% |
〰️ |
categories tree 50k subCategories > validate initial visibility |
1083 ms |
1219 ms |
-11.16% |
✅ |
categories tree 50k subCategories > validate initial visibility (P95 of main thread blocks) |
22 ms |
25 ms |
-12% |
〰️ |
categories tree 50k subCategories > change visibility |
339 ms |
348 ms |
-2.59% |
〰️ |
categories tree 50k subCategories > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
categories tree 50k subCategories > validate changed visibility |
1080 ms |
1142 ms |
-5.43% |
〰️ |
categories tree 50k subCategories > validate changed visibility (P95 of main thread blocks) |
28 ms |
25 ms |
12% |
〰️ |
categories tree 50k categories > collect nodes |
2070 ms |
2481 ms |
-16.57% |
✅ |
categories tree 50k categories > collect nodes (P95 of main thread blocks) |
118 ms |
131 ms |
-9.92% |
〰️ |
categories tree 50k categories > validate initial visibility |
5576 ms |
6393 ms |
-12.78% |
✅ |
categories tree 50k categories > validate initial visibility (P95 of main thread blocks) |
109 ms |
130 ms |
-16.15% |
〰️ |
categories tree 50k categories > change visibility |
662 ms |
673 ms |
-1.63% |
〰️ |
categories tree 50k categories > change visibility (P95 of main thread blocks) |
50 ms |
49 ms |
2.04% |
〰️ |
categories tree 50k categories > validate changed visibility |
5197 ms |
6092 ms |
-14.69% |
✅ |
categories tree 50k categories > validate changed visibility (P95 of main thread blocks) |
40 ms |
34 ms |
17.65% |
〰️ |
classifications tree 50k classifications search > get search paths |
1722 ms |
2177 ms |
-20.90% |
✅ |
classifications tree 50k classifications search > get search paths (P95 of main thread blocks) |
119 ms |
126 ms |
-5.56% |
〰️ |
classifications tree 50k classifications search > load hierarchy from search paths |
58202 ms |
67599 ms |
-13.90% |
✅ |
classifications tree 50k classifications search > load hierarchy from search paths (P95 of main thread blocks) |
0 ms |
31 ms |
-100% |
〰️ |
classifications tree 50k classifications > collect nodes |
27878 ms |
36671 ms |
-23.98% |
✅ |
classifications tree 50k classifications > collect nodes (P95 of main thread blocks) |
72 ms |
88 ms |
-18.18% |
〰️ |
classifications tree 50k classifications > validate initial visibility |
3590 ms |
4143 ms |
-13.35% |
✅ |
classifications tree 50k classifications > validate initial visibility (P95 of main thread blocks) |
55 ms |
72 ms |
-23.61% |
〰️ |
classifications tree 50k classifications > change visibility |
26 ms |
30 ms |
-13.33% |
〰️ |
classifications tree 50k classifications > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
classifications tree 50k classifications > validate changed visibility |
3915 ms |
4484 ms |
-12.69% |
✅ |
classifications tree 50k classifications > validate changed visibility (P95 of main thread blocks) |
74 ms |
83 ms |
-10.84% |
〰️ |
This comment was automatically generated by workflow using github-action-benchmark.
There was a problem hiding this comment.
Pull request overview
This PR updates Tree Widget element visibility computation to correctly reflect parent-element visibility when navigating “next”, by separating an element’s own visibility from its descendants’ visibility and computing descendant visibility per actual descendant category (via DescendantsCountCache). It also removes the prior childrenCount-based approach and simplifies search-results handling by using an ignoreDescendants flag.
Changes:
- Reworked
BaseVisibilityHelper.getElementsVisibilityStatusinto “own visibility” + “descendants visibility (grouped by actual category)” + “sub-models”, and addedignoreDescendants. - Extended
AlwaysAndNeverDrawnElementInfoCache.getAlwaysOrNeverDrawnElementswith an optionalchildCategoryIdsfilter to support descendant-category-specific queries. - Removed
childrenCountandsearchTargetsextended data (and related ECSQL selectors) across tree definitions/handlers; updated tests to match new visibility semantics.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.ts | Removes childrenCount extended data and its recursive ECSQL selector from models tree nodes. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHelper.ts | Updates helper calls to new getElementsVisibilityStatus signature (no childrenCount). |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/models-tree/internal/visibility/ModelsTreeVisibilityHandler.ts | Updates search-target visibility logic to split search targets vs non-targets using ignoreDescendants. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNodeInternal.ts | Removes childrenCount/searchTargets from internal node typing. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.ts | Core refactor: compute own visibility separately; compute descendants visibility per descendant category; introduces ignoreDescendants. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/Utils.ts | Simplifies groupingNodeDataFromChildren to only derive search-related flags. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/useTreeHooks/UseCachedVisibility.ts | Adjusts getSearchTargetsVisibilityStatus signature usage (no node parameter). |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/AlwaysAndNeverDrawnElementInfoCache.ts | Adds childCategoryIds filtering when collecting always/never-drawn element IDs. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/classifications-tree/internal/visibility/ClassificationsTreeVisibilityHandler.ts | Updates element/search-target visibility logic to use ignoreDescendants instead of childrenCount. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeNodeInternal.ts | Removes childrenCount from internal node typing. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.ts | Removes recursive ECSQL childrenCount selector from classification element nodes. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHelper.ts | Updates helper calls to new getElementsVisibilityStatus signature (no childrenCount). |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/visibility/CategoriesTreeVisibilityHandler.ts | Updates search-target visibility logic to split search targets vs non-targets using ignoreDescendants. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeNodeInternal.ts | Removes childrenCount/searchTargets from internal node typing. |
| packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.ts | Removes childrenCount extended data and its recursive ECSQL selector from categories tree nodes. |
| packages/itwin/tree-widget/src/test/trees/models-tree/Utils.ts | Updates test node factories to remove childrenCount. |
| packages/itwin/tree-widget/src/test/trees/models-tree/internal/ModelsTreeVisibilityHandler.test.ts | Updates expectations and adds coverage for parent partial visibility when descendant category differs. |
| packages/itwin/tree-widget/src/test/trees/categories-tree/internal/Utils.ts | Updates test node factories to remove childrenCount. |
Comments suppressed due to low confidence (1)
packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.ts:399
getDescendantsVisibilityStatusiterateselementIdsusingfrom(Id64.iterable(...)), which emits synchronously and can enqueue a large number of descendant-count queries without yielding. To avoid UI jank for large grouped-element sets, consider usingfromWithRelease({ source: elementIds, releaseOnCount: ... })(consistent with other loops in this file) and, if needed, amergeMapconcurrency limit.
return from(Id64.iterable(elementIds)).pipe(
mergeMap((elementId) => this.#props.baseIdsCache.getDescendantsCounts({ parentElementId: elementId, modelId })),
reduce(
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Phase 3a. of #1678.
Skipping phase 2 for now, since it would add child categories (and visibilities would become confusing). Will do it after phase 3 is done. Changes:
BaseVisibilityHelper.ts:
getElementsVisibilityStatusto compute descendant visibility per-category usingDescendantsCountCachegetElementsOwnVisibilityStatus- computes element's own visibility without descendantsgetDescendantsVisibilityStatus- groups descendant categories by default visibility (visible/hidden), queries always/neverDrawn sets filtered by category, and merges statuseschildrenCountparameter withcomputeOnlyOwnStatusflaggetVisibilityFromAlwaysAndNeverDrawnElementsnow it accepts only category path (previously element and category)AlwaysAndNeverDrawnElementInfoCache.ts:
childCategoryIds?: Id64Setfilter togetAlwaysOrNeverDrawnElements- returns only elements whose actual category matches the filterTree handlers (models, categories, classifications):
childrenCountfrom allgetElementsVisibilityStatuscallscomputeOnlyOwnStatus: trueinstead ofchildrenCount: undefinedchildrenCount/searchTargetsfrom grouping node extended data and tree definitionsgroupingNodeDataFromChildrenutility