From 20b6058953f738589d7a71ed219c9062a2027e71 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 26 Jan 2026 12:43:04 +0100 Subject: [PATCH 01/14] Persist query mode to local storage --- .../shared/discover/common/constants.ts | 3 ++ .../components/tabs_view/use_app_menu_data.ts | 6 +++- .../components/top_nav/use_top_nav_links.tsx | 2 ++ .../utils/get_initial_app_state.ts | 30 +++++++++++++++++-- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/platform/plugins/shared/discover/common/constants.ts b/src/platform/plugins/shared/discover/common/constants.ts index 881d257c19cff..0298b0a09656d 100644 --- a/src/platform/plugins/shared/discover/common/constants.ts +++ b/src/platform/plugins/shared/discover/common/constants.ts @@ -26,6 +26,9 @@ export const getDefaultRowsPerPage = (uiSettings: IUiSettingsClient): number => // local storage key for the ES|QL to Dataviews transition modal export const ESQL_TRANSITION_MODAL_KEY = 'data.textLangTransitionModal'; +// local storage key for the query mode when starting a new discover session +export const DISCOVER_QUERY_MODE_KEY = 'discover.defaultQueryMode'; + /** * The id value used to indicate that a link should open in a new Discover tab. * It will be used in the `_tab` URL param to indicate that a new tab should be created. diff --git a/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts b/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts index d3869e34fed17..8a73667fb083c 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts +++ b/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts @@ -23,7 +23,10 @@ import { selectAllTabs, } from '../../state_management/redux'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; -import { ESQL_TRANSITION_MODAL_KEY } from '../../../../../common/constants'; +import { + DISCOVER_QUERY_MODE_KEY, + ESQL_TRANSITION_MODAL_KEY, +} from '../../../../../common/constants'; import { useTopNavMenuItems } from '../top_nav/use_top_nav_menu_items'; import { isEsqlSource } from '../../../../../common/data_sources'; @@ -98,6 +101,7 @@ export const useAppMenuData = ({ currentDataView }: UseAppMenuDataParams): UseAp } else { dispatch(transitionFromESQLToDataView({ dataViewId: currentDataView?.id ?? '' })); } + services.storage.set(DISCOVER_QUERY_MODE_KEY, 'classic'); }, }, ]; diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx index 7119d2fa07172..1211eb85806ee 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx @@ -22,6 +22,7 @@ import { useGetRuleTypesPermissions } from '@kbn/alerts-ui-shared'; import useObservable from 'react-use/lib/useObservable'; import type { DiscoverSession } from '@kbn/saved-search-plugin/common'; import { useI18n } from '@kbn/i18n-react'; +import { DISCOVER_QUERY_MODE_KEY } from '../../../../../common/constants'; import type { DiscoverAppLocatorParams } from '../../../../../common'; import { createDataViewDataSource } from '../../../../../common/data_sources'; import type { DiscoverServices } from '../../../../build_services'; @@ -244,6 +245,7 @@ export const useTopNavLinks = ({ }), run: () => { if (dataView) { + services.storage.set(DISCOVER_QUERY_MODE_KEY, 'esql'); dispatch(transitionFromDataViewToESQL({ dataView })); services.trackUiMetric?.(METRIC_TYPE.CLICK, `esql:try_btn_clicked`); } diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts index 139bf2d81cfd8..80c53391001e9 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts @@ -8,6 +8,7 @@ */ import type { DataView } from '@kbn/data-views-plugin/common'; +import type { AggregateQuery, Query } from '@kbn/es-query'; import { isOfAggregateQueryType } from '@kbn/es-query'; import type { DiscoverSessionTab } from '@kbn/saved-search-plugin/common'; import type { IUiSettingsClient } from '@kbn/core/public'; @@ -20,6 +21,8 @@ import { } from '@kbn/discover-utils'; import { getChartHidden } from '@kbn/unified-histogram'; import { cloneDeep } from 'lodash'; +import { getInitialESQLQuery } from '@kbn/esql-utils'; +import { DISCOVER_QUERY_MODE_KEY } from '../../../../../common/constants'; import type { DiscoverServices } from '../../../../build_services'; import type { DiscoverAppState } from '../redux'; import { @@ -77,6 +80,30 @@ function getDefaultColumns( : undefined; } +function isDataView(dataView: unknown): dataView is DataView { + return !!dataView && typeof dataView === 'object' && 'getIndexPattern' in dataView; +} + +function getDefaultQuery({ + persistedTab, + storage, + data, + dataView, +}: { + persistedTab: DiscoverSessionTab | undefined; + storage: DiscoverServices['storage']; + data: DiscoverServices['data']; + dataView: DataView | Pick | undefined; +}): Query | AggregateQuery | undefined { + if (persistedTab?.serializedSearchSource.query) return persistedTab.serializedSearchSource.query; + + const queryMode = storage.get(DISCOVER_QUERY_MODE_KEY); + if (queryMode === 'esql' && isDataView(dataView)) + return { esql: getInitialESQLQuery(dataView, true) }; + + return data.query.queryString.getDefaultQuery(); +} + function getDefaultAppState({ persistedTab, dataView, @@ -87,8 +114,7 @@ function getDefaultAppState({ services: DiscoverServices; }) { const { data, uiSettings, storage } = services; - const query = - persistedTab?.serializedSearchSource.query || data.query.queryString.getDefaultQuery(); + const query = getDefaultQuery({ persistedTab, storage, data, dataView }); const isEsqlQuery = isOfAggregateQueryType(query); // If the data view doesn't have a getFieldByName method (e.g. if it's a spec or list item), // we assume the sort array is valid since we can't know for sure From d0129fd8b5037a7c9ad8c8b184b053368f092f69 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 26 Jan 2026 16:12:44 +0100 Subject: [PATCH 02/14] Reset query mode before testing --- .../functional/apps/discover/context_awareness/_telemetry.ts | 1 + .../test/functional/apps/discover/group10/_lens_vis.ts | 1 + .../discover/group2_data_grid2/_data_grid_field_tokens.ts | 1 + .../test/functional/apps/discover/group8/_sidenav_link.ts | 4 ++++ src/platform/test/functional/apps/discover/tabs/_new_tab.ts | 4 ++++ src/platform/test/functional/apps/discover/tabs2/_sharing.ts | 1 + src/platform/test/functional/page_objects/discover_page.ts | 4 ++++ 7 files changed, 16 insertions(+) diff --git a/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts b/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts index ae16a0541797a..2ffe8621077d7 100644 --- a/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts +++ b/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts @@ -230,6 +230,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('field usage events', () => { beforeEach(async () => { + await discover.resetQueryMode(); await common.navigateToApp('discover'); await header.waitUntilLoadingHasFinished(); await discover.waitUntilSearchingHasFinished(); diff --git a/src/platform/test/functional/apps/discover/group10/_lens_vis.ts b/src/platform/test/functional/apps/discover/group10/_lens_vis.ts index 9d6a668b466c3..11e30545c1727 100644 --- a/src/platform/test/functional/apps/discover/group10/_lens_vis.ts +++ b/src/platform/test/functional/apps/discover/group10/_lens_vis.ts @@ -110,6 +110,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(async function () { await timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update(defaultSettings); + await discover.resetQueryMode(); await common.navigateToApp('discover'); await header.waitUntilLoadingHasFinished(); await discover.waitUntilSearchingHasFinished(); diff --git a/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts b/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts index 4d4c1d6743d5b..1b1890e729537 100644 --- a/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts +++ b/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts @@ -94,6 +94,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(async function () { await timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update(defaultSettings); + await discover.resetQueryMode(); await common.navigateToApp('discover'); await discover.waitUntilSearchingHasFinished(); }); diff --git a/src/platform/test/functional/apps/discover/group8/_sidenav_link.ts b/src/platform/test/functional/apps/discover/group8/_sidenav_link.ts index ecf9f24802d80..04852a6edda8d 100644 --- a/src/platform/test/functional/apps/discover/group8/_sidenav_link.ts +++ b/src/platform/test/functional/apps/discover/group8/_sidenav_link.ts @@ -51,6 +51,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.savedObjects.cleanStandardList(); }); + beforeEach(async function () { + await discover.resetQueryMode(); + }); + it('saves the last URL when in data view mode', async function () { await common.navigateToApp('discover'); await header.waitUntilLoadingHasFinished(); diff --git a/src/platform/test/functional/apps/discover/tabs/_new_tab.ts b/src/platform/test/functional/apps/discover/tabs/_new_tab.ts index ed7d4640bf544..6bb2acadd7633 100644 --- a/src/platform/test/functional/apps/discover/tabs/_new_tab.ts +++ b/src/platform/test/functional/apps/discover/tabs/_new_tab.ts @@ -28,6 +28,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.setWindowSize(1920, 1080); }); + beforeEach(async () => { + await discover.resetQueryMode(); + }); + it('should create a new tab in classic mode', async () => { // tab 0 - with the default data view diff --git a/src/platform/test/functional/apps/discover/tabs2/_sharing.ts b/src/platform/test/functional/apps/discover/tabs2/_sharing.ts index 3925fa9659813..d0027daa56879 100644 --- a/src/platform/test/functional/apps/discover/tabs2/_sharing.ts +++ b/src/platform/test/functional/apps/discover/tabs2/_sharing.ts @@ -21,6 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('tabs sharing', function () { beforeEach(async () => { + await discover.resetQueryMode(); await unifiedTabs.clearRecentlyClosedTabs(); }); diff --git a/src/platform/test/functional/page_objects/discover_page.ts b/src/platform/test/functional/page_objects/discover_page.ts index 03b260505bc4f..06d1e0c5c6d1d 100644 --- a/src/platform/test/functional/page_objects/discover_page.ts +++ b/src/platform/test/functional/page_objects/discover_page.ts @@ -1005,4 +1005,8 @@ export class DiscoverPageObject extends FtrService { public async ensureNoUnsavedChangesIndicator() { await this.testSubjects.missingOrFail('split-button-notification-indicator'); } + + public resetQueryMode() { + return this.browser.removeLocalStorageItem('discover.defaultQueryMode'); + } } From eeff2418e7066283af1295e97ac7bde2cd8ce708 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 27 Jan 2026 11:23:31 +0100 Subject: [PATCH 03/14] Fix tabs code + tests --- .../utils/get_initial_app_state.test.ts | 105 ++++++++++++++++++ .../utils/get_initial_app_state.ts | 16 ++- .../discover/context_awareness/_telemetry.ts | 2 +- .../apps/discover/group10/_lens_vis.ts | 5 +- .../_data_grid_in_table_search.ts | 4 + .../apps/discover/tabs2/_sharing.ts | 2 +- 6 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts index 4e6098b148293..039307d5d86f0 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts @@ -341,6 +341,111 @@ describe('getInitialAppState', () => { `); }); + describe('when there is no persistedTab', () => { + describe('when there is a query in the url state', () => { + it('should use the query from the url state', () => { + // Given + const services = createDiscoverServicesMock(); + const query = { language: 'kuery', query: 'url state query' }; + + // When + const appState = getInitialAppState({ + initialUrlState: { query }, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query, + }) + ); + }); + }); + + describe('when there is no query in the url state', () => { + describe('when there is a data source in the url state', () => { + it('should use the default query', () => { + // Given + const services = createDiscoverServicesMock(); + const dataSource = createDataViewDataSource({ dataViewId: 'some-data-view-id' }); + services.data.query.queryString.getDefaultQuery = jest.fn().mockReturnValue(defaultQuery); + + // When + const appState = getInitialAppState({ + initialUrlState: { dataSource }, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query: defaultQuery, + }) + ); + }); + }); + + describe('when there is no data source in the url state', () => { + describe('when the query mode is esql', () => { + it('should return an esql initial query', () => { + // Given + const services = createDiscoverServicesMock(); + services.storage.get = jest.fn().mockReturnValue('esql'); + + // When + const appState = getInitialAppState({ + initialUrlState: undefined, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query: { esql: 'FROM the-data-view-title' }, + }) + ); + }); + }); + + describe.each([ + { queryMode: 'classic', description: 'classic' }, + { queryMode: undefined, description: 'unset' }, + ])('when the query mode is $description', ({ queryMode }) => { + it('should return the default query', () => { + // Given + const services = createDiscoverServicesMock(); + services.storage.get = jest.fn().mockReturnValue(queryMode); + services.data.query.queryString.getDefaultQuery = jest + .fn() + .mockReturnValue(defaultQuery); + + // When + const appState = getInitialAppState({ + initialUrlState: undefined, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query: defaultQuery, + }) + ); + }); + }); + }); + }); + }); + describe('default sort array', () => { test('should use persistedTab sort array if valid and data view is provided', () => { const services = createDiscoverServicesMock(); diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts index 80c53391001e9..404ba23ae939f 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts @@ -48,6 +48,7 @@ export function getInitialAppState({ persistedTab, dataView, services, + initialUrlState, }); const mergedState = { ...defaultAppState, ...initialUrlState }; @@ -85,6 +86,7 @@ function isDataView(dataView: unknown): dataView is DataView { } function getDefaultQuery({ + initialUrlState, persistedTab, storage, data, @@ -94,9 +96,19 @@ function getDefaultQuery({ storage: DiscoverServices['storage']; data: DiscoverServices['data']; dataView: DataView | Pick | undefined; + initialUrlState: DiscoverAppState | undefined; }): Query | AggregateQuery | undefined { if (persistedTab?.serializedSearchSource.query) return persistedTab.serializedSearchSource.query; + // This scenarios are used when we are adding a new tab: + // 1. We only have the query set if: + // a. The tab is in ES|QL mode + // b. The tab is in other mode but has some filter in place + // 2. We have no query set but we do have a data source if we are in classic mode with no filters + if (initialUrlState?.query) return initialUrlState.query; + if (initialUrlState?.dataSource) return data.query.queryString.getDefaultQuery(); + + // Fallback to last query mode for new sessions const queryMode = storage.get(DISCOVER_QUERY_MODE_KEY); if (queryMode === 'esql' && isDataView(dataView)) return { esql: getInitialESQLQuery(dataView, true) }; @@ -108,13 +120,15 @@ function getDefaultAppState({ persistedTab, dataView, services, + initialUrlState, }: { persistedTab: DiscoverSessionTab | undefined; dataView: DataView | Pick | undefined; services: DiscoverServices; + initialUrlState: DiscoverAppState | undefined; }) { const { data, uiSettings, storage } = services; - const query = getDefaultQuery({ persistedTab, storage, data, dataView }); + const query = getDefaultQuery({ persistedTab, storage, data, dataView, initialUrlState }); const isEsqlQuery = isOfAggregateQueryType(query); // If the data view doesn't have a getFieldByName method (e.g. if it's a spec or list item), // we assume the sort array is valid since we can't know for sure diff --git a/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts b/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts index 2ffe8621077d7..d9584924f068d 100644 --- a/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts +++ b/src/platform/test/functional/apps/discover/context_awareness/_telemetry.ts @@ -230,7 +230,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('field usage events', () => { beforeEach(async () => { - await discover.resetQueryMode(); await common.navigateToApp('discover'); await header.waitUntilLoadingHasFinished(); await discover.waitUntilSearchingHasFinished(); @@ -434,6 +433,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('trackSubmittingQuery telemetry', () => { beforeEach(async () => { + await discover.resetQueryMode(); await common.navigateToApp('discover'); await discover.waitUntilTabIsLoaded(); await ebtUIHelper.setOptIn(true); diff --git a/src/platform/test/functional/apps/discover/group10/_lens_vis.ts b/src/platform/test/functional/apps/discover/group10/_lens_vis.ts index 11e30545c1727..19666740a344b 100644 --- a/src/platform/test/functional/apps/discover/group10/_lens_vis.ts +++ b/src/platform/test/functional/apps/discover/group10/_lens_vis.ts @@ -110,12 +110,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeEach(async function () { await timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update(defaultSettings); - await discover.resetQueryMode(); await common.navigateToApp('discover'); await header.waitUntilLoadingHasFinished(); await discover.waitUntilSearchingHasFinished(); }); + afterEach(async function () { + await discover.resetQueryMode(); + }); + it('should show histogram by default', async () => { await checkHistogramVis(defaultTimespan, defaultTotalCount); diff --git a/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_in_table_search.ts b/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_in_table_search.ts index f1dcc4df26237..fd5a7548e632b 100644 --- a/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_in_table_search.ts +++ b/src/platform/test/functional/apps/discover/group2_data_grid2/_data_grid_in_table_search.ts @@ -59,6 +59,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await discover.waitUntilSearchingHasFinished(); }); + afterEach(async function () { + await discover.resetQueryMode(); + }); + it('should show highlights for in-table search', async () => { expect(await dataGrid.getCurrentPageNumber()).to.be('1'); diff --git a/src/platform/test/functional/apps/discover/tabs2/_sharing.ts b/src/platform/test/functional/apps/discover/tabs2/_sharing.ts index d0027daa56879..e4edeb771c79a 100644 --- a/src/platform/test/functional/apps/discover/tabs2/_sharing.ts +++ b/src/platform/test/functional/apps/discover/tabs2/_sharing.ts @@ -21,11 +21,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('tabs sharing', function () { beforeEach(async () => { - await discover.resetQueryMode(); await unifiedTabs.clearRecentlyClosedTabs(); }); afterEach(async () => { + await discover.resetQueryMode(); await browser.closeCurrentWindow(); await browser.switchTab(0); }); From ebccd712c2782d2d61a61ee7a79b806e3a633e15 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 27 Jan 2026 13:22:20 +0100 Subject: [PATCH 04/14] Another test fix --- src/platform/test/functional/apps/discover/tabs/_new_tab.ts | 2 +- .../functional/apps/discover/tabs2/_recently_closed_tabs.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/platform/test/functional/apps/discover/tabs/_new_tab.ts b/src/platform/test/functional/apps/discover/tabs/_new_tab.ts index 6bb2acadd7633..1d7f14a6ca6c4 100644 --- a/src/platform/test/functional/apps/discover/tabs/_new_tab.ts +++ b/src/platform/test/functional/apps/discover/tabs/_new_tab.ts @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.setWindowSize(1920, 1080); }); - beforeEach(async () => { + afterEach(async () => { await discover.resetQueryMode(); }); diff --git a/src/platform/test/functional/apps/discover/tabs2/_recently_closed_tabs.ts b/src/platform/test/functional/apps/discover/tabs2/_recently_closed_tabs.ts index 921305bacedb6..7411553a82db3 100644 --- a/src/platform/test/functional/apps/discover/tabs2/_recently_closed_tabs.ts +++ b/src/platform/test/functional/apps/discover/tabs2/_recently_closed_tabs.ts @@ -29,6 +29,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedTabs.clearRecentlyClosedTabs(); }); + afterEach(async () => { + await discover.resetQueryMode(); + }); + it('should start with no recently closed tabs', async () => { const recentlyClosedTabs = await unifiedTabs.getRecentlyClosedTabTitles(); expect(recentlyClosedTabs.length).to.be(0); From 116f0f627c41a15f220f07bd162ecdef233efd38 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 27 Jan 2026 16:59:00 +0100 Subject: [PATCH 05/14] Fix tests --- .../test/functional/apps/discover/tabs/_save_and_load.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/platform/test/functional/apps/discover/tabs/_save_and_load.ts b/src/platform/test/functional/apps/discover/tabs/_save_and_load.ts index e4a03dc971a68..6629e68b35c96 100644 --- a/src/platform/test/functional/apps/discover/tabs/_save_and_load.ts +++ b/src/platform/test/functional/apps/discover/tabs/_save_and_load.ts @@ -25,6 +25,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); describe('tabs saving and loading', function () { + afterEach(async () => { + await discover.resetQueryMode(); + }); + describe('legacy Discover sessions', () => { const legacySessionName = 'A Saved Search'; const updatedSessionName = 'Updated legacy session'; From 2f1163d3ed4df8599ab7bc3e8eeaddec057d5c38 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Wed, 28 Jan 2026 11:38:31 +0100 Subject: [PATCH 06/14] Add functional tests --- .buildkite/ftr_platform_stateful_configs.yml | 1 + .../query_mode/_default_query_mode.ts | 49 +++++++++++++++++++ .../discover/query_mode/_update_query_mode.ts | 39 +++++++++++++++ .../apps/discover/query_mode/config.ts | 19 +++++++ .../apps/discover/query_mode/index.ts | 32 ++++++++++++ .../functional/page_objects/discover_page.ts | 12 ++++- 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts create mode 100644 src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts create mode 100644 src/platform/test/functional/apps/discover/query_mode/config.ts create mode 100644 src/platform/test/functional/apps/discover/query_mode/index.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index 7206211b291b8..a4997615cb18d 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -91,6 +91,7 @@ enabled: - src/platform/test/functional/apps/discover/group10/config.ts - src/platform/test/functional/apps/discover/context_awareness/config.ts - src/platform/test/functional/apps/discover/observability/config.ts + - src/platform/test/functional/apps/discover/query_mode/config.ts - src/platform/test/functional/apps/discover/tabs/config.ts - src/platform/test/functional/apps/discover/tabs2/config.ts - src/platform/test/functional/apps/discover/tabs3/config.ts diff --git a/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts new file mode 100644 index 0000000000000..b80134fd0b99f --- /dev/null +++ b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import type { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + + const { discover, common } = getPageObjects(['discover', 'common']); + + describe('Default query mode', () => { + afterEach(async () => { + await discover.resetQueryMode(); + }); + + beforeEach(async () => { + await common.navigateToApp('discover'); + }); + + describe('when the default query mode is ES|QL', () => { + it('should open Discover in ES|QL mode', async () => { + await discover.setQueryMode('esql'); + await common.navigateToApp('discover'); + await discover.expectSourceViewerToExist(); + }); + }); + + describe('when the default query mode is classic', () => { + it('should open Discover in classic mode', async () => { + await discover.setQueryMode('classic'); + await common.navigateToApp('discover'); + await testSubjects.existOrFail('discover-dataView-switch-link'); + }); + }); + + describe('when the default query mode is unset', () => { + it('should open Discover in classic mode', async () => { + await discover.resetQueryMode(); + await common.navigateToApp('discover'); + await testSubjects.existOrFail('discover-dataView-switch-link'); + }); + }); + }); +} diff --git a/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts b/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts new file mode 100644 index 0000000000000..3bc137f3dbd34 --- /dev/null +++ b/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getPageObjects }: FtrProviderContext) { + const { discover, common } = getPageObjects(['discover', 'common']); + + describe('Update query mode', () => { + afterEach(async () => { + await discover.resetQueryMode(); + }); + + describe('when the user clicks ES|QL mode', () => { + it('should set the default mode to ES|QL', async () => { + await common.navigateToApp('discover'); + await discover.selectTextBaseLang(); + const queryMode = await discover.getQueryMode(); + expect(queryMode).to.contain('esql'); + }); + }); + + describe('when the user clicks classic', () => { + it('should set the default mode to classic', async () => { + await common.navigateToApp('discover'); + await discover.selectTextBaseLang(); + await discover.selectDataViewMode(); + const queryMode = await discover.getQueryMode(); + expect(queryMode).to.contain('classic'); + }); + }); + }); +} diff --git a/src/platform/test/functional/apps/discover/query_mode/config.ts b/src/platform/test/functional/apps/discover/query_mode/config.ts new file mode 100644 index 0000000000000..9d42f45669d4e --- /dev/null +++ b/src/platform/test/functional/apps/discover/query_mode/config.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/src/platform/test/functional/apps/discover/query_mode/index.ts b/src/platform/test/functional/apps/discover/query_mode/index.ts new file mode 100644 index 0000000000000..fdb580870af4c --- /dev/null +++ b/src/platform/test/functional/apps/discover/query_mode/index.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import type { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/query_mode', function () { + before(async function () { + await esArchiver.loadIfNeeded( + 'src/platform/test/functional/fixtures/es_archiver/logstash_functional' + ); + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload( + 'src/platform/test/functional/fixtures/es_archiver/logstash_functional' + ); + }); + + loadTestFile(require.resolve('./_update_query_mode')); + loadTestFile(require.resolve('./_default_query_mode')); + }); +} diff --git a/src/platform/test/functional/page_objects/discover_page.ts b/src/platform/test/functional/page_objects/discover_page.ts index 06d1e0c5c6d1d..dd7b6c68b5933 100644 --- a/src/platform/test/functional/page_objects/discover_page.ts +++ b/src/platform/test/functional/page_objects/discover_page.ts @@ -11,6 +11,8 @@ import expect from '@kbn/expect'; import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrService } from '../ftr_provider_context'; +const DISCOVER_QUERY_MODE_KEY = 'discover.defaultQueryMode'; + export class DiscoverPageObject extends FtrService { private readonly retry = this.ctx.getService('retry'); private readonly testSubjects = this.ctx.getService('testSubjects'); @@ -1007,6 +1009,14 @@ export class DiscoverPageObject extends FtrService { } public resetQueryMode() { - return this.browser.removeLocalStorageItem('discover.defaultQueryMode'); + return this.browser.removeLocalStorageItem(DISCOVER_QUERY_MODE_KEY); + } + + public getQueryMode() { + return this.browser.getLocalStorageItem(DISCOVER_QUERY_MODE_KEY); + } + + public setQueryMode(mode: string) { + return this.browser.setLocalStorageItem(DISCOVER_QUERY_MODE_KEY, JSON.stringify(mode)); } } From 2d3a1b975f56763f557d6f861df88a4c44e89023 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 2 Feb 2026 08:57:33 +0100 Subject: [PATCH 07/14] Update dataview check and use uisettings --- .../utils/get_initial_app_state.test.ts | 14 ++++++++-- .../utils/get_initial_app_state.ts | 28 ++++++++----------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts index 039307d5d86f0..9484e2646e74f 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts @@ -18,6 +18,7 @@ import { dataViewWithTimefieldMock } from '../../../../__mocks__/data_view_with_ import type { DiscoverServices } from '../../../../build_services'; import { VIEW_MODE } from '@kbn/saved-search-plugin/common'; import { DEFAULT_COLUMNS_SETTING } from '@kbn/discover-utils'; +import { DataView } from '@kbn/data-views-plugin/common'; describe('getInitialAppState', () => { const customQuery = { @@ -396,12 +397,16 @@ describe('getInitialAppState', () => { // Given const services = createDiscoverServicesMock(); services.storage.get = jest.fn().mockReturnValue('esql'); + services.uiSettings.get = jest.fn().mockReturnValue(true); // When const appState = getInitialAppState({ initialUrlState: undefined, persistedTab: undefined, - dataView: dataViewMock, + dataView: new DataView({ + spec: dataViewMock.toSpec(), + fieldFormats: {} as DataView['fieldFormats'], + }), services, }); @@ -415,6 +420,7 @@ describe('getInitialAppState', () => { }); describe.each([ + { queryMode: 'esql', description: 'esql but esql is disabled' }, { queryMode: 'classic', description: 'classic' }, { queryMode: undefined, description: 'unset' }, ])('when the query mode is $description', ({ queryMode }) => { @@ -422,6 +428,7 @@ describe('getInitialAppState', () => { // Given const services = createDiscoverServicesMock(); services.storage.get = jest.fn().mockReturnValue(queryMode); + services.uiSettings.get = jest.fn().mockReturnValue(false); services.data.query.queryString.getDefaultQuery = jest .fn() .mockReturnValue(defaultQuery); @@ -430,7 +437,10 @@ describe('getInitialAppState', () => { const appState = getInitialAppState({ initialUrlState: undefined, persistedTab: undefined, - dataView: dataViewMock, + dataView: new DataView({ + spec: dataViewMock.toSpec(), + fieldFormats: {} as DataView['fieldFormats'], + }), services, }); diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts index 404ba23ae939f..15e9b95ddddfd 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { DataView } from '@kbn/data-views-plugin/common'; +import { DataView } from '@kbn/data-views-plugin/common'; import type { AggregateQuery, Query } from '@kbn/es-query'; import { isOfAggregateQueryType } from '@kbn/es-query'; import type { DiscoverSessionTab } from '@kbn/saved-search-plugin/common'; @@ -21,7 +21,7 @@ import { } from '@kbn/discover-utils'; import { getChartHidden } from '@kbn/unified-histogram'; import { cloneDeep } from 'lodash'; -import { getInitialESQLQuery } from '@kbn/esql-utils'; +import { ENABLE_ESQL, getInitialESQLQuery } from '@kbn/esql-utils'; import { DISCOVER_QUERY_MODE_KEY } from '../../../../../common/constants'; import type { DiscoverServices } from '../../../../build_services'; import type { DiscoverAppState } from '../redux'; @@ -81,20 +81,14 @@ function getDefaultColumns( : undefined; } -function isDataView(dataView: unknown): dataView is DataView { - return !!dataView && typeof dataView === 'object' && 'getIndexPattern' in dataView; -} - function getDefaultQuery({ initialUrlState, persistedTab, - storage, - data, + services, dataView, }: { persistedTab: DiscoverSessionTab | undefined; - storage: DiscoverServices['storage']; - data: DiscoverServices['data']; + services: DiscoverServices; dataView: DataView | Pick | undefined; initialUrlState: DiscoverAppState | undefined; }): Query | AggregateQuery | undefined { @@ -106,14 +100,16 @@ function getDefaultQuery({ // b. The tab is in other mode but has some filter in place // 2. We have no query set but we do have a data source if we are in classic mode with no filters if (initialUrlState?.query) return initialUrlState.query; - if (initialUrlState?.dataSource) return data.query.queryString.getDefaultQuery(); + if (initialUrlState?.dataSource) return services.data.query.queryString.getDefaultQuery(); // Fallback to last query mode for new sessions - const queryMode = storage.get(DISCOVER_QUERY_MODE_KEY); - if (queryMode === 'esql' && isDataView(dataView)) + const hasEsqlEnabled = services.uiSettings.get(ENABLE_ESQL); + + const queryMode = services.storage.get(DISCOVER_QUERY_MODE_KEY); + if (hasEsqlEnabled && queryMode === 'esql' && dataView instanceof DataView) return { esql: getInitialESQLQuery(dataView, true) }; - return data.query.queryString.getDefaultQuery(); + return services.data.query.queryString.getDefaultQuery(); } function getDefaultAppState({ @@ -127,8 +123,8 @@ function getDefaultAppState({ services: DiscoverServices; initialUrlState: DiscoverAppState | undefined; }) { - const { data, uiSettings, storage } = services; - const query = getDefaultQuery({ persistedTab, storage, data, dataView, initialUrlState }); + const { uiSettings, storage } = services; + const query = getDefaultQuery({ persistedTab, services, dataView, initialUrlState }); const isEsqlQuery = isOfAggregateQueryType(query); // If the data view doesn't have a getFieldByName method (e.g. if it's a spec or list item), // we assume the sort array is valid since we can't know for sure From 26d21b891eb5c938c8b5cdb7172f861f283538af Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 2 Feb 2026 13:04:43 +0100 Subject: [PATCH 08/14] Combine functional tests --- .../query_mode/_default_query_mode.ts | 48 ++++++++++++------- .../discover/query_mode/_update_query_mode.ts | 39 --------------- .../apps/discover/query_mode/index.ts | 1 - 3 files changed, 31 insertions(+), 57 deletions(-) delete mode 100644 src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts diff --git a/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts index b80134fd0b99f..05040828141a8 100644 --- a/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts +++ b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts @@ -6,42 +6,56 @@ * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ +import expect from '@kbn/expect'; import type { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const testSubjects = getService('testSubjects'); - const { discover, common } = getPageObjects(['discover', 'common']); + const testSubjects = getService('testSubjects'); + describe('Default query mode', () => { afterEach(async () => { await discover.resetQueryMode(); }); - beforeEach(async () => { - await common.navigateToApp('discover'); - }); - - describe('when the default query mode is ES|QL', () => { - it('should open Discover in ES|QL mode', async () => { - await discover.setQueryMode('esql'); + describe('when there is no default query mode set', () => { + it('should open Discover in classic mode', async () => { + // Validate that no default query mode is set await common.navigateToApp('discover'); - await discover.expectSourceViewerToExist(); + const queryMode = await discover.getQueryMode(); + expect(queryMode).to.be(null); + + // Go to discover and validate classic mode + await testSubjects.existOrFail('discover-dataView-switch-link'); }); }); - describe('when the default query mode is classic', () => { - it('should open Discover in classic mode', async () => { - await discover.setQueryMode('classic'); + describe('when the user clicks ES|QL mode', () => { + it('should set the default mode to ES|QL', async () => { + // Go to discover and select ES|QL mode await common.navigateToApp('discover'); - await testSubjects.existOrFail('discover-dataView-switch-link'); + await discover.selectTextBaseLang(); + const queryMode = await discover.getQueryMode(); + expect(queryMode).to.contain('esql'); + + // Reload the app and validate ES|QL mode is persisted + await common.navigateToApp('discover', { path: '' }); + await discover.expectSourceViewerToExist(); }); }); - describe('when the default query mode is unset', () => { - it('should open Discover in classic mode', async () => { - await discover.resetQueryMode(); + describe('when the user clicks classic', () => { + it('should set the default mode to classic', async () => { + // Go to discover and select classic mode await common.navigateToApp('discover'); + await discover.selectTextBaseLang(); + await discover.selectDataViewMode(); + const queryMode = await discover.getQueryMode(); + expect(queryMode).to.contain('classic'); + + // Reload the app and validate classic mode is persisted + await common.navigateToApp('discover', { path: '' }); await testSubjects.existOrFail('discover-dataView-switch-link'); }); }); diff --git a/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts b/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts deleted file mode 100644 index 3bc137f3dbd34..0000000000000 --- a/src/platform/test/functional/apps/discover/query_mode/_update_query_mode.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ -import expect from '@kbn/expect'; -import type { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getPageObjects }: FtrProviderContext) { - const { discover, common } = getPageObjects(['discover', 'common']); - - describe('Update query mode', () => { - afterEach(async () => { - await discover.resetQueryMode(); - }); - - describe('when the user clicks ES|QL mode', () => { - it('should set the default mode to ES|QL', async () => { - await common.navigateToApp('discover'); - await discover.selectTextBaseLang(); - const queryMode = await discover.getQueryMode(); - expect(queryMode).to.contain('esql'); - }); - }); - - describe('when the user clicks classic', () => { - it('should set the default mode to classic', async () => { - await common.navigateToApp('discover'); - await discover.selectTextBaseLang(); - await discover.selectDataViewMode(); - const queryMode = await discover.getQueryMode(); - expect(queryMode).to.contain('classic'); - }); - }); - }); -} diff --git a/src/platform/test/functional/apps/discover/query_mode/index.ts b/src/platform/test/functional/apps/discover/query_mode/index.ts index fdb580870af4c..2f091fb965333 100644 --- a/src/platform/test/functional/apps/discover/query_mode/index.ts +++ b/src/platform/test/functional/apps/discover/query_mode/index.ts @@ -26,7 +26,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { ); }); - loadTestFile(require.resolve('./_update_query_mode')); loadTestFile(require.resolve('./_default_query_mode')); }); } From bdd9f10c0180f654c0c47b30592694429a665429 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 2 Feb 2026 13:06:22 +0100 Subject: [PATCH 09/14] Use available query mode or classic when _a or _g are present2 --- .../redux/actions/initialize_single_tab.ts | 1 + .../utils/get_initial_app_state.test.ts | 126 ++++++++++++++---- .../utils/get_initial_app_state.ts | 29 ++-- 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/initialize_single_tab.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/initialize_single_tab.ts index a2c8242a0c1ba..82b13b3592e47 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/initialize_single_tab.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/initialize_single_tab.ts @@ -235,6 +235,7 @@ export const initializeSingleTab = createInternalStateAsyncThunk( // then get an updated copy of the saved search with the applied initial state const initialAppState = getInitialAppState({ initialUrlState: urlAppState, + hasGlobalState: Object.keys(urlGlobalState || {}).length > 0, persistedTab, dataView, services, diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts index 9484e2646e74f..2c953ce93d5d8 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.test.ts @@ -78,6 +78,7 @@ describe('getInitialAppState', () => { services, }); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab, dataView: dataViewMock, @@ -123,6 +124,7 @@ describe('getInitialAppState', () => { services, }); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab, dataView: dataViewMock, @@ -152,6 +154,7 @@ describe('getInitialAppState', () => { test('data view with timefield', () => { const services = createDiscoverServicesMock(); const actual = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: undefined, dataView: dataViewWithTimefieldMock, @@ -193,6 +196,7 @@ describe('getInitialAppState', () => { test('data view without timefield', () => { const services = createDiscoverServicesMock(); const actual = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: undefined, dataView: dataViewMock, @@ -236,6 +240,7 @@ describe('getInitialAppState', () => { test('should set view mode correctly', () => { const services = createDiscoverServicesMock(); const actualForUndefinedViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -247,6 +252,7 @@ describe('getInitialAppState', () => { expect(actualForUndefinedViewMode.viewMode).toBeUndefined(); const actualForEsqlWithAggregatedViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -259,6 +265,7 @@ describe('getInitialAppState', () => { expect(actualForEsqlWithAggregatedViewMode.viewMode).toBe(VIEW_MODE.AGGREGATED_LEVEL); const actualForEsqlWithInvalidPatternLevelViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -271,6 +278,7 @@ describe('getInitialAppState', () => { expect(actualForEsqlWithInvalidPatternLevelViewMode.viewMode).toBe(VIEW_MODE.DOCUMENT_LEVEL); const actualForEsqlWithValidViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -284,6 +292,7 @@ describe('getInitialAppState', () => { expect(actualForEsqlWithValidViewMode.dataSource).toEqual(createEsqlDataSource()); const actualForWithValidAggLevelViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -298,6 +307,7 @@ describe('getInitialAppState', () => { ); const actualForWithValidPatternLevelViewMode = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -315,6 +325,7 @@ describe('getInitialAppState', () => { test('should return expected dataSource', () => { const services = createDiscoverServicesMock(); const actualForEsql = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -329,6 +340,7 @@ describe('getInitialAppState', () => { } `); const actualForDataView = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: getPersistedTab({ services }), dataView: dataViewMock, @@ -343,31 +355,32 @@ describe('getInitialAppState', () => { }); describe('when there is no persistedTab', () => { - describe('when there is a query in the url state', () => { - it('should use the query from the url state', () => { - // Given - const services = createDiscoverServicesMock(); - const query = { language: 'kuery', query: 'url state query' }; - - // When - const appState = getInitialAppState({ - initialUrlState: { query }, - persistedTab: undefined, - dataView: dataViewMock, - services, - }); + describe('when there is a global state', () => { + describe('when there is a query in the url', () => { + it('should use the query from the url state', () => { + // Given + const services = createDiscoverServicesMock(); + const query = { language: 'kuery', query: 'url state query' }; - // Then - expect(appState).toEqual( - expect.objectContaining({ - query, - }) - ); + // When + const appState = getInitialAppState({ + hasGlobalState: true, + initialUrlState: { query }, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query, + }) + ); + }); }); - }); - describe('when there is no query in the url state', () => { - describe('when there is a data source in the url state', () => { + describe('when there is no query in the url', () => { it('should use the default query', () => { // Given const services = createDiscoverServicesMock(); @@ -376,6 +389,7 @@ describe('getInitialAppState', () => { // When const appState = getInitialAppState({ + hasGlobalState: true, initialUrlState: { dataSource }, persistedTab: undefined, dataView: dataViewMock, @@ -390,8 +404,63 @@ describe('getInitialAppState', () => { ); }); }); + }); + + describe('when there is no global state', () => { + describe('when there is initial url state', () => { + describe('when there is a query in the url state', () => { + it('should use the query from the url state', () => { + // Given + const services = createDiscoverServicesMock(); + const query = { language: 'kuery', query: 'url state query' }; + + // When + const appState = getInitialAppState({ + hasGlobalState: false, + initialUrlState: { query }, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query, + }) + ); + }); + }); + + describe('when there is no query in the url state', () => { + it('should use the default query', () => { + // Given + const services = createDiscoverServicesMock(); + const dataSource = createDataViewDataSource({ dataViewId: 'some-data-view-id' }); + services.data.query.queryString.getDefaultQuery = jest + .fn() + .mockReturnValue(defaultQuery); + + // When + const appState = getInitialAppState({ + hasGlobalState: false, + initialUrlState: { dataSource }, + persistedTab: undefined, + dataView: dataViewMock, + services, + }); + + // Then + expect(appState).toEqual( + expect.objectContaining({ + query: defaultQuery, + }) + ); + }); + }); + }); - describe('when there is no data source in the url state', () => { + describe('when there is no initial url state', () => { describe('when the query mode is esql', () => { it('should return an esql initial query', () => { // Given @@ -401,6 +470,7 @@ describe('getInitialAppState', () => { // When const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: undefined, dataView: new DataView({ @@ -435,6 +505,7 @@ describe('getInitialAppState', () => { // When const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: undefined, dataView: new DataView({ @@ -460,6 +531,7 @@ describe('getInitialAppState', () => { test('should use persistedTab sort array if valid and data view is provided', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -474,6 +546,7 @@ describe('getInitialAppState', () => { test('should not use persistedTab sort array if invalid and data view is provided', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -488,6 +561,7 @@ describe('getInitialAppState', () => { test('should use persistedTab sort array when data view is not provided', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -502,6 +576,7 @@ describe('getInitialAppState', () => { test('should use persistedTab sort array when partial data view is provided', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -518,6 +593,7 @@ describe('getInitialAppState', () => { test('should use persistedTab columns if provided', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -532,6 +608,7 @@ describe('getInitialAppState', () => { test('should use default columns if empty columns are stored for persistedTab', () => { const services = createDiscoverServicesMock(); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -551,6 +628,7 @@ describe('getInitialAppState', () => { } }); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: { ...getPersistedTab({ services }), @@ -570,6 +648,7 @@ describe('getInitialAppState', () => { } }); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: { columns: [] }, persistedTab: undefined, dataView: dataViewWithTimefieldMock, @@ -586,6 +665,7 @@ describe('getInitialAppState', () => { } }); const appState = getInitialAppState({ + hasGlobalState: false, initialUrlState: undefined, persistedTab: undefined, dataView: dataViewWithTimefieldMock, diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts index 15e9b95ddddfd..cd4431d4ce006 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts @@ -35,11 +35,13 @@ import { getValidViewMode } from '../../utils/get_valid_view_mode'; export function getInitialAppState({ initialUrlState, + hasGlobalState, persistedTab, dataView, services, }: { initialUrlState: DiscoverAppState | undefined; + hasGlobalState: boolean; persistedTab: DiscoverSessionTab | undefined; dataView: DataView | Pick | undefined; services: DiscoverServices; @@ -49,6 +51,7 @@ export function getInitialAppState({ dataView, services, initialUrlState, + hasGlobalState, }); const mergedState = { ...defaultAppState, ...initialUrlState }; @@ -83,6 +86,7 @@ function getDefaultColumns( function getDefaultQuery({ initialUrlState, + hasGlobalState, persistedTab, services, dataView, @@ -91,18 +95,17 @@ function getDefaultQuery({ services: DiscoverServices; dataView: DataView | Pick | undefined; initialUrlState: DiscoverAppState | undefined; + hasGlobalState: boolean; }): Query | AggregateQuery | undefined { if (persistedTab?.serializedSearchSource.query) return persistedTab.serializedSearchSource.query; - // This scenarios are used when we are adding a new tab: - // 1. We only have the query set if: - // a. The tab is in ES|QL mode - // b. The tab is in other mode but has some filter in place - // 2. We have no query set but we do have a data source if we are in classic mode with no filters - if (initialUrlState?.query) return initialUrlState.query; - if (initialUrlState?.dataSource) return services.data.query.queryString.getDefaultQuery(); + // If there is global or app state (_g or _a) in the URL we should respect it and assume it's a classic query + // This is also useful to reuse the query mode if we are opening a new tab from an existing one + const hasInitialUrlState = Object.keys(initialUrlState || {}).length > 0; + if (hasGlobalState || hasInitialUrlState) + return initialUrlState?.query || services.data.query.queryString.getDefaultQuery(); - // Fallback to last query mode for new sessions + // Lastly fall back to the last selected query mode if available const hasEsqlEnabled = services.uiSettings.get(ENABLE_ESQL); const queryMode = services.storage.get(DISCOVER_QUERY_MODE_KEY); @@ -117,14 +120,22 @@ function getDefaultAppState({ dataView, services, initialUrlState, + hasGlobalState, }: { persistedTab: DiscoverSessionTab | undefined; dataView: DataView | Pick | undefined; services: DiscoverServices; initialUrlState: DiscoverAppState | undefined; + hasGlobalState: boolean; }) { const { uiSettings, storage } = services; - const query = getDefaultQuery({ persistedTab, services, dataView, initialUrlState }); + const query = getDefaultQuery({ + persistedTab, + services, + dataView, + initialUrlState, + hasGlobalState, + }); const isEsqlQuery = isOfAggregateQueryType(query); // If the data view doesn't have a getFieldByName method (e.g. if it's a spec or list item), // we assume the sort array is valid since we can't know for sure From 80c56788b2042e44dca0af4511ef8ad2e225477c Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Mon, 2 Feb 2026 13:21:34 +0100 Subject: [PATCH 10/14] Make hasGlobalState default false --- .../main/state_management/utils/get_initial_app_state.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts index cd4431d4ce006..9f525de0366f2 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/utils/get_initial_app_state.ts @@ -35,13 +35,13 @@ import { getValidViewMode } from '../../utils/get_valid_view_mode'; export function getInitialAppState({ initialUrlState, - hasGlobalState, + hasGlobalState = false, persistedTab, dataView, services, }: { initialUrlState: DiscoverAppState | undefined; - hasGlobalState: boolean; + hasGlobalState?: boolean; persistedTab: DiscoverSessionTab | undefined; dataView: DataView | Pick | undefined; services: DiscoverServices; From 5a4c68b6ba5eac872021fed8914eb6e0930374f2 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 3 Feb 2026 17:19:04 +0100 Subject: [PATCH 11/14] Move storage updates to redux listener --- .../components/tabs_view/use_app_menu_data.ts | 6 +---- .../components/top_nav/use_top_nav_links.tsx | 2 -- .../state_management/redux/internal_state.ts | 23 +++++++++++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts b/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts index 8a73667fb083c..d3869e34fed17 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts +++ b/src/platform/plugins/shared/discover/public/application/main/components/tabs_view/use_app_menu_data.ts @@ -23,10 +23,7 @@ import { selectAllTabs, } from '../../state_management/redux'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; -import { - DISCOVER_QUERY_MODE_KEY, - ESQL_TRANSITION_MODAL_KEY, -} from '../../../../../common/constants'; +import { ESQL_TRANSITION_MODAL_KEY } from '../../../../../common/constants'; import { useTopNavMenuItems } from '../top_nav/use_top_nav_menu_items'; import { isEsqlSource } from '../../../../../common/data_sources'; @@ -101,7 +98,6 @@ export const useAppMenuData = ({ currentDataView }: UseAppMenuDataParams): UseAp } else { dispatch(transitionFromESQLToDataView({ dataViewId: currentDataView?.id ?? '' })); } - services.storage.set(DISCOVER_QUERY_MODE_KEY, 'classic'); }, }, ]; diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx index 779a4d21af576..945431ad77c2f 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.tsx @@ -22,7 +22,6 @@ import { useGetRuleTypesPermissions } from '@kbn/alerts-ui-shared'; import useObservable from 'react-use/lib/useObservable'; import type { DiscoverSession } from '@kbn/saved-search-plugin/common'; import { useI18n } from '@kbn/i18n-react'; -import { DISCOVER_QUERY_MODE_KEY } from '../../../../../common/constants'; import type { DiscoverAppLocatorParams } from '../../../../../common'; import { createDataViewDataSource } from '../../../../../common/data_sources'; import type { DiscoverServices } from '../../../../build_services'; @@ -233,7 +232,6 @@ export const useTopNavLinks = ({ }), run: () => { if (dataView) { - services.storage.set(DISCOVER_QUERY_MODE_KEY, 'esql'); dispatch(transitionFromDataViewToESQL({ dataView })); services.trackUiMetric?.(METRIC_TYPE.CLICK, `esql:try_btn_clicked`); } diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts index 8cd5dec30b72a..ab46af8231ef5 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts @@ -30,6 +30,7 @@ import type { ESQLControlVariable } from '@kbn/esql-types'; import type { DiscoverSession } from '@kbn/saved-search-plugin/common'; import { type AggregateQuery, isOfAggregateQueryType } from '@kbn/es-query'; import { getESQLStatsQueryMeta } from '@kbn/esql-utils'; +import { DISCOVER_QUERY_MODE_KEY } from '../../../../../common/constants'; import type { DiscoverCustomizationContext } from '../../../../customizations'; import type { DiscoverServices } from '../../../../build_services'; import { type RuntimeStateManager, selectTabRuntimeInternalState } from './runtime_state'; @@ -552,6 +553,28 @@ const createMiddleware = (options: InternalStateDependencies) => { }, }); + startListening({ + actionCreator: internalStateSlice.actions.setAppState, + effect: (action, listenerApi) => { + const { services } = listenerApi.extra; + const tabId = action.payload.tabId; + + const previousState = listenerApi.getOriginalState(); + const previousTabState = previousState.tabs.byId[tabId]; + + const wasEsqlQuery = isOfAggregateQueryType(previousTabState.appState.query); + const isEsqlQuery = isOfAggregateQueryType(action.payload.appState.query); + + // Still ES|QL so we don't need to do anything + if (wasEsqlQuery && isEsqlQuery) return; + // Updated from ES|QL to Data View + else if (wasEsqlQuery && !isEsqlQuery) + services.storage.set(DISCOVER_QUERY_MODE_KEY, 'classic'); + // Updated from Data View to ES|QL + else if (!wasEsqlQuery && isEsqlQuery) services.storage.set(DISCOVER_QUERY_MODE_KEY, 'esql'); + }, + }); + return listenerMiddleware.middleware; }; From 9676c7d095e86899351b1ae2879fd10f8f1c6e01 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 3 Feb 2026 17:21:45 +0100 Subject: [PATCH 12/14] Add comment on the feature flag default --- .../main/state_management/redux/internal_state.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts index ab46af8231ef5..56190f133d7d3 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts @@ -556,6 +556,12 @@ const createMiddleware = (options: InternalStateDependencies) => { startListening({ actionCreator: internalStateSlice.actions.setAppState, effect: (action, listenerApi) => { + // This listener updates the default query mode based on the last used query type (ES|QL vs Data View), we use + // this so new discover sessions use that query mode as a default. + // + // NOTE: In the short term we will add a feature flag to default to ES|QL when there is no existing preference saved. + // Right now we use classic - this means that users will have to switch to ES|QL manually the first time if they already + // had classic stored as their last used mode. const { services } = listenerApi.extra; const tabId = action.payload.tabId; From a135bf055eb75d65c1f15450bac96f2a5b48a675 Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Tue, 3 Feb 2026 17:59:50 +0100 Subject: [PATCH 13/14] Create 2 individual actions to listen to --- .../redux/actions/tab_state.ts | 6 +++ .../state_management/redux/internal_state.ts | 44 ++++++++++--------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/tab_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/tab_state.ts index d81d1c2ceae46..7a4a036e3f8db 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/tab_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/actions/tab_state.ts @@ -26,6 +26,8 @@ import { internalStateSlice, type InternalStateThunkActionCreator, type TabActionPayload, + transitionedFromEsqlToDataView, + transitionedFromDataViewToEsql, } from '../internal_state'; import { selectTab } from '../selectors'; import { selectTabRuntimeState } from '../runtime_state'; @@ -175,6 +177,8 @@ export const transitionFromESQLToDataView: InternalStateThunkActionCreator< }, }) ); + + dispatch(transitionedFromEsqlToDataView({ tabId })); }; const clearTimeFieldFromSort = ( @@ -220,6 +224,8 @@ export const transitionFromDataViewToESQL: InternalStateThunkActionCreator< // clears pinned filters dispatch(updateGlobalState({ tabId, globalState: { filters: [] } })); + + dispatch(transitionedFromDataViewToEsql({ tabId })); }; /** diff --git a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts index 515fa48dce43d..089301f7da4e8 100644 --- a/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts +++ b/src/platform/plugins/shared/discover/public/application/main/state_management/redux/internal_state.ts @@ -449,6 +449,14 @@ export const syncLocallyPersistedTabState = createAction( export const discardFlyoutsOnTabChange = createAction('internalState/discardFlyoutsOnTabChange'); +export const transitionedFromEsqlToDataView = createAction( + 'internalState/transitionedFromEsqlToDataView' +); + +export const transitionedFromDataViewToEsql = createAction( + 'internalState/transitionedFromDataViewToEsql' +); + type InternalStateListenerEffect< TActionCreator extends PayloadActionCreator, TPayload = TActionCreator extends PayloadActionCreator ? T : never @@ -512,31 +520,25 @@ const createMiddleware = (options: InternalStateDependencies) => { }, }); + // This pair of listeners updates the default query mode based on the last used query type (ES|QL vs Data View), we use + // this so new discover sessions use that query mode as a default. + // + // NOTE: In the short term we will add a feature flag to default to ES|QL when there is no existing preference saved. + // Right now we use classic - this means that users will have to switch to ES|QL manually the first time if they already + // had classic stored as their last used mode. startListening({ - actionCreator: internalStateSlice.actions.setAppState, + actionCreator: transitionedFromDataViewToEsql, effect: (action, listenerApi) => { - // This listener updates the default query mode based on the last used query type (ES|QL vs Data View), we use - // this so new discover sessions use that query mode as a default. - // - // NOTE: In the short term we will add a feature flag to default to ES|QL when there is no existing preference saved. - // Right now we use classic - this means that users will have to switch to ES|QL manually the first time if they already - // had classic stored as their last used mode. const { services } = listenerApi.extra; - const tabId = action.payload.tabId; - - const previousState = listenerApi.getOriginalState(); - const previousTabState = previousState.tabs.byId[tabId]; - - const wasEsqlQuery = isOfAggregateQueryType(previousTabState.appState.query); - const isEsqlQuery = isOfAggregateQueryType(action.payload.appState.query); + services.storage.set(DISCOVER_QUERY_MODE_KEY, 'esql'); + }, + }); - // Still ES|QL so we don't need to do anything - if (wasEsqlQuery && isEsqlQuery) return; - // Updated from ES|QL to Data View - else if (wasEsqlQuery && !isEsqlQuery) - services.storage.set(DISCOVER_QUERY_MODE_KEY, 'classic'); - // Updated from Data View to ES|QL - else if (!wasEsqlQuery && isEsqlQuery) services.storage.set(DISCOVER_QUERY_MODE_KEY, 'esql'); + startListening({ + actionCreator: transitionedFromEsqlToDataView, + effect: (action, listenerApi) => { + const { services } = listenerApi.extra; + services.storage.set(DISCOVER_QUERY_MODE_KEY, 'classic'); }, }); From 3e64040b15efdf4532e9e854aaf31af86d96c37e Mon Sep 17 00:00:00 2001 From: AlexGPlay Date: Wed, 4 Feb 2026 08:36:56 +0100 Subject: [PATCH 14/14] Update functional tests --- .../apps/discover/query_mode/_default_query_mode.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts index 05040828141a8..0d088010b539b 100644 --- a/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts +++ b/src/platform/test/functional/apps/discover/query_mode/_default_query_mode.ts @@ -10,7 +10,11 @@ import expect from '@kbn/expect'; import type { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const { discover, common } = getPageObjects(['discover', 'common']); + const { discover, common, unifiedSearch } = getPageObjects([ + 'discover', + 'common', + 'unifiedSearch', + ]); const testSubjects = getService('testSubjects'); @@ -50,7 +54,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // Go to discover and select classic mode await common.navigateToApp('discover'); await discover.selectTextBaseLang(); - await discover.selectDataViewMode(); + await unifiedSearch.switchToDataViewMode(); const queryMode = await discover.getQueryMode(); expect(queryMode).to.contain('classic');