Skip to content

[Tree widget]: change how categories handle their visibility on next#1694

Merged
JonasDov merged 11 commits into
tree-widget/nextfrom
JonasD/phase-3b
Jun 1, 2026
Merged

[Tree widget]: change how categories handle their visibility on next#1694
JonasDov merged 11 commits into
tree-widget/nextfrom
JonasD/phase-3b

Conversation

@JonasDov
Copy link
Copy Markdown
Contributor

Phases 3b and 3d. of #1678.
In addition: changed model visibility to always use includeOnlyIfCategoryOfTopMostElement: true (previously only if isAlwaysDrawnExclusive mode), since top-most categories now correctly determine visibility of nested children in differentcategories.

Copilot AI review requested due to automatic review settings May 26, 2026 08:41
@JonasDov JonasDov requested review from a team as code owners May 26, 2026 08:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates tree-widget visibility computation to better account for descendant elements whose categories differ from their ancestors, and aligns model/category visibility calculations with “top-most category” semantics.

Changes:

  • Always compute model visibility using only categories of top-most elements (includeOnlyIfCategoryOfTopMostElement: true) and rely on descendant-category grouping for correctness.
  • Refactor always/never-drawn-based visibility to group descendant counts by the descendants’ actual categories and compute visibility per visible/hidden group.
  • Update visibility tests to expect “all-visible” outcomes for cross-category descendant scenarios; adjust test cache mock behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/visibility/BaseVisibilityHelper.ts Refactors visibility computation to use top-most categories and grouped descendant-category logic; updates change flows to account for cross-category descendants.
packages/itwin/tree-widget/src/test/trees/models-tree/Utils.ts Updates fake IDs cache getDescendantsCounts mock used by tests.
packages/itwin/tree-widget/src/test/trees/models-tree/internal/ModelsTreeVisibilityHandler.test.ts Updates expectations for model/category/element visibility in “child element category differs from parent’s” scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/itwin/tree-widget/src/test/trees/models-tree/Utils.ts
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tree-Widget Next benchmark

Benchmark suite Current: c4f6b1e Previous: b618ede Deviation Status
models tree 50k 3D elements search > get search paths 1170 ms 1207 ms -3.07% 〰️
models tree 50k 3D elements search > get search paths (P95 of main thread blocks) 53 ms 58 ms -8.62% 〰️
models tree 50k 3D elements search > load hierarchy from search paths 104792 ms 117082 ms -10.50%
models tree 50k 3D elements search > load hierarchy from search paths (P95 of main thread blocks) 32 ms 33 ms -3.03% 〰️
models tree 50k categories > collect nodes 2855 ms 3016 ms -5.34% 〰️
models tree 50k categories > collect nodes (P95 of main thread blocks) 127 ms 169 ms -24.85% 〰️
models tree 50k categories > validate initial visibility 1911 ms 2072 ms -7.77% 〰️
models tree 50k categories > validate initial visibility (P95 of main thread blocks) 0 ms 0 ms 0% 🟰
models tree 50k categories > change visibility 217 ms 87 ms 149.43% 🚨
models tree 50k categories > change visibility (P95 of main thread blocks) 56 ms 76 ms -26.32% 〰️
models tree 50k categories > validate changed visibility 3637 ms 3647 ms -0.27% 〰️
models tree 50k categories > validate changed visibility (P95 of main thread blocks) 28 ms 39 ms -28.21% 〰️
models tree 50k 3D elements > collect nodes 41176 ms 46645 ms -11.72%
models tree 50k 3D elements > collect nodes (P95 of main thread blocks) 69 ms 76 ms -9.21% 〰️
models tree 50k 3D elements > validate initial visibility 1478 ms 1748 ms -15.45%
models tree 50k 3D elements > validate initial visibility (P95 of main thread blocks) 23 ms 0 ms 2300% 〰️
models tree 50k 3D elements > change model visibility 103 ms 21 ms 390.48% 🚨
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 1988 ms 3216 ms -38.18%
models tree 50k 3D elements > validate changed model visibility (P95 of main thread blocks) 0 ms 24 ms -100% 〰️
models tree 50k 3D elements > change category node visibility 490 ms 505 ms -2.97% 〰️
models tree 50k 3D elements > change category node visibility (P95 of main thread blocks) 57 ms 59 ms -3.39% 〰️
models tree 50k 3D elements > validate changed category visibility 1355 ms 1931 ms -29.83%
models tree 50k 3D elements > validate changed category visibility (P95 of main thread blocks) 0 ms 0 ms 0% 🟰
models tree 50k 3D elements > validate per-model category override 1329 ms 1874 ms -29.08%
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 33 ms 0% 🟰
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 2126 ms 2616 ms -18.73%
models tree 50k 3D elements > validate changed element visibility (P95 of main thread blocks) 67 ms 67 ms 0% 🟰
models tree 50k 3D child elements with different categories > collect nodes 41435 ms 46646 ms -11.17%
models tree 50k 3D child elements with different categories > collect nodes (P95 of main thread blocks) 76 ms 68 ms 11.76% 〰️
models tree 50k 3D child elements with different categories > validate initial visibility 1447 ms 1677 ms -13.71%
models tree 50k 3D child elements with different categories > validate initial visibility (P95 of main thread blocks) 30 ms 0 ms 3000% 〰️
models tree 50k 3D child elements with different categories > change visibility 52 ms 53 ms -1.89% 〰️
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 2546 ms 3803 ms -33.05%
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) 86 ms 82 ms 4.88% 〰️
categories tree 50k subCategories search > get search paths 1743 ms 1888 ms -7.68% 〰️
categories tree 50k subCategories search > get search paths (P95 of main thread blocks) 40 ms 44 ms -9.09% 〰️
categories tree 50k subCategories search > load hierarchy from search paths 5371 ms 5657 ms -5.06% 〰️
categories tree 50k subCategories search > load hierarchy from search paths (P95 of main thread blocks) 51 ms 55 ms -7.27% 〰️
categories tree 50k subCategories > collect nodes 5699 ms 6112 ms -6.76% 〰️
categories tree 50k subCategories > collect nodes (P95 of main thread blocks) 42 ms 49 ms -14.29% 〰️
categories tree 50k subCategories > validate initial visibility 1188 ms 1190 ms -0.17% 〰️
categories tree 50k subCategories > validate initial visibility (P95 of main thread blocks) 26 ms 27 ms -3.70% 〰️
categories tree 50k subCategories > change visibility 340 ms 370 ms -8.11% 〰️
categories tree 50k subCategories > change visibility (P95 of main thread blocks) 24 ms 37 ms -35.14% 〰️
categories tree 50k subCategories > validate changed visibility 1067 ms 1083 ms -1.48% 〰️
categories tree 50k subCategories > validate changed visibility (P95 of main thread blocks) 32 ms 44 ms -27.27% 〰️
categories tree 50k categories > collect nodes 2424 ms 2520 ms -3.81% 〰️
categories tree 50k categories > collect nodes (P95 of main thread blocks) 123 ms 136 ms -9.56% 〰️
categories tree 50k categories > validate initial visibility 5087 ms 5378 ms -5.41% 〰️
categories tree 50k categories > validate initial visibility (P95 of main thread blocks) 128 ms 117 ms 9.40% 〰️
categories tree 50k categories > change visibility 772 ms 685 ms 12.70% 🚨
categories tree 50k categories > change visibility (P95 of main thread blocks) 62 ms 61 ms 1.64% 〰️
categories tree 50k categories > validate changed visibility 4865 ms 5001 ms -2.72% 〰️
categories tree 50k categories > validate changed visibility (P95 of main thread blocks) 35 ms 46 ms -23.91% 〰️
classifications tree 50k classifications search > get search paths 2106 ms 2159 ms -2.45% 〰️
classifications tree 50k classifications search > get search paths (P95 of main thread blocks) 128 ms 152 ms -15.79% 〰️
classifications tree 50k classifications search > load hierarchy from search paths 64416 ms 73053 ms -11.82%
classifications tree 50k classifications search > load hierarchy from search paths (P95 of main thread blocks) 0 ms 0 ms 0% 🟰
classifications tree 50k classifications > collect nodes 35123 ms 39556 ms -11.21%
classifications tree 50k classifications > collect nodes (P95 of main thread blocks) 76 ms 93 ms -18.28% 〰️
classifications tree 50k classifications > validate initial visibility 3463 ms 3821 ms -9.37% 〰️
classifications tree 50k classifications > validate initial visibility (P95 of main thread blocks) 66 ms 89 ms -25.84% 〰️
classifications tree 50k classifications > change visibility 34 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 3911 ms 4151 ms -5.78% 〰️
classifications tree 50k classifications > validate changed visibility (P95 of main thread blocks) 101 ms 104 ms -2.88% 〰️

This comment was automatically generated by workflow using github-action-benchmark.

@grigasp
Copy link
Copy Markdown
Member

grigasp commented May 26, 2026

Did you look at the performance regressions? The following seem worth having a look at:

Benchmark suite Current: 1d284b8 Previous: b618ede Deviation Status
models tree 50k categories > change visibility 1372 ms 87 ms 1477.01% 🚨
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) 219 ms 82 ms 167.07% 🚨
categories tree 50k categories > change visibility 1676 ms 685 ms 144.67% 🚨
classifications tree 50k classifications > validate changed visibility 5835 ms 4151 ms 40.57% 🚨

@JonasDov JonasDov mentioned this pull request May 28, 2026
@JonasDov
Copy link
Copy Markdown
Contributor Author

Did you look at the performance regressions? The following seem worth having a look at:

Benchmark suite Current: 1d284b8 Previous: b618ede Deviation Status
models tree 50k categories > change visibility 1372 ms 87 ms 1477.01% 🚨
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) 219 ms 82 ms 167.07% 🚨
categories tree 50k categories > change visibility 1676 ms 685 ms 144.67% 🚨
classifications tree 50k classifications > validate changed visibility 5835 ms 4151 ms 40.57% 🚨

Adjusted implementation, a few things:

  1. BatchingCache.ts - Replaced shareReplay(1) observable with an event based sharing mechanism. Instead of tracking subscribers in an array, the completion is notified using BeEvent. This removes rxjs arrRemove (O(n²)) cleanup for removing subscriptions.
  2. Similarly added subscribeAll helper (uses a plain array for subscription tracking), which is used when changing descendants visibility. Previously RxJS's from + mergeMap was used, which internally uses arrRemove.
  3. Changed get/change element visibility, so it does not request children count when element does not have children.
  4. Added additional information to ElementModelCategoriesCache which stores which categories have indirect children. (small modification to existing query). This is used:
    4.1. When getting category visibility, first a check is made to see if category does not have indirect children AND if the opposide A/N drawn set is empty. If that is the case, descendants counts is not requested. (opposite set: set different from category default visibility).
    4.2. When changing category visbility, first check if it does not have indirect children. If that is the case, child counts are not requested.

This improved the performance (at least in current perf tests) without adding much overhead IMO. Now performance is very similar to what it was before these changes.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

@JonasDov JonasDov marked this pull request as draft June 1, 2026 07:15
@JonasDov JonasDov marked this pull request as ready for review June 1, 2026 07:15
@JonasDov JonasDov merged commit 9acaf27 into tree-widget/next Jun 1, 2026
15 of 16 checks passed
@JonasDov JonasDov deleted the JonasD/phase-3b branch June 1, 2026 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants