From 8a6b524eb65cb8fab9ffd2c0b563c64199a4d4b6 Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Thu, 15 Feb 2024 18:46:44 +0000 Subject: [PATCH 1/4] [MQL] support different query languages Only adds the quick startup for OpenSearch cluster with a SQL plugin and observability with: ``` yarn opensearch snapshot --sql ``` Also, adds SQL to the language selector stolen shamelessly from https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5623 Next steps to intercept and send to SQL API or just transform basic syntax to DSL Signed-off-by: Kawika Avilla Working query enhance Signed-off-by: Kawika Avilla Reget search enhance Signed-off-by: Kawika Avilla data frames Signed-off-by: Kawika Avilla temp state need to pass df Signed-off-by: Kawika Avilla sending data frame Signed-off-by: Kawika Avilla gets df type Signed-off-by: Kawika Avilla add some small ui things Signed-off-by: Kawika Avilla move back query language switcher Signed-off-by: Kawika Avilla updating side panel Signed-off-by: Kawika Avilla add ui config on query enhancement Signed-off-by: Kawika Avilla support query string input Signed-off-by: Kawika Avilla update to say search bar Signed-off-by: Kawika Avilla update ppl to call once Signed-off-by: Kawika Avilla update when fields update Signed-off-by: Kawika Avilla add unknown Signed-off-by: Kawika Avilla --- config/opensearch_dashboards.yml | 2 + package.json | 2 +- packages/opensearch-datemath/index.d.ts | 2 + packages/opensearch-datemath/index.js | 4 +- .../src/cli_commands/snapshot.js | 7 + packages/osd-opensearch/src/cluster.js | 25 ++- src/cli/serve/serve.js | 1 + src/plugins/data/common/constants.ts | 1 + .../data/common/data_frames/_df_cache.ts | 35 ++++ .../data/common/data_frames/fields/index.ts | 12 ++ .../data/common/data_frames/fields/types.ts | 24 +++ src/plugins/data/common/data_frames/index.ts | 13 ++ src/plugins/data/common/data_frames/types.ts | 41 +++++ src/plugins/data/common/data_frames/utils.ts | 155 +++++++++++++++++ src/plugins/data/common/index.ts | 1 + .../index_patterns/index_patterns.ts | 4 + .../build_opensearch_query.ts | 11 ++ .../opensearch_query/from_sql.ts | 21 +++ .../opensearch_query/index.ts | 1 + .../opensearch_query/sql_string_to_dsl.ts | 23 +++ .../common/search/opensearch_search/types.ts | 1 + .../create_search_source.test.ts | 5 + .../data/common/search/search_source/mocks.ts | 3 + .../search_source/search_source.test.ts | 5 + .../search/search_source/search_source.ts | 85 ++++++++- .../data/common/search/search_source/types.ts | 3 +- src/plugins/data/common/search/types.ts | 5 +- src/plugins/data/common/types.ts | 1 + .../datasource_services/datasource_service.ts | 1 + .../register_default_datasource.ts | 3 +- src/plugins/data/public/index.ts | 2 +- src/plugins/data/public/plugin.ts | 26 +-- .../search/expressions/opensearchdsl.ts | 2 + .../data/public/search/search_interceptor.ts | 7 + .../data/public/search/search_service.ts | 30 +++- src/plugins/data/public/search/types.ts | 2 + src/plugins/data/public/services.ts | 2 + src/plugins/data/public/types.ts | 15 +- src/plugins/data/public/ui/index.ts | 1 + .../index_pattern_select.tsx | 12 ++ .../public/ui/query_string_input/_index.scss | 1 + .../_language_switcher.scss | 4 + .../query_string_input/language_switcher.tsx | 161 +++++++----------- .../query_string_input/query_bar_top_row.tsx | 15 +- .../query_string_input/query_string_input.tsx | 33 +++- .../ui/search_bar/create_search_bar.tsx | 7 +- .../data/public/ui/search_bar/search_bar.tsx | 11 +- src/plugins/data/public/ui/types.ts | 47 +++++ src/plugins/data/public/ui/ui_service.ts | 71 ++++++++ .../get_default_search_params.ts | 4 + .../data/server/search/search_service.ts | 35 +++- src/plugins/data/server/search/types.ts | 9 +- src/plugins/data/server/ui_settings.ts | 46 +++++ .../components/sidebar/discover_field.tsx | 43 +++++ .../sidebar/discover_field_edit.tsx | 62 +++++++ .../view_components/panel/index.tsx | 22 ++- .../utils/update_search_source.ts | 18 +- .../view_components/utils/use_search.ts | 21 ++- yarn.lock | 9 +- 59 files changed, 1051 insertions(+), 164 deletions(-) create mode 100644 src/plugins/data/common/data_frames/_df_cache.ts create mode 100644 src/plugins/data/common/data_frames/fields/index.ts create mode 100644 src/plugins/data/common/data_frames/fields/types.ts create mode 100644 src/plugins/data/common/data_frames/index.ts create mode 100644 src/plugins/data/common/data_frames/types.ts create mode 100644 src/plugins/data/common/data_frames/utils.ts create mode 100644 src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts create mode 100644 src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts create mode 100644 src/plugins/data/public/ui/query_string_input/_language_switcher.scss create mode 100644 src/plugins/data/public/ui/types.ts create mode 100644 src/plugins/data/public/ui/ui_service.ts create mode 100644 src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index 40d643b014fd..91a048b00760 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -313,3 +313,5 @@ # Set the value to true to enable workspace feature # workspace.enabled: false +opensearch_alerting.enabled: false +opensearch_security.enabled: false diff --git a/package.json b/package.json index c728618fcbcd..f1fa8e46f069 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ }, "dependencies": { "@aws-crypto/client-node": "^3.1.1", - "@elastic/datemath": "5.0.3", + "@elastic/datemath": "link:packages/opensearch-datemath", "@elastic/eui": "npm:@opensearch-project/oui@1.5.1", "@elastic/good": "^9.0.1-kibana3", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", diff --git a/packages/opensearch-datemath/index.d.ts b/packages/opensearch-datemath/index.d.ts index d5a38f0176ea..0706d7d0dccf 100644 --- a/packages/opensearch-datemath/index.d.ts +++ b/packages/opensearch-datemath/index.d.ts @@ -43,6 +43,8 @@ declare const datemath: { unitsAsc: Unit[]; unitsDesc: Unit[]; + isDateTime(input: any): boolean; + /** * Parses a string into a moment object. The string can be something like "now - 15m". * @param options.forceNow If this optional parameter is supplied, "now" will be treated as this diff --git a/packages/opensearch-datemath/index.js b/packages/opensearch-datemath/index.js index 4367949d7cf0..eba9fd2be5a6 100644 --- a/packages/opensearch-datemath/index.js +++ b/packages/opensearch-datemath/index.js @@ -49,6 +49,7 @@ const isDate = (d) => Object.prototype.toString.call(d) === '[object Date]'; const isValidDate = (d) => isDate(d) && !isNaN(d.valueOf()); +const isDateTime = (d) => moment.isMoment(d); /* * This is a simplified version of opensearch's date parser. * If you pass in a momentjs instance as the third parameter the calculation @@ -57,7 +58,7 @@ const isValidDate = (d) => isDate(d) && !isNaN(d.valueOf()); */ function parse(text, { roundUp = false, momentInstance = moment, forceNow } = {}) { if (!text) return undefined; - if (momentInstance.isMoment(text)) return text; + if (isDateTime(text)) return text; if (isDate(text)) return momentInstance(text); if (forceNow !== undefined && !isValidDate(forceNow)) { throw new Error('forceNow must be a valid Date'); @@ -164,6 +165,7 @@ function parseDateMath(mathString, time, roundUp) { module.exports = { parse: parse, + isDateTime: isDateTime, unitsMap: Object.freeze(unitsMap), units: Object.freeze(units), unitsAsc: Object.freeze(unitsAsc), diff --git a/packages/osd-opensearch/src/cli_commands/snapshot.js b/packages/osd-opensearch/src/cli_commands/snapshot.js index ff21dbe851c8..84d6acee104e 100644 --- a/packages/osd-opensearch/src/cli_commands/snapshot.js +++ b/packages/osd-opensearch/src/cli_commands/snapshot.js @@ -50,6 +50,7 @@ exports.help = (defaults = {}) => { --download-only Download the snapshot but don't actually start it --ssl Sets up SSL on OpenSearch --security Installs and sets up the OpenSearch Security plugin on the cluster + --sql Installs and sets up the required OpenSearch SQL/PPL plugins on the cluster --P OpenSearch plugin artifact URL to install it on the cluster. We can use the flag multiple times to install multiple plugins on the cluster snapshot. The argument value can be url to zip file, maven coordinates of the plugin or for local zip files, use file:. @@ -77,6 +78,8 @@ exports.run = async (defaults = {}) => { boolean: ['security'], + boolean: ['sql'], + default: defaults, }); @@ -98,6 +101,10 @@ exports.run = async (defaults = {}) => { await cluster.setupSecurity(installPath, options.version ?? defaults.version); } + if (options.sql) { + await cluster.setupSql(installPath, options.version ?? defaults.version); + } + options.bundledJDK = true; await cluster.run(installPath, options); diff --git a/packages/osd-opensearch/src/cluster.js b/packages/osd-opensearch/src/cluster.js index 455a1e5f919f..4b1c8b38259d 100644 --- a/packages/osd-opensearch/src/cluster.js +++ b/packages/osd-opensearch/src/cluster.js @@ -70,10 +70,11 @@ const first = (stream, map) => }); exports.Cluster = class Cluster { - constructor({ log = defaultLog, ssl = false, security = false } = {}) { + constructor({ log = defaultLog, ssl = false, security = false, sql = false } = {}) { this._log = log; this._ssl = ssl; this._security = security; + this._sql = sql; this._caCertPromise = ssl ? readFile(CA_CERT_PATH) : undefined; } @@ -224,6 +225,28 @@ exports.Cluster = class Cluster { } } + /** + * Setups cluster with SQL/PPL plugins + * + * @param {string} installPath + * @property {String} version - version of OpenSearch + */ + async setupSql(installPath, version) { + await this.installSqlPlugin(installPath, version, 'opensearch-sql'); + await this.installSqlPlugin(installPath, version, 'opensearch-observability'); + } + + async installSqlPlugin(installPath, version, id) { + this._log.info(`Setting up: ${id}`); + try { + const pluginUrl = generateEnginePluginUrl(version, id); + await this.installOpenSearchPlugins(installPath, pluginUrl); + this._log.info(`Completed setup: ${id}`); + } catch (ex) { + this._log.warning(`Failed to setup: ${id}`); + } + } + /** * Starts OpenSearch and returns resolved promise once started * diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index aed5d74a2c01..c1e489afb4ef 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -249,6 +249,7 @@ export default function (program) { .option('--dev', 'Run the server with development mode defaults') .option('--ssl', 'Run the dev server using HTTPS') .option('--security', 'Run the dev server using security defaults') + .option('--sql', 'Run the dev server using SQL/PPL defaults') .option('--dist', 'Use production assets from osd/optimizer') .option( '--no-base-path', diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index 43db1fe72b9e..cbbd31665de5 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -60,4 +60,5 @@ export const UI_SETTINGS = { INDEXPATTERN_PLACEHOLDER: 'indexPattern:placeholder', FILTERS_PINNED_BY_DEFAULT: 'filters:pinnedByDefault', FILTERS_EDITOR_SUGGEST_VALUES: 'filterEditor:suggestValues', + DATAFRAME_HYDRATION_STRATEGY: 'dataframe:hydrationStrategy', } as const; diff --git a/src/plugins/data/common/data_frames/_df_cache.ts b/src/plugins/data/common/data_frames/_df_cache.ts new file mode 100644 index 000000000000..2cec9ccc4fab --- /dev/null +++ b/src/plugins/data/common/data_frames/_df_cache.ts @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { IDataFrame } from '..'; + +export interface DfCache { + get: () => IDataFrame | undefined; + set: (value: IDataFrame) => IDataFrame; + clear: () => void; +} + +export function createDataFrameCache(): DfCache { + let df: IDataFrame | undefined; + const cache: DfCache = { + get: () => { + return df; + }, + set: (prom: IDataFrame) => { + df = prom; + return prom; + }, + clear: () => { + df = undefined; + }, + }; + return cache; +} diff --git a/src/plugins/data/common/data_frames/fields/index.ts b/src/plugins/data/common/data_frames/fields/index.ts new file mode 100644 index 000000000000..a2d334e05ba7 --- /dev/null +++ b/src/plugins/data/common/data_frames/fields/index.ts @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export * from './types'; diff --git a/src/plugins/data/common/data_frames/fields/types.ts b/src/plugins/data/common/data_frames/fields/types.ts new file mode 100644 index 000000000000..d433f3b02a81 --- /dev/null +++ b/src/plugins/data/common/data_frames/fields/types.ts @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export interface IFieldType { + name: string; + type: string; + values: any[]; + count?: number; + aggregatable?: boolean; + filterable?: boolean; + searchable?: boolean; + sortable?: boolean; + visualizable?: boolean; + displayName?: string; + format?: any; +} diff --git a/src/plugins/data/common/data_frames/index.ts b/src/plugins/data/common/data_frames/index.ts new file mode 100644 index 000000000000..2668d0d813d1 --- /dev/null +++ b/src/plugins/data/common/data_frames/index.ts @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export * from './types'; +export * from './utils'; diff --git a/src/plugins/data/common/data_frames/types.ts b/src/plugins/data/common/data_frames/types.ts new file mode 100644 index 000000000000..551243e3b405 --- /dev/null +++ b/src/plugins/data/common/data_frames/types.ts @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { IFieldType } from './fields'; + +export * from './_df_cache'; + +export interface IDataFrame { + name?: string; + schema?: Array>; + fields: IFieldType[]; + size: number; +} + +export interface DataFrameAgg { + key: string; + value: number; +} + +export interface PartialDataFrame extends Omit { + fields: Array>; +} + +/** + * To be utilize with aggregations and will map to buckets + * Plugins can get the aggreted value by their own logic + * Setting to null will disable the aggregation if plugin wishes + * In future, if the plugin doesn't intentionally set the value to null, + * we can calculate the value based on the fields. + */ +export interface IDataFrameWithAggs extends IDataFrame { + aggs: DataFrameAgg[] | null; +} diff --git a/src/plugins/data/common/data_frames/utils.ts b/src/plugins/data/common/data_frames/utils.ts new file mode 100644 index 000000000000..acc23a4d3c56 --- /dev/null +++ b/src/plugins/data/common/data_frames/utils.ts @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { SearchResponse } from 'elasticsearch'; +import datemath from '@elastic/datemath'; +import { IDataFrame, IDataFrameWithAggs, PartialDataFrame } from './types'; +import { IFieldType } from './fields'; +import { IndexPatternFieldMap, IndexPatternSpec } from '../index_patterns'; +import { IOpenSearchDashboardsSearchRequest } from '../search'; + +const name = 'data_frame'; + +export interface IDataFrameResponse extends SearchResponse { + type: typeof name; + body: IDataFrame | IDataFrameWithAggs; + took: number; +} + +export const getRawQueryString = ( + searchRequest: IOpenSearchDashboardsSearchRequest +): string | undefined => { + return searchRequest.params?.body?.query?.queries[0]?.query; +}; + +export const convertResult = (response: IDataFrameResponse): SearchResponse => { + const data = response.body; + const hits: any[] = []; + for (let index = 0; index < data.size; index++) { + const hit: { [key: string]: any } = {}; + data.fields.forEach((field) => { + hit[field.name] = field.values[index]; + }); + hits.push({ + _index: data.name ?? '', + _type: '', + _id: '', + _score: 0, + _source: hit, + }); + } + const searchResponse: SearchResponse = { + took: response.took, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: 0, + max_score: 0, + hits, + }, + }; + + if (data.hasOwnProperty('aggs')) { + const dataWithAggs = data as IDataFrameWithAggs; + if (!dataWithAggs.aggs) { + // TODO: SQL best guess, get timestamp field and caculate it here + return searchResponse; + } + searchResponse.aggregations = { + 2: { + buckets: dataWithAggs.aggs.map((agg) => { + searchResponse.hits.total += agg.value; + return { + key: new Date(agg.key).getTime(), + key_as_string: agg.key, + doc_count: agg.value, + }; + }), + }, + }; + } + + return searchResponse; +}; + +export const formatFieldValue = (field: IFieldType | Partial, value: any): any => { + return field.format && field.format.convert ? field.format.convert(value) : value; +}; + +export const getFieldType = (field: IFieldType | Partial): string | undefined => { + if (field.name) { + const fieldName = field.name.toLowerCase(); + // TODO: feels little biased to check if timestamp. + // Has to be a better way to know so to be fair to all data sources + if (fieldName.includes('date') || fieldName.includes('timestamp')) { + return 'date'; + } + } + if (!field.values) return field.type; + const firstValue = field.values.filter((value) => value !== null && value !== undefined)[0]; + if (firstValue instanceof Date || datemath.isDateTime(firstValue)) { + return 'date'; + } + return field.type; +}; + +export const getTimeField = (data: IDataFrame): IFieldType | undefined => { + return data.fields.find((field) => field.type === 'date'); +}; + +export const createDataFrame = (partial: PartialDataFrame): IDataFrame | IDataFrameWithAggs => { + let size = 0; + const fields = partial.fields.map((field) => { + if (!field.values) { + field.values = new Array(size); + } else if (field.values.length > size) { + size = field.values.length; + } + field.type = getFieldType(field); + // if (!field.type) { + // need to think if this needs to be mapped to OSD field type for example + // PPL type for date is TIMESTAMP + // OSD is expecting date + // field.type = get type + // } + // get timeseries field + return field as IFieldType; + }); + + return { + ...partial, + fields, + size, + }; +}; + +export const dataFrameToSpec = (dataFrame: IDataFrame): IndexPatternSpec => { + return { + id: 'data_frame', + title: dataFrame.name, + timeFieldName: getTimeField(dataFrame)?.name, + fields: dataFrame.fields.reduce((acc, field) => { + acc[field.name] = { + name: field.name, + type: field.type, + aggregatable: true, + searchable: true, + }; + return acc; + }, {} as IndexPatternFieldMap), + // TODO: SQL dataSourceRef + }; +}; diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index 1eefb2383f8b..d7b7e56e2280 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -30,6 +30,7 @@ export * from './constants'; export * from './opensearch_query'; +export * from './data_frames'; export * from './field_formats'; export * from './field_mapping'; export * from './index_patterns'; 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 688605821097..5b2bf71433b9 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 @@ -208,6 +208,10 @@ export class IndexPatternsService { return this.savedObjectsCache; }; + getIndexPatternCache = () => { + return indexPatternCache; + }; + /** * Get default index pattern */ diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/build_opensearch_query.ts b/src/plugins/data/common/opensearch_query/opensearch_query/build_opensearch_query.ts index 481eae12d121..5a00faf890f0 100644 --- a/src/plugins/data/common/opensearch_query/opensearch_query/build_opensearch_query.ts +++ b/src/plugins/data/common/opensearch_query/opensearch_query/build_opensearch_query.ts @@ -66,6 +66,17 @@ export function buildOpenSearchQuery( const validQueries = queries.filter((query) => has(query, 'query')); const queriesByLanguage = groupBy(validQueries, 'language'); + const unsupportedQueries = Object.keys(queriesByLanguage).filter( + (language) => language !== 'kuery' && language !== 'lucene' + ); + if (unsupportedQueries.length > 0) { + return { + type: 'unsupported', + queries, + filters, + }; + } + const kueryQuery = buildQueryFromKuery( indexPattern, queriesByLanguage.kuery, diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts b/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts new file mode 100644 index 000000000000..9d802bc95e3c --- /dev/null +++ b/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts @@ -0,0 +1,21 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { decorateQuery } from './decorate_query'; +import { getIndexPatternFromSql, sqlStringToDsl } from './sql_string_to_dsl'; +import { Query } from '../../query/types'; + +export function buildQueryFromSql(queries: Query[], dateFormatTZ?: string) { + const combinedQueries = (queries || []).map((query) => { + const indexPattern = getIndexPatternFromSql(query.query); + const queryDsl = sqlStringToDsl(query.query); + + return decorateQuery(queryDsl, indexPattern, dateFormatTZ); + }); + + return { + combinedQueries, + }; +} diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/index.ts b/src/plugins/data/common/opensearch_query/opensearch_query/index.ts index ba3fe8817006..263bb1970a65 100644 --- a/src/plugins/data/common/opensearch_query/opensearch_query/index.ts +++ b/src/plugins/data/common/opensearch_query/opensearch_query/index.ts @@ -31,5 +31,6 @@ export { buildOpenSearchQuery, OpenSearchQueryConfig } from './build_opensearch_query'; export { buildQueryFromFilters } from './from_filters'; export { luceneStringToDsl } from './lucene_string_to_dsl'; +export { getIndexPatternFromSql, sqlStringToDsl } from './sql_string_to_dsl'; export { decorateQuery } from './decorate_query'; export { getOpenSearchQueryConfig } from './get_opensearch_query_config'; diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts b/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts new file mode 100644 index 000000000000..19cdca1945dc --- /dev/null +++ b/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isString } from 'lodash'; +import { DslQuery } from './opensearch_query_dsl'; + +export function getIndexPatternFromSql(query: string | any) { + const from = query.match(new RegExp(/FROM\s+([\w*-.!@$^()~;]+)/, 'i')); + if (from) { + return from[1]; + } + return ''; +} + +export function sqlStringToDsl(query: string | any): DslQuery { + if (isString(query)) { + return { query_string: { query } }; + } + + return query; +} diff --git a/src/plugins/data/common/search/opensearch_search/types.ts b/src/plugins/data/common/search/opensearch_search/types.ts index 3b93177bf201..f90a3f1de245 100644 --- a/src/plugins/data/common/search/opensearch_search/types.ts +++ b/src/plugins/data/common/search/opensearch_search/types.ts @@ -57,6 +57,7 @@ export type ISearchRequestParams> = { export interface IOpenSearchSearchRequest extends IOpenSearchDashboardsSearchRequest { indexType?: string; + language?: string; dataSourceId?: string; } diff --git a/src/plugins/data/common/search/search_source/create_search_source.test.ts b/src/plugins/data/common/search/search_source/create_search_source.test.ts index 467ecec59f5a..68dfa7699e13 100644 --- a/src/plugins/data/common/search/search_source/create_search_source.test.ts +++ b/src/plugins/data/common/search/search_source/create_search_source.test.ts @@ -50,6 +50,11 @@ describe('createSearchSource', () => { callMsearch: jest.fn(), loadingCount$: new BehaviorSubject(0), }, + df: { + get: jest.fn().mockReturnValue({}), + set: jest.fn().mockReturnValue({}), + clear: jest.fn(), + }, }; indexPatternContractMock = ({ diff --git a/src/plugins/data/common/search/search_source/mocks.ts b/src/plugins/data/common/search/search_source/mocks.ts index 959d1aebfe53..3f69f14ec688 100644 --- a/src/plugins/data/common/search/search_source/mocks.ts +++ b/src/plugins/data/common/search/search_source/mocks.ts @@ -47,6 +47,8 @@ export const searchSourceInstanceMock: MockedKeys = { createChild: jest.fn().mockReturnThis(), setParent: jest.fn(), getParent: jest.fn().mockReturnThis(), + setDataFrame: jest.fn(), + getDataFrame: jest.fn().mockReturnThis(), fetch: jest.fn().mockResolvedValue({}), onRequestStart: jest.fn(), getSearchRequestBody: jest.fn(), @@ -54,6 +56,7 @@ export const searchSourceInstanceMock: MockedKeys = { history: [], getSerializedFields: jest.fn(), serialize: jest.fn(), + flatten: jest.fn().mockReturnThis(), }; export const searchSourceCommonMock: jest.Mocked = { diff --git a/src/plugins/data/common/search/search_source/search_source.test.ts b/src/plugins/data/common/search/search_source/search_source.test.ts index 92cc0682a136..09adc867d213 100644 --- a/src/plugins/data/common/search/search_source/search_source.test.ts +++ b/src/plugins/data/common/search/search_source/search_source.test.ts @@ -84,6 +84,11 @@ describe('SearchSource', () => { callMsearch: jest.fn(), loadingCount$: new BehaviorSubject(0), }, + df: { + get: jest.fn().mockReturnValue({}), + set: jest.fn().mockReturnValue({}), + clear: jest.fn(), + }, }; }); 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 abe6fa1b5cb4..586d84480acf 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -87,6 +87,7 @@ import { normalizeSortRequest } from './normalize_sort_request'; import { filterDocvalueFields } from './filter_docvalue_fields'; import { fieldWildcardFilter } from '../../../../opensearch_dashboards_utils/common'; import { IIndexPattern } from '../../index_patterns'; +import { IDataFrame, IDataFrameResponse, convertResult, dataFrameToSpec } from '../../data_frames'; import { IOpenSearchSearchRequest, IOpenSearchSearchResponse, ISearchOptions } from '../..'; import { IOpenSearchDashboardsSearchRequest, IOpenSearchDashboardsSearchResponse } from '../types'; import { ISearchSource, SearchSourceOptions, SearchSourceFields } from './types'; @@ -116,6 +117,7 @@ export const searchSourceRequiredUiSettings = [ UI_SETTINGS.QUERY_STRING_OPTIONS, UI_SETTINGS.SEARCH_INCLUDE_FROZEN, UI_SETTINGS.SORT_OPTIONS, + UI_SETTINGS.DATAFRAME_HYDRATION_STRATEGY, ]; export interface SearchSourceDependencies extends FetchHandlers { @@ -123,11 +125,18 @@ export interface SearchSourceDependencies extends FetchHandlers { // search options required here and returning a promise instead of observable. search: < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( request: SearchStrategyRequest, options: ISearchOptions ) => Promise; + df: { + get: () => IDataFrame | undefined; + set: (dataFrame: IDataFrame) => Promise; + clear: () => void; + }; } /** @public **/ @@ -267,6 +276,39 @@ export class SearchSource { return this.parent; } + /** + * Get the data frame of this SearchSource + * @return {undefined|IDataFrame} + */ + getDataFrame() { + return this.dependencies.df.get(); + } + + /** + * Set the data frame of this SearchSource + * @return {undefined|IDataFrame} + */ + async setDataFrame(dataFrame: IDataFrame | undefined) { + if (dataFrame) { + await this.dependencies.df.set(dataFrame); + } else { + this.dependencies.df.clear(); + } + return this.getDataFrame(); + } + + /** + * Get the data set of this SearchSource + * @return {undefined|IndexPattern} + */ + getDataSet() { + const df = this.dependencies.df.get(); + if (!df) { + return undefined; + } + return dataFrameToSpec(df); + } + /** * Fetch this source and reject the returned Promise on error * @@ -282,6 +324,8 @@ export class SearchSource { let response; if (getConfig(UI_SETTINGS.COURIER_BATCH_SEARCHES)) { response = await this.legacyFetch(searchRequest, options); + } else if (this.isUnsupportedRequest(searchRequest)) { + response = await this.fetchExternalSearch(searchRequest, options); } else { const indexPattern = this.getField('index'); searchRequest.dataSourceId = indexPattern?.dataSourceRef?.id; @@ -335,6 +379,11 @@ export class SearchSource { private fetchSearch(searchRequest: SearchRequest, options: ISearchOptions) { const { search, getConfig, onResponse } = this.dependencies; + if (this.getDataFrame()) { + delete searchRequest.body!.df; + this.setDataFrame(undefined); + } + const params = getSearchParamsFromRequest(searchRequest, { getConfig, }); @@ -342,7 +391,35 @@ export class SearchSource { return search( { params, indexType: searchRequest.indexType, dataSourceId: searchRequest.dataSourceId }, options - ).then(({ rawResponse }) => onResponse(searchRequest, rawResponse)); + ).then((response: any) => onResponse(searchRequest, response.rawResponse)); + } + + /** + * Run a non-native search using the search service + * @return {Promise>} + */ + private async fetchExternalSearch(searchRequest: SearchRequest, options: ISearchOptions) { + const { search, getConfig, onResponse } = this.dependencies; + + const params = getSearchParamsFromRequest(searchRequest, { + getConfig, + }); + + if (this.getDataFrame() && this.getDataFrame()!.name === searchRequest.index.title) { + params.body!.df = this.getDataFrame(); + } + + return search({ params }, options).then(async (response: any) => { + if (response.hasOwnProperty('type')) { + if ((response as IDataFrameResponse).type === 'data_frame') { + const dataFrameResponse = response as IDataFrameResponse; + await this.setDataFrame(dataFrameResponse.body as IDataFrame); + return onResponse(searchRequest, convertResult(response as IDataFrameResponse)); + } + // TODO: SQL else if data_frame_poll then poll for the data frame updating the df fields only + } + return onResponse(searchRequest, response.rawResponse); + }); } /** @@ -366,6 +443,10 @@ export class SearchSource { ); } + private isUnsupportedRequest(request: SearchRequest): boolean { + return request.body!.query.hasOwnProperty('type') && request.body!.query.type === 'unsupported'; + } + /** * Called by requests of this search source when they are started * @param options diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index 13b100aab1a7..9f3fd75e1ce9 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -29,7 +29,7 @@ */ import { NameList } from 'elasticsearch'; -import { Filter, IndexPattern, Query } from '../..'; +import { Filter, IDataFrame, IndexPattern, Query } from '../..'; import { SearchSource } from './search_source'; /** @@ -103,6 +103,7 @@ export interface SearchSourceFields { searchAfter?: OpenSearchQuerySearchAfter; timeout?: string; terminate_after?: number; + df?: IDataFrame; } export interface SearchSourceOptions { diff --git a/src/plugins/data/common/search/types.ts b/src/plugins/data/common/search/types.ts index e05c0adb46f0..d2bcdc0f4d05 100644 --- a/src/plugins/data/common/search/types.ts +++ b/src/plugins/data/common/search/types.ts @@ -34,6 +34,7 @@ import { IOpenSearchSearchResponse, ISearchOptions, } from '../../common/search'; +import { IDataFrameResponse } from '../data_frames'; export type ISearch = ( request: IOpenSearchDashboardsSearchRequest, @@ -42,7 +43,9 @@ export type ISearch = ( export type ISearchGeneric = < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( request: SearchStrategyRequest, options?: ISearchOptions diff --git a/src/plugins/data/common/types.ts b/src/plugins/data/common/types.ts index 361ba39edfec..fba5473624dc 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -31,6 +31,7 @@ export * from './query/types'; export * from './osd_field_types/types'; export * from './index_patterns/types'; +export * from './data_frames/types'; /** * If a service is being shared on both the client and the server, and diff --git a/src/plugins/data/public/data_sources/datasource_services/datasource_service.ts b/src/plugins/data/public/data_sources/datasource_services/datasource_service.ts index 8ead65633c7f..5a77d7b60d72 100644 --- a/src/plugins/data/public/data_sources/datasource_services/datasource_service.ts +++ b/src/plugins/data/public/data_sources/datasource_services/datasource_service.ts @@ -14,6 +14,7 @@ import { DataSource } from '../datasource/datasource'; export class DataSourceService { private static dataSourceService: DataSourceService; + // A record to store all registered data sources, using the data source name as the key. private dataSources: Record = {}; private dataSourcesSubject: BehaviorSubject>; diff --git a/src/plugins/data/public/data_sources/register_default_datasource.ts b/src/plugins/data/public/data_sources/register_default_datasource.ts index a4198b4e8e3a..967cc0a55dd8 100644 --- a/src/plugins/data/public/data_sources/register_default_datasource.ts +++ b/src/plugins/data/public/data_sources/register_default_datasource.ts @@ -7,8 +7,9 @@ import { i18n } from '@osd/i18n'; import { htmlIdGenerator } from '@elastic/eui'; import { DataPublicPluginStart } from '../types'; import { DefaultDslDataSource } from './default_datasource'; +import { DataSourceTypeKey } from './datasource'; -export const DEFAULT_DATASOURCE_TYPE = 'DEFAULT_INDEX_PATTERNS'; +export const DEFAULT_DATASOURCE_TYPE: DataSourceTypeKey = 'DEFAULT_INDEX_PATTERNS'; export const DEFAULT_DATASOURCE_NAME = i18n.translate('data.datasource.type.openSearchDefault', { defaultMessage: 'OpenSearch Default', }); diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 127e3dc720da..726facad30e5 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -434,6 +434,7 @@ export { IndexPatternSelectProps, QueryStringInput, QueryStringInputProps, + DataPublicPluginStartUi, } from './ui'; /** @@ -490,7 +491,6 @@ export { DataPublicPluginSetup, DataPublicPluginStart, IDataPluginServices, - DataPublicPluginStartUi, DataPublicPluginStartActions, } from './types'; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 179b6c0a8c83..edf73dbfbd0d 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -46,9 +46,9 @@ import { } from './types'; import { AutocompleteService } from './autocomplete'; import { SearchService } from './search/search_service'; +import { UiService } from './ui/ui_service'; import { FieldFormatsService } from './field_formats'; import { QueryService } from './query'; -import { createIndexPatternSelect } from './ui/index_pattern_select'; import { IndexPatternsService, onRedirectNoIndexPattern, @@ -63,9 +63,9 @@ import { setOverlays, setQueryService, setSearchService, + setUiService, setUiSettings, } from './services'; -import { createSearchBar } from './ui/search_bar/create_search_bar'; import { opensearchaggs } from './search/expressions'; import { SELECT_RANGE_TRIGGER, @@ -110,12 +110,14 @@ export class DataPublicPlugin > { private readonly autocomplete: AutocompleteService; private readonly searchService: SearchService; + private readonly uiService: UiService; private readonly fieldFormatsService: FieldFormatsService; private readonly queryService: QueryService; private readonly storage: IStorageWrapper; constructor(initializerContext: PluginInitializerContext) { this.searchService = new SearchService(initializerContext); + this.uiService = new UiService(initializerContext); this.queryService = new QueryService(); this.fieldFormatsService = new FieldFormatsService(); this.autocomplete = new AutocompleteService(initializerContext); @@ -159,13 +161,17 @@ export class DataPublicPlugin expressions, }); + const uiService = this.uiService.setup(core, {}); + return { + // TODO: SQL autocomplete: this.autocomplete.setup(core), search: searchService, fieldFormats: this.fieldFormatsService.setup(core), query: queryService, __enhance: (enhancements: DataPublicPluginEnhancements) => { - searchService.__enhance(enhancements.search); + if (enhancements.search) searchService.__enhance(enhancements.search); + if (enhancements.ui) uiService.__enhance(enhancements.ui); }, }; } @@ -234,21 +240,14 @@ export class DataPublicPlugin dataSourceFactory, }, }; - registerDefaultDatasource(dataServices); - const SearchBar = createSearchBar({ - core, - data: dataServices, - storage: this.storage, - }); + const uiService = this.uiService.start(core, { dataServices, storage: this.storage }); + setUiService(uiService); return { ...dataServices, - ui: { - IndexPatternSelect: createIndexPatternSelect(core.savedObjects.client), - SearchBar, - }, + ui: uiService, }; } @@ -256,5 +255,6 @@ export class DataPublicPlugin this.autocomplete.clearProviders(); this.queryService.stop(); this.searchService.stop(); + this.uiService.stop(); } } diff --git a/src/plugins/data/public/search/expressions/opensearchdsl.ts b/src/plugins/data/public/search/expressions/opensearchdsl.ts index 5c8d8350f260..57e014890956 100644 --- a/src/plugins/data/public/search/expressions/opensearchdsl.ts +++ b/src/plugins/data/public/search/expressions/opensearchdsl.ts @@ -28,6 +28,8 @@ * under the License. */ +// TODO: SQL this file seems important + import { i18n } from '@osd/i18n'; import { OpenSearchDashboardsContext, diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 153ac80a249c..f77d7e05c8f9 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -28,6 +28,8 @@ * under the License. */ +// TODO: SQL this file seems important + import { get, trimEnd, debounce } from 'lodash'; import { BehaviorSubject, throwError, timer, defer, from, Observable, NEVER } from 'rxjs'; import { catchError, finalize } from 'rxjs/operators'; @@ -236,6 +238,11 @@ export class SearchInterceptor { }); this.pendingCount$.next(this.pendingCount$.getValue() + 1); + // TODO: SQL this isn't the right place but if core includes SQL then we dont need to do this + // TODO: hack setting to undefined + // console.log(request); + // console.log(options); + return this.runSearch( request, combinedSignal, diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index c73e7881faa6..77e58feac7de 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -57,6 +57,12 @@ import { getShardDelayBucketAgg, } from '../../common/search/aggs/buckets/shard_delay'; import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; +import { + IDataFrame, + IDataFrameResponse, + createDataFrameCache, + dataFrameToSpec, +} from '../../common'; /** @internal */ export interface SearchServiceSetupDependencies { @@ -73,7 +79,9 @@ export interface SearchServiceStartDependencies { export class SearchService implements Plugin { private readonly aggsService = new AggsService(); private readonly searchSourceService = new SearchSourceService(); + private readonly dfCache = createDataFrameCache(); private searchInterceptor!: ISearchInterceptor; + private defaultSearchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; constructor(private initializerContext: PluginInitializerContext) {} @@ -95,6 +103,7 @@ export class SearchService implements Plugin { startServices: getStartServices(), usageCollector: this.usageCollector!, }); + this.defaultSearchInterceptor = this.searchInterceptor; expressions.registerFunction(opensearchdsl); expressions.registerType(opensearchRawResponse); @@ -133,7 +142,9 @@ export class SearchService implements Plugin { getConfig: uiSettings.get.bind(uiSettings), search: < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( request: SearchStrategyRequest, options: ISearchOptions @@ -145,6 +156,19 @@ export class SearchService implements Plugin { callMsearch: getCallMsearch({ http }), loadingCount$, }, + df: { + get: () => this.dfCache.get(), + set: async (dataFrame: IDataFrame) => { + this.dfCache.set(dataFrame); + const dataSet = await indexPatterns.create(dataFrameToSpec(dataFrame), true); + indexPatterns.getIndexPatternCache().set(dataSet.title!, dataSet); + }, + clear: () => { + if (this.dfCache.get() === undefined) return; + indexPatterns.getIndexPatternCache().clear(this.dfCache.get()!.name!); + this.dfCache.clear(); + }, + }, }; return { @@ -154,6 +178,10 @@ export class SearchService implements Plugin { this.searchInterceptor.showError(e); }, searchSource: this.searchSourceService.start(indexPatterns, searchSourceDependencies), + __enhance: (enhancements: SearchEnhancements) => { + this.searchInterceptor = enhancements.searchInterceptor; + }, + getDefaultSearchInterceptor: () => this.defaultSearchInterceptor, }; } diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index 8a0d82b855c8..679c6624bad4 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -78,6 +78,8 @@ export interface ISearchStart { * {@link ISearchStartSearchSource} */ searchSource: ISearchStartSearchSource; + __enhance: (enhancements: SearchEnhancements) => void; + getDefaultSearchInterceptor: () => ISearchInterceptor; } export { SEARCH_EVENT_TYPE } from './collectors'; diff --git a/src/plugins/data/public/services.ts b/src/plugins/data/public/services.ts index 3bcc9d69a9a4..d75dab2986ca 100644 --- a/src/plugins/data/public/services.ts +++ b/src/plugins/data/public/services.ts @@ -59,3 +59,5 @@ export const [getQueryService, setQueryService] = createGetterSetter< export const [getSearchService, setSearchService] = createGetterSetter< DataPublicPluginStart['search'] >('Search'); + +export const [getUiService, setUiService] = createGetterSetter('Ui'); diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 5870ea7def8e..f3ff3f4968d6 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -28,7 +28,6 @@ * under the License. */ -import React from 'react'; import { CoreStart } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; @@ -39,12 +38,14 @@ import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } import { ISearchSetup, ISearchStart, SearchEnhancements } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternsContract } from './index_patterns'; -import { IndexPatternSelectProps, StatefulSearchBarProps } from './ui'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { DataSourceStart } from './data_sources/datasource_services/types'; +import { UiEnhancements } from './ui'; +import { DataPublicPluginStartUi } from './ui/types'; export interface DataPublicPluginEnhancements { - search: SearchEnhancements; + search?: SearchEnhancements; + ui?: UiEnhancements; } export interface DataSetupDependencies { @@ -71,14 +72,6 @@ export interface DataPublicPluginSetup { __enhance: (enhancements: DataPublicPluginEnhancements) => void; } -/** - * Data plugin prewired UI components - */ -export interface DataPublicPluginStartUi { - IndexPatternSelect: React.ComponentType; - SearchBar: React.ComponentType; -} - /** * utilities to generate filters from action context */ diff --git a/src/plugins/data/public/ui/index.ts b/src/plugins/data/public/ui/index.ts index c618df1783b5..8d92ef1f6e3c 100644 --- a/src/plugins/data/public/ui/index.ts +++ b/src/plugins/data/public/ui/index.ts @@ -28,6 +28,7 @@ * under the License. */ +export { UiEnhancements, DataPublicPluginStartUi } from './types'; export { IndexPatternSelectProps } from './index_pattern_select'; export { FilterLabel } from './filter_bar'; export { QueryStringInput, QueryStringInputProps } from './query_string_input'; diff --git a/src/plugins/data/public/ui/index_pattern_select/index_pattern_select.tsx b/src/plugins/data/public/ui/index_pattern_select/index_pattern_select.tsx index 9d2d98591bc9..869e122478f3 100644 --- a/src/plugins/data/public/ui/index_pattern_select/index_pattern_select.tsx +++ b/src/plugins/data/public/ui/index_pattern_select/index_pattern_select.tsx @@ -110,6 +110,18 @@ export default class IndexPatternSelect extends Component { + // if (this.props.df) { + // const df = this.props.df.getDataFrame(); + // if (df && this.isMounted) { + // this.setState({ + // selectedIndexPattern: { + // value: df.name, + // label: df.name, + // }, + // }); + // return; + // } + // } if (!indexPatternId) { this.setState({ selectedIndexPattern: undefined, diff --git a/src/plugins/data/public/ui/query_string_input/_index.scss b/src/plugins/data/public/ui/query_string_input/_index.scss index 8686490016c5..f21b9cbb4327 100644 --- a/src/plugins/data/public/ui/query_string_input/_index.scss +++ b/src/plugins/data/public/ui/query_string_input/_index.scss @@ -1 +1,2 @@ @import "./query_bar"; +@import "./language_switcher" diff --git a/src/plugins/data/public/ui/query_string_input/_language_switcher.scss b/src/plugins/data/public/ui/query_string_input/_language_switcher.scss new file mode 100644 index 000000000000..9ee71b9fc7e2 --- /dev/null +++ b/src/plugins/data/public/ui/query_string_input/_language_switcher.scss @@ -0,0 +1,4 @@ +// From: https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5623 +.languageSwitcher { + max-width: 150px; +} diff --git a/src/plugins/data/public/ui/query_string_input/language_switcher.tsx b/src/plugins/data/public/ui/query_string_input/language_switcher.tsx index 816c21bc0848..43c76ffb010e 100644 --- a/src/plugins/data/public/ui/query_string_input/language_switcher.tsx +++ b/src/plugins/data/public/ui/query_string_input/language_switcher.tsx @@ -28,21 +28,10 @@ * under the License. */ -import { - EuiButtonEmpty, - EuiForm, - EuiFormRow, - EuiLink, - EuiPopover, - EuiPopoverTitle, - EuiSpacer, - EuiSwitch, - EuiText, - PopoverAnchorPosition, -} from '@elastic/eui'; -import { FormattedMessage } from '@osd/i18n/react'; -import React, { useState } from 'react'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { EuiComboBox, EuiComboBoxOptionOption, PopoverAnchorPosition } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; +import { getSearchService, getUiService } from '../../services'; interface Props { language: string; @@ -50,94 +39,70 @@ interface Props { anchorPosition?: PopoverAnchorPosition; } +function mapExternalLanguageToOptions(language: string) { + return { + label: language, + value: language, + }; +} + export function QueryLanguageSwitcher(props: Props) { - const osdDQLDocs = useOpenSearchDashboards().services.docLinks?.links.opensearchDashboards.dql - .base; - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const luceneLabel = ( - - ); - const dqlLabel = ( - - ); - const dqlFullName = ( - - ); + const luceneLabel = i18n.translate('data.query.queryBar.luceneLanguageName', { + defaultMessage: 'Lucene', + }); + const dqlLabel = i18n.translate('data.query.queryBar.dqlLanguageName', { + defaultMessage: 'DQL', + }); + + const languageOptions: EuiComboBoxOptionOption[] = [ + { + label: luceneLabel, + value: 'lucene', + }, + { + label: dqlLabel, + value: 'dql', + }, + ]; - const button = ( - setIsPopoverOpen(!isPopoverOpen)} - className="euiFormControlLayout__append dqlQueryBar__languageSwitcherButton" - data-test-subj={'switchQueryLanguageButton'} - > - {props.language === 'lucene' ? luceneLabel : dqlLabel} - + const queryEnhancements = getUiService().queryEnhancements; + queryEnhancements.forEach((enhancement) => + languageOptions.push(mapExternalLanguageToOptions(enhancement.language)) ); - return ( - setIsPopoverOpen(false)} - repositionOnScroll - > - - - -
- -

- - {dqlFullName} - - ), - }} - /> -

-
+ const selectedLanguage = { + label: props.language === 'kuery' ? 'DQL' : props.language, + }; + + const setSearchEnhance = (queryLanguage: string) => { + const queryEnhancement = queryEnhancements.get(queryLanguage); + const searchService = getSearchService(); + + searchService.__enhance({ + searchInterceptor: queryEnhancement + ? queryEnhancement.search + : searchService.getDefaultSearchInterceptor(), + }); + }; - + const handleLanguageChange = (newLanguage: EuiComboBoxOptionOption[]) => { + const queryLanguage = newLanguage[0].label === 'DQL' ? 'kuery' : newLanguage[0].label; + props.onSelectLanguage(queryLanguage); + setSearchEnhance(queryLanguage); + }; - - - - ) : ( - - ) - } - checked={props.language === 'kuery'} - onChange={() => { - const newLanguage = props.language === 'lucene' ? 'kuery' : 'lucene'; - props.onSelectLanguage(newLanguage); - }} - data-test-subj="languageToggle" - /> - - -
-
+ setSearchEnhance(props.language); + + return ( + ); } diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx index 8c509d573e1b..cd7d7b02fb4d 100644 --- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx @@ -56,12 +56,14 @@ import QueryStringInputUI from './query_string_input'; import { doesKueryExpressionHaveLuceneSyntaxError, UI_SETTINGS } from '../../../common'; import { PersistedLog, getQueryLog } from '../../query'; import { NoDataPopover } from './no_data_popover'; +import { QueryEnhancement } from '../types'; const QueryStringInput = withOpenSearchDashboards(QueryStringInputUI); // @internal export interface QueryBarTopRowProps { query?: Query; + queryEnhancements?: Map; onSubmit: (payload: { dateRange: TimeRange; query?: Query }) => void; onChange: (payload: { dateRange: TimeRange; query?: Query }) => void; onRefresh?: (payload: { dateRange: TimeRange }) => void; @@ -97,6 +99,11 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { const osdDQLDocs: string = docLinks!.links.opensearchDashboards.dql.base; const queryLanguage = props.query && props.query.language; + const queryUiEnhancement = + (queryLanguage && + props.queryEnhancements && + props.queryEnhancements.get(queryLanguage)?.searchBar) || + null; const persistedLog: PersistedLog | undefined = React.useMemo( () => queryLanguage && uiSettings && storage && appName @@ -205,6 +212,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { indexPatterns={props.indexPatterns!} prepend={props.prepend} query={props.query!} + queryEnhancements={props.queryEnhancements} screenTitle={props.screenTitle} onChange={onQueryChange} onChangeQueryInputFocus={onChangeQueryInputFocus} @@ -233,10 +241,15 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { } function shouldRenderDatePicker(): boolean { - return Boolean(props.showDatePicker || props.showAutoRefreshOnly); + return Boolean( + (props.showDatePicker && (queryUiEnhancement?.showDatePicker ?? true)) ?? + (props.showAutoRefreshOnly && (queryUiEnhancement?.showAutoRefreshOnly ?? true)) + ); } function shouldRenderQueryInput(): boolean { + // TODO: SQL probably can modify to not care about index patterns + // TODO: call queryUiEnhancement?.showQueryInput return Boolean(props.showQueryInput && props.indexPatterns && props.query && storage); } diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 5d071748700c..c7e6ff89b390 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -59,10 +59,12 @@ import { QueryLanguageSwitcher } from './language_switcher'; import { PersistedLog, getQueryLog, matchPairs, toUser, fromUser } from '../../query'; import { SuggestionsListSize } from '../typeahead/suggestions_component'; import { SuggestionsComponent } from '..'; +import { QueryEnhancement } from '../types'; export interface QueryStringInputProps { indexPatterns: Array; query: Query; + queryEnhancements?: Map; disableAutoFocus?: boolean; screenTitle?: string; prepend?: any; @@ -108,6 +110,7 @@ const KEY_CODES = { }; // Needed for React.lazy +// TODO: SQL export this and let people extended this // eslint-disable-next-line import/no-default-export export default class QueryStringInputUI extends Component { public state: State = { @@ -129,10 +132,25 @@ export default class QueryStringInputUI extends Component { private componentIsUnmounting = false; private queryBarInputDivRefInstance: RefObject = createRef(); + private getQueryStringInitialValue = (language: string) => { + const input = this.props.queryEnhancements?.get(language)?.searchBar?.queryStringInput; + // TODO: SQL replace with data_source length + if (!input || !input.initialValue || this.state.indexPatterns.length === 0) return ''; + const defaultDataSource = this.state.indexPatterns[0]; + return input.initialValue.replace( + '', + typeof defaultDataSource === 'string' ? defaultDataSource : defaultDataSource.title + ); + }; + private getQueryString = () => { + if (!this.props.query.query) { + return this.getQueryStringInitialValue(this.props.query.language); + } return toUser(this.props.query.query); }; + // TODO: SQL don't do this here? || Fetch data sources private fetchIndexPatterns = async () => { const stringPatterns = this.props.indexPatterns.filter( (indexPattern) => typeof indexPattern === 'string' @@ -457,6 +475,8 @@ export default class QueryStringInputUI extends Component { } }; + // TODO: SQL consider moving language select language of setting search source here + // Should consider creating search source then private onSelectLanguage = (language: 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 @@ -466,9 +486,18 @@ export default class QueryStringInputUI extends Component { }); this.services.storage.set('opensearchDashboards.userQueryLanguage', language); - - const newQuery = { query: '', language }; + // TODO: SQL proof you can modify search bar, consider remove the extra stuff here + // Will work on adding more to search bar of UI service + // const input = this.props.queryEnhancement?.ui?.queryStringInput; + // const submitOnLanguageSelect = input?.submitOnLanguageSelect ?? true; + const newQuery = { + query: this.getQueryStringInitialValue(language), + language, + }; this.onChange(newQuery); + // if (submitOnLanguageSelect) { + // this.onSubmit(newQuery); + // } this.onSubmit(newQuery); }; diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index c739b955ff19..a480a7b34d68 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -41,11 +41,13 @@ import { useSavedQuery } from './lib/use_saved_query'; import { DataPublicPluginStart } from '../../types'; import { Filter, Query, TimeRange } from '../../../common'; import { useQueryStringManager } from './lib/use_query_string_manager'; +import { QueryEnhancement } from '../types'; interface StatefulSearchBarDeps { core: CoreStart; data: Omit; storage: IStorageWrapper; + queryEnhancements: Map; } export type StatefulSearchBarProps = SearchBarOwnProps & { @@ -130,11 +132,12 @@ const overrideDefaultBehaviors = (props: StatefulSearchBarProps) => { return props.useDefaultBehaviors ? {} : props; }; -export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) { +export function createSearchBar({ core, storage, data, queryEnhancements }: StatefulSearchBarDeps) { // 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 } = props; + // Handle queries const onQuerySubmitRef = useRef(props.onQuerySubmit); @@ -148,6 +151,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) query: props.query, queryStringManager: data.query.queryString, }); + const { timeRange, refreshInterval } = useTimefilter({ dateRangeFrom: props.dateRangeFrom, dateRangeTo: props.dateRangeTo, @@ -201,6 +205,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) isRefreshPaused={refreshInterval.pause} filters={filters} query={query} + queryEnhancements={queryEnhancements} onFiltersUpdated={defaultFiltersUpdated(data.query)} onRefreshChange={defaultOnRefreshChange(data.query)} savedQuery={savedQuery} 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 b05b18b6d64e..04550f81fa94 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -47,6 +47,7 @@ import { TimeRange, Query, Filter, IIndexPattern } from '../../../common'; import { FilterBar } from '../filter_bar/filter_bar'; import { SavedQueryMeta, SaveQueryForm } from '../saved_query_form'; import { SavedQueryManagementComponent } from '../saved_query_management'; +import { QueryEnhancement } from '../types'; interface SearchBarInjectedDeps { opensearchDashboards: OpenSearchDashboardsReactContextValue; @@ -78,6 +79,7 @@ export interface SearchBarOwnProps { dateRangeTo?: string; // Query bar - should be in SearchBarInjectedDeps query?: Query; + queryEnhancements: Map; // Show when user has privileges to save showSaveQuery?: boolean; savedQuery?: SavedQuery; @@ -96,6 +98,7 @@ export interface SearchBarOwnProps { export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps; +// TODO: SQL: include query enhancement in state in case make adding data sources at runtime? interface State { isFiltersVisible: boolean; showSaveQueryModal: boolean; @@ -202,6 +205,7 @@ class SearchBarUI extends Component { }; private shouldRenderQueryBar() { + // TODO: SQL handle no index patterns? const showDatePicker = this.props.showDatePicker || this.props.showAutoRefreshOnly; const showQueryInput = this.props.showQueryInput && this.props.indexPatterns && this.state.query; @@ -209,11 +213,14 @@ class SearchBarUI extends Component { } private shouldRenderFilterBar() { + // TODO: SQL handle no index patterns? return ( this.props.showFilterBar && this.props.filters && this.props.indexPatterns && - compact(this.props.indexPatterns).length > 0 + compact(this.props.indexPatterns).length > 0 && + (this.props.queryEnhancements.get(this.state.query?.language!)?.searchBar?.showFilterBar ?? + true) ); } @@ -393,9 +400,11 @@ class SearchBarUI extends Component { let queryBar; if (this.shouldRenderQueryBar()) { + // TODO: SQL make this default query bar top row but this.props.queryEnhancements.get(language) can pass a component queryBar = ( ; + searchBar?: { + showQueryInput?: boolean; + showFilterBar?: boolean; + showDatePicker?: boolean; + showAutoRefreshOnly?: boolean; + queryStringInput?: { + // will replace '' with the data source name + initialValue?: string; + }; + }; +} + +export interface UiEnhancements { + query?: QueryEnhancement; +} + +/** + * Data plugin prewired UI components + */ +export interface DataPublicPluginStartUi { + queryEnhancements: Map; + IndexPatternSelect: React.ComponentType; + SearchBar: React.ComponentType; +} diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts new file mode 100644 index 000000000000..13a444a18372 --- /dev/null +++ b/src/plugins/data/public/ui/ui_service.ts @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { Plugin, CoreSetup, CoreStart, PluginInitializerContext } from 'src/core/public'; +import { DataPublicPluginStartUi, QueryEnhancement, UiEnhancements } from './types'; + +import { ConfigSchema } from '../../config'; +import { createIndexPatternSelect } from './index_pattern_select'; +import { createSearchBar } from './search_bar/create_search_bar'; +import { DataPublicPluginStart } from '../types'; +import { IStorageWrapper } from '../../../opensearch_dashboards_utils/public'; + +/** @internal */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UiServiceSetupDependencies {} + +/** @internal */ +export interface UiServiceStartDependencies { + dataServices: Omit; + storage: IStorageWrapper; +} + +export class UiService implements Plugin { + constructor(private _: PluginInitializerContext) {} + private queryEnhancements: Map = new Map(); + + public setup( + { http, getStartServices, notifications, uiSettings }: CoreSetup, + {}: UiServiceSetupDependencies + ) { + return { + __enhance: (enhancements?: UiEnhancements) => { + if (!enhancements) return; + if (enhancements.query && enhancements.query.language) { + this.queryEnhancements.set(enhancements.query.language, enhancements.query); + } + // if (enhancements.dataSource && enhancements.dataSource.getName()) { + // this.dataSourceEnhancements.set( + // enhancements.dataSource.getName(), + // enhancements.dataSource + // ); + // } + }, + }; + } + + public start(core: CoreStart, { dataServices, storage }: UiServiceStartDependencies) { + const SearchBar = createSearchBar({ + core, + data: dataServices, + storage, + queryEnhancements: this.queryEnhancements, + }); + + return { + queryEnhancements: this.queryEnhancements, + IndexPatternSelect: createIndexPatternSelect(core.savedObjects.client), + SearchBar, + }; + } + + public stop() {} +} diff --git a/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts b/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts index d7cbd48a6507..172acf9f0e2e 100644 --- a/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts +++ b/src/plugins/data/server/search/opensearch_search/get_default_search_params.ts @@ -45,10 +45,14 @@ export async function getDefaultSearchParams(uiSettingsClient: IUiSettingsClient const maxConcurrentShardRequests = await uiSettingsClient.get( UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS ); + const dataFrameHydrationStrategy = await uiSettingsClient.get( + UI_SETTINGS.DATAFRAME_HYDRATION_STRATEGY + ); return { maxConcurrentShardRequests: maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined, ignoreThrottled, + dataFrameHydrationStrategy, ignoreUnavailable: true, // Don't fail if the index/indices don't exist trackTotalHits: true, }; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index b955596922a0..b2173e00085d 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -73,6 +73,12 @@ import { } from '../../common/search/aggs/buckets/shard_delay'; import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; import { ConfigSchema } from '../../config'; +import { + IDataFrame, + IDataFrameResponse, + createDataFrameCache, + dataFrameToSpec, +} from '../../common'; type StrategyMap = Record>; @@ -98,6 +104,7 @@ export interface SearchRouteDependencies { export class SearchService implements Plugin { private readonly aggsService = new AggsService(); private readonly searchSourceService = new SearchSourceService(); + private readonly dfCache = createDataFrameCache(); private defaultSearchStrategyName: string = OPENSEARCH_SEARCH_STRATEGY; private searchStrategies: StrategyMap = {}; @@ -166,7 +173,8 @@ export class SearchService implements Plugin { }); return { - __enhance: (enhancements: SearchEnhancements) => { + __enhance: (enhancements?: SearchEnhancements) => { + if (!enhancements) return; if (this.searchStrategies.hasOwnProperty(enhancements.defaultStrategy)) { this.defaultSearchStrategyName = enhancements.defaultStrategy; } @@ -237,6 +245,19 @@ export class SearchService implements Plugin { }), loadingCount$: new BehaviorSubject(0), }, + df: { + get: () => this.dfCache.get(), + set: async (dataFrame: IDataFrame) => { + this.dfCache.set(dataFrame); + const dataSet = await scopedIndexPatterns.create(dataFrameToSpec(dataFrame), true); + scopedIndexPatterns.getIndexPatternCache().set(dataSet.title!, dataSet); + }, + clear: () => { + if (this.dfCache.get() === undefined) return; + scopedIndexPatterns.getIndexPatternCache().clear(this.dfCache.get()!.name!); + this.dfCache.clear(); + }, + }, }; return this.searchSourceService.start(scopedIndexPatterns, searchSourceDependencies); @@ -251,7 +272,9 @@ export class SearchService implements Plugin { private registerSearchStrategy = < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( name: string, strategy: ISearchStrategy @@ -261,7 +284,9 @@ export class SearchService implements Plugin { private search = < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( context: RequestHandlerContext, searchRequest: SearchStrategyRequest, @@ -274,7 +299,9 @@ export class SearchService implements Plugin { private getSearchStrategy = < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( name: string ): ISearchStrategy => { diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 75f21d39c0bf..6927d1289673 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -38,6 +38,7 @@ import { import { AggsSetup, AggsStart } from './aggs'; import { SearchUsage } from './collectors'; import { IOpenSearchSearchRequest, IOpenSearchSearchResponse } from './opensearch_search'; +import { IDataFrameResponse } from '../../common'; export interface SearchEnhancements { defaultStrategy: string; @@ -51,7 +52,9 @@ export interface ISearchSetup { */ registerSearchStrategy: < SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse >( name: string, strategy: ISearchStrategy @@ -96,7 +99,9 @@ export interface ISearchStart< */ export interface ISearchStrategy< SearchStrategyRequest extends IOpenSearchDashboardsSearchRequest = IOpenSearchSearchRequest, - SearchStrategyResponse extends IOpenSearchDashboardsSearchResponse = IOpenSearchSearchResponse + SearchStrategyResponse extends + | IOpenSearchDashboardsSearchResponse + | IDataFrameResponse = IOpenSearchSearchResponse > { search: ( context: RequestHandlerContext, diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index 77f4afd11887..76a46eb148b5 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -55,6 +55,21 @@ const requestPreferenceOptionLabels = { }), }; +const dataFrameHydrationStrategyOptionLabels = { + perSource: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyPerSourceText', { + defaultMessage: 'On data source change', + }), + perQuery: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyPerQueryText', { + defaultMessage: 'Per query', + }), + perResponse: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyPerResponseText', { + defaultMessage: 'Per response', + }), + advanced: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyAdvancedText', { + defaultMessage: 'Advanced', + }), +}; + // We add the `en` key manually here, since that's not a real numeral locale, but the // default fallback in case the locale is not found. const numeralLanguageIds = [ @@ -690,5 +705,36 @@ export function getUiSettings(): Record> { }), schema: schema.boolean(), }, + [UI_SETTINGS.DATAFRAME_HYDRATION_STRATEGY]: { + name: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyTitle', { + defaultMessage: 'Data frame hydration strategy', + }), + value: 'perSource', + // TODO: SQL does PPL/SQL support this ? Where if the schema contains all fields but nulls out the values that are not present? + options: ['perSource', 'perQuery'], + optionLabels: dataFrameHydrationStrategyOptionLabels, + type: 'select', + description: i18n.translate('data.advancedSettings.dataFrameHydrationStrategyText', { + defaultMessage: `Allows you to set how often the data frame schema is updated. +
    +
  • {perSource}: hydrates the schema when the data source changes. + For example, any time the index pattern is change the data frame schema is hydrated.
  • +
  • {perQuery}: hydrates the schema per query to the data source. + Could be expensive, but ensures the schema of the data frame fits the result set.
  • +
  • {perResponse}: hydrates the schema if the data source returns a schema. + Not Implemented.
  • +
  • {advanced}: hydrates the schema in intervals. If the schema hasn't changed the interval increases. + If the schema has changed the interval resets. Not Implemented.
  • +
`, + values: { + perSource: dataFrameHydrationStrategyOptionLabels.perSource, + perQuery: dataFrameHydrationStrategyOptionLabels.perQuery, + perResponse: dataFrameHydrationStrategyOptionLabels.perResponse, + advanced: dataFrameHydrationStrategyOptionLabels.advanced, + }, + }), + category: ['search'], + schema: schema.string(), + }, }; } diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx index b7aa9cf7b36e..0436804501f8 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx @@ -46,6 +46,7 @@ import { IndexPatternField, IndexPattern } from '../../../../../data/public'; import { shortenDottedString } from '../../helpers'; import { getFieldTypeName } from './lib/get_field_type_name'; import './discover_field.scss'; +import { DiscoverFieldEdit } from './discover_field_edit'; export interface DiscoverFieldProps { /** @@ -113,9 +114,14 @@ export const DiscoverField = ({ defaultMessage: 'View {field} summary', values: { field: field.name }, }); + const editLabelAria = i18n.translate('discover.fieldChooser.discoverField.editButtonAriaLabel', { + defaultMessage: 'Edit {field}', + values: { field: field.name }, + }); const isSourceField = field.name === '_source'; const [infoIsOpen, setOpen] = useState(false); + const [editIsOpen, setEditIsOpen] = useState(false); const toggleDisplay = (f: IndexPatternField) => { if (selected) { @@ -244,6 +250,43 @@ export const DiscoverField = ({ )} + {!isSourceField && indexPattern.id === 'data_frame' && ( + + setEditIsOpen(false)} + anchorPosition="rightUp" + button={ + setEditIsOpen((state) => !state)} + aria-label={editLabelAria} + data-test-subj={`field-${field.name}-showEdit`} + className="dscSidebarField__actionButton" + /> + } + panelClassName="dscSidebarItem__fieldPopoverPanel" + > + + {' '} + {i18n.translate('discover.fieldChooser.discoverField.editFieldLabel', { + defaultMessage: 'Edit field', + })} + + {editIsOpen && ( + + )} + + + )} {!isSourceField && {actionButton}} ); diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx new file mode 100644 index 000000000000..23fedfee7b9c --- /dev/null +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import React, { useState } from 'react'; +import { EuiText, EuiSelect } from '@elastic/eui'; +import { FieldDetails } from './types'; +import { IndexPatternField, IndexPattern, OSD_FIELD_TYPES } from '../../../../../data/public'; + +interface DiscoverFieldEditProps { + columns: string[]; + details: FieldDetails; + field: IndexPatternField; + indexPattern: IndexPattern; +} + +export function DiscoverFieldEdit({ + columns, + details, + field, + indexPattern, +}: DiscoverFieldEditProps) { + const options = Object.keys(OSD_FIELD_TYPES).map((fieldType) => ({ + value: fieldType.toLowerCase(), + text: fieldType, + })); + options.unshift({ value: 'unknown', text: 'UNKNOWN' }); + const [value, setValue] = useState(field.type.toLowerCase()); + + return ( + <> +
+ {details.error && ( + + {details.error} + + )} + + {!details.error && ( +
+ { + setValue(e.target.value); + // TODO: Handle the selected type + }} + /> +
+ )} +
+ + ); +} diff --git a/src/plugins/discover/public/application/view_components/panel/index.tsx b/src/plugins/discover/public/application/view_components/panel/index.tsx index 6b4cd2a87c91..8a6920ace3e7 100644 --- a/src/plugins/discover/public/application/view_components/panel/index.tsx +++ b/src/plugins/discover/public/application/view_components/panel/index.tsx @@ -92,8 +92,12 @@ export default function DiscoverPanel(props: ViewProps) { fieldCounts={fetchState.fieldCounts || {}} hits={fetchState.rows || []} onAddField={(fieldName, index) => { - if (indexPattern && capabilities.discover?.save) { - popularizeField(indexPattern, fieldName, indexPatterns); + const dataSet = + fetchState.title && fetchState.title !== indexPattern?.title + ? indexPatterns.getIndexPatternCache().get(fetchState.title!) + : indexPattern; + if (dataSet && capabilities.discover?.save) { + popularizeField(dataSet!, fieldName, indexPatterns); } dispatch( @@ -104,8 +108,12 @@ export default function DiscoverPanel(props: ViewProps) { ); }} onRemoveField={(fieldName) => { - if (indexPattern && capabilities.discover?.save) { - popularizeField(indexPattern, fieldName, indexPatterns); + const dataSet = + fetchState.title && fetchState.title !== indexPattern?.title + ? indexPatterns.getIndexPatternCache().get(fetchState.title!) + : indexPattern; + if (dataSet && capabilities.discover?.save) { + popularizeField(dataSet!, fieldName, indexPatterns); } dispatch(removeColumn(fieldName)); @@ -118,7 +126,11 @@ export default function DiscoverPanel(props: ViewProps) { }) ); }} - selectedIndexPattern={indexPattern} + selectedIndexPattern={ + fetchState.title && fetchState.title !== indexPattern?.title + ? indexPatterns.getIndexPatternCache().get(fetchState.title!) + : indexPattern + } onAddFilter={onAddFilter} /> ); diff --git a/src/plugins/discover/public/application/view_components/utils/update_search_source.ts b/src/plugins/discover/public/application/view_components/utils/update_search_source.ts index 1404773eb9d4..b8a11e012d34 100644 --- a/src/plugins/discover/public/application/view_components/utils/update_search_source.ts +++ b/src/plugins/discover/public/application/view_components/utils/update_search_source.ts @@ -30,9 +30,19 @@ export const updateSearchSource = async ({ histogramConfigs, }: Props) => { const { uiSettings, data } = services; + let dataSet = indexPattern; + if ( + searchSource && + searchSource.getDataFrame() && + dataSet.title !== searchSource.getDataFrame()?.name + ) { + dataSet = await data.indexPatterns.get(searchSource.getDataFrame()?.name!); + searchSource.setField('index', dataSet); + } + const sortForSearchSource = getSortForSearchSource( sort, - indexPattern, + dataSet, uiSettings.get(SORT_DEFAULT_ORDER_SETTING) ); const size = uiSettings.get(SAMPLE_SIZE_SETTING); @@ -43,18 +53,18 @@ export const updateSearchSource = async ({ // searchSource which applies time range const timeRangeSearchSource = await data.search.searchSource.create(); const { isDefault } = indexPatternUtils; - if (isDefault(indexPattern)) { + if (isDefault(dataSet)) { const timefilter = data.query.timefilter.timefilter; timeRangeSearchSource.setField('filter', () => { - return timefilter.createFilter(indexPattern); + return timefilter.createFilter(dataSet); }); } searchSourceInstance.setParent(timeRangeSearchSource); searchSourceInstance.setFields({ - index: indexPattern, + index: dataSet, sort: sortForSearchSource, size, query: data.query.queryString.getQuery() || null, 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 94e415b21111..eca92353719b 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 @@ -49,6 +49,7 @@ export interface SearchData { rows?: OpenSearchSearchHit[]; bucketInterval?: TimechartHeaderBucketInterval | {}; chartData?: Chart; + title?: string; } export type SearchRefetch = 'refetch' | undefined; @@ -115,13 +116,15 @@ export const useSearch = (services: DiscoverViewServices) => { const refetch$ = useMemo(() => new Subject(), []); const fetch = useCallback(async () => { - if (!indexPattern) { + let dataSet = indexPattern; + if (!dataSet) { data$.next({ status: shouldSearchOnPageLoad() ? ResultStatus.LOADING : ResultStatus.UNINITIALIZED, }); return; } + // TODO: SQL disable this check BASED on ui service if (!validateTimeRange(timefilter.getTime(), toastNotifications)) { return data$.next({ status: ResultStatus.NO_RESULTS, @@ -132,17 +135,19 @@ export const useSearch = (services: DiscoverViewServices) => { // Abort any in-progress requests before fetching again if (fetchStateRef.current.abortController) fetchStateRef.current.abortController.abort(); fetchStateRef.current.abortController = new AbortController(); - const histogramConfigs = indexPattern.timeFieldName - ? createHistogramConfigs(indexPattern, interval || 'auto', data) + const histogramConfigs = dataSet.timeFieldName + ? createHistogramConfigs(dataSet, interval || 'auto', data) : undefined; const searchSource = await updateSearchSource({ - indexPattern, + indexPattern: dataSet, services, sort, searchSource: savedSearch?.searchSource, histogramConfigs, }); + dataSet = searchSource.getField('index'); + try { // Only show loading indicator if we are fetching when the rows are empty if (fetchStateRef.current.rows?.length === 0) { @@ -159,7 +164,7 @@ export const useSearch = (services: DiscoverViewServices) => { }); const inspectorRequest = inspectorAdapters.requests.start(title, { description }); inspectorRequest.stats(getRequestInspectorStats(searchSource)); - searchSource.getSearchRequestBody().then((body) => { + searchSource.getSearchRequestBody().then((body: object) => { inspectorRequest.json(body); }); @@ -177,7 +182,7 @@ export const useSearch = (services: DiscoverViewServices) => { let bucketInterval = {}; let chartData; for (const row of rows) { - const fields = Object.keys(indexPattern.flattenHit(row)); + const fields = Object.keys(dataSet!.flattenHit(row)); for (const fieldName of fields) { fetchStateRef.current.fieldCounts[fieldName] = (fetchStateRef.current.fieldCounts[fieldName] || 0) + 1; @@ -206,6 +211,10 @@ export const useSearch = (services: DiscoverViewServices) => { rows, bucketInterval, chartData, + title: + indexPattern?.title !== searchSource.getDataFrame()?.name + ? searchSource.getDataFrame()?.name + : indexPattern?.title, }); } catch (error) { // If the request was aborted then no need to surface this error in the UI diff --git a/yarn.lock b/yarn.lock index 1e6f3635138d..50061aad092e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1486,12 +1486,9 @@ utility-types "^3.10.0" uuid "^3.3.2" -"@elastic/datemath@5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@elastic/datemath/-/datemath-5.0.3.tgz#7baccdab672b9a3ecb7fe8387580670936b58573" - integrity sha512-8Hbr1Uyjm5OcYBfEB60K7sCP6U3IXuWDaLaQmYv3UxgI4jqBWbakoemwWvsqPVUvnwEjuX6z7ghPZbefs8xiaA== - dependencies: - tslib "^1.9.3" +"@elastic/datemath@link:packages/opensearch-datemath": + version "0.0.0" + uid "" "@elastic/ecs-helpers@^1.1.0": version "1.1.0" From c304b37f97f2cbd13d4319fe7151e25d111f55af Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Mon, 22 Apr 2024 20:07:48 +0000 Subject: [PATCH 2/4] clean up Signed-off-by: Kawika Avilla --- config/opensearch_dashboards.yml | 2 -- .../data/public/data_sources/register_default_datasource.ts | 3 +-- src/plugins/data/public/search/expressions/opensearchdsl.ts | 2 -- src/plugins/data/public/search/search_interceptor.ts | 5 ----- .../public/application/view_components/utils/use_search.ts | 1 + 5 files changed, 2 insertions(+), 11 deletions(-) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index 91a048b00760..40d643b014fd 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -313,5 +313,3 @@ # Set the value to true to enable workspace feature # workspace.enabled: false -opensearch_alerting.enabled: false -opensearch_security.enabled: false diff --git a/src/plugins/data/public/data_sources/register_default_datasource.ts b/src/plugins/data/public/data_sources/register_default_datasource.ts index 967cc0a55dd8..a4198b4e8e3a 100644 --- a/src/plugins/data/public/data_sources/register_default_datasource.ts +++ b/src/plugins/data/public/data_sources/register_default_datasource.ts @@ -7,9 +7,8 @@ import { i18n } from '@osd/i18n'; import { htmlIdGenerator } from '@elastic/eui'; import { DataPublicPluginStart } from '../types'; import { DefaultDslDataSource } from './default_datasource'; -import { DataSourceTypeKey } from './datasource'; -export const DEFAULT_DATASOURCE_TYPE: DataSourceTypeKey = 'DEFAULT_INDEX_PATTERNS'; +export const DEFAULT_DATASOURCE_TYPE = 'DEFAULT_INDEX_PATTERNS'; export const DEFAULT_DATASOURCE_NAME = i18n.translate('data.datasource.type.openSearchDefault', { defaultMessage: 'OpenSearch Default', }); diff --git a/src/plugins/data/public/search/expressions/opensearchdsl.ts b/src/plugins/data/public/search/expressions/opensearchdsl.ts index 57e014890956..5c8d8350f260 100644 --- a/src/plugins/data/public/search/expressions/opensearchdsl.ts +++ b/src/plugins/data/public/search/expressions/opensearchdsl.ts @@ -28,8 +28,6 @@ * under the License. */ -// TODO: SQL this file seems important - import { i18n } from '@osd/i18n'; import { OpenSearchDashboardsContext, diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index f77d7e05c8f9..adb02450d609 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -238,11 +238,6 @@ export class SearchInterceptor { }); this.pendingCount$.next(this.pendingCount$.getValue() + 1); - // TODO: SQL this isn't the right place but if core includes SQL then we dont need to do this - // TODO: hack setting to undefined - // console.log(request); - // console.log(options); - return this.runSearch( request, combinedSignal, 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 eca92353719b..5e15186e0c2a 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 @@ -82,6 +82,7 @@ export const useSearch = (services: DiscoverViewServices) => { core, toastNotifications, osdUrlStateStorage, + chrome, } = services; const timefilter = data.query.timefilter.timefilter; const fetchStateRef = useRef<{ From 07697fa030221dbef2dbf4231382d5b76d374b69 Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Mon, 22 Apr 2024 20:10:04 +0000 Subject: [PATCH 3/4] more clean up Signed-off-by: Kawika Avilla --- .../opensearch_query/from_sql.ts | 21 ------------------- src/plugins/data/public/ui/ui_service.ts | 6 ------ 2 files changed, 27 deletions(-) delete mode 100644 src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts b/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts deleted file mode 100644 index 9d802bc95e3c..000000000000 --- a/src/plugins/data/common/opensearch_query/opensearch_query/from_sql.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { decorateQuery } from './decorate_query'; -import { getIndexPatternFromSql, sqlStringToDsl } from './sql_string_to_dsl'; -import { Query } from '../../query/types'; - -export function buildQueryFromSql(queries: Query[], dateFormatTZ?: string) { - const combinedQueries = (queries || []).map((query) => { - const indexPattern = getIndexPatternFromSql(query.query); - const queryDsl = sqlStringToDsl(query.query); - - return decorateQuery(queryDsl, indexPattern, dateFormatTZ); - }); - - return { - combinedQueries, - }; -} diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 13a444a18372..84bdf67daaf8 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -42,12 +42,6 @@ export class UiService implements Plugin { if (enhancements.query && enhancements.query.language) { this.queryEnhancements.set(enhancements.query.language, enhancements.query); } - // if (enhancements.dataSource && enhancements.dataSource.getName()) { - // this.dataSourceEnhancements.set( - // enhancements.dataSource.getName(), - // enhancements.dataSource - // ); - // } }, }; } From 867a1f5995c1d49c81f41d8df9a805dcf5e09be9 Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Mon, 22 Apr 2024 20:14:54 +0000 Subject: [PATCH 4/4] clean up licenses Signed-off-by: Kawika Avilla --- .../data/common/data_frames/_df_cache.ts | 8 +------ .../data/common/data_frames/fields/index.ts | 8 +------ .../data/common/data_frames/fields/types.ts | 8 +------ src/plugins/data/common/data_frames/index.ts | 8 +------ src/plugins/data/common/data_frames/types.ts | 8 +------ src/plugins/data/common/data_frames/utils.ts | 8 +------ .../opensearch_query/sql_string_to_dsl.ts | 23 ------------------- src/plugins/data/public/ui/types.ts | 11 ++------- src/plugins/data/public/ui/ui_service.ts | 8 +------ .../sidebar/discover_field_edit.tsx | 8 +------ 10 files changed, 10 insertions(+), 88 deletions(-) delete mode 100644 src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts diff --git a/src/plugins/data/common/data_frames/_df_cache.ts b/src/plugins/data/common/data_frames/_df_cache.ts index 2cec9ccc4fab..177f26840874 100644 --- a/src/plugins/data/common/data_frames/_df_cache.ts +++ b/src/plugins/data/common/data_frames/_df_cache.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ import { IDataFrame } from '..'; diff --git a/src/plugins/data/common/data_frames/fields/index.ts b/src/plugins/data/common/data_frames/fields/index.ts index a2d334e05ba7..9f269633f307 100644 --- a/src/plugins/data/common/data_frames/fields/index.ts +++ b/src/plugins/data/common/data_frames/fields/index.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ export * from './types'; diff --git a/src/plugins/data/common/data_frames/fields/types.ts b/src/plugins/data/common/data_frames/fields/types.ts index d433f3b02a81..47144c0c0198 100644 --- a/src/plugins/data/common/data_frames/fields/types.ts +++ b/src/plugins/data/common/data_frames/fields/types.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ export interface IFieldType { diff --git a/src/plugins/data/common/data_frames/index.ts b/src/plugins/data/common/data_frames/index.ts index 2668d0d813d1..8b6a31eaea68 100644 --- a/src/plugins/data/common/data_frames/index.ts +++ b/src/plugins/data/common/data_frames/index.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ export * from './types'; diff --git a/src/plugins/data/common/data_frames/types.ts b/src/plugins/data/common/data_frames/types.ts index 551243e3b405..ce845281c7c7 100644 --- a/src/plugins/data/common/data_frames/types.ts +++ b/src/plugins/data/common/data_frames/types.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ import { IFieldType } from './fields'; diff --git a/src/plugins/data/common/data_frames/utils.ts b/src/plugins/data/common/data_frames/utils.ts index acc23a4d3c56..591be5c268e4 100644 --- a/src/plugins/data/common/data_frames/utils.ts +++ b/src/plugins/data/common/data_frames/utils.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ import { SearchResponse } from 'elasticsearch'; diff --git a/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts b/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts deleted file mode 100644 index 19cdca1945dc..000000000000 --- a/src/plugins/data/common/opensearch_query/opensearch_query/sql_string_to_dsl.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { isString } from 'lodash'; -import { DslQuery } from './opensearch_query_dsl'; - -export function getIndexPatternFromSql(query: string | any) { - const from = query.match(new RegExp(/FROM\s+([\w*-.!@$^()~;]+)/, 'i')); - if (from) { - return from[1]; - } - return ''; -} - -export function sqlStringToDsl(query: string | any): DslQuery { - if (isString(query)) { - return { query_string: { query } }; - } - - return query; -} diff --git a/src/plugins/data/public/ui/types.ts b/src/plugins/data/public/ui/types.ts index 3403629f5d99..6ea748a42888 100644 --- a/src/plugins/data/public/ui/types.ts +++ b/src/plugins/data/public/ui/types.ts @@ -1,15 +1,8 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ -import { GenericDataSource } from '../data_sources/datasource_services'; import { SearchInterceptor } from '../search'; import { IndexPatternSelectProps } from './index_pattern_select'; import { StatefulSearchBarProps } from './search_bar'; @@ -20,7 +13,7 @@ export interface QueryEnhancement { language: string; search: SearchInterceptor; // Leave blank to support all data sources - supportedDataSourceTypes?: Record; + // supportedDataSourceTypes?: Record; searchBar?: { showQueryInput?: boolean; showFilterBar?: boolean; diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 84bdf67daaf8..59ab47e8d607 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ import { Plugin, CoreSetup, CoreStart, PluginInitializerContext } from 'src/core/public'; diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx index 23fedfee7b9c..77aeb425a6c0 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_edit.tsx @@ -1,12 +1,6 @@ /* + * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. */ import React, { useState } from 'react';