From 40f319db2cfdf9153c1a7e659f2f7d56929329b0 Mon Sep 17 00:00:00 2001 From: Clint Andrew Hall Date: Mon, 2 Aug 2021 14:20:12 -0400 Subject: [PATCH] Create Expression Factories; remove legacy search service --- .../functions/browser/escount.ts | 152 ++++++----- .../functions/browser/esdocs.ts | 251 +++++++++++------- .../functions/browser/essql.ts | 189 ++++++++----- .../functions/browser/index.ts | 18 +- .../canvas/canvas_plugin_src/plugin.ts | 10 +- .../canvas/i18n/functions/dict/escount.ts | 35 --- .../canvas/i18n/functions/dict/esdocs.ts | 59 ---- .../canvas/i18n/functions/dict/essql.ts | 49 ---- .../canvas/i18n/functions/function_help.ts | 14 +- x-pack/plugins/canvas/public/application.tsx | 24 +- x-pack/plugins/canvas/public/index.ts | 10 +- x-pack/plugins/canvas/public/plugin_api.ts | 15 +- .../plugins/canvas/public/services/index.ts | 2 - .../canvas/public/services/legacy/context.tsx | 44 --- .../canvas/public/services/legacy/index.ts | 96 ------- .../public/services/legacy/reporting.ts | 42 --- .../canvas/public/services/legacy/search.ts | 24 -- .../public/services/legacy/stubs/index.ts | 21 -- .../public/services/legacy/stubs/search.ts | 11 - .../canvas/public/services/stubs/index.ts | 2 - .../canvas/storybook/decorators/index.ts | 3 +- .../decorators/services_decorator.tsx | 7 - x-pack/plugins/canvas/types/expressions.ts | 19 ++ x-pack/plugins/canvas/types/index.ts | 1 + 24 files changed, 414 insertions(+), 684 deletions(-) delete mode 100644 x-pack/plugins/canvas/i18n/functions/dict/escount.ts delete mode 100644 x-pack/plugins/canvas/i18n/functions/dict/esdocs.ts delete mode 100644 x-pack/plugins/canvas/i18n/functions/dict/essql.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/context.tsx delete mode 100644 x-pack/plugins/canvas/public/services/legacy/index.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/reporting.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/search.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/stubs/index.ts delete mode 100644 x-pack/plugins/canvas/public/services/legacy/stubs/search.ts create mode 100644 x-pack/plugins/canvas/types/expressions.ts diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts index 97aa934280414..cd6d87e140123 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/escount.ts @@ -9,86 +9,110 @@ import { ExpressionFunctionDefinition, ExpressionValueFilter, } from 'src/plugins/expressions/common'; +import { i18n } from '@kbn/i18n'; + +import { StartDeps } from '../../../canvas_plugin_src/plugin'; +import { ExpressionFunctionDefinitionFactory } from '../../../types'; +import { ELASTICSEARCH, LUCENE } from '../../../i18n/constants'; // @ts-expect-error untyped local import { buildESRequest } from '../../../common/lib/request/build_es_request'; -import { searchService } from '../../../public/services'; - -import { getFunctionHelp } from '../../../i18n'; - -interface Arguments { +export interface Arguments { index: string | null; query: string; } -export function escount(): ExpressionFunctionDefinition< - 'escount', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().escount; - - return { - name: 'escount', - type: 'number', - context: { - types: ['filter'], +const strings = { + help: i18n.translate('xpack.canvas.functions.escountHelpText', { + defaultMessage: 'Query {ELASTICSEARCH} for the number of hits matching the specified query.', + values: { + ELASTICSEARCH, }, - help, - args: { - query: { - types: ['string'], - aliases: ['_', 'q'], - help: argHelp.query, - default: '"-_index:.kibana"', + }), + args: { + query: i18n.translate('xpack.canvas.functions.escount.args.queryHelpText', { + defaultMessage: 'A {LUCENE} query string.', + values: { + LUCENE, }, - index: { - types: ['string'], - default: '_all', - help: argHelp.index, + }), + index: i18n.translate('xpack.canvas.functions.escount.args.indexHelpText', { + defaultMessage: 'An index or index pattern. For example, {example}.', + values: { + example: '`"logstash-*"`', }, - }, - fn: (input, args, handlers) => { - input.and = input.and.concat([ - { - type: 'filter', - filterType: 'luceneQueryString', - query: args.query, - and: [], + }), + }, +}; + +type Fn = ExpressionFunctionDefinition<'escount', ExpressionValueFilter, Arguments, any>; + +export const escountFactory: ExpressionFunctionDefinitionFactory = ({ + startPlugins, +}) => { + return function escount(): Fn { + const { help, args: argHelp } = strings; + + return { + name: 'escount', + type: 'number', + context: { + types: ['filter'], + }, + help, + args: { + query: { + types: ['string'], + aliases: ['_', 'q'], + help: argHelp.query, + default: '"-_index:.kibana"', }, - ]); + index: { + types: ['string'], + default: '_all', + help: argHelp.index, + }, + }, + fn: (input, args, _handlers) => { + input.and = input.and.concat([ + { + type: 'filter', + filterType: 'luceneQueryString', + query: args.query, + and: [], + }, + ]); - const esRequest = buildESRequest( - { - index: args.index, - body: { - track_total_hits: true, - size: 0, - query: { - bool: { - must: [{ match_all: {} }], + const esRequest = buildESRequest( + { + index: args.index, + body: { + track_total_hits: true, + size: 0, + query: { + bool: { + must: [{ match_all: {} }], + }, }, }, }, - }, - input - ); + input + ); - const search = searchService.getService().search; - const req = { - params: { - ...esRequest, - }, - }; + const { search } = startPlugins.data.search; + const req = { + params: { + ...esRequest, + }, + }; - return search - .search(req) - .toPromise() - .then((resp: any) => { - return resp.rawResponse.hits.total; - }); - }, + return search(req) + .toPromise() + .then((resp: any) => { + return resp.rawResponse.hits.total; + }); + }, + }; }; -} +}; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts index c40e1ffd62439..84e5170cd1b90 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/esdocs.ts @@ -9,16 +9,18 @@ import { ExpressionFunctionDefinition, ExpressionValueFilter, } from 'src/plugins/expressions/common'; +import { i18n } from '@kbn/i18n'; // @ts-expect-error untyped local import { buildESRequest } from '../../../common/lib/request/build_es_request'; -import { searchService } from '../../../public/services'; +import { StartDeps } from '../../../canvas_plugin_src/plugin'; +import { ExpressionFunctionDefinitionFactory } from '../../../types'; import { ESSQL_SEARCH_STRATEGY } from '../../../common/lib/constants'; import { EssqlSearchStrategyRequest, EssqlSearchStrategyResponse } from '../../../types'; -import { getFunctionHelp } from '../../../i18n'; +import { ELASTICSEARCH, LUCENE } from '../../../i18n/constants'; -interface Arguments { +export interface Arguments { index: string; query: string; sort: string; @@ -27,115 +29,162 @@ interface Arguments { count: number; } -export function esdocs(): ExpressionFunctionDefinition< - 'esdocs', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().esdocs; - - return { - name: 'esdocs', - type: 'datatable', - context: { - types: ['filter'], +const strings = { + help: i18n.translate('xpack.canvas.functions.esdocsHelpText', { + defaultMessage: + 'Query {ELASTICSEARCH} for raw documents. Specify the fields you want to retrieve, ' + + 'especially if you are asking for a lot of rows.', + values: { + ELASTICSEARCH, }, - help, - args: { - query: { - types: ['string'], - aliases: ['_', 'q'], - help: argHelp.query, - default: '-_index:.kibana', - }, - count: { - types: ['number'], - default: 1000, - help: argHelp.count, + }), + args: { + query: i18n.translate('xpack.canvas.functions.esdocs.args.queryHelpText', { + defaultMessage: 'A {LUCENE} query string.', + values: { + LUCENE, }, - fields: { - help: argHelp.fields, - types: ['string'], + }), + count: i18n.translate('xpack.canvas.functions.esdocs.args.countHelpText', { + defaultMessage: + 'The number of documents to retrieve. For better performance, use a smaller data set.', + }), + fields: i18n.translate('xpack.canvas.functions.esdocs.args.fieldsHelpText', { + defaultMessage: 'A comma-separated list of fields. For better performance, use fewer fields.', + }), + index: i18n.translate('xpack.canvas.functions.esdocs.args.indexHelpText', { + defaultMessage: 'An index or index pattern. For example, {example}.', + values: { + example: '`"logstash-*"`', }, - index: { - types: ['string'], - default: '_all', - help: argHelp.index, + }), + metaFields: i18n.translate('xpack.canvas.functions.esdocs.args.metaFieldsHelpText', { + defaultMessage: 'Comma separated list of meta fields. For example, {example}.', + values: { + example: '`"_index,_type"`', }, - // TODO: This arg isn't being used in the function. - // We need to restore this functionality or remove it as an arg. - metaFields: { - help: argHelp.metaFields, - types: ['string'], + }), + sort: i18n.translate('xpack.canvas.functions.esdocs.args.sortHelpText', { + defaultMessage: + 'The sort direction formatted as {directions}. For example, {example1} or {example2}.', + values: { + directions: `\`"${['field', 'direction'].join(', ')}"\``, + example1: `\`"${['@timestamp', 'desc'].join(', ')}"\``, + example2: `\`"${['bytes', 'asc'].join(', ')}"\``, }, - sort: { - types: ['string'], - help: argHelp.sort, + }), + }, +}; + +type Fn = ExpressionFunctionDefinition<'esdocs', ExpressionValueFilter, Arguments, any>; + +export const esdocsFactory: ExpressionFunctionDefinitionFactory = ({ + startPlugins, +}) => { + return function esdocs(): Fn { + const { help, args: argHelp } = strings; + + return { + name: 'esdocs', + type: 'datatable', + context: { + types: ['filter'], }, - }, - fn: async (input, args, handlers) => { - const { count, index, fields, sort } = args; - - input.and = input.and.concat([ - { - type: 'filter', - filterType: 'luceneQueryString', - query: args.query, - and: [], + help, + args: { + query: { + types: ['string'], + aliases: ['_', 'q'], + help: argHelp.query, + default: '-_index:.kibana', + }, + count: { + types: ['number'], + default: 1000, + help: argHelp.count, }, - ]); - - // Load ad-hoc to avoid adding to the page load bundle size - const squel = await import('safe-squel'); - - let query = squel.select({ - autoQuoteTableNames: true, - autoQuoteFieldNames: true, - autoQuoteAliasNames: true, - nameQuoteCharacter: '"', - }); - - if (index) { - query.from(index); - } - - if (fields) { - const allFields = fields.split(',').map((field) => field.trim()); - allFields.forEach((field) => (query = query.field(field))); - } - - if (sort) { - const [sortField, sortOrder] = sort.split(',').map((str) => str.trim()); - if (sortField) { - query.order(`"${sortField}"`, sortOrder === 'asc'); + fields: { + help: argHelp.fields, + types: ['string'], + }, + index: { + types: ['string'], + default: '_all', + help: argHelp.index, + }, + // TODO: This arg isn't being used in the function. + // We need to restore this functionality or remove it as an arg. + metaFields: { + help: argHelp.metaFields, + types: ['string'], + }, + sort: { + types: ['string'], + help: argHelp.sort, + }, + }, + fn: async (input, args, handlers) => { + const { count, index, fields, sort } = args; + + input.and = input.and.concat([ + { + type: 'filter', + filterType: 'luceneQueryString', + query: args.query, + and: [], + }, + ]); + + // Load ad-hoc to avoid adding to the page load bundle size + const squel = await import('safe-squel'); + + let query = squel.select({ + autoQuoteTableNames: true, + autoQuoteFieldNames: true, + autoQuoteAliasNames: true, + nameQuoteCharacter: '"', + }); + + if (index) { + query.from(index); + } + + if (fields) { + const allFields = fields.split(',').map((field) => field.trim()); + allFields.forEach((field) => (query = query.field(field))); } - } - const search = searchService.getService().search; + if (sort) { + const [sortField, sortOrder] = sort.split(',').map((str) => str.trim()); + if (sortField) { + query.order(`"${sortField}"`, sortOrder === 'asc'); + } + } + + const { search } = startPlugins.data.search; - const req = { - count, - query: query.toString(), - filter: input.and, - }; + const req = { + count, + query: query.toString(), + filter: input.and, + }; - // We're requesting the data using the ESSQL strategy because - // the SQL routes return type information with the result set - return search - .search(req, { + // We're requesting the data using the ESSQL strategy because + // the SQL routes return type information with the result set + return search(req, { strategy: ESSQL_SEARCH_STRATEGY, }) - .toPromise() - .then((resp: EssqlSearchStrategyResponse) => { - return { - type: 'datatable', - meta: { - type: 'essql', - }, - ...resp, - }; - }); - }, + .toPromise() + .then((resp: EssqlSearchStrategyResponse) => { + return { + type: 'datatable', + meta: { + type: 'essql', + }, + ...resp, + }; + }); + }, + }; }; -} +}; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/essql.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/essql.ts index 1339c93032ea9..359a593eb1bf7 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/essql.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/essql.ts @@ -9,95 +9,138 @@ import { ExpressionFunctionDefinition, ExpressionValueFilter, } from 'src/plugins/expressions/common'; -import { searchService } from '../../../public/services'; +import { i18n } from '@kbn/i18n'; + +import { StartDeps } from '../../../canvas_plugin_src/plugin'; +import { ELASTICSEARCH, SQL, ISO8601, UTC } from '../../../i18n/constants'; import { ESSQL_SEARCH_STRATEGY } from '../../../common/lib/constants'; -import { EssqlSearchStrategyRequest, EssqlSearchStrategyResponse } from '../../../types'; -import { getFunctionHelp } from '../../../i18n'; +import { + EssqlSearchStrategyRequest, + EssqlSearchStrategyResponse, + ExpressionFunctionDefinitionFactory, +} from '../../../types'; -interface Arguments { +export interface Arguments { query: string; parameter: Array; count: number; timezone: string; } -export function essql(): ExpressionFunctionDefinition< - 'essql', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().essql; - - return { - name: 'essql', - type: 'datatable', - context: { - types: ['filter'], +const strings = { + help: i18n.translate('xpack.canvas.functions.essqlHelpText', { + defaultMessage: 'Queries {ELASTICSEARCH} using {ELASTICSEARCH} {SQL}.', + values: { + ELASTICSEARCH, + SQL, }, - help, - args: { - query: { - aliases: ['_', 'q'], - types: ['string'], - help: argHelp.query, + }), + args: { + query: i18n.translate('xpack.canvas.functions.essql.args.queryHelpText', { + defaultMessage: 'An {ELASTICSEARCH} {SQL} query.', + values: { + ELASTICSEARCH, + SQL, }, - parameter: { - aliases: ['param'], - types: ['string', 'number', 'boolean'], - multi: true, - help: argHelp.parameter, + }), + parameter: i18n.translate('xpack.canvas.functions.essql.args.parameterHelpText', { + defaultMessage: 'A parameter to be passed to the {SQL} query.', + values: { + SQL, }, - count: { - types: ['number'], - help: argHelp.count, - default: 1000, + }), + count: i18n.translate('xpack.canvas.functions.essql.args.countHelpText', { + defaultMessage: + 'The number of documents to retrieve. For better performance, use a smaller data set.', + }), + timezone: i18n.translate('xpack.canvas.functions.essql.args.timezoneHelpText', { + defaultMessage: + 'The timezone to use for date operations. Valid {ISO8601} formats and {UTC} offsets both work.', + values: { + ISO8601, + UTC, }, - timezone: { - aliases: ['tz'], - types: ['string'], - default: 'UTC', - help: argHelp.timezone, + }), + }, +}; + +type Fn = ExpressionFunctionDefinition<'essql', ExpressionValueFilter, Arguments, any>; + +export const essqlFactory: ExpressionFunctionDefinitionFactory = ({ + startPlugins, +}) => { + return function essql(): Fn { + const { help, args: argHelp } = strings; + + return { + name: 'essql', + type: 'datatable', + context: { + types: ['filter'], }, - }, - fn: (input, args, handlers) => { - const search = searchService.getService().search; - const { parameter, ...restOfArgs } = args; - const req = { - ...restOfArgs, - params: parameter, - filter: input.and, - }; + help, + args: { + query: { + aliases: ['_', 'q'], + types: ['string'], + help: argHelp.query, + }, + parameter: { + aliases: ['param'], + types: ['string', 'number', 'boolean'], + multi: true, + help: argHelp.parameter, + }, + count: { + types: ['number'], + help: argHelp.count, + default: 1000, + }, + timezone: { + aliases: ['tz'], + types: ['string'], + default: 'UTC', + help: argHelp.timezone, + }, + }, + fn: (input, args, _handlers) => { + const { search } = startPlugins.data.search; + const { parameter, ...restOfArgs } = args; + const req = { + ...restOfArgs, + params: parameter, + filter: input.and, + }; - return search - .search(req, { + return search(req, { strategy: ESSQL_SEARCH_STRATEGY, }) - .toPromise() - .then((resp: EssqlSearchStrategyResponse) => { - return { - type: 'datatable', - meta: { - type: 'essql', - }, - ...resp, - }; - }) - .catch((e) => { - let message = `Unexpected error from Elasticsearch: ${e.message}`; - if (e.err) { - const { type, reason } = e.err.attributes; - if (type === 'parsing_exception') { - message = `Couldn't parse Elasticsearch SQL query. You may need to add double quotes to names containing special characters. Check your query and try again. Error: ${reason}`; - } else { - message = `Unexpected error from Elasticsearch: ${type} - ${reason}`; + .toPromise() + .then((resp: EssqlSearchStrategyResponse) => { + return { + type: 'datatable', + meta: { + type: 'essql', + }, + ...resp, + }; + }) + .catch((e) => { + let message = `Unexpected error from Elasticsearch: ${e.message}`; + if (e.err) { + const { type, reason } = e.err.attributes; + if (type === 'parsing_exception') { + message = `Couldn't parse Elasticsearch SQL query. You may need to add double quotes to names containing special characters. Check your query and try again. Error: ${reason}`; + } else { + message = `Unexpected error from Elasticsearch: ${type} - ${reason}`; + } } - } - // Re-write the error message before surfacing it up - e.message = message; - throw e; - }); - }, + // Re-write the error message before surfacing it up + e.message = message; + throw e; + }); + }, + }; }; -} +}; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts index 2cfdebafb70df..15ad78eb2b919 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/browser/index.ts @@ -10,17 +10,9 @@ import { functions as externalFunctions } from '../external'; import { location } from './location'; import { markdown } from './markdown'; import { urlparam } from './urlparam'; -import { escount } from './escount'; -import { esdocs } from './esdocs'; -import { essql } from './essql'; +import { escountFactory } from './escount'; +import { esdocsFactory } from './esdocs'; +import { essqlFactory } from './essql'; -export const functions = [ - location, - markdown, - urlparam, - escount, - esdocs, - essql, - ...commonFunctions, - ...externalFunctions, -]; +export const functions = [location, markdown, urlparam, ...commonFunctions, ...externalFunctions]; +export const factories = [escountFactory, essqlFactory, esdocsFactory]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts index a30b3bf9b2121..5482ddccb9eb7 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/plugin.ts @@ -7,12 +7,14 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ChartsPluginStart } from 'src/plugins/charts/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; + import { CanvasSetup } from '../public'; import { EmbeddableStart } from '../../../../src/plugins/embeddable/public'; import { UiActionsStart } from '../../../../src/plugins/ui_actions/public'; import { Start as InspectorStart } from '../../../../src/plugins/inspector/public'; -import { functions } from './functions/browser'; +import { functions, factories } from './functions/browser'; import { typeFunctions } from './expression_types'; import { renderFunctions, renderFunctionFactories } from './renderers'; interface SetupDeps { @@ -20,6 +22,7 @@ interface SetupDeps { } export interface StartDeps { + data: DataPublicPluginStart; embeddable: EmbeddableStart; uiActions: UiActionsStart; inspector: InspectorStart; @@ -37,9 +40,10 @@ export class CanvasSrcPlugin implements Plugin plugins.canvas.addRenderers(renderFunctions); - core.getStartServices().then(([coreStart, depsStart]) => { + core.getStartServices().then(([coreStart, startPlugins]) => { + plugins.canvas.addFunctionFactories(factories, { coreStart, startPlugins }); plugins.canvas.addRenderers( - renderFunctionFactories.map((factory: any) => factory(coreStart, depsStart)) + renderFunctionFactories.map((factory: any) => factory(coreStart, startPlugins)) ); }); diff --git a/x-pack/plugins/canvas/i18n/functions/dict/escount.ts b/x-pack/plugins/canvas/i18n/functions/dict/escount.ts deleted file mode 100644 index af1337360ba6d..0000000000000 --- a/x-pack/plugins/canvas/i18n/functions/dict/escount.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { escount } from '../../../canvas_plugin_src/functions/browser/escount'; -import { FunctionHelp } from '../function_help'; -import { FunctionFactory } from '../../../types'; -import { ELASTICSEARCH, LUCENE } from '../../constants'; - -export const help: FunctionHelp> = { - help: i18n.translate('xpack.canvas.functions.escountHelpText', { - defaultMessage: 'Query {ELASTICSEARCH} for the number of hits matching the specified query.', - values: { - ELASTICSEARCH, - }, - }), - args: { - query: i18n.translate('xpack.canvas.functions.escount.args.queryHelpText', { - defaultMessage: 'A {LUCENE} query string.', - values: { - LUCENE, - }, - }), - index: i18n.translate('xpack.canvas.functions.escount.args.indexHelpText', { - defaultMessage: 'An index or index pattern. For example, {example}.', - values: { - example: '`"logstash-*"`', - }, - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/functions/dict/esdocs.ts b/x-pack/plugins/canvas/i18n/functions/dict/esdocs.ts deleted file mode 100644 index 6be5acdb8bc90..0000000000000 --- a/x-pack/plugins/canvas/i18n/functions/dict/esdocs.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { esdocs } from '../../../canvas_plugin_src/functions/browser/esdocs'; -import { FunctionHelp } from '../function_help'; -import { FunctionFactory } from '../../../types'; -import { ELASTICSEARCH, LUCENE } from '../../constants'; - -export const help: FunctionHelp> = { - help: i18n.translate('xpack.canvas.functions.esdocsHelpText', { - defaultMessage: - 'Query {ELASTICSEARCH} for raw documents. Specify the fields you want to retrieve, ' + - 'especially if you are asking for a lot of rows.', - values: { - ELASTICSEARCH, - }, - }), - args: { - query: i18n.translate('xpack.canvas.functions.esdocs.args.queryHelpText', { - defaultMessage: 'A {LUCENE} query string.', - values: { - LUCENE, - }, - }), - count: i18n.translate('xpack.canvas.functions.esdocs.args.countHelpText', { - defaultMessage: - 'The number of documents to retrieve. For better performance, use a smaller data set.', - }), - fields: i18n.translate('xpack.canvas.functions.esdocs.args.fieldsHelpText', { - defaultMessage: 'A comma-separated list of fields. For better performance, use fewer fields.', - }), - index: i18n.translate('xpack.canvas.functions.esdocs.args.indexHelpText', { - defaultMessage: 'An index or index pattern. For example, {example}.', - values: { - example: '`"logstash-*"`', - }, - }), - metaFields: i18n.translate('xpack.canvas.functions.esdocs.args.metaFieldsHelpText', { - defaultMessage: 'Comma separated list of meta fields. For example, {example}.', - values: { - example: '`"_index,_type"`', - }, - }), - sort: i18n.translate('xpack.canvas.functions.esdocs.args.sortHelpText', { - defaultMessage: - 'The sort direction formatted as {directions}. For example, {example1} or {example2}.', - values: { - directions: `\`"${['field', 'direction'].join(', ')}"\``, - example1: `\`"${['@timestamp', 'desc'].join(', ')}"\``, - example2: `\`"${['bytes', 'asc'].join(', ')}"\``, - }, - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/functions/dict/essql.ts b/x-pack/plugins/canvas/i18n/functions/dict/essql.ts deleted file mode 100644 index 6304db945fc3f..0000000000000 --- a/x-pack/plugins/canvas/i18n/functions/dict/essql.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { essql } from '../../../canvas_plugin_src/functions/browser/essql'; -import { FunctionHelp } from '../function_help'; -import { FunctionFactory } from '../../../types'; -import { ELASTICSEARCH, SQL, ISO8601, UTC } from '../../constants'; - -export const help: FunctionHelp> = { - help: i18n.translate('xpack.canvas.functions.essqlHelpText', { - defaultMessage: 'Queries {ELASTICSEARCH} using {ELASTICSEARCH} {SQL}.', - values: { - ELASTICSEARCH, - SQL, - }, - }), - args: { - query: i18n.translate('xpack.canvas.functions.essql.args.queryHelpText', { - defaultMessage: 'An {ELASTICSEARCH} {SQL} query.', - values: { - ELASTICSEARCH, - SQL, - }, - }), - parameter: i18n.translate('xpack.canvas.functions.essql.args.parameterHelpText', { - defaultMessage: 'A parameter to be passed to the {SQL} query.', - values: { - SQL, - }, - }), - count: i18n.translate('xpack.canvas.functions.essql.args.countHelpText', { - defaultMessage: - 'The number of documents to retrieve. For better performance, use a smaller data set.', - }), - timezone: i18n.translate('xpack.canvas.functions.essql.args.timezoneHelpText', { - defaultMessage: - 'The timezone to use for date operations. Valid {ISO8601} formats and {UTC} offsets both work.', - values: { - ISO8601, - UTC, - }, - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/functions/function_help.ts b/x-pack/plugins/canvas/i18n/functions/function_help.ts index 5eae785fefa2e..f9271823f33f0 100644 --- a/x-pack/plugins/canvas/i18n/functions/function_help.ts +++ b/x-pack/plugins/canvas/i18n/functions/function_help.ts @@ -27,9 +27,6 @@ import { help as demodata } from './dict/demodata'; import { help as doFn } from './dict/do'; import { help as dropdownControl } from './dict/dropdown_control'; import { help as eq } from './dict/eq'; -import { help as escount } from './dict/escount'; -import { help as esdocs } from './dict/esdocs'; -import { help as essql } from './dict/essql'; import { help as exactly } from './dict/exactly'; import { help as filterrows } from './dict/filterrows'; import { help as filters } from './dict/filters'; @@ -74,12 +71,12 @@ import { help as to } from './dict/to'; import { help as urlparam } from './dict/urlparam'; /** - * This type defines an entry in the `FunctionHelpMap`. It uses - * an `ExpressionFunction` to infer its `Arguments` in order to strongly-type that + * This type defines an entry in the `FunctionHelpMap`. It uses + * an `ExpressionFunction` to infer its `Arguments` in order to strongly-type that * entry. - * + * * For example: - * + * ``` interface Arguments { bar: string; @@ -182,9 +179,6 @@ export const getFunctionHelp = (): FunctionHelpDict => ({ do: doFn, dropdownControl, eq, - escount, - esdocs, - essql, exactly, filterrows, filters, diff --git a/x-pack/plugins/canvas/public/application.tsx b/x-pack/plugins/canvas/public/application.tsx index 30b2d78a6b1fe..fb1ea667b81ef 100644 --- a/x-pack/plugins/canvas/public/application.tsx +++ b/x-pack/plugins/canvas/public/application.tsx @@ -32,12 +32,7 @@ import { init as initStatsReporter } from './lib/ui_metric'; import { CapabilitiesStrings } from '../i18n'; -import { - startLegacyServices, - services, - LegacyServicesProvider, - CanvasPluginServices, -} from './services'; +import { CanvasPluginServices } from './services'; import { initFunctions } from './functions'; // @ts-expect-error untyped local import { appUnload } from './state/actions/app'; @@ -73,15 +68,13 @@ export const renderApp = ({ ReactDOM.render( - - - - - - - - - + + + + + + + , element @@ -101,7 +94,6 @@ export const initializeCanvas = async ( appUpdater: BehaviorSubject, pluginServices: PluginServices ) => { - await startLegacyServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater); const { expressions } = pluginServices.getServices(); // Adding these functions here instead of in plugin.ts. diff --git a/x-pack/plugins/canvas/public/index.ts b/x-pack/plugins/canvas/public/index.ts index a15b15fcae333..a8a7c614a8d7a 100644 --- a/x-pack/plugins/canvas/public/index.ts +++ b/x-pack/plugins/canvas/public/index.ts @@ -6,17 +6,9 @@ */ import { PluginInitializerContext } from 'kibana/public'; -import { CoreStart } from '../../../../src/core/public'; -import { CanvasServices } from './services'; -import { CanvasSetup, CanvasStart, CanvasStartDeps, CanvasPlugin } from './plugin'; +import { CanvasSetup, CanvasStart, CanvasPlugin } from './plugin'; export { CanvasSetup, CanvasStart }; -export interface WithKibanaProps { - kibana: { - services: CoreStart & CanvasStartDeps & { canvas: CanvasServices }; - }; -} - export const plugin = (initializerContext: PluginInitializerContext) => new CanvasPlugin(initializerContext); diff --git a/x-pack/plugins/canvas/public/plugin_api.ts b/x-pack/plugins/canvas/public/plugin_api.ts index 55a7390437c2b..42ac6c4903ae5 100644 --- a/x-pack/plugins/canvas/public/plugin_api.ts +++ b/x-pack/plugins/canvas/public/plugin_api.ts @@ -11,7 +11,11 @@ import { AnyExpressionRenderDefinition, AnyRendererFactory, } from '../types'; -import { ElementFactory } from '../types'; +import { + ElementFactory, + ExpressionFunctionDefinitionFactory, + ExpressionFunctionDefinitionFactoryParams, +} from '../types'; import { ExpressionsSetup } from '../../../../src/plugins/expressions/public'; type SpecPromiseFn = () => Promise; @@ -25,6 +29,10 @@ export interface CanvasApi { addFunctions: AddSpecsToRegistry< (() => AnyExpressionFunctionDefinition) | AnyExpressionFunctionDefinition >; + addFunctionFactories: ( + factories: Array>, + params: ExpressionFunctionDefinitionFactoryParams + ) => void; addModelUIs: AddToRegistry; addRenderers: AddSpecsToRegistry; addTagUIs: AddToRegistry; @@ -76,6 +84,11 @@ export function getPluginApi( expressionsPluginSetup.registerFunction(fn); }); }, + addFunctionFactories: (factories, params) => { + factories.forEach((factory) => { + expressionsPluginSetup.registerFunction(factory(params)); + }); + }, addTypes: (types) => { types.forEach((type) => { expressionsPluginSetup.registerType(type as any); diff --git a/x-pack/plugins/canvas/public/services/index.ts b/x-pack/plugins/canvas/public/services/index.ts index f4292810b8089..ae63986eb3b67 100644 --- a/x-pack/plugins/canvas/public/services/index.ts +++ b/x-pack/plugins/canvas/public/services/index.ts @@ -5,8 +5,6 @@ * 2.0. */ -export * from './legacy'; - import { PluginServices } from '../../../../../src/plugins/presentation_util/public'; import { CanvasCustomElementService } from './custom_element'; diff --git a/x-pack/plugins/canvas/public/services/legacy/context.tsx b/x-pack/plugins/canvas/public/services/legacy/context.tsx deleted file mode 100644 index 79c13ed753ac9..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/context.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { - useContext, - createElement, - createContext, - ComponentType, - FC, - ReactElement, -} from 'react'; -import { CanvasServices, CanvasServiceProviders, services } from '.'; - -export interface WithServicesProps { - services: CanvasServices; -} - -const defaultContextValue = { - search: {}, -}; - -export const ServicesContext = createContext(defaultContextValue as CanvasServices); - -export const useServices = () => useContext(ServicesContext); -export const withServices = (type: ComponentType) => { - const EnhancedType: FC = (props) => - createElement(type, { ...props, services: useServices() }); - return EnhancedType; -}; - -export const LegacyServicesProvider: FC<{ - providers?: Partial; - children: ReactElement; -}> = ({ providers = {}, children }) => { - const specifiedProviders: CanvasServiceProviders = { ...services, ...providers }; - const value = { - search: specifiedProviders.search.getService(), - }; - return {children}; -}; diff --git a/x-pack/plugins/canvas/public/services/legacy/index.ts b/x-pack/plugins/canvas/public/services/legacy/index.ts deleted file mode 100644 index fdc4e30cabe51..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/index.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BehaviorSubject } from 'rxjs'; -import { CoreSetup, CoreStart, AppUpdater } from '../../../../../../src/core/public'; -import { CanvasSetupDeps, CanvasStartDeps } from '../../plugin'; -import { searchServiceFactory } from './search'; - -export { SearchService } from './search'; -export { ExpressionsService } from '../../../../../../src/plugins/expressions/common'; -export * from './context'; - -export type CanvasServiceFactory = ( - coreSetup: CoreSetup, - coreStart: CoreStart, - canvasSetupPlugins: CanvasSetupDeps, - canvasStartPlugins: CanvasStartDeps, - appUpdater: BehaviorSubject -) => Service | Promise; - -export class CanvasServiceProvider { - private factory: CanvasServiceFactory; - private service: Service | undefined; - - constructor(factory: CanvasServiceFactory) { - this.factory = factory; - } - - setService(service: Service) { - this.service = service; - } - - async start( - coreSetup: CoreSetup, - coreStart: CoreStart, - canvasSetupPlugins: CanvasSetupDeps, - canvasStartPlugins: CanvasStartDeps, - appUpdater: BehaviorSubject - ) { - this.service = await this.factory( - coreSetup, - coreStart, - canvasSetupPlugins, - canvasStartPlugins, - appUpdater - ); - } - - getService(): Service { - if (!this.service) { - throw new Error('Service not ready'); - } - - return this.service; - } - - stop() { - this.service = undefined; - } -} - -export type ServiceFromProvider

= P extends CanvasServiceProvider ? T : never; - -export const services = { - search: new CanvasServiceProvider(searchServiceFactory), -}; - -export type CanvasServiceProviders = typeof services; - -export interface CanvasServices { - search: ServiceFromProvider; -} - -export const startLegacyServices = async ( - coreSetup: CoreSetup, - coreStart: CoreStart, - canvasSetupPlugins: CanvasSetupDeps, - canvasStartPlugins: CanvasStartDeps, - appUpdater: BehaviorSubject -) => { - const startPromises = Object.values(services).map((provider) => - provider.start(coreSetup, coreStart, canvasSetupPlugins, canvasStartPlugins, appUpdater) - ); - - await Promise.all(startPromises); -}; - -export const stopServices = () => { - Object.values(services).forEach((provider) => provider.stop()); -}; - -export const { search: searchService } = services; diff --git a/x-pack/plugins/canvas/public/services/legacy/reporting.ts b/x-pack/plugins/canvas/public/services/legacy/reporting.ts deleted file mode 100644 index e594475360dff..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/reporting.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReportingStart } from '../../../../reporting/public'; -import { CanvasServiceFactory } from './'; - -export interface ReportingService { - start?: ReportingStart; -} - -export const reportingServiceFactory: CanvasServiceFactory = ( - _coreSetup, - coreStart, - _setupPlugins, - startPlugins -): ReportingService => { - const { reporting } = startPlugins; - - const reportingEnabled = () => ({ start: reporting }); - const reportingDisabled = () => ({ start: undefined }); - - if (!reporting) { - // Reporting is not enabled - return reportingDisabled(); - } - - if (reporting.usesUiCapabilities()) { - if (coreStart.application.capabilities.canvas?.generatePdf === true) { - // Canvas has declared Reporting as a subfeature with the `generatePdf` UI Capability - return reportingEnabled(); - } else { - return reportingDisabled(); - } - } - - // Legacy/Deprecated: Reporting is enabled as an Elasticsearch feature - return reportingEnabled(); -}; diff --git a/x-pack/plugins/canvas/public/services/legacy/search.ts b/x-pack/plugins/canvas/public/services/legacy/search.ts deleted file mode 100644 index 0fe5c89c77096..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/search.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataPublicPluginStart } from 'src/plugins/data/public'; -import { CanvasServiceFactory } from '.'; - -export interface SearchService { - search: DataPublicPluginStart['search']; -} - -export const searchServiceFactory: CanvasServiceFactory = ( - setup, - start, - canvasSetup, - canvasStart -) => { - return { - search: canvasStart.data.search, - }; -}; diff --git a/x-pack/plugins/canvas/public/services/legacy/stubs/index.ts b/x-pack/plugins/canvas/public/services/legacy/stubs/index.ts deleted file mode 100644 index af43e9ed75c98..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/stubs/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CanvasServices, services } from '../'; -import { searchService } from './search'; - -export const stubs: CanvasServices = { - search: searchService, -}; - -export const startServices = async (providedServices: Partial = {}) => { - Object.entries(services).forEach(([key, provider]) => { - // @ts-expect-error Object.entries isn't strongly typed - const stub = providedServices[key] || stubs[key]; - provider.setService(stub); - }); -}; diff --git a/x-pack/plugins/canvas/public/services/legacy/stubs/search.ts b/x-pack/plugins/canvas/public/services/legacy/stubs/search.ts deleted file mode 100644 index a4558a93e38a4..0000000000000 --- a/x-pack/plugins/canvas/public/services/legacy/stubs/search.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -const noop = (..._args: any[]): any => {}; - -export const searchService: any = { - search: noop, -}; diff --git a/x-pack/plugins/canvas/public/services/stubs/index.ts b/x-pack/plugins/canvas/public/services/stubs/index.ts index 06a5ff49e9c04..aaee135093970 100644 --- a/x-pack/plugins/canvas/public/services/stubs/index.ts +++ b/x-pack/plugins/canvas/public/services/stubs/index.ts @@ -5,8 +5,6 @@ * 2.0. */ -export * from '../legacy/stubs'; - import { PluginServiceProviders, PluginServiceProvider, diff --git a/x-pack/plugins/canvas/storybook/decorators/index.ts b/x-pack/plugins/canvas/storybook/decorators/index.ts index 68481e27ae48b..598a2333be554 100644 --- a/x-pack/plugins/canvas/storybook/decorators/index.ts +++ b/x-pack/plugins/canvas/storybook/decorators/index.ts @@ -8,7 +8,7 @@ import { addDecorator } from '@storybook/react'; import { routerContextDecorator } from './router_decorator'; import { kibanaContextDecorator } from './kibana_decorator'; -import { servicesContextDecorator, legacyContextDecorator } from './services_decorator'; +import { servicesContextDecorator } from './services_decorator'; export { reduxDecorator } from './redux_decorator'; export { servicesContextDecorator } from './services_decorator'; @@ -21,6 +21,5 @@ export const addDecorators = () => { addDecorator(kibanaContextDecorator); addDecorator(routerContextDecorator); - addDecorator(legacyContextDecorator()); addDecorator(servicesContextDecorator()); }; diff --git a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx index 23dcc7b21a8b8..ea0992970d493 100644 --- a/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx +++ b/x-pack/plugins/canvas/storybook/decorators/services_decorator.tsx @@ -13,8 +13,6 @@ import { I18nProvider } from '@kbn/i18n/react'; import { PluginServiceRegistry } from '../../../../../src/plugins/presentation_util/public'; import { pluginServices, CanvasPluginServices } from '../../public/services'; import { pluginServiceProviders, StorybookParams } from '../../public/services/storybook'; -import { LegacyServicesProvider } from '../../public/services/legacy'; -import { startServices } from '../../public/services/legacy/stubs'; export const servicesContextDecorator = (): DecoratorFn => { const pluginServiceRegistry = new PluginServiceRegistry( @@ -38,8 +36,3 @@ export const servicesContextDecorator = (): DecoratorFn => { ); }; }; - -export const legacyContextDecorator = () => { - startServices(); - return (story: Function) => {story()}; -}; diff --git a/x-pack/plugins/canvas/types/expressions.ts b/x-pack/plugins/canvas/types/expressions.ts new file mode 100644 index 0000000000000..da1211cc176c0 --- /dev/null +++ b/x-pack/plugins/canvas/types/expressions.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExpressionFunctionDefinition } from 'src/plugins/expressions'; +import { CoreStart } from 'src/core/public'; + +export interface ExpressionFunctionDefinitionFactoryParams { + coreStart: CoreStart; + startPlugins: StartPlugins; +} + +export type ExpressionFunctionDefinitionFactory< + StartPlugins extends {} | void, + Fn extends ExpressionFunctionDefinition +> = (params: ExpressionFunctionDefinitionFactoryParams) => () => Fn; diff --git a/x-pack/plugins/canvas/types/index.ts b/x-pack/plugins/canvas/types/index.ts index 09ae1510be6da..dfc5b632f0258 100644 --- a/x-pack/plugins/canvas/types/index.ts +++ b/x-pack/plugins/canvas/types/index.ts @@ -9,6 +9,7 @@ export * from '../../../../src/plugins/expressions/common'; export * from './assets'; export * from './canvas'; export * from './elements'; +export * from './expressions'; export * from './filters'; export * from './functions'; export * from './renderers';