Skip to content

[Discover] [Group By] Support restoring UI state when switching tabs#253608

Merged
eokoneyo merged 17 commits into
elastic:mainfrom
davismcphee:discover-group-by-ui-state-final
Apr 3, 2026
Merged

[Discover] [Group By] Support restoring UI state when switching tabs#253608
eokoneyo merged 17 commits into
elastic:mainfrom
davismcphee:discover-group-by-ui-state-final

Conversation

@davismcphee
Copy link
Copy Markdown
Contributor

@davismcphee davismcphee commented Feb 18, 2026

Summary

This PR adds persisted group by UI state in Discover so switching between tabs restores the cascade where the user left it. It preserves the main cascade scroll position, expanded groups, and nested row state for expanded groups, so returning to a tab restores the previous view instead of starting fresh.

Feature flag for testing: feature_flags.overrides.discover.cascadeLayoutEnabled: true

Example queries for testing:

  • FROM kibana_sample_data_logs | STATS count = COUNT(*) BY extension.keyword
  • FROM kibana_sample_data_logs | STATS count = COUNT(*) BY ip

Resolves #249456.
Resolves #246985.

Checklist

  • Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

@davismcphee davismcphee self-assigned this Feb 18, 2026
@davismcphee davismcphee added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting Team:DataDiscovery Discover, search (data plugin and KQL), data views, saved searches. For ES|QL, use Team:ES|QL. t// labels Feb 18, 2026
Copy link
Copy Markdown
Contributor Author

@davismcphee davismcphee left a comment

Choose a reason for hiding this comment

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

I was planning to add some FTR tests for the Discover changes, but the scroll restoring doesn't seem to work for me, and I noticed an odd regression. I think we're quite close on this, maybe just need to work through the last bit together including scrolling.

@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from 828b0d6 to 6a20f72 Compare February 23, 2026 13:49
Copy link
Copy Markdown
Contributor Author

@davismcphee davismcphee left a comment

Choose a reason for hiding this comment

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

Thanks for working on the scroll restoration @eokoneyo, definitely working better now. I added some functional tests to cover our changes and attempted to fix type and lint errors. Not sure if you have any other changes you need to do, but otherwise at this point I think things work well enough for the MVP once it passes CI.

);

virtualizerRef.current = useCascadeVirtualizer<DataTableRecord>({
// @ts-expect-error -- it's fine to do this as long as we're not using the sticky group header functionality
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not a fan of using @ts-expect-error here, but not a blocker for MVP.

Copy link
Copy Markdown
Contributor

@eokoneyo eokoneyo Feb 26, 2026

Choose a reason for hiding this comment

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

I know... I'll make some changes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've rather opted to track this here #255075, when it gets fixed this will error and we'd remove the @ts-expect-error

@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from b532874 to b55b542 Compare February 26, 2026 12:53
@kertal kertal added the ci:cloud-deploy Create or update a Cloud deployment label Mar 2, 2026
@kibanamachine
Copy link
Copy Markdown
Contributor

Cloud deployment initiated, see credentials at: https://buildkite.com/elastic/kibana-deploy-cloud-from-pr/builds/774

Comment on lines +503 to +505
scrollToVirtualizedIndex: ((offset, options = {}) => {
return virtualizerImpl.options.scrollToFn(offset, options, virtualizerImpl);
}) satisfies CascadeVirtualizerReturnValue['scrollToVirtualizedIndex'],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High virtualizer/index.tsx:503

scrollToVirtualizedIndex calls virtualizerImpl.options.scrollToFn(offset, ...) which expects a pixel offset, but scrollToLastVirtualizedRow (line 517) passes rows.length - 1 as an index. This causes scrollToLastVirtualizedRow() to scroll to pixel position N-1 instead of the actual offset of the last row. Consider using virtualizerImpl.scrollToIndex which handles the index-to-offset conversion.

-      scrollToVirtualizedIndex: ((offset, options = {}) => {
-        return virtualizerImpl.options.scrollToFn(offset, options, virtualizerImpl);
-      }) satisfies CascadeVirtualizerReturnValue['scrollToVirtualizedIndex'],
🤖 Copy this AI Prompt to have your agent fix this:
In file src/platform/packages/shared/shared-ux/document_data_cascade/impl/src/lib/core/virtualizer/index.tsx around lines 503-505:

`scrollToVirtualizedIndex` calls `virtualizerImpl.options.scrollToFn(offset, ...)` which expects a pixel offset, but `scrollToLastVirtualizedRow` (line 517) passes `rows.length - 1` as an index. This causes `scrollToLastVirtualizedRow()` to scroll to pixel position `N-1` instead of the actual offset of the last row. Consider using `virtualizerImpl.scrollToIndex` which handles the index-to-offset conversion.

Evidence trail:
- Kibana code: src/platform/packages/shared/shared-ux/document_data_cascade/impl/src/lib/core/virtualizer/index.tsx lines 454, 503-505, 516-518 at REVIEWED_COMMIT
- TanStack Virtual library source: https://github.com/TanStack/virtual/blob/main/packages/virtual-core/src/index.ts - scrollToFn signature shows first parameter is pixel offset, not index (line ~295 type definition, line ~824 _scrollToOffset implementation)
- TanStack Virtual scrollToIndex method (line ~716) shows proper index-to-offset conversion using getOffsetForIndex()

@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from c827c6e to ba60223 Compare March 25, 2026 16:03
@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from ba60223 to 0000ee1 Compare March 25, 2026 16:31
@kertal
Copy link
Copy Markdown
Member

kertal commented Mar 26, 2026

/ci

1 similar comment
@eokoneyo
Copy link
Copy Markdown
Contributor

/ci

@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from 627a902 to 0e1f7dd Compare March 30, 2026 14:04
@kertal
Copy link
Copy Markdown
Member

kertal commented Mar 31, 2026

/ci

@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from 0e1f7dd to 8cc9f5a Compare March 31, 2026 07:46
@kertal kertal removed the ci:cloud-deploy Create or update a Cloud deployment label Mar 31, 2026
@eokoneyo eokoneyo force-pushed the discover-group-by-ui-state-final branch from 8cc9f5a to a7a82c5 Compare March 31, 2026 11:39
@eokoneyo
Copy link
Copy Markdown
Contributor

eokoneyo commented Apr 2, 2026

Latest changes look good, and I tested locally and it's working well 👍 We're still a bit off on scroll position with an expanded group, but we agreed that was ok for tech preview. I pushed one commit (1712043) with a few final cleanups, but otherwise I think it's good to go. I'll have someone else from my team do a final review since I can't approve my own PR.

Appreciate the cleanup... I also made some changes to address valid AI feedback, I'll also reach out to my team to give this a look.

Copy link
Copy Markdown
Member

@kowalczyk-krzysztof kowalczyk-krzysztof left a comment

Choose a reason for hiding this comment

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

Code changes LGTM. I didn't test the functionality, leaving that up to @eokoneyo

davismcphee and others added 11 commits April 2, 2026 14:48
- handling for non-viable row marked as expanded in persisted state
- get scroll position restoration on switching tabs to work
- opt to reset persisted state once the query changes
- prevent measurement updates before first paint
- improvement to cascade component for restoration phase
- scroll position restoration for nested virtualized grid
- Minor type cleanup
- improve exposed public API for cascade component to include index of topmost visible item
- consolidate scroll position restoration into helper hook
- leverage scroll restoration util within row grid
- consolidate scroll restoration into cascade virtualizer and adopt it for nested virtualizer use case
- specify containment options for cascade wrapper, row and cell
- defer overscan config till after next paint
- Fix types and linting
- Fix aggregatedValues badge rendering
- Add functional tests
- cleanup cascade component
- remove reference to removed apis
- structural changes to virtualizer implementation
- favor anchor item index over scroll offset for scroll restoration
- use cascade virtualizer for nesting in discover
- deferred mounting for nested rows
- add foundation for controlled child virtualizer
- add orchestration for nested virtualized children
- adjustments so returning expanded rows do not show loading skeleton
- render a loader in place of white screen whilst cascade is bootstrapping
- opt to reset persisted state once the query changes
- scroll position restoration for nested virtualized grid
- adjustments so scroll restoration matches previous row exactly
Copy link
Copy Markdown
Contributor

@akowalska622 akowalska622 left a comment

Choose a reason for hiding this comment

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

Code looks good to me and I tested it locally. I'll leave the final approval to @MiloszRadzynski who volunteered to give it a second look 👀

Copy link
Copy Markdown
Contributor

@MiloszRadzynski MiloszRadzynski left a comment

Choose a reason for hiding this comment

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

LGTM 🚀 Tested I didn't notice any issues! Thank you

@eokoneyo
Copy link
Copy Markdown
Contributor

eokoneyo commented Apr 2, 2026

@elasticmachine merge upstream

@davismcphee
Copy link
Copy Markdown
Contributor Author

/flaky ftrConfig:src/platform/test/functional/apps/discover/cascade_layout/config.ts:25

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner

✅ Build triggered - kibana-flaky-test-suite-runner#11358

  • src/platform/test/functional/apps/discover/cascade_layout/config.ts x25

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

🟠 Some tests failed. - kibana-flaky-test-suite-runner#11358

[❌] src/platform/test/functional/apps/discover/cascade_layout/config.ts: 0/25 tests passed.

see run history

kertal added 3 commits April 3, 2026 17:40
Replace fixed sleep(100) waits with retry-based polling in
expectScrollToBeRoughly. The helper already has a 5-second retry
window, so the sleep was both wasteful and insufficient. Also measure
actual scroll position before tab switch instead of predicting it
based on arithmetic, which is unreliable after row expansion.
Wrap isCascadeLayoutRowExpanded and the find+click sequence in
toggleCascadeLayoutRow with retry.try() to handle
StaleElementReferenceError when the virtualizer re-renders DOM
elements between finding and interacting with them.
@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

🎉 All tests passed! - kibana-flaky-test-suite-runner#11370

[✅] src/platform/test/functional/apps/discover/cascade_layout/config.ts: 25/25 tests passed.

see run history

@elasticmachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Jest Tests #8 / AssetDocumentTab should select json tab when clicked
  • [job] [logs] FTR Configs #139 / Entity Analytics - Risk Score Maintainer @ess @serverless @serverlessQA Risk Score Maintainer Resolution Scoring with test log data produces a resolution score that aggregates alerts from both target and alias

Metrics [docs]

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/shared-ux-document-data-cascade 106 105 -1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
discover 1.6MB 1.6MB +1.7KB
Unknown metric groups

API count

id before after diff
@kbn/shared-ux-document-data-cascade 127 124 -3

ESLint disabled line counts

id before after diff
discover 17 19 +2

Total ESLint disabled count

id before after diff
discover 19 21 +2

History

cc @davismcphee

});

const NO_VALUE_PLACEHOLDER = i18n.translate('discover.dataCascade.row.action.noValue', {
defaultMessage: '(blank)',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes I think that makes sense. Opened a followup issue for it here: #261839.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:DataDiscovery Discover, search (data plugin and KQL), data views, saved searches. For ES|QL, use Team:ES|QL. t// v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Discover] [Group By] Restore group by UI state when switching between Discover tabs [Discover] [Group By] Group by integration with Discover tabs

9 participants