From 676693882acb079063ffa9e6136baba022d48ace Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Sat, 24 Aug 2024 08:17:23 +0000 Subject: [PATCH] language service Signed-off-by: Kawika Avilla --- src/plugins/data/common/constants.ts | 99 ------- src/plugins/data/common/datasets/types.ts | 4 +- src/plugins/data/public/index.ts | 10 +- src/plugins/data/public/query/index.tsx | 3 +- .../data/public/query/query_service.ts | 30 +-- .../dataset_manager/dataset_manager.ts | 44 ---- .../dataset_manager/lib/index_handler.test.ts | 241 ------------------ .../dataset_manager/lib/index_handler.ts | 25 +- .../lib/index_pattern_handler.test.ts | 196 -------------- .../lib/index_pattern_handler.ts | 4 +- .../query_string/dataset_manager/types.ts | 2 +- .../dataset_service/dataset_service.ts | 28 +- .../query_string/dataset_service/index.ts | 7 + .../query_string/dataset_service/lib/index.ts | 7 + .../dataset_service/lib/index_pattern_type.ts | 74 ++++++ .../dataset_service/lib/index_type.ts | 143 +++++++++++ .../query_string/dataset_service/types.ts | 47 ++++ .../data/public/query/query_string/index.ts | 3 +- .../query_string/language_service/index.ts | 7 + .../language_service/language_service.ts | 46 ++++ .../language_service/lib/dql_language.ts | 30 +++ .../language_service/lib/index.ts | 7 + .../language_service/lib/lucene_language.ts | 30 +++ .../query_string/language_service/types.ts | 36 +++ .../query_string/query_string_manager.ts | 51 +++- src/plugins/data/public/query/types.ts | 46 ++++ src/plugins/data/public/search/index.ts | 2 +- .../data/public/search/search_service.ts | 14 +- .../ui/dataset_selector/configurator.tsx | 2 +- .../ui/query_editor/language_selector.tsx | 25 +- .../public/ui/query_editor/query_editor.tsx | 21 +- .../ui/query_editor/query_editor_top_row.tsx | 40 ++- .../data/public/ui/search_bar/search_bar.tsx | 15 +- .../data/public/ui/settings/settings.ts | 42 +-- src/plugins/data/public/ui/types.ts | 35 --- src/plugins/data/public/ui/ui_service.ts | 8 +- 36 files changed, 643 insertions(+), 781 deletions(-) delete mode 100644 src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.test.ts delete mode 100644 src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.test.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/index.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/index.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/types.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/language_service.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/lib/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/types.ts create mode 100644 src/plugins/data/public/query/types.ts diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index c3328d0a1a5..f81f63066ea 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -42,105 +42,6 @@ export const DEFAULT_DATA = { tooltip: 'Root Data Structure', }, } as DataStructure, - - NULL: { - id: 'NULL', - title: 'Empty', - type: 'NULL', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'empty', - tooltip: 'Empty Data Structure', - }, - } as DataStructure, - - CATEGORY: { - id: 'CATEGORY', - title: 'Categories', - type: 'CATEGORY', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'listAdd', - tooltip: 'Data Categories', - }, - } as DataStructure, - - DATA_SOURCE: { - id: 'DATA_SOURCE', - title: 'Clusters', - type: 'DATA_SOURCE', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'cluster', - tooltip: 'Data Clusters', - }, - } as DataStructure, - - CONNECTION: { - id: 'CONNECTION', - title: 'Connections', - type: 'CONNECTION', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'link', - tooltip: 'Data Connections', - }, - } as DataStructure, - - INDEX: { - id: 'INDEX', - title: 'Indexes', - type: 'INDEX', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'indexOpen', - tooltip: 'Data Indexes', - }, - } as DataStructure, - - FIELD: { - id: 'FIELD', - title: 'Fields', - type: 'FIELD', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'field', - tooltip: 'Data Fields', - }, - } as DataStructure, - - TIME_FIELD: { - id: 'TIME_FIELD', - title: 'Time fields', - type: 'TIME_FIELD', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'clock', - tooltip: 'Time Fields', - }, - } as DataStructure, - - DATASET: { - id: 'DATASET', - title: 'Datasets', - type: 'DATASET', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'document', - tooltip: 'Datasets', - }, - } as DataStructure, - - DATASET_CATEGORY: { - id: 'DATASET_CATEGORY', - title: 'Datasets', - type: 'DATASET_CATEGORY', - meta: { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'documents', - tooltip: 'Dataset Categories', - }, - } as DataStructure, }, SET_TYPES: { diff --git a/src/plugins/data/common/datasets/types.ts b/src/plugins/data/common/datasets/types.ts index 5e2cfd4673c..c3d61fba001 100644 --- a/src/plugins/data/common/datasets/types.ts +++ b/src/plugins/data/common/datasets/types.ts @@ -121,8 +121,8 @@ export interface DataStructure { children?: DataStructure[]; /** Optional array of data structures of ancestors */ path?: DataStructure[]; - isLeaf?: boolean; - columnHeader?: string; + hasNext?: boolean; + groupName?: string; /** Optional metadata for the data structure */ meta?: DataStructureMeta; } diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e5cb26ceaf1..dc70d564bb4 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -445,7 +445,6 @@ export { QueryEditorTopRow, // for BWC, keeping the old name IUiStart as DataPublicPluginStartUi, - DataSetNavigator, } from './ui'; /** @@ -462,9 +461,12 @@ export { QueryState, getDefaultQuery, FilterManager, - DatasetContract, - DatasetManager, - DatasetHandlerConfig, + DatasetTypeConfig, + DatasetService, + DatasetServiceContract, + LanguageConfig, + LanguageService, + LanguageServiceContract, SavedQuery, SavedQueryService, SavedQueryTimeFilter, diff --git a/src/plugins/data/public/query/index.tsx b/src/plugins/data/public/query/index.tsx index 44ee2e050ab..d5dda197917 100644 --- a/src/plugins/data/public/query/index.tsx +++ b/src/plugins/data/public/query/index.tsx @@ -29,11 +29,10 @@ */ export * from './lib'; - +export * from './types'; export * from './query_service'; export * from './filter_manager'; export * from './query_string'; -export * from './query_string/dataset_manager'; export * from './timefilter'; export * from './saved_query'; export * from './persisted_log'; diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index 3ef86b49c81..fd1f7e11157 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -29,39 +29,27 @@ */ import { share } from 'rxjs/operators'; -import { IUiSettingsClient, SavedObjectsClientContract } from 'src/core/public'; import { FilterManager } from './filter_manager'; import { createAddToQueryLog } from './lib'; import { TimefilterService, TimefilterSetup } from './timefilter'; import { createSavedQueryService } from './saved_query/saved_query_service'; import { createQueryStateObservable } from './state_sync/create_global_query_observable'; import { QueryStringManager, QueryStringContract } from './query_string'; -import { - buildOpenSearchQuery, - DataStorage, - getOpenSearchQueryConfig, - IndexPatternsService, -} from '../../common'; +import { buildOpenSearchQuery, getOpenSearchQueryConfig } from '../../common'; import { getUiSettings } from '../services'; import { IndexPattern } from '..'; +import { + IQuerySetup, + IQueryStart, + QueryServiceSetupDependencies, + QueryServiceStartDependencies, +} from './types'; /** * Query Service * @internal */ -interface QueryServiceSetupDependencies { - storage: DataStorage; - uiSettings: IUiSettingsClient; -} - -interface QueryServiceStartDependencies { - savedObjectsClient: SavedObjectsClientContract; - storage: DataStorage; - uiSettings: IUiSettingsClient; - indexPatterns: IndexPatternsService; -} - export class QueryService { filterManager!: FilterManager; timefilter!: TimefilterSetup; @@ -69,7 +57,7 @@ export class QueryService { state$!: ReturnType; - public setup({ storage, uiSettings }: QueryServiceSetupDependencies) { + public setup({ storage, uiSettings }: QueryServiceSetupDependencies): IQuerySetup { this.filterManager = new FilterManager(uiSettings); const timefilterService = new TimefilterService(); @@ -99,7 +87,7 @@ export class QueryService { storage, uiSettings, indexPatterns, - }: QueryServiceStartDependencies) { + }: QueryServiceStartDependencies): IQueryStart { this.queryStringManager.getDatasetManager().init(indexPatterns); return { addToQueryLog: createAddToQueryLog({ diff --git a/src/plugins/data/public/query/query_string/dataset_manager/dataset_manager.ts b/src/plugins/data/public/query/query_string/dataset_manager/dataset_manager.ts index 120781967ec..e8106a6fb64 100644 --- a/src/plugins/data/public/query/query_string/dataset_manager/dataset_manager.ts +++ b/src/plugins/data/public/query/query_string/dataset_manager/dataset_manager.ts @@ -11,9 +11,7 @@ import { DataStructure, CachedDataStructure, DataStructureCache, - toCachedDataStructure, createDataStructureCache, - DatasetField, IndexPatternSpec, } from '../../../../common'; import { IndexPatternsContract } from '../../../index_patterns'; @@ -128,48 +126,6 @@ export class DatasetManager { return handler; } - /** - * Gets cached children for a given parent ID. - * @param parentId - The ID of the parent data structure. - * @returns An array of child data structures. - */ - private getCachedChildren(parentId: string): DataStructure[] { - const cachedStructure = this.dataStructureCache.get(parentId); - if (!cachedStructure) return []; - - return cachedStructure.children - .map((childId) => this.dataStructuresMap.get(childId)) - .filter((child): child is DataStructure => !!child); - } - - /** - * Caches an array of data structures. - * @param dataStructures - The data structures to cache. - */ - private cacheDataStructures(dataStructures: DataStructure[]) { - dataStructures.forEach((ds) => { - const fullId = this.getFullId(ds); - this.dataStructuresMap.set(fullId, ds); - const cachedDs = toCachedDataStructure(ds); - this.dataStructureCache.set(fullId, cachedDs); - }); - } - - /** - * Gets the full ID for a data structure, including its parent's ID. - * @param dataStructure - The data structure to get the full ID for. - * @returns The full ID of the data structure. - */ - private getFullId(dataStructure: DataStructure): string { - if (!dataStructure.parent) { - return dataStructure.id; - } - const parentId = this.getFullId(dataStructure.parent); - const separator = - dataStructure.parent.type === DEFAULT_DATA.STRUCTURES.DATA_SOURCE.type ? '::' : '.'; - return `${parentId}${separator}${dataStructure.id}`; - } - /** * Sets the current dataset. * @param dataset - The dataset to set. diff --git a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.test.ts b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.test.ts deleted file mode 100644 index f5f25ed890c..00000000000 --- a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.test.ts +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { indexHandlerConfig, indexToDataStructure, indexToDataset } from './index_handler'; -import { Dataset, DEFAULT_DATA, DataStructure } from '../../../../../common'; -import { IndexPatternsContract } from '../../../../index_patterns'; - -describe('Index Handler', () => { - describe('indexHandlerConfig.toDataset()', () => { - it('should convert a data structure to a dataset for index', () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexHandlerConfig.toDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle data structure without parent', () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - - const result = indexHandlerConfig.toDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: undefined, - }); - }); - }); - - describe('indexHandlerConfig.toDataStructure()', () => { - it('should convert a dataset to a data structure for index', () => { - const dataset: Dataset = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexHandlerConfig.toDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle dataset without data source', () => { - const dataset: Dataset = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - - const result = indexHandlerConfig.toDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: undefined, - }); - }); - }); - - describe('indexHandlerConfig.fetchOptions()', () => { - it('should fetch options for an index', async () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'test-*', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - - const mockIndexPatterns: Partial = { - getFieldsForWildcard: jest - .fn() - .mockResolvedValue([{ name: 'test-index-1' }, { name: 'test-index-2' }]), - }; - - const result = await indexHandlerConfig.fetchOptions( - dataStructure, - mockIndexPatterns as IndexPatternsContract - ); - - expect(result).toEqual([ - { - id: 'test-index-1', - title: 'test-index-1', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: dataStructure, - }, - { - id: 'test-index-2', - title: 'test-index-2', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: dataStructure, - }, - ]); - - expect(mockIndexPatterns.getFieldsForWildcard).toHaveBeenCalledWith({ - pattern: 'test-*', - }); - }); - }); - - describe('indexHandlerConfig.isLeaf()', () => { - it('should return true for index', () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'test-*', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - expect(indexHandlerConfig.isLeaf(dataStructure)).toBe(true); - }); - }); - - describe('indexToDataStructure()', () => { - it('should convert a dataset to a data structure for index', () => { - const dataset: Dataset = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexToDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle dataset without data source', () => { - const dataset: Dataset = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - - const result = indexToDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: undefined, - }); - }); - }); - - describe('indexToDataset()', () => { - it('should convert a data structure to a dataset for index', () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexToDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle data structure without parent', () => { - const dataStructure: DataStructure = { - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - }; - - const result = indexToDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-index', - title: 'Test Index', - type: DEFAULT_DATA.SET_TYPES.INDEX, - dataSource: undefined, - }); - }); - }); -}); diff --git a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.ts b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.ts index ad719533627..42ed61af04d 100644 --- a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.ts +++ b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_handler.ts @@ -5,14 +5,7 @@ import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { map } from 'rxjs/operators'; -import { - DEFAULT_DATA, - DataStructure, - DATA_STRUCTURE_META_TYPES, - DataStructureFeatureMeta, - DatasetField, - Dataset, -} from '../../../../../common'; +import { DEFAULT_DATA, DataStructure, DatasetField, Dataset } from '../../../../../common'; import { DatasetTypeConfig } from '../types'; import { getSearchService, getIndexPatterns } from '../../../../services'; @@ -27,12 +20,6 @@ const INDEX_INFO = { }, }; -const meta = { - type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: INDEX_INFO.ICON, - tooltip: INDEX_INFO.TITLE, -} as DataStructureFeatureMeta; - export const indexHandlerConfig: DatasetTypeConfig = { id: DEFAULT_DATA.SET_TYPES.INDEX, title: 'Indexes', @@ -69,12 +56,12 @@ export const indexHandlerConfig: DatasetTypeConfig = { const indices = await fetchIndices(dataStructure); return { ...dataStructure, - isLeaf: true, - columnHeader: 'Indices', + hasNext: true, + groupName: 'Indexes', children: indices.map((indexName) => ({ id: `${dataStructure.id}::${indexName}`, title: indexName, - type: DEFAULT_DATA.STRUCTURES.INDEX.type, + type: 'INDEX', })), }; } @@ -83,8 +70,8 @@ export const indexHandlerConfig: DatasetTypeConfig = { const dataSources = await fetchDataSources(savedObjects); return { ...dataStructure, - columnHeader: 'Cluster', - isLeaf: false, + groupName: 'Cluster', + hasNext: false, children: dataSources, }; } diff --git a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.test.ts b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.test.ts deleted file mode 100644 index b60e16463bd..00000000000 --- a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { indexPatternHandlerConfig, indexPatternToDataStructure } from './index_pattern_handler'; -import { Dataset, DEFAULT_DATA, DataStructure } from '../../../../../common'; -import { IndexPatternsContract } from '../../../../index_patterns'; - -describe('Index Pattern Handler', () => { - describe('indexPatternHandlerConfig.toDataset()', () => { - it('should convert a data structure to a dataset for index pattern', () => { - const dataStructure: DataStructure = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexPatternHandlerConfig.toDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle data structure without parent', () => { - const dataStructure: DataStructure = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - }; - - const result = indexPatternHandlerConfig.toDataset(dataStructure); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - dataSource: undefined, - }); - }); - }); - - describe('indexPatternHandlerConfig.toDataStructure()', () => { - it('should convert a dataset to a data structure for index pattern', () => { - const dataset: Dataset = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexPatternHandlerConfig.toDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle dataset without data source', () => { - const dataset: Dataset = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - }; - - const result = indexPatternHandlerConfig.toDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: undefined, - }); - }); - }); - - describe('indexPatternHandlerConfig.fetchOptions()', () => { - it('should fetch options for an index pattern', async () => { - const dataStructure: DataStructure = { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }; - - const mockIndexPatterns: Partial = { - getIdsWithTitle: jest.fn().mockResolvedValue([ - { id: 'pattern-1', title: 'Pattern 1' }, - { id: 'pattern-2', title: 'Pattern 2' }, - ]), - }; - - const result = await indexPatternHandlerConfig.fetchOptions( - dataStructure, - mockIndexPatterns as IndexPatternsContract - ); - - expect(result).toEqual([ - { - id: 'pattern-1', - title: 'Pattern 1', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: dataStructure, - }, - { - id: 'pattern-2', - title: 'Pattern 2', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: dataStructure, - }, - ]); - - expect(mockIndexPatterns.getIdsWithTitle).toHaveBeenCalled(); - }); - }); - - describe('indexPatternHandlerConfig.isLeaf()', () => { - it('should return true for index pattern', () => { - const dataStructure: DataStructure = { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }; - - expect(indexPatternHandlerConfig.isLeaf(dataStructure)).toBe(true); - }); - }); - - describe('indexPatternToDataStructure()', () => { - it('should convert a dataset to a data structure for index pattern', () => { - const dataset: Dataset = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - dataSource: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }; - - const result = indexPatternToDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: { - id: 'test-source', - title: 'Test Source', - type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, - }, - }); - }); - - it('should handle dataset without data source', () => { - const dataset: Dataset = { - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - }; - - const result = indexPatternToDataStructure(dataset); - - expect(result).toEqual({ - id: 'test-pattern', - title: 'Test Pattern', - type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, - parent: undefined, - }); - }); - }); -}); diff --git a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.ts b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.ts index b3903ed2588..37a7d738bb0 100644 --- a/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.ts +++ b/src/plugins/data/public/query/query_string/dataset_manager/lib/index_pattern_handler.ts @@ -40,9 +40,9 @@ export const indexPatternHandlerConfig: DatasetTypeConfig = { const indexPatterns = await fetchIndexPatterns(savedObjects); return { ...dataStructure, - columnHeader: 'Index patterns', + groupName: 'Index patterns', children: indexPatterns, - isLeaf: false, + hasNext: false, }; }, diff --git a/src/plugins/data/public/query/query_string/dataset_manager/types.ts b/src/plugins/data/public/query/query_string/dataset_manager/types.ts index 5b293effec4..0d7bf37703c 100644 --- a/src/plugins/data/public/query/query_string/dataset_manager/types.ts +++ b/src/plugins/data/public/query/query_string/dataset_manager/types.ts @@ -4,7 +4,7 @@ */ import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { EuiIconProps } from '@elastic/eui'; -import { BaseDataset, Dataset, DatasetField, DataStructure } from '../../../../common'; +import { Dataset, DatasetField, DataStructure } from '../../../../common'; /** * Configuration for handling dataset operations. diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts index 01e2fabcfdc..59e8138726a 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts @@ -4,15 +4,32 @@ */ import { CoreStart, SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { Dataset, UI_SETTINGS, DataStructure, IndexPatternSpec } from 'src/plugins/data/common'; -import { DatasetTypeConfig } from '../dataset_manager'; +import { + Dataset, + UI_SETTINGS, + DataStructure, + IndexPatternSpec, + DEFAULT_DATA, +} from '../../../../common'; import { getIndexPatterns } from '../../../services'; +import { DatasetTypeConfig } from './types'; +import { indexPatternTypeConfig, indexTypeConfig } from './lib'; export class DatasetService { private defaultDataset?: Dataset; private typesRegistry: Map = new Map(); - constructor(private readonly uiSettings: CoreStart['uiSettings']) {} + constructor(private readonly uiSettings: CoreStart['uiSettings']) { + this.registerDefaultTypes(); + } + + /** + * Registers default handlers for index patterns and indices. + */ + private registerDefaultTypes() { + this.registerType(indexPatternTypeConfig); + this.registerType(indexTypeConfig); + } public async init(): Promise { if (!this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) return; @@ -55,7 +72,6 @@ export class DatasetService { path: DataStructure[], dataType: string ): Promise { - // ROOT is the zero index const type = this.typesRegistry.get(dataType); if (!type) { throw new Error(`No handler found for type: ${path[0]}`); @@ -78,13 +94,13 @@ export class DatasetService { return undefined; } - const handler = this.typesRegistry.get('INDEX_PATTERNS'); + const handler = this.typesRegistry.get(DEFAULT_DATA.SET_TYPES.INDEX_PATTERN); if (handler) { const dataset = handler.toDataset([ { id: indexPattern.id, title: indexPattern.title, - type: 'INDEX_PATTERNS', + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, }, ]); return { ...dataset, timeFieldName: indexPattern.timeFieldName }; diff --git a/src/plugins/data/public/query/query_string/dataset_service/index.ts b/src/plugins/data/public/query/query_string/dataset_service/index.ts new file mode 100644 index 00000000000..8becfe4126a --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './types'; +export { DatasetServiceContract, DatasetService } from './dataset_service'; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index.ts new file mode 100644 index 00000000000..68ba7d2d09b --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './index_type'; +export * from './index_pattern_type'; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts new file mode 100644 index 00000000000..0ef460e329e --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts @@ -0,0 +1,74 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { DEFAULT_DATA, DataStructure, DatasetField, Dataset } from '../../../../../common'; +import { DatasetTypeConfig } from '../types'; +import { getIndexPatterns } from '../../../../services'; + +export const indexPatternTypeConfig: DatasetTypeConfig = { + id: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + title: 'Index Patterns', + meta: { + icon: { type: 'indexPatternApp' }, + tooltip: 'OpenSearch Index Patterns', + }, + + toDataset: (path: DataStructure[]): Dataset => { + const pattern = path[path.length - 1]; + return { + id: pattern.id, + title: pattern.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + dataSource: pattern.parent + ? { + id: pattern.parent.id, + title: pattern.parent.title, + type: pattern.parent.type, + } + : undefined, + }; + }, + + fetch: async ( + savedObjects: SavedObjectsClientContract, + path: DataStructure[] + ): Promise => { + const dataStructure = path[path.length - 1]; + const indexPatterns = await fetchIndexPatterns(savedObjects); + return { + ...dataStructure, + groupName: 'Index patterns', + children: indexPatterns, + hasNext: false, + }; + }, + + fetchFields: async (dataset: Dataset): Promise => { + const indexPattern = await getIndexPatterns().get(dataset.id); + return indexPattern.fields.map((field: any) => ({ + name: field.name, + type: field.type, + })); + }, + + supportedLanguages: (): string[] => { + return ['sql', 'ppl', 'kuery', 'lucene']; + }, +}; + +const fetchIndexPatterns = async (client: SavedObjectsClientContract): Promise => { + const resp = await client.find({ + type: 'index-pattern', + fields: ['title'], + perPage: 10000, + }); + return resp.savedObjects.map((savedObject) => ({ + id: savedObject.id, + title: savedObject.attributes.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + isLeaf: true, + })); +}; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts new file mode 100644 index 00000000000..7453fd1dc2f --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -0,0 +1,143 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { map } from 'rxjs/operators'; +import { DEFAULT_DATA, DataStructure, DatasetField, Dataset } from '../../../../../common'; +import { DatasetTypeConfig } from '../types'; +import { getSearchService, getIndexPatterns } from '../../../../services'; + +const INDEX_INFO = { + LOCAL_DATASOURCE: { + id: '', + title: 'Local Cluster', + type: 'DATA_SOURCE', + }, +}; + +export const indexTypeConfig: DatasetTypeConfig = { + id: DEFAULT_DATA.SET_TYPES.INDEX, + title: 'Indexes', + meta: { + icon: { type: 'logoOpenSearch' }, + tooltip: 'OpenSearch Indexes', + }, + + toDataset: (path: DataStructure[]): Dataset => { + const index = path[path.length - 1]; + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + + return { + id: index.id, + title: index.title, + type: DEFAULT_DATA.SET_TYPES.INDEX, + dataSource: dataSource + ? { + id: dataSource.id, + title: dataSource.title, + type: dataSource.type, + } + : INDEX_INFO.LOCAL_DATASOURCE, + }; + }, + + fetch: async ( + savedObjects: SavedObjectsClientContract, + path: DataStructure[] + ): Promise => { + const dataStructure = path[path.length - 1]; + switch (dataStructure.type) { + case 'DATA_SOURCE': { + const indices = await fetchIndices(dataStructure); + return { + ...dataStructure, + hasNext: true, + groupName: 'Indexes', + children: indices.map((indexName) => ({ + id: `${dataStructure.id}::${indexName}`, + title: indexName, + type: 'INDEX', + })), + }; + } + + default: { + const dataSources = await fetchDataSources(savedObjects); + return { + ...dataStructure, + groupName: 'Cluster', + hasNext: false, + children: dataSources, + }; + } + } + }, + + fetchFields: async (dataset: Dataset): Promise => { + const fields = await getIndexPatterns().getFieldsForWildcard({ + pattern: dataset.title, + dataSourceId: dataset.dataSource?.id, + }); + return fields.map((field: any) => ({ + name: field.name, + type: field.type, + })); + }, + + supportedLanguages: (): string[] => { + return ['sql', 'ppl']; + }, +}; + +const fetchDataSources = async (client: SavedObjectsClientContract) => { + const resp = await client.find({ + type: 'data-source', + perPage: 10000, + }); + const dataSources: DataStructure[] = [INDEX_INFO.LOCAL_DATASOURCE]; + return dataSources.concat( + resp.savedObjects.map((savedObject) => ({ + id: savedObject.id, + title: savedObject.attributes.title, + type: 'DATA_SOURCE', + })) + ); +}; + +const fetchIndices = async (dataStructure: DataStructure): Promise => { + const search = getSearchService(); + const buildSearchRequest = () => ({ + params: { + ignoreUnavailable: true, + expand_wildcards: 'all', + index: '*', + body: { + size: 0, + aggs: { + indices: { + terms: { + field: '_index', + size: 100, + }, + }, + }, + }, + }, + dataSourceId: dataStructure.id, + }); + + const searchResponseToArray = (response: any) => { + const { rawResponse } = response; + return rawResponse.aggregations + ? rawResponse.aggregations.indices.buckets.map((bucket: { key: any }) => bucket.key) + : []; + }; + + return search + .getDefaultSearchInterceptor() + .search(buildSearchRequest()) + .pipe(map(searchResponseToArray)) + .toPromise(); +}; diff --git a/src/plugins/data/public/query/query_string/dataset_service/types.ts b/src/plugins/data/public/query/query_string/dataset_service/types.ts new file mode 100644 index 00000000000..a8ef97eda6f --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { EuiIconProps } from '@elastic/eui'; +import { Dataset, DatasetField, DataStructure } from '../../../../common'; + +/** + * Configuration for handling dataset operations. + */ +export interface DatasetTypeConfig { + /** Unique identifier for the dataset handler */ + id: string; + /** Human-readable title for the dataset type */ + title: string; + /** Metadata for UI representation */ + meta: { + /** Icon to represent the dataset type */ + icon: EuiIconProps; + /** Optional tooltip text */ + tooltip?: string; + }; + /** + * Converts a DataStructure to a Dataset. + * @param {DataStructure} dataStructure - The data structure to convert. + * @returns {Dataset} Dataset. + */ + toDataset: (path: DataStructure[]) => Dataset; + /** + * Fetches child options for a given DataStructure. + * @param {SavedObjectsClientContract} client - The saved objects client. + * @param {DataStructure} dataStructure - The parent DataStructure. + * @returns {Promise} A promise that resolves to a DatasetHandlerFetchResponse. + */ + fetch: (client: SavedObjectsClientContract, path: DataStructure[]) => Promise; + /** + * Fetches fields for the dataset. + * @returns {Promise} A promise that resolves to an array of DatasetFields. + */ + fetchFields: (dataset: Dataset) => Promise; + /** + * Retrieves the supported query languages for this dataset type. + * @returns {Promise} A promise that resolves to an array of supported language names. + */ + supportedLanguages: () => string[]; +} diff --git a/src/plugins/data/public/query/query_string/index.ts b/src/plugins/data/public/query/query_string/index.ts index 84b15ba62cc..61d25349fbc 100644 --- a/src/plugins/data/public/query/query_string/index.ts +++ b/src/plugins/data/public/query/query_string/index.ts @@ -29,4 +29,5 @@ */ export { QueryStringContract, QueryStringManager } from './query_string_manager'; -export { DatasetHandlerConfig } from './dataset_manager'; +export { DatasetServiceContract, DatasetService, DatasetTypeConfig } from './dataset_service'; +export { LanguageServiceContract, LanguageService, LanguageConfig } from './language_service'; diff --git a/src/plugins/data/public/query/query_string/language_service/index.ts b/src/plugins/data/public/query/query_string/language_service/index.ts new file mode 100644 index 00000000000..79aea071de3 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './types'; +export { LanguageServiceContract, LanguageService } from './language_service'; diff --git a/src/plugins/data/public/query/query_string/language_service/language_service.ts b/src/plugins/data/public/query/query_string/language_service/language_service.ts new file mode 100644 index 00000000000..20962892cdb --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/language_service.ts @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart } from 'opensearch-dashboards/public'; +import { UI_SETTINGS } from 'src/plugins/data/common'; +import { LanguageConfig } from './types'; +import { dqlLanguageConfig, luceneLanguageConfig } from './lib'; + +export class LanguageService { + private languages: Map = new Map(); + + constructor(private readonly uiSettings: CoreStart['uiSettings']) {} + + public async init(): Promise { + if (!this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) return; + this.registerDefaultLanguages(); + } + + /** + * Registers default handlers for index patterns and indices. + */ + private registerDefaultLanguages() { + this.registerLanguage(dqlLanguageConfig); + this.registerLanguage(luceneLanguageConfig); + } + + public registerLanguage(config: LanguageConfig): void { + this.languages.set(config.id, config); + } + + public getLanguage(language: string): LanguageConfig | undefined { + return this.languages.get(language); + } + + public getLanguages(): string[] { + return Array.from(this.languages.keys()); + } + + public getDefaultLanguage(): LanguageConfig { + return this.languages.get('kuery') || this.languages.values().next().value; + } +} + +export type LanguageServiceContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts new file mode 100644 index 00000000000..15eafea516b --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageConfig } from '../types'; +import { getSearchService } from '../../../../services'; + +export const dqlLanguageConfig: LanguageConfig = { + id: 'kuery', + title: 'DQL', + search: getSearchService().getDefaultSearchInterceptor(), + searchBar: { + showDataSetsSelector: true, + showDataSourcesSelector: false, + showQueryInput: true, + showFilterBar: true, + showDatePicker: true, + showAutoRefreshOnly: false, + queryStringInput: { + initialValue: '', + }, + }, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + supportedAppNames: ['discover'], +}; diff --git a/src/plugins/data/public/query/query_string/language_service/lib/index.ts b/src/plugins/data/public/query/query_string/language_service/lib/index.ts new file mode 100644 index 00000000000..42b8f7f2fb1 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/lib/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './dql_language'; +export * from './lucene_language'; diff --git a/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts new file mode 100644 index 00000000000..3e8549ca478 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getSearchService } from '../../../../services'; +import { LanguageConfig } from '../types'; + +export const luceneLanguageConfig: LanguageConfig = { + id: 'lucene', + title: 'Lucene', + search: getSearchService().getDefaultSearchInterceptor(), + searchBar: { + showDataSetsSelector: true, + showDataSourcesSelector: false, + showQueryInput: true, + showFilterBar: true, + showDatePicker: true, + showAutoRefreshOnly: false, + queryStringInput: { + initialValue: '', + }, + }, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + supportedAppNames: ['discover'], +}; diff --git a/src/plugins/data/public/query/query_string/language_service/types.ts b/src/plugins/data/public/query/query_string/language_service/types.ts new file mode 100644 index 00000000000..f434f8a81ac --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/types.ts @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ISearchInterceptor } from '../../../search'; + +export interface LanguageConfig { + id: string; + title: string; + search: ISearchInterceptor; + // Leave blank to support all data sources + // supportedDataSourceTypes?: Record; + searchBar?: { + showDataSetsSelector?: boolean; + showDataSourcesSelector?: boolean; + showQueryInput?: boolean; + showFilterBar?: boolean; + showDatePicker?: boolean; + showAutoRefreshOnly?: boolean; + queryStringInput?: { + // will replace '' with the data source name + initialValue?: string; + }; + dateRange?: { + initialFrom?: string; + initialTo?: string; + }; + }; + fields?: { + filterable?: boolean; + visualizable?: boolean; + }; + showDocLinks?: boolean; + supportedAppNames: string[]; +} 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 68b1ce8b540..5023030e8da 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 @@ -34,11 +34,15 @@ import { CoreStart } from 'opensearch-dashboards/public'; import { Dataset, DataStorage, Query, TimeRange, UI_SETTINGS } from '../../../common'; import { createHistory, QueryHistory } from './query_history'; import { DatasetContract, DatasetManager } from './dataset_manager'; +import { DatasetService, DatasetServiceContract } from './dataset_service'; +import { LanguageConfig, LanguageService, LanguageServiceContract } from './language_service'; export class QueryStringManager { private query$: BehaviorSubject; private queryHistory: QueryHistory; private datasetManager!: DatasetContract; + private datasetService!: DatasetServiceContract; + private languageService!: LanguageServiceContract; constructor( private readonly storage: DataStorage, @@ -47,28 +51,22 @@ export class QueryStringManager { this.query$ = new BehaviorSubject(this.getDefaultQuery()); this.queryHistory = createHistory({ storage }); this.datasetManager = new DatasetManager(uiSettings); + this.datasetService = new DatasetService(uiSettings); + this.languageService = new LanguageService(uiSettings); } private getDefaultQueryString() { return this.storage.get('userQueryString') || ''; } - private getDefaultLanguage() { - return ( - this.storage.get('userQueryLanguage') || - this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) - ); - } - public getDefaultQuery() { return { query: this.getDefaultQueryString(), language: this.getDefaultLanguage(), - // ...(this.uiSettings && - // this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { - // dataset: this.getDatasetManager().getDefaultDataset(), - // }), - // }; + ...(this.uiSettings && + this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { + dataset: this.datasetService.getDefault(), + }), }; } @@ -79,6 +77,10 @@ export class QueryStringManager { return { query, language: this.getDefaultLanguage(), + ...(this.uiSettings && + this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { + dataset: this.datasetService.getDefault(), + }), }; } else { return query; @@ -99,7 +101,11 @@ export class QueryStringManager { */ public setQuery = (query: Query) => { const curQuery = this.query$.getValue(); - if (query?.language !== curQuery.language || query?.query !== curQuery.query) { + if ( + query?.language !== curQuery.language || + query?.query !== curQuery.query || + query?.dataset !== curQuery.dataset + ) { this.query$.next(query); } }; @@ -135,6 +141,25 @@ export class QueryStringManager { public getDatasetManager = () => { return this.datasetManager; }; + + public getLanguage = (language: string) => { + return this.languageService.getLanguage(language); + }; + + private getDefaultLanguage() { + return ( + this.storage.get('userQueryLanguage') || + this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) + ); + } + + public getLanguages = () => { + return this.languageService.getLanguages(); + }; + + public registerLanguage = (languageConfig: LanguageConfig) => { + this.languageService.registerLanguage(languageConfig); + }; } export type QueryStringContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/types.ts b/src/plugins/data/public/query/types.ts new file mode 100644 index 00000000000..4eaf7689d0a --- /dev/null +++ b/src/plugins/data/public/query/types.ts @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IUiSettingsClient, SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { Observable } from 'rxjs'; +import { DataStorage } from '../../common'; +import { IndexPattern, IndexPatternsService } from '../index_patterns'; +import { FilterManager } from './filter_manager'; +import { QueryStringContract } from './query_string'; +import { QueryStateChange, QueryState } from './state_sync'; +import { createAddToQueryLog } from './lib'; +import { createSavedQueryService } from './saved_query'; +import { TimefilterSetup } from './timefilter'; + +export interface IQuerySetup { + filterManager: FilterManager; + timefilter: TimefilterSetup; + queryString: QueryStringContract; + state$: Observable<{ changes: QueryStateChange; state: QueryState }>; +} + +export interface IQueryStart { + addToQueryLog: ReturnType; + filterManager: FilterManager; + queryString: QueryStringContract; + savedQueries: ReturnType; + state$: Observable<{ changes: QueryStateChange; state: QueryState }>; + timefilter: TimefilterSetup; + getOpenSearchQuery: (indexPattern: IndexPattern) => any; +} + +/** @internal */ +export interface QueryServiceSetupDependencies { + storage: DataStorage; + uiSettings: IUiSettingsClient; +} + +/** @internal */ +export interface QueryServiceStartDependencies { + savedObjectsClient: SavedObjectsClientContract; + storage: DataStorage; + uiSettings: IUiSettingsClient; + indexPatterns: IndexPatternsService; +} diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index bfd0bc1ed78..f5ff39c40c4 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -56,5 +56,5 @@ export { export { getOpenSearchPreference } from './opensearch_search'; -export { SearchInterceptor, SearchInterceptorDeps } from './search_interceptor'; +export { SearchInterceptor, SearchInterceptorDeps, ISearchInterceptor } from './search_interceptor'; export * from './errors'; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 5516b4abc79..c0f3c7d7c0b 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -135,19 +135,19 @@ export class SearchService implements Plugin { { fieldFormats, indexPatterns }: SearchServiceStartDependencies ): ISearchStart { const search = ((request, options) => { - const selectedLanguage = getQueryService().queryString.getQuery().language; - const uiService = getUiService(); - const enhancement = uiService.Settings.getQueryEnhancements(selectedLanguage); - uiService.Settings.setUiOverridesByUserQueryLanguage(selectedLanguage); + const queryStringManager = getQueryService().queryString; + const languageId = queryStringManager.getQuery().language; + const selectedLanguage = queryStringManager.getLanguage(languageId); + getUiService().Settings.setUiOverridesByUserQueryLanguage(languageId); const isEnhancedEnabled = uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED); - if (enhancement) { + if (selectedLanguage) { if (!isEnhancedEnabled) { notifications.toasts.addWarning( - `Query enhancements are disabled. Please enable to use: ${selectedLanguage}.` + `Query enhancements are disabled. Please enable to use: ${selectedLanguage.id}.` ); } - return enhancement.search.search(request, options); + return selectedLanguage.search.search(request, options); } return this.defaultSearchInterceptor.search(request, options); }) as ISearchGeneric; diff --git a/src/plugins/data/public/ui/dataset_selector/configurator.tsx b/src/plugins/data/public/ui/dataset_selector/configurator.tsx index d4651179429..433fe65dfd1 100644 --- a/src/plugins/data/public/ui/dataset_selector/configurator.tsx +++ b/src/plugins/data/public/ui/dataset_selector/configurator.tsx @@ -19,7 +19,7 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; -import { BaseDataset, Dataset, DatasetField, DataStructure } from '../../../common'; +import { BaseDataset, Dataset, DatasetField } from '../../../common'; import { getQueryService, getIndexPatterns } from '../../services'; export const Configurator = ({ 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 455540d28df..50655f59267 100644 --- a/src/plugins/data/public/ui/query_editor/language_selector.tsx +++ b/src/plugins/data/public/ui/query_editor/language_selector.tsx @@ -12,7 +12,8 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React, { useState } from 'react'; -import { getUiService } from '../../services'; +import { getQueryService, getUiService } from '../../services'; +import { LanguageConfig } from '../../query'; export interface QueryLanguageSelectorProps { language: string; @@ -21,10 +22,10 @@ export interface QueryLanguageSelectorProps { appName?: string; } -const mapExternalLanguageToOptions = (language: string) => { +const mapExternalLanguageToOptions = (language: LanguageConfig) => { return { - label: language, - value: language, + label: language.id, + value: language.title, }; }; @@ -54,19 +55,17 @@ export const QueryLanguageSelector = (props: QueryLanguageSelectorProps) => { ]; const uiService = getUiService(); + const queryService = getQueryService(); - const queryEnhancements = uiService.Settings.getAllQueryEnhancements(); - queryEnhancements.forEach((enhancement) => { + const languages = queryService.queryString.getLanguages(); + languages.forEach((languageId) => { + const language = queryService.queryString.getLanguage(languageId); if ( - (enhancement.supportedAppNames && - props.appName && - !enhancement.supportedAppNames.includes(props.appName)) || - uiService.Settings.getUserQueryLanguageBlocklist().includes( - enhancement.language.toLowerCase() - ) + (language && props.appName && !language.supportedAppNames.includes(props.appName)) || + uiService.Settings.getUserQueryLanguageBlocklist().includes(language?.id) ) return; - languageOptions.unshift(mapExternalLanguageToOptions(enhancement.language)); + languageOptions.unshift(mapExternalLanguageToOptions(language!)); }); const selectedLanguage = { 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 036f925f352..0e454b1eb3a 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -12,7 +12,7 @@ import { Settings } from '..'; import { IDataPluginServices, IFieldType, IIndexPattern, Query, TimeRange } from '../..'; import { OpenSearchDashboardsReactContextValue } from '../../../../opensearch_dashboards_react/public'; import { QuerySuggestion } from '../../autocomplete'; -import { fromUser, getQueryLog, PersistedLog, toUser } from '../../query'; +import { fromUser, getQueryLog, LanguageConfig, PersistedLog, toUser } from '../../query'; import { SuggestionsListSize } from '../typeahead/suggestions_component'; import { DataSettings } from '../types'; import { QueryLanguageSelector } from './language_selector'; @@ -44,7 +44,7 @@ export interface QueryEditorProps { onChange?: (query: Query, dateRange?: TimeRange) => void; onChangeQueryEditorFocus?: (isFocused: boolean) => void; onSubmit?: (query: Query, dateRange?: TimeRange) => void; - getQueryStringInitialValue?: (language: string) => string; + getQueryStringInitialValue?: (language: LanguageConfig) => string; dataTestSubj?: string; size?: SuggestionsListSize; className?: string; @@ -97,7 +97,8 @@ export default class QueryEditorUI extends Component { private getQueryString = () => { if (!this.props.query.query) { - return this.props.getQueryStringInitialValue?.(this.props.query.language) ?? ''; + const language = this.queryService.queryString.getLanguage(this.props.query.language); + return this.props.getQueryStringInitialValue?.(language!) ?? ''; } return toUser(this.props.query.query); }; @@ -173,21 +174,21 @@ export default class QueryEditorUI extends Component { }; // TODO: MQL consider moving language select language of setting search source here - private onSelectLanguage = (language: string) => { + private onSelectLanguage = (languageId: string) => { // Send telemetry info every time the user opts in or out of kuery // As a result it is important this function only ever gets called in the // UI component's change handler. this.services.http.post('/api/opensearch-dashboards/dql_opt_in_stats', { - body: JSON.stringify({ opt_in: language === 'kuery' }), + body: JSON.stringify({ opt_in: languageId === 'kuery' }), }); + const language = this.queryService.queryString.getLanguage(this.props.query.language); const newQuery = { - query: this.props.getQueryStringInitialValue?.(language) ?? '', - language, + query: this.props.getQueryStringInitialValue?.(language!) ?? '', + language: language?.id || languageId, }; - const enhancement = this.props.settings.getQueryEnhancements(newQuery.language); - const fields = enhancement?.fields; + const fields = language?.fields; const newSettings: DataSettings = { userQueryLanguage: newQuery.language, userQueryString: newQuery.query, @@ -195,7 +196,7 @@ export default class QueryEditorUI extends Component { }; this.props.settings?.updateSettings(newSettings); - const dateRangeEnhancement = enhancement?.searchBar?.dateRange; + const dateRangeEnhancement = language?.searchBar?.dateRange; const dateRange = dateRangeEnhancement ? { from: dateRangeEnhancement.initialFrom!, diff --git a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx index b6a35565b42..3e391c4b8b9 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx @@ -22,7 +22,7 @@ import { withOpenSearchDashboards, } from '../../../../opensearch_dashboards_react/public'; import { UI_SETTINGS } from '../../../common'; -import { getQueryLog, PersistedLog } from '../../query'; +import { getQueryLog, LanguageConfig, PersistedLog } from '../../query'; import { Settings } from '../types'; import { NoDataPopover } from './no_data_popover'; import QueryEditorUI from './query_editor'; @@ -76,16 +76,12 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { const datasetManager = queryString.getDatasetManager(); const { dataset } = useDatasetManager({ datasetManager }); - const queryLanguage = props.query && props.query.language; - const queryUiEnhancement = - (queryLanguage && - props.settings && - props.settings.getQueryEnhancements(queryLanguage)?.searchBar) || - null; + const queryLanguageId = props.query && props.query.language; + const queryLanguage = queryString.getLanguage(queryLanguageId!) || null; const parsedQuery = - !queryUiEnhancement || isValidQuery(props.query) + !queryLanguageId || isValidQuery(props.query) ? props.query! - : { query: getQueryStringInitialValue(queryLanguage!), language: queryLanguage! }; + : { query: getQueryStringInitialValue(queryLanguage!), language: queryLanguageId! }; if (!isEqual(parsedQuery?.query, props.query?.query)) { onQueryChange(parsedQuery); onSubmit({ query: parsedQuery, dateRange: getDateRange() }); @@ -93,9 +89,9 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { const persistedLog: PersistedLog | undefined = React.useMemo( () => queryLanguage && uiSettings && storage && appName - ? getQueryLog(uiSettings!, storage, appName, queryLanguage) + ? getQueryLog(uiSettings!, storage, appName, queryLanguageId!) : undefined, - [appName, queryLanguage, uiSettings, storage] + [queryLanguage, uiSettings, storage, appName, queryLanguageId] ); function onClickSubmitButton(event: React.MouseEvent) { @@ -111,14 +107,17 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { return { from: props.dateRangeFrom || - queryUiEnhancement?.dateRange?.initialFrom || + queryLanguage?.searchBar?.dateRange?.initialFrom || defaultTimeSetting.from, - to: props.dateRangeTo || queryUiEnhancement?.dateRange?.initialTo || defaultTimeSetting.to, + to: + props.dateRangeTo || + queryLanguage?.searchBar?.dateRange?.initialTo || + defaultTimeSetting.to, }; } function onQueryChange(query: Query, dateRange?: TimeRange) { - if (queryUiEnhancement && !isValidQuery(query)) return; + if (queryLanguage && !isValidQuery(query)) return; props.onChange({ query, dateRange: dateRange ?? getDateRange(), @@ -195,10 +194,8 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { if (query && query.query) return true; } - function getQueryStringInitialValue(language: string) { - const { settings } = props; - const input = settings?.getQueryEnhancements(language)?.searchBar?.queryStringInput - ?.initialValue; + function getQueryStringInitialValue(language: LanguageConfig) { + const input = language.searchBar?.queryStringInput?.initialValue; if (!input) return ''; @@ -223,7 +220,6 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { persistedLog={persistedLog} className="osdQueryEditor" dataTestSubj={props.dataTestSubj} - queryLanguage={queryLanguage} filterBar={props.filterBar} /> @@ -247,9 +243,11 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { } function shouldRenderDatePicker(): boolean { + const languageId = queryString.getQuery().language; + const language = queryString.getLanguage(languageId); return Boolean( - (props.showDatePicker && (queryUiEnhancement?.showDatePicker ?? true)) ?? - (props.showAutoRefreshOnly && (queryUiEnhancement?.showAutoRefreshOnly ?? true)) + (props.showDatePicker && (language?.searchBar?.showDatePicker ?? true)) ?? + (props.showAutoRefreshOnly && (language?.searchBar?.showAutoRefreshOnly ?? true)) ); } diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index e6f1c74b6bb..f5581947b6e 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -119,9 +119,8 @@ class SearchBarUI extends Component { }; private services = this.props.opensearchDashboards.services; - private dataSetService = this.services.data.query.dataSetManager; - private queryStringService = this.services.data.query.queryString; - private savedQueryService = this.services.data.query.savedQueries; + private queryService = this.services.data.query; + private savedQueryService = this.queryService.savedQueries; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; private useNewHeader = Boolean(this.services.uiSettings.get(UI_SETTINGS.NEW_HOME_PAGE)); @@ -238,7 +237,7 @@ class SearchBarUI extends Component { (!this.useNewHeader || this.props.filters.length > 0) && this.props.indexPatterns && compact(this.props.indexPatterns).length > 0 && - (this.props.settings?.getQueryEnhancements(this.state.query?.language!)?.searchBar + (this.queryService.queryString.getLanguage(this.state.query?.language!)?.searchBar ?.showFilterBar ?? true) ); @@ -374,10 +373,10 @@ class SearchBarUI extends Component { } } ); - const dataSet = this.dataSetService.getDataSet(); - if (dataSet && queryAndDateRange.query) { - this.queryStringService.addToQueryHistory( - dataSet, + const dataset = this.queryService.queryString.getQuery().dataset; + if (dataset && queryAndDateRange.query) { + this.queryService.queryString.addToQueryHistory( + dataset, queryAndDateRange.query, queryAndDateRange.dateRange ); diff --git a/src/plugins/data/public/ui/settings/settings.ts b/src/plugins/data/public/ui/settings/settings.ts index 7fc758712ad..6c5a6e6991f 100644 --- a/src/plugins/data/public/ui/settings/settings.ts +++ b/src/plugins/data/public/ui/settings/settings.ts @@ -8,7 +8,7 @@ import { DataStorage, setOverrides as setFieldOverrides } from '../../../common' import { ConfigSchema } from '../../../config'; import { ISearchStart } from '../../search'; import { QueryEditorExtensionConfig } from '../query_editor/query_editor_extensions'; -import { QueryEnhancement } from '../types'; +import { IQueryStart } from '../../query'; export interface DataSettings { userQueryLanguage: string; @@ -30,8 +30,8 @@ export class Settings { constructor( private readonly config: ConfigSchema['enhancements'], private readonly search: ISearchStart, + private readonly query: IQueryStart, private readonly storage: DataStorage, - private readonly queryEnhancements: Map, private readonly queryEditorExtensionMap: Record ) { this.isEnabled = true; @@ -58,14 +58,6 @@ export class Settings { return true; } - getAllQueryEnhancements() { - return this.queryEnhancements; - } - - getQueryEnhancements(language: string) { - return this.queryEnhancements.get(language); - } - getQueryEditorExtensionMap() { return this.queryEditorExtensionMap; } @@ -86,18 +78,18 @@ export class Settings { return this.storage.get('userQueryLanguage') || 'kuery'; } - setUserQueryLanguage(language: string) { - if (language !== this.getUserQueryLanguage()) { + setUserQueryLanguage(languageId: string) { + if (languageId !== this.getUserQueryLanguage()) { this.search.df.clear(); } - this.storage.set('userQueryLanguage', language); - const queryEnhancement = this.queryEnhancements.get(language); + this.storage.set('userQueryLanguage', languageId); + const queryEnhancement = this.query.queryString.getLanguage(languageId); this.search.__enhance({ searchInterceptor: queryEnhancement ? queryEnhancement.search : this.search.getDefaultSearchInterceptor(), }); - this.setUiOverridesByUserQueryLanguage(language); + this.setUiOverridesByUserQueryLanguage(languageId); return true; } @@ -126,10 +118,10 @@ export class Settings { return true; } - setUiOverridesByUserQueryLanguage(language: string) { - const queryEnhancement = this.queryEnhancements.get(language); - if (queryEnhancement) { - const { fields = {}, showDocLinks } = queryEnhancement; + setUiOverridesByUserQueryLanguage(languageId: string) { + const language = this.query.queryString.getLanguage(languageId); + if (language) { + const { fields = {}, showDocLinks } = language; this.setUiOverrides({ fields, showDocLinks }); } else { this.setUiOverrides({ fields: undefined, showDocLinks: undefined }); @@ -170,17 +162,11 @@ export class Settings { interface Deps { config: ConfigSchema['enhancements']; search: ISearchStart; + query: IQueryStart; storage: DataStorage; - queryEnhancements: Map; queryEditorExtensionMap: Record; } -export function createSettings({ - config, - search, - storage, - queryEnhancements, - queryEditorExtensionMap, -}: Deps) { - return new Settings(config, search, storage, queryEnhancements, queryEditorExtensionMap); +export function createSettings({ config, search, query, storage, queryEditorExtensionMap }: Deps) { + return new Settings(config, search, query, storage, queryEditorExtensionMap); } diff --git a/src/plugins/data/public/ui/types.ts b/src/plugins/data/public/ui/types.ts index 0890ea1c13b..1d13a13c604 100644 --- a/src/plugins/data/public/ui/types.ts +++ b/src/plugins/data/public/ui/types.ts @@ -4,7 +4,6 @@ */ import { Observable } from 'rxjs'; -import { SearchInterceptor } from '../search'; import { IndexPatternSelectProps } from './index_pattern_select'; import { StatefulSearchBarProps } from './search_bar'; import { QueryEditorExtensionConfig } from './query_editor/query_editor_extensions'; @@ -13,41 +12,7 @@ import { SuggestionsComponentProps } from './typeahead/suggestions_component'; export * from './settings'; -export interface QueryEnhancement { - // TODO: MQL do want to default have supported all data_sources? - // or should data connect have a record of query enhancements that are supported - language: string; - search: SearchInterceptor; - // Leave blank to support all data sources - // supportedDataSourceTypes?: Record; - searchBar?: { - showDataSetsSelector?: boolean; - showDataSourcesSelector?: boolean; - showQueryInput?: boolean; - showFilterBar?: boolean; - showDatePicker?: boolean; - showAutoRefreshOnly?: boolean; - queryStringInput?: { - // will replace '' with the data source name - initialValue?: string; - }; - dateRange?: { - initialFrom?: string; - initialTo?: string; - }; - }; - fields?: { - filterable?: boolean; - visualizable?: boolean; - }; - showDocLinks?: boolean; - // List of supported app names that this enhancement should be enabled for, - // if not provided it will be enabled for all apps - supportedAppNames?: string[]; -} - export interface UiEnhancements { - query?: QueryEnhancement; queryEditorExtension?: QueryEditorExtensionConfig; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index ff7d32bb246..faea0b73857 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -12,7 +12,7 @@ import { QueryEditorExtensionConfig } from './query_editor'; import { createSearchBar } from './search_bar/create_search_bar'; import { createSettings } from './settings'; import { SuggestionsComponent } from './typeahead'; -import { IUiSetup, IUiStart, QueryEnhancement, UiEnhancements } from './types'; +import { IUiSetup, IUiStart, UiEnhancements } from './types'; import { DataStorage } from '../../common'; /** @internal */ @@ -27,7 +27,6 @@ export interface UiServiceStartDependencies { export class UiService implements Plugin { enhancementsConfig: ConfigSchema['enhancements']; - private queryEnhancements: Map = new Map(); private queryEditorExtensionMap: Record = {}; private dataSetContainer$ = new BehaviorSubject(null); @@ -41,9 +40,6 @@ export class UiService implements Plugin { return { __enhance: (enhancements?: UiEnhancements) => { if (!enhancements) return; - if (enhancements.query && enhancements.query.language) { - this.queryEnhancements.set(enhancements.query.language, enhancements.query); - } if (enhancements.queryEditorExtension) { this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] = enhancements.queryEditorExtension; @@ -56,8 +52,8 @@ export class UiService implements Plugin { const Settings = createSettings({ config: this.enhancementsConfig, search: dataServices.search, + query: dataServices.query, storage, - queryEnhancements: this.queryEnhancements, queryEditorExtensionMap: this.queryEditorExtensionMap, });