Skip to content

[Discover][Metrics] Persist flyout state across navigation#251637

Draft
lucaslopezf wants to merge 21 commits intoelastic:mainfrom
lucaslopezf:235834-persist-view-flyout-details-across-navigation
Draft

[Discover][Metrics] Persist flyout state across navigation#251637
lucaslopezf wants to merge 21 commits intoelastic:mainfrom
lucaslopezf:235834-persist-view-flyout-details-across-navigation

Conversation

@lucaslopezf
Copy link
Copy Markdown
Contributor

@lucaslopezf lucaslopezf commented Feb 4, 2026

Closes #235834

Summary

This PR implements persistence of the metrics flyout state when duplicating Discover tabs. Previously, when a user duplicated a Discover tab with an open "View details" flyout, the flyout would close in the new tab, forcing the user to find the metric and reopen it.

Demo

Screen.Recording.2026-02-04.at.18.35.26.mov

Manual Testing

  1. Open Discover with metrics data
  2. Click "View details" on any metric to open the flyout
  3. Select the "ES|QL Query" tab in the flyout
  4. Duplicate the Discover tab (right-click tab → Duplicate)
  5. Expected: The new tab opens with the same flyout visible, showing the same metric and the "ES|QL Query" tab selected
  6. Change the tab in the duplicated view to "Overview"
  7. Expected: The original tab remains on "ES|QL Query" (states are independent)

Known Limitations (Out of Scope)

There are edge cases where the flyout may not restore after duplicating a tab. These will be addressed in a follow-up issue after discussing with Miguel:

  1. Metric not available in new tab: Each tab executes its own query. If the metric that was open in the flyout doesn't exist in the new tab's query results (e.g., due to real-time data changes, sampling differences, or timing), the flyout won't render since there's no data to display.

  2. Pagination reset: When the number of metrics differs between tabs, pagination resets to page 1. If the flyout was open for a metric on a different page, it won't render because the lookup only searches within the current page.

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

  • 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.

Identify risks

Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging.

@lucaslopezf lucaslopezf changed the title Discover(metrics): Persist flyout state across navigation [Discover][Metrics]: Persist flyout state across navigation Feb 4, 2026
@lucaslopezf lucaslopezf changed the title [Discover][Metrics]: Persist flyout state across navigation [Discover][Metrics] Persist flyout state across navigation Feb 4, 2026
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

lucaslopezf commented Feb 4, 2026

/oblt-deploy

1 similar comment
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf lucaslopezf added release_note:enhancement backport:skip This PR does not require backporting Team:obs-exploration Observability Exploration team v9.4.0 labels Feb 4, 2026
const chartRefs = useRef<Map<string, HTMLDivElement>>(new Map());
const { euiTheme } = useEuiTheme();
const { flyoutState, onFlyoutStateChange } = useMetricsExperienceState();
const fieldsMap = useMemo(() => createMetricFieldsMap(fields), [fields]);
Copy link
Copy Markdown
Contributor Author

@lucaslopezf lucaslopezf Feb 4, 2026

Choose a reason for hiding this comment

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

Note for reviewer:

Since we now save the flyout state in Redux and need to retrieve it, we store a unique key (creating a Map for performance with O(1) lookup) to later retrieve the correct data whenever we want to render the flyout.

Key format: {dataViewIndex}::{metricName}

We use this structure because metricName alone is not unique (the same metric can exist in multiple data views).

actionCreator: discardFlyoutsOnTabChange,
effect: () => {
dismissFlyouts([DiscoverFlyouts.lensEdit, DiscoverFlyouts.metricInsights]);
dismissFlyouts([DiscoverFlyouts.lensEdit]);
Copy link
Copy Markdown
Contributor Author

@lucaslopezf lucaslopezf Feb 4, 2026

Choose a reason for hiding this comment

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

Note for reviewer:

The dismissFlyouts function programmatically clicks the close button of flyouts. When switching between Discover tabs, this was causing the metrics flyout to close and clear its state. Since now the flyout state is now managed per-tab in Redux (tab.uiState.metricsGrid.flyoutState) and each tab has its own independent flyout state we are fine

});

const metricsGridState = useCurrentTabSelector((state) => state.uiState.metricsGrid);
const isTabSelected = useInternalStateSelector(
Copy link
Copy Markdown
Contributor Author

@lucaslopezf lucaslopezf Feb 4, 2026

Choose a reason for hiding this comment

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

Note for reviewer:

This solves a rendering conflict when multiple Discover tabs have flyouts open.

The problem: (using Metrics as example but is generic)

  • Each Discover tab renders its own MetricsGrid component
  • When a flyout is open, it uses EuiPortal to render to document.body
  • If Tab 1 and Tab 2 both have flyout state, both would render flyouts to document.body
  • This causes visual overlap and event capture issues (clicking in Tab 2's flyout could affect Tab 1's state)

The solution:

  • Compare the current tab's ID (currentTabId from CurrentTabContext) with the active tab ID (state.tabs.unsafeCurrentId)
  • Pass isTabSelected to child components
  • Only render the flyout when isTabSelected === true

This ensures only the active tab renders its flyout, while inactive tabs preserve their flyout state in Redux for when they become active again.

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.

Yeah kinda an unfortunate consequence of not unmounting the chart section when switching tabs (to preserve Lens state) that the flyout isn't unmounted. But I think what you've got here is probably the best we can do atm.

</EuiFlexGrid>
</A11yGridWrapper>
{expandedMetric && (
{flyoutData && isTabSelected && (
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.

We only render the flyout when isTabSelected is true to prevent multiple flyouts from overlapping.

More details here

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/ci

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf lucaslopezf marked this pull request as ready for review February 5, 2026 08:48
@lucaslopezf lucaslopezf requested review from a team as code owners February 5, 2026 08:48
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/obs-exploration-team (Team:obs-exploration)

Copy link
Copy Markdown
Contributor

@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.

Data Discover changes LGTM 👍 Gave it a quick test locally, works well!

});

const metricsGridState = useCurrentTabSelector((state) => state.uiState.metricsGrid);
const isTabSelected = useInternalStateSelector(
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.

Yeah kinda an unfortunate consequence of not unmounting the chart section when switching tabs (to preserve Lens state) that the flyout isn't unmounted. But I think what you've got here is probably the best we can do atm.

Copy link
Copy Markdown
Contributor

@kpatticha kpatticha left a comment

Choose a reason for hiding this comment

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

Regarding:

Pagination reset:
https://github.com/user-attachments/assets/576f4797-bc51-4baf-814f-61d64658eb16

can we know in advance if the pagination is different so we won't open the flyout and close it immediately? How could we solve it in the future?

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

Regarding:

Pagination reset: https://github.com/user-attachments/assets/576f4797-bc51-4baf-814f-61d64658eb16

How could we solve it in the future?

I created issue 5190 in observability-dev. After talking with Miguel, he’ll close it and add more context, since the problem should be solved once metrics_info is in place (I haven’t looked into it, just relaying his explanation).
Right now, the main issue is that we don’t have consistency between queries on each refresh. If the time range is relative, that’s somewhat understandable, but this is also happening with absolute time ranges. Because of that, it’s currently impossible something like the next scenario:

1- go to page 4,
2- open a flyout,
3- duplicate the Discover tab
4- expect the flyout to still be open.

This should be automatically fixed once we have consistent query results.

can we know in advance if the pagination is different so we won't open the flyout and close it immediately?

I didn't notice this before your comment! It doesn't seem to happen consistently (at least in my case) but I'll take a look and see if we can fix in this PR! Thanks for catching this!!

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf lucaslopezf force-pushed the 235834-persist-view-flyout-details-across-navigation branch from e4996ee to a8d2a33 Compare February 9, 2026 10:42
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

1 similar comment
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf lucaslopezf force-pushed the 235834-persist-view-flyout-details-across-navigation branch from a5baff4 to e2c01fb Compare February 9, 2026 14:20
@lucaslopezf lucaslopezf force-pushed the 235834-persist-view-flyout-details-across-navigation branch from b43c150 to 0cbea55 Compare March 9, 2026 09:59
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

1 similar comment
@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/ci

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/flaky scoutConfig:src/platform/plugins/shared/discover/test/scout/ui/parallel.playwright.config.ts:50

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner

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

  • src/platform/plugins/shared/discover/test/scout/ui/parallel.playwright.config.ts x50

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

/oblt-deploy

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

@kpatticha I’m testing this PR before merging it, but I’m wondering if merging it could interfere with your metrics_info work.
Would you prefer to merge the metrics_info PR first and then I can rebase this one? Since metrics_info is more important

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

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

[✅] src/platform/plugins/shared/discover/test/scout/ui/parallel.playwright.config.ts: 50/50 tests passed.

see run history

@lucaslopezf
Copy link
Copy Markdown
Contributor Author

lucaslopezf commented Mar 11, 2026

Everything working as expected after EUI fix, but since this PR touches a lot of files, I’d prefer to wait for metrics_info PR to be to avoid creating extra rebase work on the work in progress. After that, I'll rebase and move forward. I've already mark the task as blocked by

justinkambic added a commit that referenced this pull request Mar 18, 2026
…255036)

## Summary

Related to elastic/observability-dev#5219.

Implements Tier 2 E2E coverage for Discover Metrics journeys, aligned
with the existing metrics_experience test architecture and config
pattern.

Adds two new parallel Scout specs in metrics_experience:

- `query_kickstart.spec.ts`: validates recommended-query kickstart
behavior from the ES|QL help flow, with environment-aware handling when
Search all metrics is unavailable and Search all fields is shown.
- `breakdown_by_dimension.spec.ts`: validates that selecting “Breakdown
by dimension” from the field list is reflected in the metrics toolbar
and preserves metrics grid rendering.

This patch introduces coverage for the two unblocked journeys, but does
not yet implement the "switch between tabs" third journey, which is
blocked by #251637.

## Test Plan
Validated via Scout metrics parallel config:
```
node scripts/scout.js run-tests --arch stateful --domain classic --config src/platform/plugins/shared/discover/test/scout/ui/metrics_experience_parallel.playwright.config.ts
```

Result on latest run:
```
All tests pass: 36 passed, 8 skipped, 0 failed. Exit code 0.
```

---------

Co-authored-by: Lucas Francisco López <lucaslopezf@gmail.com>
flash1293 pushed a commit to flash1293/kibana that referenced this pull request Mar 19, 2026
…lastic#255036)

## Summary

Related to elastic/observability-dev#5219.

Implements Tier 2 E2E coverage for Discover Metrics journeys, aligned
with the existing metrics_experience test architecture and config
pattern.

Adds two new parallel Scout specs in metrics_experience:

- `query_kickstart.spec.ts`: validates recommended-query kickstart
behavior from the ES|QL help flow, with environment-aware handling when
Search all metrics is unavailable and Search all fields is shown.
- `breakdown_by_dimension.spec.ts`: validates that selecting “Breakdown
by dimension” from the field list is reflected in the metrics toolbar
and preserves metrics grid rendering.

This patch introduces coverage for the two unblocked journeys, but does
not yet implement the "switch between tabs" third journey, which is
blocked by elastic#251637.

## Test Plan
Validated via Scout metrics parallel config:
```
node scripts/scout.js run-tests --arch stateful --domain classic --config src/platform/plugins/shared/discover/test/scout/ui/metrics_experience_parallel.playwright.config.ts
```

Result on latest run:
```
All tests pass: 36 passed, 8 skipped, 0 failed. Exit code 0.
```

---------

Co-authored-by: Lucas Francisco López <lucaslopezf@gmail.com>
jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Mar 26, 2026
…lastic#255036)

## Summary

Related to elastic/observability-dev#5219.

Implements Tier 2 E2E coverage for Discover Metrics journeys, aligned
with the existing metrics_experience test architecture and config
pattern.

Adds two new parallel Scout specs in metrics_experience:

- `query_kickstart.spec.ts`: validates recommended-query kickstart
behavior from the ES|QL help flow, with environment-aware handling when
Search all metrics is unavailable and Search all fields is shown.
- `breakdown_by_dimension.spec.ts`: validates that selecting “Breakdown
by dimension” from the field list is reflected in the metrics toolbar
and preserves metrics grid rendering.

This patch introduces coverage for the two unblocked journeys, but does
not yet implement the "switch between tabs" third journey, which is
blocked by elastic#251637.

## Test Plan
Validated via Scout metrics parallel config:
```
node scripts/scout.js run-tests --arch stateful --domain classic --config src/platform/plugins/shared/discover/test/scout/ui/metrics_experience_parallel.playwright.config.ts
```

Result on latest run:
```
All tests pass: 36 passed, 8 skipped, 0 failed. Exit code 0.
```

---------

Co-authored-by: Lucas Francisco López <lucaslopezf@gmail.com>
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 Feature:Metrics in Discover release_note:enhancement Team:obs-exploration Observability Exploration team Team:One Workflow Team label for One Workflow (Workflow automation) v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Metrics][Discover] Persist View details flyout state across navigation

6 participants