diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index ccda27870313..26daee2c58bf 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -234,6 +234,14 @@ export class IndexPatternsService { indexPatternCache.set(id, indexPattern); }; + isPresentInCache(id: string) { + const indexPattern = indexPatternCache.get(id); + if (indexPattern) { + return true; + } + return false; + } + /** * Get default index pattern */ diff --git a/src/plugins/data/common/search/search_source/create_search_source.ts b/src/plugins/data/common/search/search_source/create_search_source.ts index 74b164369018..ff97add20267 100644 --- a/src/plugins/data/common/search/search_source/create_search_source.ts +++ b/src/plugins/data/common/search/search_source/create_search_source.ts @@ -28,6 +28,7 @@ * under the License. */ +import { QueryStringContract } from 'src/plugins/data/public/'; import { migrateLegacyQuery } from './migrate_legacy_query'; import { SearchSource, SearchSourceDependencies } from './search_source'; import { IndexPatternsContract } from '../../index_patterns/index_patterns'; @@ -56,6 +57,18 @@ export const createSearchSource = ( ) => async (searchSourceFields: SearchSourceFields = {}) => { const fields = { ...searchSourceFields }; + // When we load a saved search and the saved search contains a non index pattern data source this step creates the temperary index patterns and sets the appriopriate query + if ( + searchSourceDependencies.queryStringService && + fields.query?.dataset && + fields.query?.dataset?.type !== 'INDEX_PATTERN' && + !indexPatterns.isPresentInCache(fields.query.dataset.id) + ) { + await searchSourceDependencies.queryStringService + .getDatasetService() + .cacheDataset(fields.query?.dataset); + } + // hydrating index pattern if (fields.index && typeof fields.index === 'string') { fields.index = await indexPatterns.get(searchSourceFields.index as any); diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index df57a8800ed1..f6ca2aec310e 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -83,6 +83,7 @@ import { setWith } from '@elastic/safer-lodash-set'; import { stringify } from '@osd/std'; import { uniqueId, uniq, extend, pick, difference, omit, isObject, keys, isFunction } from 'lodash'; +import { QueryStringContract } from 'src/plugins/data/public'; import { normalizeSortRequest } from './normalize_sort_request'; import { filterDocvalueFields } from './filter_docvalue_fields'; import { fieldWildcardFilter } from '../../../../opensearch_dashboards_utils/common'; @@ -157,6 +158,7 @@ export interface SearchSourceDependencies extends FetchHandlers { set: (dataFrame: IDataFrame) => void; clear: () => void; }; + queryStringService?: QueryStringContract; } /** @public **/ diff --git a/src/plugins/data/common/search/search_source/search_source_service.test.ts b/src/plugins/data/common/search/search_source/search_source_service.test.ts index 8be71dbdacc2..6616342df377 100644 --- a/src/plugins/data/common/search/search_source/search_source_service.test.ts +++ b/src/plugins/data/common/search/search_source/search_source_service.test.ts @@ -31,6 +31,7 @@ import { BehaviorSubject } from 'rxjs'; import { IndexPatternsContract } from '../../index_patterns/index_patterns'; import { SearchSourceService, SearchSourceDependencies } from './'; +import { QueryStringContract } from 'src/plugins/data/public'; describe('SearchSource service', () => { let dependencies: jest.Mocked; @@ -45,6 +46,7 @@ describe('SearchSource service', () => { callMsearch: jest.fn(), loadingCount$: new BehaviorSubject(0), }, + queryStringService: (jest.fn() as unknown) as jest.Mocked, }; }); diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 94d0eb318791..9cd445f7c25a 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -31,7 +31,7 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; import { CoreStart, NotificationsSetup } from 'opensearch-dashboards/public'; -import { debounce, isEqual } from 'lodash'; +import { isEqual } from 'lodash'; import { i18n } from '@osd/i18n'; import { Dataset, DataStorage, Query, TimeRange, UI_SETTINGS } from '../../../common'; import { createHistory, QueryHistory } from './query_history'; @@ -106,8 +106,8 @@ export class QueryStringManager { } } - public getUpdates$ = () => { - return this.query$.asObservable().pipe(skip(1)); + public getUpdates$ = (defaultSkip = 1) => { + return this.query$.asObservable().pipe(skip(defaultSkip)); }; public getQuery = (): Query => { diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 0c0dd0cb8043..818d7a08aecc 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -207,6 +207,9 @@ export class SearchService implements Plugin { loadingCount$, }, df: dfService, + queryStringService: uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) + ? getQueryService().queryString + : undefined, }; return { diff --git a/src/plugins/data/public/ui/dataset_selector/index.test.tsx b/src/plugins/data/public/ui/dataset_selector/index.test.tsx index 77528eaea532..ca1e75b62c5e 100644 --- a/src/plugins/data/public/ui/dataset_selector/index.test.tsx +++ b/src/plugins/data/public/ui/dataset_selector/index.test.tsx @@ -9,6 +9,7 @@ import { DatasetSelector as ConnectedDatasetSelector } from './index'; import { DatasetSelector } from './dataset_selector'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { Dataset } from '../../../common'; +import { of } from 'rxjs'; jest.mock('../../../../opensearch_dashboards_react/public', () => ({ useOpenSearchDashboards: jest.fn(), diff --git a/src/plugins/data/public/ui/query_editor/language_selector.tsx b/src/plugins/data/public/ui/query_editor/language_selector.tsx index ed7598fea563..b5d519553b12 100644 --- a/src/plugins/data/public/ui/query_editor/language_selector.tsx +++ b/src/plugins/data/public/ui/query_editor/language_selector.tsx @@ -44,7 +44,7 @@ export const QueryLanguageSelector = (props: QueryLanguageSelectorProps) => { : undefined; useEffect(() => { - const subscription = queryString.getUpdates$().subscribe((query: Query) => { + const subscription = queryString.getUpdates$(0).subscribe((query: Query) => { if (query.language !== currentLanguage) { setCurrentLanguage(query.language); } diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index b4299cb6c829..ea624c3034ca 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -240,11 +240,10 @@ export default class QueryEditorUI extends Component { if (!isEqual(this.props.query.dataset, prevQuery.dataset)) { if (this.inputRef) { - const newQuery = this.queryString.getInitialQuery(); - const newQueryString = newQuery.query; - if (this.inputRef.getValue() !== newQueryString) { + const newQueryString = this.props.query.query; + if (this.inputRef.getValue() !== newQueryString && typeof newQueryString === 'string') { this.inputRef.setValue(newQueryString); - this.onSubmit(newQuery); + this.onSubmit(this.props.query); } } } diff --git a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx index d87e1e47f702..278612eb76f0 100644 --- a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx +++ b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx @@ -54,6 +54,7 @@ const getLegacyTopNavLinks = ( defaultMessage: 'New Search', }), run() { + query.filterManager.setFilters([]); // resetting the filters while we are loading a new search core.application.navigateToApp('discover', { path: '#/', }); @@ -306,6 +307,7 @@ export const getTopNavLinks = ( defaultMessage: 'New', }), run() { + query.filterManager.setFilters([]); // resetting the filters while we are loading a new search core.application.navigateToApp('discover', { path: '#/', }); diff --git a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx index 6bb3a54e71f7..9acd1dc52a54 100644 --- a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx +++ b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx @@ -92,6 +92,7 @@ export function OpenSearchPanel({ onClose, makeUrl }: Props) { }, ]} onChoose={(id) => { + data.query.filterManager.setFilters([]); // resetting the filters application.navigateToApp('discover', { path: `#/view/${id}` }); onClose(); }} diff --git a/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx b/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx index 026599d7fc65..442da1d2e25c 100644 --- a/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx +++ b/src/plugins/discover/public/application/utils/state_management/discover_slice.tsx @@ -11,7 +11,11 @@ import { RootState, DefaultViewState } from '../../../../../data_explorer/public import { buildColumns } from '../columns'; import * as utils from './common'; import { SortOrder } from '../../../saved_searches/types'; -import { DEFAULT_COLUMNS_SETTING, PLUGIN_ID } from '../../../../common'; +import { + DEFAULT_COLUMNS_SETTING, + PLUGIN_ID, + QUERY_ENHANCEMENT_ENABLED_SETTING, +} from '../../../../common'; export interface DiscoverState { /** @@ -88,9 +92,12 @@ export const getPreloadedState = async ({ preloadedState.state.sort = savedSearchInstance.sort; preloadedState.state.savedSearch = savedSearchInstance.id; const indexPatternId = savedSearchInstance.searchSource.getField('index')?.id; + + // If the query enhancement is enabled don't add the indexpattern id to the root since they will be migrated into the _q state preloadedState.root = { metadata: { - indexPattern: indexPatternId, + ...(indexPatternId && + !config.get(QUERY_ENHANCEMENT_ENABLED_SETTING) && { indexPattern: indexPatternId }), view: PLUGIN_ID, }, }; diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 3796faea1142..60d821b1c72b 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -12,7 +12,7 @@ import { cloneDeep } from 'lodash'; import { useLocation } from 'react-router-dom'; import { RequestAdapter } from '../../../../../inspector/public'; import { DiscoverViewServices } from '../../../build_services'; -import { search } from '../../../../../data/public'; +import { QueryState, search } from '../../../../../data/public'; import { validateTimeRange } from '../../helpers/validate_time_range'; import { updateSearchSource } from './update_search_source'; import { useIndexPattern } from './use_index_pattern'; @@ -354,16 +354,21 @@ export const useSearch = (services: DiscoverViewServices) => { const savedSearchInstance = await getSavedSearchById(savedSearchId); setSavedSearch(savedSearchInstance); - // if saved search does not exist, do not atempt to sync filters and query from savedObject - if (!savedSearch) { + // if saved search does not exist, or the URL has filter tyhen don't sync the saved search state with that + if (!savedSearchInstance || !savedSearchId) { return; } - // sync initial app filters from savedObject to filterManager - const filters = cloneDeep(savedSearchInstance.searchSource.getOwnField('filter')); + // Sync Query from the saved search const query = savedSearchInstance.searchSource.getField('query') || data.query.queryString.getDefaultQuery(); + + data.query.queryString.setQuery(query); + + // Sync Filters from the saved search + const filters = cloneDeep(savedSearchInstance.searchSource.getOwnField('filter')); + const actualFilters = []; if (filters !== undefined) { @@ -373,8 +378,11 @@ export const useSearch = (services: DiscoverViewServices) => { } } - filterManager.setAppFilters(actualFilters); - data.query.queryString.setQuery(query); + // Filters in URL are higher priority than the filters in saved search + const urlFilters = (osdUrlStateStorage.get('_q') as QueryState)?.filters ?? []; + if (!Array.isArray(urlFilters) || urlFilters.length === 0) { + filterManager.setAppFilters(actualFilters); + } if (savedSearchInstance?.id) { chrome.recentlyAccessed.add( diff --git a/src/plugins/query_enhancements/public/plugin.tsx b/src/plugins/query_enhancements/public/plugin.tsx index cbd40cb60b60..ef3512cb797b 100644 --- a/src/plugins/query_enhancements/public/plugin.tsx +++ b/src/plugins/query_enhancements/public/plugin.tsx @@ -96,7 +96,7 @@ export class QueryEnhancementsPlugin title: 'SQL', search: sqlSearchInterceptor, getQueryString: (query: Query) => { - return `SELECT * FROM ${queryString.getQuery().dataset?.title} LIMIT 10`; + return `SELECT * FROM ${query.dataset?.title} LIMIT 10`; }, fields: { filterable: false,