From 323b1346e279aa846a31a495b1794ba518fac830 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 18 Jun 2025 17:15:22 +0200 Subject: [PATCH 1/6] POC to enable onQueryChange --- .../main/components/top_nav/discover_topnav.tsx | 17 +++++++++++++++-- .../query_string_input/query_bar_top_row.tsx | 1 + .../public/search_bar/create_search_bar.tsx | 1 + .../public/search_bar/search_bar.tsx | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx index eeeda7cb01908..268e15457d824 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -7,11 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { DataViewType } from '@kbn/data-views-plugin/public'; import type { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; import { DiscoverFlyouts, dismissAllFlyoutsExceptFor } from '@kbn/discover-utils'; import type { EuiHeaderLinksProps } from '@elastic/eui'; +import type { Query, TimeRange } from '@kbn/es-query'; import { useSavedSearchInitial } from '../../state_management/discover_state_provider'; import { ESQL_TRANSITION_MODAL_KEY } from '../../../../../common/constants'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; @@ -53,6 +54,15 @@ export const DiscoverTopNav = ({ const services = useDiscoverServices(); const { dataViewEditor, navigation, dataViewFieldEditor, data, setHeaderActionMenu } = services; const query = useAppStateSelector((state) => state.query); + const [actualQuery, setActualQuery] = useState(query); + const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: QT | Query }) => { + console.log('onQueryChange', q); + setActualQuery(q); + }, []); + useEffect(() => { + setActualQuery(query); + }, [query]); + const { savedDataViews, managedDataViews, adHocDataViews } = useDataViewsForPicker(); const dataView = useCurrentDataView(); const isESQLToDataViewTransitionModalVisible = useInternalStateSelector( @@ -214,6 +224,8 @@ export const DiscoverTopNav = ({ const shouldHideDefaultDataviewPicker = !!searchBarCustomization?.CustomDataViewPicker || !!searchBarCustomization?.hideDataViewPicker; + console.log({ actualQuery }); + return ( <> extends C currentProps: nextProps, }; if (nextQuery) { + console.log('somehow the edited query in Discover doesnt arrive here', nextQuery); nextState.query = nextQuery; } if (nextDateRange) { From 6a38282324c680f2fcfd7aab28227000d912d034 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Wed, 18 Jun 2025 23:07:55 +0200 Subject: [PATCH 2/6] Intermediate state --- .../components/top_nav/discover_topnav.tsx | 2 +- .../query_string_input/query_bar_top_row.tsx | 10 ++++------ .../public/search_bar/create_search_bar.tsx | 19 +++++++++++++++---- .../public/search_bar/search_bar.tsx | 1 + 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx index 268e15457d824..a44c426131d29 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -224,7 +224,7 @@ export const DiscoverTopNav = ({ const shouldHideDefaultDataviewPicker = !!searchBarCustomization?.CustomDataViewPicker || !!searchBarCustomization?.hideDataViewPicker; - console.log({ actualQuery }); + console.log('DiscoverTop query in use', actualQuery); return ( <> diff --git a/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx index 11ef5b9ece537..5c570a647792e 100644 --- a/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -340,7 +340,6 @@ export const QueryBarTopRow = React.memo( if (timeHistory) { timeHistory.add(dateRange); } - propsOnSubmit({ query, dateRange }); }, [timeHistory, propsOnSubmit] @@ -731,7 +730,6 @@ export const QueryBarTopRow = React.memo( if (adHocDataview && typeof adHocDataview !== 'string') { detectedTimestamp = adHocDataview?.timeFieldName; } - console.log('query', props.query); return ( isQueryLangSelected && props.query && @@ -742,12 +740,12 @@ export const QueryBarTopRow = React.memo( errors={props.textBasedLanguageModeErrors} warning={props.textBasedLanguageModeWarning} detectedTimestamp={detectedTimestamp} - onTextLangQuerySubmit={async () => - onSubmit({ + onTextLangQuerySubmit={async () => { + return onSubmit({ query: queryRef.current, dateRange: dateRangeRef.current, - }) - } + }); + }} isDisabled={props.isDisabled} hideRunQueryText={true} data-test-subj="unifiedTextLangEditor" diff --git a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx index 90f7f33db9b96..2e53f4fe1eb52 100644 --- a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx +++ b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx @@ -8,7 +8,7 @@ */ import { isEqual } from 'lodash'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useCallback } from 'react'; import type { CoreStart } from '@kbn/core/public'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; @@ -160,9 +160,19 @@ export function createSearchBar({ // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. return (props: StatefulSearchBarProps) => { - const { useDefaultBehaviors, allowSavingQueries } = props; + const { useDefaultBehaviors, allowSavingQueries, onQueryChange } = props; // Handle queries const onQuerySubmitRef = useRef(props.onQuerySubmit); + const queryEdited = useRef(''); + const onQueryChanged = useCallback( + (query) => { + queryEdited.current = query.query || ''; + if (onQueryChange) { + onQueryChange(query); + } + }, + [onQueryChange] + ); useEffect(() => { onQuerySubmitRef.current = props.onQuerySubmit; @@ -195,6 +205,7 @@ export function createSearchBar({ // Fire onQuerySubmit on query or timerange change useEffect(() => { if (!useDefaultBehaviors || !onQuerySubmitRef.current) return; + queryEdited.current = ''; onQuerySubmitRef.current( { dateRange: timeRange, @@ -244,7 +255,7 @@ export function createSearchBar({ isLoading={props.isLoading} onCancel={props.onCancel} filters={filters} - query={query} + query={queryEdited.current || query} onFiltersUpdated={defaultFiltersUpdated(data.query, props.onFiltersUpdated)} onRefreshChange={ !props.isAutoRefreshDisabled @@ -253,7 +264,7 @@ export function createSearchBar({ } savedQuery={savedQuery} onQuerySubmit={defaultOnQuerySubmit(props, data.query, query)} - onQueryChange={props.onQueryChange} + onQueryChange={onQueryChanged} onRefresh={props.onRefresh} onClearSavedQuery={defaultOnClearSavedQuery(props, clearSavedQuery)} onSavedQueryUpdated={defaultOnSavedQueryUpdated(props, setSavedQuery)} diff --git a/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx b/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx index 3ada8da309a12..166001383b33f 100644 --- a/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx +++ b/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx @@ -179,6 +179,7 @@ class SearchBarUI extends C nextProps: SearchBarProps, prevState: State ) { + console.log('getDerivedStateFromProps',{ nextProps }) if (isEqual(prevState.currentProps, nextProps)) { return null; } From a2225b2ab722b6b81fba202d55e3fa5840b76270 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 20 Jun 2025 09:01:46 +0200 Subject: [PATCH 3/6] Cleanup --- .../main/components/top_nav/discover_topnav.tsx | 6 ++++-- .../query_string_input/query_bar_top_row.tsx | 9 +++++---- .../public/search_bar/create_search_bar.tsx | 14 ++++++++++---- .../public/search_bar/search_bar.tsx | 2 -- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx index a44c426131d29..fbf85d1c3c0b2 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -55,8 +55,10 @@ export const DiscoverTopNav = ({ const { dataViewEditor, navigation, dataViewFieldEditor, data, setHeaderActionMenu } = services; const query = useAppStateSelector((state) => state.query); const [actualQuery, setActualQuery] = useState(query); + // Note, this is just experimental, if we want to store the edited / dirty state of the query + // is should be done I guess in out internal state container const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: QT | Query }) => { - console.log('onQueryChange', q); + // console.log('onQueryChange', q); setActualQuery(q); }, []); useEffect(() => { @@ -224,7 +226,7 @@ export const DiscoverTopNav = ({ const shouldHideDefaultDataviewPicker = !!searchBarCustomization?.CustomDataViewPicker || !!searchBarCustomization?.hideDataViewPicker; - console.log('DiscoverTop query in use', actualQuery); + // console.log('DiscoverTop query in use', actualQuery); return ( <> diff --git a/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx index 5c570a647792e..28e48f1c96720 100644 --- a/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/platform/plugins/shared/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -340,6 +340,7 @@ export const QueryBarTopRow = React.memo( if (timeHistory) { timeHistory.add(dateRange); } + propsOnSubmit({ query, dateRange }); }, [timeHistory, propsOnSubmit] @@ -740,12 +741,12 @@ export const QueryBarTopRow = React.memo( errors={props.textBasedLanguageModeErrors} warning={props.textBasedLanguageModeWarning} detectedTimestamp={detectedTimestamp} - onTextLangQuerySubmit={async () => { - return onSubmit({ + onTextLangQuerySubmit={async () => + onSubmit({ query: queryRef.current, dateRange: dateRangeRef.current, - }); - }} + }) + } isDisabled={props.isDisabled} hideRunQueryText={true} data-test-subj="unifiedTextLangEditor" diff --git a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx index 2e53f4fe1eb52..325b7b2d225fe 100644 --- a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx +++ b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx @@ -163,10 +163,16 @@ export function createSearchBar({ const { useDefaultBehaviors, allowSavingQueries, onQueryChange } = props; // Handle queries const onQuerySubmitRef = useRef(props.onQuerySubmit); - const queryEdited = useRef(''); + // Just to test tracking of query changes + // Problem that after this inial setting up the query, in this component subsequent changes to the props.query + // are just ignored, since there's a subscription to the queryStringManager of data.query.queryString setting the query + // and since a query edits is unknow to it, it will always return the most recent submitted query + const queryEdited = useRef(); const onQueryChanged = useCallback( (query) => { - queryEdited.current = query.query || ''; + if (query.query) { + queryEdited.current = query.query; + } if (onQueryChange) { onQueryChange(query); } @@ -205,7 +211,7 @@ export function createSearchBar({ // Fire onQuerySubmit on query or timerange change useEffect(() => { if (!useDefaultBehaviors || !onQuerySubmitRef.current) return; - queryEdited.current = ''; + queryEdited.current = undefined; onQuerySubmitRef.current( { dateRange: timeRange, @@ -255,7 +261,7 @@ export function createSearchBar({ isLoading={props.isLoading} onCancel={props.onCancel} filters={filters} - query={queryEdited.current || query} + query={queryEdited.current ?? query} onFiltersUpdated={defaultFiltersUpdated(data.query, props.onFiltersUpdated)} onRefreshChange={ !props.isAutoRefreshDisabled diff --git a/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx b/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx index 166001383b33f..9a27b0d02e0cf 100644 --- a/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx +++ b/src/platform/plugins/shared/unified_search/public/search_bar/search_bar.tsx @@ -179,7 +179,6 @@ class SearchBarUI extends C nextProps: SearchBarProps, prevState: State ) { - console.log('getDerivedStateFromProps',{ nextProps }) if (isEqual(prevState.currentProps, nextProps)) { return null; } @@ -224,7 +223,6 @@ class SearchBarUI extends C currentProps: nextProps, }; if (nextQuery) { - console.log('somehow the edited query in Discover doesnt arrive here', nextQuery); nextState.query = nextQuery; } if (nextDateRange) { From ab42d9a516465fc2485079d9a590de116f347cc4 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 20 Jun 2025 10:10:37 +0200 Subject: [PATCH 4/6] Cleanup types --- .../unified_search/public/search_bar/create_search_bar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx index 325b7b2d225fe..f29f16461c0ed 100644 --- a/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx +++ b/src/platform/plugins/shared/unified_search/public/search_bar/create_search_bar.tsx @@ -167,9 +167,9 @@ export function createSearchBar({ // Problem that after this inial setting up the query, in this component subsequent changes to the props.query // are just ignored, since there's a subscription to the queryStringManager of data.query.queryString setting the query // and since a query edits is unknow to it, it will always return the most recent submitted query - const queryEdited = useRef(); + const queryEdited = useRef(); const onQueryChanged = useCallback( - (query) => { + (query: { dateRange: TimeRange; query?: QT | Query }) => { if (query.query) { queryEdited.current = query.query; } From 0f7cc19c2398f2492e0b6ce1cadb0837122561cb Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 20 Jun 2025 11:59:28 +0200 Subject: [PATCH 5/6] Cleanup types --- .../application/main/components/top_nav/discover_topnav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx index fbf85d1c3c0b2..7eb04e609cfda 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -57,7 +57,7 @@ export const DiscoverTopNav = ({ const [actualQuery, setActualQuery] = useState(query); // Note, this is just experimental, if we want to store the edited / dirty state of the query // is should be done I guess in out internal state container - const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: QT | Query }) => { + const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: Query }) => { // console.log('onQueryChange', q); setActualQuery(q); }, []); From 0363bfc9c1f3a772447e59d1afd1004e958b443a Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 20 Jun 2025 12:38:42 +0200 Subject: [PATCH 6/6] Cleanup types --- .../components/top_nav/discover_topnav.tsx | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx index 7eb04e609cfda..b84b0c40f413c 100644 --- a/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -12,7 +12,7 @@ import { DataViewType } from '@kbn/data-views-plugin/public'; import type { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; import { DiscoverFlyouts, dismissAllFlyoutsExceptFor } from '@kbn/discover-utils'; import type { EuiHeaderLinksProps } from '@elastic/eui'; -import type { Query, TimeRange } from '@kbn/es-query'; +import type { Query, TimeRange, AggregateQuery } from '@kbn/es-query'; import { useSavedSearchInitial } from '../../state_management/discover_state_provider'; import { ESQL_TRANSITION_MODAL_KEY } from '../../../../../common/constants'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; @@ -54,15 +54,20 @@ export const DiscoverTopNav = ({ const services = useDiscoverServices(); const { dataViewEditor, navigation, dataViewFieldEditor, data, setHeaderActionMenu } = services; const query = useAppStateSelector((state) => state.query); - const [actualQuery, setActualQuery] = useState(query); + const [actualQuery, setActualQuery] = useState(query as Query); // Note, this is just experimental, if we want to store the edited / dirty state of the query // is should be done I guess in out internal state container - const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: Query }) => { + const onQueryChange = useCallback((q: { dateRange: TimeRange; query?: Query | AggregateQuery | undefined }) => { // console.log('onQueryChange', q); - setActualQuery(q); + if( q.query) { + setActualQuery(q.query); + } }, []); useEffect(() => { - setActualQuery(query); + if (query) { + setActualQuery(query); + } + }, [query]); const { savedDataViews, managedDataViews, adHocDataViews } = useDataViewsForPicker(); @@ -101,19 +106,19 @@ export const DiscoverTopNav = ({ () => canEditDataView ? async (fieldName?: string) => { - if (dataView?.id) { - const dataViewInstance = await data.dataViews.get(dataView.id); - closeFieldEditor.current = await dataViewFieldEditor.openEditor({ - ctx: { - dataView: dataViewInstance, - }, - fieldName, - onSave: async () => { - await onFieldEdited(); - }, - }); - } + if (dataView?.id) { + const dataViewInstance = await data.dataViews.get(dataView.id); + closeFieldEditor.current = await dataViewFieldEditor.openEditor({ + ctx: { + dataView: dataViewInstance, + }, + fieldName, + onSave: async () => { + await onFieldEdited(); + }, + }); } + } : undefined, [canEditDataView, dataView?.id, data.dataViews, dataViewFieldEditor, onFieldEdited] );