diff --git a/.buildkite/pipelines/pull_request/osquery_cypress.yml b/.buildkite/pipelines/pull_request/osquery_cypress.yml new file mode 100644 index 0000000000000..766d28e0877c7 --- /dev/null +++ b/.buildkite/pipelines/pull_request/osquery_cypress.yml @@ -0,0 +1,11 @@ +steps: + - command: .buildkite/scripts/steps/functional/osquery_cypress.sh + label: 'Osquery Cypress Tests' + agents: + queue: ci-group-6 + depends_on: build + timeout_in_minutes: 120 + retry: + automatic: + - exit_status: '*' + limit: 1 diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.js b/.buildkite/scripts/pipelines/pull_request/pipeline.js index d0f38dc773357..ab125d4f73377 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.js +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.js @@ -86,6 +86,16 @@ const uploadPipeline = (pipelineContent) => { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/fleet_cypress.yml')); } + if ( + (await doAnyChangesMatch([ + /^x-pack\/plugins\/osquery/, + /^x-pack\/test\/osquery_cypress/, + ])) || + process.env.GITHUB_PR_LABELS.includes('ci:all-cypress-suites') + ) { + pipeline.push(getPipeline('.buildkite/pipelines/pull_request/osquery_cypress.yml')); + } + if (await doAnyChangesMatch([/^x-pack\/plugins\/uptime/])) { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/uptime.yml')); } diff --git a/.buildkite/scripts/steps/functional/osquery_cypress.sh b/.buildkite/scripts/steps/functional/osquery_cypress.sh new file mode 100755 index 0000000000000..a23d41c4f8d4d --- /dev/null +++ b/.buildkite/scripts/steps/functional/osquery_cypress.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +.buildkite/scripts/bootstrap.sh +.buildkite/scripts/download_build_artifacts.sh + +export JOB=kibana-osquery-cypress + +echo "--- Osquery Cypress tests" + +cd "$XPACK_DIR" + +checks-reporter-with-killswitch "Osquery Cypress Tests" \ + node scripts/functional_tests \ + --debug --bail \ + --kibana-install-dir "$KIBANA_BUILD_LOCATION" \ + --config test/osquery_cypress/cli_config.ts diff --git a/dev_docs/key_concepts/performance.mdx b/dev_docs/key_concepts/performance.mdx index 0201c7774f854..5d955c789ddeb 100644 --- a/dev_docs/key_concepts/performance.mdx +++ b/dev_docs/key_concepts/performance.mdx @@ -3,11 +3,13 @@ id: kibDevPerformance slug: /kibana-dev-docs/key-concepts/performance title: Performance summary: Performance tips for Kibana development. -date: 2021-09-02 +date: 2021-12-03 tags: ['kibana', 'onboarding', 'dev', 'performance'] --- -## Keep Kibana fast +## Client-side considerations + +### Lazy load code _tl;dr_: Load as much code lazily as possible. Everyone loves snappy applications with a responsive UI and hates spinners. Users deserve the @@ -105,3 +107,15 @@ Many OSS tools allow you to analyze the generated stats file: Webpack authors - [webpack-visualizer](https://chrisbateman.github.io/webpack-visualizer/) - [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) + +## Server-side considerations + +### Don't block the event loop + +[Node.js is single threaded](https://nodejs.dev/learn/introduction-to-nodejs) which means a single CPU-intensive server-side, synchronous operation will block any other functionality waiting to execute on the Kibana server. The affects background tasks, like alerts, and search sessions, as well as search requests and page loads. + +**When writing code that will run on the server, [don't block the event loop](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)**. Instead consider: + +- Writing async code. For example, leverage [setImmediate](https://nodejs.dev/learn/understanding-setimmediate) inside for loops. +- Executing logic on the client instead. This may not be a good option if you require a lot of data going back and forth between the server and the client, as that can also slow down the user's experience, especially over slower bandwidth internet connections. +- Worker threads are also an option if the code doesn't rely on stateful Kibana services. If you are interested in using worker threads, please reach out to a tech-lead before doing so. We will likely want to implement a worker threads pool to ensure worker threads cooperate appropriately. \ No newline at end of file diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index 3acaf2ddd2c12..68b308c08aeac 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -14,10 +14,13 @@ https://github.com/elastic/dockerfiles/tree/{branch}/kibana[GitHub]. These images contain both free and subscription features. <> to try out all of the features. -[float] +[discrete] [[run-kibana-on-docker-for-dev]] === Run {kib} on Docker for development +. Start an {es} container for development or testing: ++ +-- ifeval::["{release-state}"=="unreleased"] NOTE: No Docker images are currently available for {kib} {version}. @@ -26,14 +29,16 @@ endif::[] ifeval::["{release-state}"!="unreleased"] -. Start an {es} container for development or testing: -+ [source,sh,subs="attributes"] ---- docker network create elastic docker pull {es-docker-image} docker run --name es-node01 --net elastic -p 9200:9200 -p 9300:9300 -t {es-docker-image} ---- + +endif::[] + +-- + When you start {es} for the first time, the following security configuration occurs automatically: @@ -51,30 +56,26 @@ and enrollment token. . Copy the generated password and enrollment token and save them in a secure location. These values are shown only when you start {es} for the first time. You'll use these to enroll {kib} with your {es} cluster and log in. + +. In a new terminal session, start {kib} and connect it to your {es} container: + -[NOTE] -==== -If you need to reset the password for the `elastic` user or other -built-in users, run the {ref}/reset-password.html[`elasticsearch-reset-password`] -tool. To generate new enrollment tokens for {kib} or {es} nodes, run the -{ref}/create-enrollment-token.html[`elasticsearch-create-enrollment-token`] tool. -These tools are available in the {es} `bin` directory of the Docker container. +-- +ifeval::["{release-state}"=="unreleased"] -For example: +NOTE: No Docker images are currently available for {kib} {version}. -[source,sh] ----- -docker exec -it es-node01 /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic ----- -==== +endif::[] + +ifeval::["{release-state}"!="unreleased"] -. In a new terminal session, start {kib} and connect it to your {es} container: -+ [source,sh,subs="attributes"] ---- docker pull {docker-image} docker run --name kib-01 --net elastic -p 5601:5601 {docker-image} ---- + +endif::[] +-- + When you start {kib}, a unique link is output to your terminal. @@ -86,7 +87,32 @@ When you start {kib}, a unique link is output to your terminal. .. Log in to {kib} as the `elastic` user with the password that was generated when you started {es}. -[float] +[[docker-generate]] +[discrete] +=== Generate passwords and enrollment tokens +If you need to reset the password for the `elastic` user or other +built-in users, run the {ref}/reset-password.html[`elasticsearch-reset-password`] +tool. This tool is available in the {es} `bin` directory of the Docker container. + +For example, to reset the password for the `elastic` user: + +[source,sh] +---- +docker exec -it es-node01 /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic +---- + +If you need to generate new enrollment tokens for {kib} or {es} nodes, run the +{ref}/create-enrollment-token.html[`elasticsearch-create-enrollment-token`] tool. +This tool is available in the {es} `bin` directory of the Docker container. + +For example, to generate a new enrollment token for {kib}: + +[source,sh] +---- +docker exec -it es-node01 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana +---- + +[discrete] === Remove Docker containers To remove the containers and their network, run: @@ -98,8 +124,7 @@ docker rm es-node01 docker rm kib-01 ---- -endif::[] -[float] +[discrete] [[configuring-kibana-docker]] === Configure Kibana on Docker @@ -108,7 +133,7 @@ conventional approach is to provide a `kibana.yml` file as described in {kibana-ref}/settings.html[Configuring Kibana], but it's also possible to use environment variables to define settings. -[float] +[discrete] [[bind-mount-config]] ==== Bind-mounted configuration @@ -135,7 +160,7 @@ docker run -it --rm -v full_path_to/config:/usr/share/kibana/config -v full_path docker run -it --rm -v full_path_to/config:/usr/share/kibana/config -v full_path_to/data:/usr/share/kibana/data {docker-image} bin/kibana-keystore add test_keystore_setting ---- -[float] +[discrete] [[environment-variable-config]] ==== Environment variable configuration @@ -179,7 +204,7 @@ services: Since environment variables are translated to CLI arguments, they take precedence over settings configured in `kibana.yml`. -[float] +[discrete] [[docker-defaults]] ==== Docker defaults The following settings have different default values when using the Docker diff --git a/package.json b/package.json index b2299c2391886..c88472f9125d0 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "**/hoist-non-react-statics": "^3.3.2", "**/html-minifier/uglify-js": "^3.14.3", "**/isomorphic-fetch/node-fetch": "^2.6.1", - "**/istanbul-instrumenter-loader/schema-utils": "1.0.0", + "**/istanbul-lib-coverage": "^3.2.0", "**/json-schema": "^0.4.0", "**/minimist": "^1.2.5", "**/node-jose/node-forge": "^0.10.0", @@ -103,7 +103,7 @@ "@elastic/apm-rum": "^5.9.1", "@elastic/apm-rum-react": "^1.3.1", "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", - "@elastic/charts": "40.0.0", + "@elastic/charts": "40.1.0", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.35", "@elastic/ems-client": "8.0.0", @@ -436,6 +436,7 @@ "@babel/types": "^7.16.0", "@bazel/ibazel": "^0.15.10", "@bazel/typescript": "^3.8.0", + "@cypress/code-coverage": "^3.9.11", "@cypress/snapshot": "^2.1.7", "@cypress/webpack-preprocessor": "^5.6.0", "@elastic/eslint-config-kibana": "link:bazel-bin/packages/elastic-eslint-config-kibana", @@ -565,6 +566,7 @@ "@types/kbn__apm-utils": "link:bazel-bin/packages/kbn-apm-utils/npm_module_types", "@types/kbn__cli-dev-mode": "link:bazel-bin/packages/kbn-cli-dev-mode/npm_module_types", "@types/kbn__config": "link:bazel-bin/packages/kbn-config/npm_module_types", + "@types/kbn__config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module_types", "@types/kbn__crypto": "link:bazel-bin/packages/kbn-crypto/npm_module_types", "@types/kbn__i18n": "link:bazel-bin/packages/kbn-i18n/npm_module_types", "@types/kbn__i18n-react": "link:bazel-bin/packages/kbn-i18n-react/npm_module_types", @@ -695,7 +697,9 @@ "cypress-file-upload": "^5.0.8", "cypress-multi-reporters": "^1.5.0", "cypress-pipe": "^2.0.0", + "cypress-react-selector": "^2.3.13", "cypress-real-events": "^1.5.1", + "cypress-recurse": "^1.13.1", "debug": "^2.6.9", "delete-empty": "^2.0.0", "dependency-check": "^4.1.0", @@ -750,7 +754,6 @@ "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-path-inside": "^3.0.2", - "istanbul-instrumenter-loader": "^3.0.1", "jest": "^26.6.3", "jest-canvas-mock": "^2.3.1", "jest-circus": "^26.6.3", @@ -787,7 +790,7 @@ "ncp": "^2.0.0", "node-sass": "^6.0.1", "null-loader": "^3.0.0", - "nyc": "^15.0.1", + "nyc": "^15.1.0", "oboe": "^2.1.4", "parse-link-header": "^1.0.1", "pbf": "3.2.1", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 1cf887290af77..96b1846147689 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -84,6 +84,7 @@ filegroup( "//packages/kbn-apm-utils:build_types", "//packages/kbn-cli-dev-mode:build_types", "//packages/kbn-config:build_types", + "//packages/kbn-config-schema:build_types", "//packages/kbn-crypto:build_types", "//packages/kbn-i18n:build_types", "//packages/kbn-i18n-react:build_types", diff --git a/packages/kbn-cli-dev-mode/BUILD.bazel b/packages/kbn-cli-dev-mode/BUILD.bazel index c6611e71e35ab..66e00706e9e58 100644 --- a/packages/kbn-cli-dev-mode/BUILD.bazel +++ b/packages/kbn-cli-dev-mode/BUILD.bazel @@ -49,7 +49,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "//packages/kbn-config:npm_module_types", - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "//packages/kbn-dev-utils", "//packages/kbn-logging", "//packages/kbn-optimizer", diff --git a/packages/kbn-config-schema/BUILD.bazel b/packages/kbn-config-schema/BUILD.bazel index 70de78b7617c9..ed6082527bab9 100644 --- a/packages/kbn-config-schema/BUILD.bazel +++ b/packages/kbn-config-schema/BUILD.bazel @@ -1,9 +1,10 @@ -load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") -load("//src/dev/bazel:index.bzl", "jsts_transpiler") +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") PKG_BASE_NAME = "kbn-config-schema" PKG_REQUIRE_NAME = "@kbn/config-schema" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__config-schema" SOURCE_FILES = glob([ "src/**/*.ts", @@ -72,7 +73,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], + deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) @@ -91,3 +92,20 @@ filegroup( ], visibility = ["//visibility:public"], ) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = TYPES_PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [ + ":npm_module_types", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-config-schema/package.json b/packages/kbn-config-schema/package.json index a3b6880c3293c..d6a0e91b9b429 100644 --- a/packages/kbn-config-schema/package.json +++ b/packages/kbn-config-schema/package.json @@ -1,7 +1,6 @@ { "name": "@kbn/config-schema", "main": "./target_node/index.js", - "types": "./target_types/index.d.ts", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", "private": true diff --git a/packages/kbn-config-schema/src/index.ts b/packages/kbn-config-schema/src/index.ts index 8635421beb0a1..f9db84f255ec6 100644 --- a/packages/kbn-config-schema/src/index.ts +++ b/packages/kbn-config-schema/src/index.ts @@ -49,7 +49,7 @@ import { StreamType, } from './types'; -export type { TypeOf, Props, NullableProps }; +export type { AnyType, ConditionalType, TypeOf, Props, NullableProps }; export { ObjectType, Type }; export { ByteSizeValue } from './byte_size_value'; export { SchemaTypeError, ValidationError } from './errors'; diff --git a/packages/kbn-config/BUILD.bazel b/packages/kbn-config/BUILD.bazel index c0b75ab491ac0..0353b2d16be7b 100644 --- a/packages/kbn-config/BUILD.bazel +++ b/packages/kbn-config/BUILD.bazel @@ -46,7 +46,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "//packages/elastic-safer-lodash-set", - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "//packages/kbn-logging", "//packages/kbn-std", "//packages/kbn-utility-types", diff --git a/packages/kbn-docs-utils/src/api_docs/README.md b/packages/kbn-docs-utils/src/api_docs/README.md index f980fe83b9596..728cb0690834d 100644 --- a/packages/kbn-docs-utils/src/api_docs/README.md +++ b/packages/kbn-docs-utils/src/api_docs/README.md @@ -1,6 +1,6 @@ # Autogenerated API documentation -[RFC](../../../rfcs/text/0014_api_documentation.md) +[RFC](https://github.com/elastic/kibana/blob/main/legacy_rfcs/text/0014_api_documentation.md)) This is an experimental api documentation system that is managed by the Kibana Tech Leads until we determine the value of such a system and what kind of maintenance burder it will incur. diff --git a/packages/kbn-es-query/BUILD.bazel b/packages/kbn-es-query/BUILD.bazel index 26d2030d1b0ba..70d8d659c99fe 100644 --- a/packages/kbn-es-query/BUILD.bazel +++ b/packages/kbn-es-query/BUILD.bazel @@ -32,7 +32,6 @@ NPM_MODULE_EXTRA_FILES = [ RUNTIME_DEPS = [ "//packages/kbn-utility-types", - "//packages/kbn-config-schema", "//packages/kbn-i18n", "@npm//@elastic/elasticsearch", "@npm//load-json-file", diff --git a/packages/kbn-io-ts-utils/BUILD.bazel b/packages/kbn-io-ts-utils/BUILD.bazel index e5f1de4d07f63..dd81e8318e9d9 100644 --- a/packages/kbn-io-ts-utils/BUILD.bazel +++ b/packages/kbn-io-ts-utils/BUILD.bazel @@ -45,7 +45,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "@npm//fp-ts", "@npm//io-ts", "@npm//tslib", diff --git a/packages/kbn-optimizer/BUILD.bazel b/packages/kbn-optimizer/BUILD.bazel index cc03c81070745..a389086c9ee3c 100644 --- a/packages/kbn-optimizer/BUILD.bazel +++ b/packages/kbn-optimizer/BUILD.bazel @@ -63,7 +63,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "//packages/kbn-config:npm_module_types", - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "//packages/kbn-dev-utils", "//packages/kbn-std", "//packages/kbn-ui-shared-deps-npm", diff --git a/packages/kbn-server-http-tools/BUILD.bazel b/packages/kbn-server-http-tools/BUILD.bazel index b9eae3d022439..be74c363a7acf 100644 --- a/packages/kbn-server-http-tools/BUILD.bazel +++ b/packages/kbn-server-http-tools/BUILD.bazel @@ -37,7 +37,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "//packages/kbn-crypto:npm_module_types", "@npm//@hapi/hapi", "@npm//@hapi/hoek", diff --git a/packages/kbn-server-route-repository/BUILD.bazel b/packages/kbn-server-route-repository/BUILD.bazel index 9f8a9f34061d2..6e7e10d4dd816 100644 --- a/packages/kbn-server-route-repository/BUILD.bazel +++ b/packages/kbn-server-route-repository/BUILD.bazel @@ -36,7 +36,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "//packages/kbn-io-ts-utils", "@npm//@hapi/boom", "@npm//fp-ts", diff --git a/packages/kbn-utils/BUILD.bazel b/packages/kbn-utils/BUILD.bazel index c2f82d65d3318..c4d256e7672ab 100644 --- a/packages/kbn-utils/BUILD.bazel +++ b/packages/kbn-utils/BUILD.bazel @@ -31,7 +31,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-config-schema", + "//packages/kbn-config-schema:npm_module_types", "@npm//load-json-file", "@npm//tslib", "@npm//@types/jest", diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index d4393791a74fa..c599b2f719408 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -11,7 +11,7 @@ import Boom from '@hapi/boom'; import { ByteSizeValue } from '@kbn/config-schema'; import { CliArgs } from '@kbn/config'; import type { ClientOptions } from '@elastic/elasticsearch/lib/client'; -import { ConditionalType } from '@kbn/config-schema/target_types/types'; +import { ConditionalType } from '@kbn/config-schema'; import { ConfigDeprecation } from '@kbn/config'; import { ConfigDeprecationContext } from '@kbn/config'; import { ConfigDeprecationFactory } from '@kbn/config'; diff --git a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js index 0e006856dac9b..866e19a1d0d3e 100644 --- a/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js +++ b/src/plugins/console/public/application/models/legacy_core_editor/mode/worker/worker.js @@ -2022,6 +2022,10 @@ ace.define( }, // parses and returns the method method = function () { + const [first, ...rest] = text.split(' '); + text = first.toUpperCase() + rest.join(' '); + ch = ch.toUpperCase(); + switch (ch) { case 'G': next('G'); diff --git a/src/plugins/data/common/search/search_source/create_search_source.ts b/src/plugins/data/common/search/search_source/create_search_source.ts index c6c8bb4d26f9e..3d2300940ac06 100644 --- a/src/plugins/data/common/search/search_source/create_search_source.ts +++ b/src/plugins/data/common/search/search_source/create_search_source.ts @@ -8,7 +8,7 @@ import { migrateLegacyQuery } from './migrate_legacy_query'; import { SearchSource, SearchSourceDependencies } from './search_source'; -import { IndexPatternsContract } from '../..'; +import { IndexPatternsContract, SerializedSearchSourceFields } from '../..'; import { SearchSourceFields } from './types'; /** @@ -28,16 +28,30 @@ import { SearchSourceFields } from './types'; * * * @public */ -export const createSearchSource = - (indexPatterns: IndexPatternsContract, searchSourceDependencies: SearchSourceDependencies) => - async (searchSourceFields: SearchSourceFields = {}) => { - const fields = { ...searchSourceFields }; +export const createSearchSource = ( + indexPatterns: IndexPatternsContract, + searchSourceDependencies: SearchSourceDependencies +) => { + const createFields = async (searchSourceFields: SerializedSearchSourceFields = {}) => { + const { index, parent, ...restOfFields } = searchSourceFields; + const fields: SearchSourceFields = { + ...restOfFields, + }; // hydrating index pattern - if (fields.index && typeof fields.index === 'string') { - fields.index = await indexPatterns.get(searchSourceFields.index as any); + if (searchSourceFields.index) { + fields.index = await indexPatterns.get(searchSourceFields.index); } + if (searchSourceFields.parent) { + fields.parent = await createFields(searchSourceFields.parent); + } + + return fields; + }; + + const createSearchSourceFn = async (searchSourceFields: SerializedSearchSourceFields = {}) => { + const fields = await createFields(searchSourceFields); const searchSource = new SearchSource(fields, searchSourceDependencies); // todo: move to migration script .. create issue @@ -49,3 +63,6 @@ export const createSearchSource = return searchSource; }; + + return createSearchSourceFn; +}; diff --git a/src/plugins/data/common/search/search_source/extract_references.ts b/src/plugins/data/common/search/search_source/extract_references.ts index dfcd1b12cb62f..de32836ced124 100644 --- a/src/plugins/data/common/search/search_source/extract_references.ts +++ b/src/plugins/data/common/search/search_source/extract_references.ts @@ -8,17 +8,17 @@ import { SavedObjectReference } from 'src/core/types'; import { Filter } from '@kbn/es-query'; -import { SearchSourceFields } from './types'; +import { SerializedSearchSourceFields } from './types'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '../../../../data/common'; export const extractReferences = ( - state: SearchSourceFields -): [SearchSourceFields & { indexRefName?: string }, SavedObjectReference[]] => { - let searchSourceFields: SearchSourceFields & { indexRefName?: string } = { ...state }; + state: SerializedSearchSourceFields +): [SerializedSearchSourceFields & { indexRefName?: string }, SavedObjectReference[]] => { + let searchSourceFields: SerializedSearchSourceFields & { indexRefName?: string } = { ...state }; const references: SavedObjectReference[] = []; if (searchSourceFields.index) { - const indexId = searchSourceFields.index.id || (searchSourceFields.index as any as string); + const indexId = searchSourceFields.index; const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; references.push({ name: refName, diff --git a/src/plugins/data/common/search/search_source/inject_references.test.ts b/src/plugins/data/common/search/search_source/inject_references.test.ts index d2fd10f14b633..1785e55acc792 100644 --- a/src/plugins/data/common/search/search_source/inject_references.test.ts +++ b/src/plugins/data/common/search/search_source/inject_references.test.ts @@ -7,12 +7,12 @@ */ import { SavedObjectReference } from 'src/core/types'; -import { SearchSourceFields } from './types'; +import { SerializedSearchSourceFields } from './types'; import { injectReferences } from './inject_references'; describe('injectSearchSourceReferences', () => { - let searchSourceJSON: SearchSourceFields & { indexRefName: string }; + let searchSourceJSON: SerializedSearchSourceFields & { indexRefName: string }; let references: SavedObjectReference[]; beforeEach(() => { diff --git a/src/plugins/data/common/search/search_source/inject_references.ts b/src/plugins/data/common/search/search_source/inject_references.ts index 6729025943b95..c4b39773c4401 100644 --- a/src/plugins/data/common/search/search_source/inject_references.ts +++ b/src/plugins/data/common/search/search_source/inject_references.ts @@ -7,13 +7,13 @@ */ import { SavedObjectReference } from 'src/core/types'; -import { SearchSourceFields } from './types'; +import { SerializedSearchSourceFields } from './types'; export const injectReferences = ( - searchSourceFields: SearchSourceFields & { indexRefName: string }, + searchSourceFields: SerializedSearchSourceFields & { indexRefName: string }, references: SavedObjectReference[] ) => { - const searchSourceReturnFields: SearchSourceFields = { ...searchSourceFields }; + const searchSourceReturnFields: SerializedSearchSourceFields = { ...searchSourceFields }; // Inject index id if a reference is saved if (searchSourceFields.indexRefName) { const reference = references.find((ref) => ref.name === searchSourceFields.indexRefName); diff --git a/src/plugins/data/common/search/search_source/parse_json.ts b/src/plugins/data/common/search/search_source/parse_json.ts index f34f32a0bff92..6c7d08a4f2b50 100644 --- a/src/plugins/data/common/search/search_source/parse_json.ts +++ b/src/plugins/data/common/search/search_source/parse_json.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import { SearchSourceFields } from './types'; +import { SerializedSearchSourceFields } from './types'; import { InvalidJSONProperty } from '../../../../kibana_utils/common'; export const parseSearchSourceJSON = (searchSourceJSON: string) => { // if we have a searchSource, set its values based on the searchSourceJson field - let searchSourceValues: SearchSourceFields; + let searchSourceValues: SerializedSearchSourceFields; try { searchSourceValues = JSON.parse(searchSourceJSON); } catch (e) { 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 1afd2d98782a2..87e249acab8b1 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 @@ -944,7 +944,6 @@ describe('SearchSource', () => { }, ` Object { - "index": undefined, "parent": Object { "from": 123, "index": "123", 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 a3979ffa6e943..3ac6b623fbc80 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -75,7 +75,13 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildEsQuery, Filter } from '@kbn/es-query'; import { normalizeSortRequest } from './normalize_sort_request'; import { fieldWildcardFilter } from '../../../../kibana_utils/common'; -import { IIndexPattern, IndexPattern, IndexPatternField } from '../..'; +import { + AggConfigSerialized, + IIndexPattern, + IndexPattern, + IndexPatternField, + SerializedSearchSourceFields, +} from '../..'; import { AggConfigs, EsQuerySortValue, @@ -846,12 +852,26 @@ export class SearchSource { /** * serializes search source fields (which can later be passed to {@link ISearchStartSearchSource}) */ - public getSerializedFields(recurse = false) { - const { filter: originalFilters, size: omit, ...searchSourceFields } = this.getFields(); - let serializedSearchSourceFields: SearchSourceFields = { + public getSerializedFields(recurse = false): SerializedSearchSourceFields { + const { + filter: originalFilters, + aggs: searchSourceAggs, + parent, + size: omit, + sort, + index, + ...searchSourceFields + } = this.getFields(); + + let serializedSearchSourceFields: SerializedSearchSourceFields = { ...searchSourceFields, - index: (searchSourceFields.index ? searchSourceFields.index.id : undefined) as any, }; + if (index) { + serializedSearchSourceFields.index = index.id; + } + if (sort) { + serializedSearchSourceFields.sort = !Array.isArray(sort) ? [sort] : sort; + } if (originalFilters) { const filters = this.getFilters(originalFilters); serializedSearchSourceFields = { @@ -859,6 +879,17 @@ export class SearchSource { filter: filters, }; } + if (searchSourceAggs) { + let aggs = searchSourceAggs; + if (typeof aggs === 'function') { + aggs = (searchSourceAggs as Function)(); + } + if (aggs instanceof AggConfigs) { + serializedSearchSourceFields.aggs = aggs.getAll().map((agg) => agg.serialize()); + } else { + serializedSearchSourceFields.aggs = aggs as AggConfigSerialized[]; + } + } if (recurse && this.getParent()) { serializedSearchSourceFields.parent = this.getParent()!.getSerializedFields(recurse); } diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index c411e53abfcd2..acfdf17263169 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -5,8 +5,10 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ + import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { IAggConfigs } from 'src/plugins/data/public'; +import { AggConfigSerialized, IAggConfigs } from 'src/plugins/data/public'; +import { SerializableRecord } from '@kbn/utility-types'; import { Query } from '../..'; import { Filter } from '../../es_query'; import { IndexPattern } from '../..'; @@ -27,7 +29,7 @@ export interface ISearchStartSearchSource { * creates {@link SearchSource} based on provided serialized {@link SearchSourceFields} * @param fields */ - create: (fields?: SearchSourceFields) => Promise; + create: (fields?: SerializedSearchSourceFields) => Promise; /** * creates empty {@link SearchSource} */ @@ -112,6 +114,53 @@ export interface SearchSourceFields { parent?: SearchSourceFields; } +export interface SerializedSearchSourceFields { + type?: string; + /** + * {@link Query} + */ + query?: Query; + /** + * {@link Filter} + */ + filter?: Filter[]; + /** + * {@link EsQuerySortValue} + */ + sort?: EsQuerySortValue[]; + highlight?: SerializableRecord; + highlightAll?: boolean; + trackTotalHits?: boolean | number; + // todo: needs aggconfigs serializable type + /** + * {@link AggConfigs} + */ + aggs?: AggConfigSerialized[]; + from?: number; + size?: number; + source?: boolean | estypes.Fields; + version?: boolean; + /** + * Retrieve fields via the search Fields API + */ + fields?: SearchFieldValue[]; + /** + * Retreive fields directly from _source (legacy behavior) + * + * @deprecated It is recommended to use `fields` wherever possible. + */ + fieldsFromSource?: estypes.Fields; + /** + * {@link IndexPatternService} + */ + index?: string; + searchAfter?: EsQuerySearchAfter; + timeout?: string; + terminate_after?: number; + + parent?: SerializedSearchSourceFields; +} + export interface SearchSourceOptions { callParentStartHandlers?: boolean; } diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index a54a9c7f35e3f..567a0b1d8c6d9 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -187,6 +187,7 @@ export type { ISearchSource, SearchRequest, SearchSourceFields, + SerializedSearchSourceFields, // errors IEsError, Reason, diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 2cd7993e3b183..810436dc30b98 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -27,6 +27,7 @@ export type { SearchRequest, SearchSourceDependencies, SearchSourceFields, + SerializedSearchSourceFields, } from '../../common/search'; export { ES_SEARCH_STRATEGY, diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index b4006a691afca..e14ae252da95e 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -9,7 +9,7 @@ import type { Capabilities } from 'kibana/public'; import type { IUiSettingsClient } from 'kibana/public'; import type { DataPublicPluginStart } from 'src/plugins/data/public'; -import type { Filter, ISearchSource, SearchSourceFields } from 'src/plugins/data/common'; +import type { Filter, ISearchSource, SerializedSearchSourceFields } from 'src/plugins/data/common'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../common'; import type { SavedSearch, SortOrder } from '../services/saved_searches'; import { getSortForSearchSource } from '../components/doc_table'; @@ -55,7 +55,7 @@ export async function getSharingData( } return { - getSearchSource: (absoluteTime?: boolean): SearchSourceFields => { + getSearchSource: (absoluteTime?: boolean): SerializedSearchSourceFields => { const timeFilter = absoluteTime ? data.query.timefilter.timefilter.createFilter(index) : data.query.timefilter.timefilter.createRelativeFilter(index); diff --git a/src/plugins/expression_image/kibana.json b/src/plugins/expression_image/kibana.json index 4f4b736d82d1a..7391b17bce779 100755 --- a/src/plugins/expression_image/kibana.json +++ b/src/plugins/expression_image/kibana.json @@ -10,5 +10,6 @@ "server": true, "ui": true, "requiredPlugins": ["expressions", "presentationUtil"], - "optionalPlugins": [] + "optionalPlugins": [], + "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/expression_image/public/expression_renderers/__stories__/image_renderer.stories.tsx b/src/plugins/expression_image/public/expression_renderers/__stories__/image_renderer.stories.tsx index d75aa1a4263eb..dc54194d5d83f 100644 --- a/src/plugins/expression_image/public/expression_renderers/__stories__/image_renderer.stories.tsx +++ b/src/plugins/expression_image/public/expression_renderers/__stories__/image_renderer.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; import { Render, waitFor } from '../../../../presentation_util/public/__stories__'; -import { imageRenderer } from '../image_renderer'; +import { getImageRenderer } from '../image_renderer'; import { getElasticLogo } from '../../../../../../src/plugins/presentation_util/common/lib'; import { ImageMode } from '../../../common'; @@ -19,7 +19,7 @@ const Renderer = ({ elasticLogo }: { elasticLogo: string }) => { mode: ImageMode.COVER, }; - return ; + return ; }; storiesOf('renderers/image', module).add( diff --git a/src/plugins/expression_image/public/expression_renderers/image_renderer.tsx b/src/plugins/expression_image/public/expression_renderers/image_renderer.tsx index 3d542a9978a83..a38649f13fb32 100644 --- a/src/plugins/expression_image/public/expression_renderers/image_renderer.tsx +++ b/src/plugins/expression_image/public/expression_renderers/image_renderer.tsx @@ -9,7 +9,11 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { ExpressionRenderDefinition, IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { i18n } from '@kbn/i18n'; -import { getElasticLogo, isValidUrl } from '../../../presentation_util/public'; +import { Observable } from 'rxjs'; +import { CoreTheme } from 'kibana/public'; +import { CoreSetup } from '../../../../core/public'; +import { KibanaThemeProvider } from '../../../kibana_react/public'; +import { getElasticLogo, isValidUrl, defaultTheme$ } from '../../../presentation_util/public'; import { ImageRendererConfig } from '../../common/types'; const strings = { @@ -23,31 +27,41 @@ const strings = { }), }; -export const imageRenderer = (): ExpressionRenderDefinition => ({ - name: 'image', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render: async ( - domNode: HTMLElement, - config: ImageRendererConfig, - handlers: IInterpreterRenderHandlers - ) => { - const { elasticLogo } = await getElasticLogo(); - const dataurl = isValidUrl(config.dataurl ?? '') ? config.dataurl : elasticLogo; +export const getImageRenderer = + (theme$: Observable = defaultTheme$) => + (): ExpressionRenderDefinition => ({ + name: 'image', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async ( + domNode: HTMLElement, + config: ImageRendererConfig, + handlers: IInterpreterRenderHandlers + ) => { + const { elasticLogo } = await getElasticLogo(); + const dataurl = isValidUrl(config.dataurl ?? '') ? config.dataurl : elasticLogo; - const style = { - height: '100%', - backgroundImage: `url(${dataurl})`, - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center center', - backgroundSize: config.mode as string, - }; + const style = { + height: '100%', + backgroundImage: `url(${dataurl})`, + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundSize: config.mode as string, + }; - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); - render(
, domNode, () => handlers.done()); - }, -}); + render( + +
+ , + domNode, + () => handlers.done() + ); + }, + }); + +export const imageRendererFactory = (core: CoreSetup) => getImageRenderer(core.theme.theme$); diff --git a/src/plugins/expression_image/public/expression_renderers/index.ts b/src/plugins/expression_image/public/expression_renderers/index.ts index 96c274f05a7a9..6b4c4b03f7922 100644 --- a/src/plugins/expression_image/public/expression_renderers/index.ts +++ b/src/plugins/expression_image/public/expression_renderers/index.ts @@ -6,8 +6,4 @@ * Side Public License, v 1. */ -import { imageRenderer } from './image_renderer'; - -export const renderers = [imageRenderer]; - -export { imageRenderer }; +export { imageRendererFactory, getImageRenderer } from './image_renderer'; diff --git a/src/plugins/expression_image/public/index.ts b/src/plugins/expression_image/public/index.ts index 661a12e7cf028..c379dd05dc221 100755 --- a/src/plugins/expression_image/public/index.ts +++ b/src/plugins/expression_image/public/index.ts @@ -6,9 +6,6 @@ * Side Public License, v 1. */ -// TODO: https://github.com/elastic/kibana/issues/110893 -/* eslint-disable @kbn/eslint/no_export_all */ - import { ExpressionImagePlugin } from './plugin'; export type { ExpressionImagePluginSetup, ExpressionImagePluginStart } from './plugin'; @@ -17,4 +14,4 @@ export function plugin() { return new ExpressionImagePlugin(); } -export * from './expression_renderers'; +export { imageRendererFactory, getImageRenderer } from './expression_renderers'; diff --git a/src/plugins/expression_image/public/plugin.ts b/src/plugins/expression_image/public/plugin.ts index 6e6c02248642f..ba7e2baded8d8 100755 --- a/src/plugins/expression_image/public/plugin.ts +++ b/src/plugins/expression_image/public/plugin.ts @@ -8,7 +8,7 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { ExpressionsStart, ExpressionsSetup } from '../../expressions/public'; -import { imageRenderer } from './expression_renderers'; +import { imageRendererFactory } from './expression_renderers'; import { imageFunction } from '../common/expression_functions'; interface SetupDeps { @@ -27,7 +27,7 @@ export class ExpressionImagePlugin { public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionImagePluginSetup { expressions.registerFunction(imageFunction); - expressions.registerRenderer(imageRenderer); + expressions.registerRenderer(imageRendererFactory(core)); } public start(core: CoreStart): ExpressionImagePluginStart {} diff --git a/src/plugins/expression_shape/common/index.ts b/src/plugins/expression_shape/common/index.ts index 6019cda7a51bd..2a889e6de1bb3 100755 --- a/src/plugins/expression_shape/common/index.ts +++ b/src/plugins/expression_shape/common/index.ts @@ -6,10 +6,31 @@ * Side Public License, v 1. */ -// TODO: https://github.com/elastic/kibana/issues/110893 -/* eslint-disable @kbn/eslint/no_export_all */ +export { + PLUGIN_ID, + PLUGIN_NAME, + SVG, + CSS, + FONT_FAMILY, + FONT_WEIGHT, + BOOLEAN_TRUE, + BOOLEAN_FALSE, +} from './constants'; -export * from './constants'; -export * from './types'; +export type { + Output, + ExpressionShapeFunction, + ProgressArguments, + ProgressOutput, + ExpressionProgressFunction, + OriginString, + ShapeRendererConfig, + NodeDimensions, + ParentNodeParams, + ViewBoxParams, + ProgressRendererConfig, +} from './types'; + +export { Progress, Shape } from './types'; export { getAvailableShapes, getAvailableProgressShapes } from './lib/available_shapes'; diff --git a/src/plugins/expression_shape/common/types/index.ts b/src/plugins/expression_shape/common/types/index.ts index ec934e7affe88..ef45082ac2d96 100644 --- a/src/plugins/expression_shape/common/types/index.ts +++ b/src/plugins/expression_shape/common/types/index.ts @@ -5,5 +5,21 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -export * from './expression_functions'; -export * from './expression_renderers'; + +export type { + Output, + ExpressionShapeFunction, + ProgressArguments, + ProgressOutput, + ExpressionProgressFunction, +} from './expression_functions'; +export { Progress, Shape } from './expression_functions'; + +export type { + OriginString, + ShapeRendererConfig, + NodeDimensions, + ParentNodeParams, + ViewBoxParams, + ProgressRendererConfig, +} from './expression_renderers'; diff --git a/src/plugins/expression_shape/kibana.json b/src/plugins/expression_shape/kibana.json index adf95689e271b..5d831f8e98f60 100755 --- a/src/plugins/expression_shape/kibana.json +++ b/src/plugins/expression_shape/kibana.json @@ -12,5 +12,5 @@ "extraPublicDirs": ["common"], "requiredPlugins": ["expressions", "presentationUtil"], "optionalPlugins": [], - "requiredBundles": [] + "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/expression_shape/public/expression_renderers/__stories__/progress_renderer.stories.tsx b/src/plugins/expression_shape/public/expression_renderers/__stories__/progress_renderer.stories.tsx index dcf2daaafcfc1..862718f775c5e 100644 --- a/src/plugins/expression_shape/public/expression_renderers/__stories__/progress_renderer.stories.tsx +++ b/src/plugins/expression_shape/public/expression_renderers/__stories__/progress_renderer.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; import { Render } from '../../../../presentation_util/public/__stories__'; -import { progressRenderer } from '../progress_renderer'; +import { getProgressRenderer } from '../progress_renderer'; import { Progress } from '../../../common'; storiesOf('renderers/progress', module).add('default', () => { @@ -29,5 +29,5 @@ storiesOf('renderers/progress', module).add('default', () => { valueWeight: 15, }; - return ; + return ; }); diff --git a/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx b/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx index 10ac3df88e81c..d7098e8378c60 100644 --- a/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx +++ b/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; -import { shapeRenderer as shape } from '../'; +import { getShapeRenderer } from '../'; import { Render } from '../../../../presentation_util/public/__stories__'; import { Shape } from '../../../common/types'; @@ -22,5 +22,5 @@ storiesOf('renderers/shape', module).add('default', () => { maintainAspect: true, }; - return ; + return ; }); diff --git a/src/plugins/expression_shape/public/expression_renderers/index.ts b/src/plugins/expression_shape/public/expression_renderers/index.ts index fc031c4a03c8a..59d98e7bd6f8f 100644 --- a/src/plugins/expression_shape/public/expression_renderers/index.ts +++ b/src/plugins/expression_shape/public/expression_renderers/index.ts @@ -6,9 +6,5 @@ * Side Public License, v 1. */ -import { shapeRenderer } from './shape_renderer'; -import { progressRenderer } from './progress_renderer'; - -export const renderers = [shapeRenderer, progressRenderer]; - -export { shapeRenderer, progressRenderer }; +export { getShapeRenderer, shapeRendererFactory } from './shape_renderer'; +export { getProgressRenderer, progressRendererFactory } from './progress_renderer'; diff --git a/src/plugins/expression_shape/public/expression_renderers/progress_renderer.tsx b/src/plugins/expression_shape/public/expression_renderers/progress_renderer.tsx index 5f81ffcffd3d9..b618d24d26fb0 100644 --- a/src/plugins/expression_shape/public/expression_renderers/progress_renderer.tsx +++ b/src/plugins/expression_shape/public/expression_renderers/progress_renderer.tsx @@ -7,11 +7,16 @@ */ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; +import { Observable } from 'rxjs'; +import { CoreTheme } from 'kibana/public'; import { ExpressionRenderDefinition, IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { i18n } from '@kbn/i18n'; +import { I18nProvider } from '@kbn/i18n-react'; +import { KibanaThemeProvider } from '../../../kibana_react/public'; +import { CoreSetup } from '../../../../core/public'; import { ProgressRendererConfig } from '../../common/types'; import { LazyProgressComponent } from '../components/progress'; -import { withSuspense } from '../../../presentation_util/public'; +import { withSuspense, defaultTheme$ } from '../../../presentation_util/public'; const ProgressComponent = withSuspense(LazyProgressComponent); @@ -26,23 +31,31 @@ const strings = { }), }; -export const progressRenderer = (): ExpressionRenderDefinition => ({ - name: 'progress', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render: async ( - domNode: HTMLElement, - config: ProgressRendererConfig, - handlers: IInterpreterRenderHandlers - ) => { - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); +export const getProgressRenderer = + (theme$: Observable = defaultTheme$) => + (): ExpressionRenderDefinition => ({ + name: 'progress', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async ( + domNode: HTMLElement, + config: ProgressRendererConfig, + handlers: IInterpreterRenderHandlers + ) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); - render( - , - domNode - ); - }, -}); + render( + + + + + , + domNode + ); + }, + }); + +export const progressRendererFactory = (core: CoreSetup) => getProgressRenderer(core.theme.theme$); diff --git a/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx b/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx index d6fc7c4d27107..fb2a32884d03b 100644 --- a/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx +++ b/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx @@ -7,10 +7,14 @@ */ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; +import { Observable } from 'rxjs'; +import { CoreTheme } from 'kibana/public'; import { I18nProvider } from '@kbn/i18n-react'; import { ExpressionRenderDefinition, IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { i18n } from '@kbn/i18n'; -import { withSuspense } from '../../../presentation_util/public'; +import { CoreSetup } from '../../../../core/public'; +import { KibanaThemeProvider } from '../../../kibana_react/public'; +import { withSuspense, defaultTheme$ } from '../../../presentation_util/public'; import { ShapeRendererConfig } from '../../common/types'; import { LazyShapeComponent } from '../components/shape'; @@ -27,25 +31,31 @@ const strings = { const ShapeComponent = withSuspense(LazyShapeComponent); -export const shapeRenderer = (): ExpressionRenderDefinition => ({ - name: 'shape', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render: async ( - domNode: HTMLElement, - config: ShapeRendererConfig, - handlers: IInterpreterRenderHandlers - ) => { - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); +export const getShapeRenderer = + (theme$: Observable = defaultTheme$) => + (): ExpressionRenderDefinition => ({ + name: 'shape', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async ( + domNode: HTMLElement, + config: ShapeRendererConfig, + handlers: IInterpreterRenderHandlers + ) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); - render( - - - , - domNode - ); - }, -}); + render( + + + + + , + domNode + ); + }, + }); + +export const shapeRendererFactory = (core: CoreSetup) => getShapeRenderer(core.theme.theme$); diff --git a/src/plugins/expression_shape/public/index.ts b/src/plugins/expression_shape/public/index.ts index 21276d3fb4df9..be260c4c8c80b 100755 --- a/src/plugins/expression_shape/public/index.ts +++ b/src/plugins/expression_shape/public/index.ts @@ -6,9 +6,6 @@ * Side Public License, v 1. */ -// TODO: https://github.com/elastic/kibana/issues/110893 -/* eslint-disable @kbn/eslint/no_export_all */ - import { ExpressionShapePlugin } from './plugin'; export type { ExpressionShapePluginSetup, ExpressionShapePluginStart } from './plugin'; @@ -17,10 +14,50 @@ export function plugin() { return new ExpressionShapePlugin(); } -export * from './expression_renderers'; +export { + getShapeRenderer, + shapeRendererFactory, + getProgressRenderer, + progressRendererFactory, +} from './expression_renderers'; + export { LazyShapeDrawer } from './components/shape'; export { LazyProgressDrawer } from './components/progress'; export { getDefaultShapeData } from './components/reusable'; -export * from './components/shape/types'; -export * from './components/reusable/types'; -export * from '../common/types'; + +export type { + ShapeProps, + ShapeAttributes, + ShapeContentAttributes, + SvgConfig, + SvgTextAttributes, + CircleParams, + RectParams, + PathParams, + PolygonParams, + SpecificShapeContentAttributes, + ShapeDrawerProps, + ShapeDrawerComponentProps, + ShapeRef, + ShapeType, +} from './components/reusable/types'; + +export { SvgElementTypes } from './components/reusable/types'; + +export type { + Output, + ExpressionShapeFunction, + ProgressArguments, + ProgressOutput, + ExpressionProgressFunction, + OriginString, + ShapeRendererConfig, + NodeDimensions, + ParentNodeParams, + ViewBoxParams, + ProgressRendererConfig, +} from '../common/types'; + +export { Progress, Shape } from '../common/types'; + +export type { ShapeComponentProps, Dimensions } from './components/shape/types'; diff --git a/src/plugins/expression_shape/public/plugin.ts b/src/plugins/expression_shape/public/plugin.ts index 9403bce0af728..5728b92e97f94 100755 --- a/src/plugins/expression_shape/public/plugin.ts +++ b/src/plugins/expression_shape/public/plugin.ts @@ -8,7 +8,7 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { ExpressionsStart, ExpressionsSetup } from '../../expressions/public'; -import { shapeRenderer, progressRenderer } from './expression_renderers'; +import { shapeRendererFactory, progressRendererFactory } from './expression_renderers'; import { shapeFunction, progressFunction } from '../common/expression_functions'; interface SetupDeps { @@ -28,8 +28,8 @@ export class ExpressionShapePlugin public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionShapePluginSetup { expressions.registerFunction(shapeFunction); expressions.registerFunction(progressFunction); - expressions.registerRenderer(shapeRenderer); - expressions.registerRenderer(progressRenderer); + expressions.registerRenderer(shapeRendererFactory(core)); + expressions.registerRenderer(progressRendererFactory(core)); } public start(core: CoreStart): ExpressionShapePluginStart {} diff --git a/src/plugins/input_control_vis/public/control/create_search_source.ts b/src/plugins/input_control_vis/public/control/create_search_source.ts index 940bf2221fb94..87dec8b1d9a24 100644 --- a/src/plugins/input_control_vis/public/control/create_search_source.ts +++ b/src/plugins/input_control_vis/public/control/create_search_source.ts @@ -8,7 +8,7 @@ import { Filter } from '@kbn/es-query'; import { - SearchSourceFields, + SerializedSearchSourceFields, IndexPattern, TimefilterContract, DataPublicPluginStart, @@ -16,7 +16,7 @@ import { export async function createSearchSource( { create }: DataPublicPluginStart['search']['searchSource'], - initialState: SearchSourceFields | null, + initialState: SerializedSearchSourceFields | null, indexPattern: IndexPattern, aggs: any, useTimeFilter: boolean, diff --git a/src/plugins/input_control_vis/public/control/list_control_factory.ts b/src/plugins/input_control_vis/public/control/list_control_factory.ts index 342e05460b8f2..39c5f259c2735 100644 --- a/src/plugins/input_control_vis/public/control/list_control_factory.ts +++ b/src/plugins/input_control_vis/public/control/list_control_factory.ts @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { IndexPatternField, TimefilterContract, - SearchSourceFields, + SerializedSearchSourceFields, DataPublicPluginStart, } from 'src/plugins/data/public'; import { Control, noValuesDisableMsg, noIndexPatternMsg } from './control'; @@ -127,7 +127,7 @@ export class ListControl extends Control { const fieldName = this.filterManager.fieldName; const settings = await this.getSettings(); - const initialSearchSourceState: SearchSourceFields = { + const initialSearchSourceState: SerializedSearchSourceFields = { timeout: `${settings.autocompleteTimeout}ms`, terminate_after: Number(settings.autocompleteTerminateAfter), }; diff --git a/src/plugins/presentation_util/common/index.ts b/src/plugins/presentation_util/common/index.ts index 4510a0aac5a0b..a84a78c823a5f 100644 --- a/src/plugins/presentation_util/common/index.ts +++ b/src/plugins/presentation_util/common/index.ts @@ -12,4 +12,10 @@ export const PLUGIN_ID = 'presentationUtil'; export const PLUGIN_NAME = 'presentationUtil'; +/** + * The unique identifier for the Expressions Language for use in the ExpressionInput + * and CodeEditor components. + */ +export const EXPRESSIONS_LANGUAGE_ID = 'kibana-expressions'; + export * from './labs'; diff --git a/src/plugins/presentation_util/kibana.json b/src/plugins/presentation_util/kibana.json index 210937b335e50..32460a8455152 100644 --- a/src/plugins/presentation_util/kibana.json +++ b/src/plugins/presentation_util/kibana.json @@ -9,7 +9,16 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "extraPublicDirs": ["common/lib"], - "requiredPlugins": ["savedObjects", "data", "dataViews", "embeddable", "kibanaReact"], + "extraPublicDirs": [ + "common/lib" + ], + "requiredPlugins": [ + "savedObjects", + "data", + "dataViews", + "embeddable", + "kibanaReact", + "expressions" + ], "optionalPlugins": [] } diff --git a/x-pack/plugins/canvas/common/lib/autocomplete.ts b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts similarity index 98% rename from x-pack/plugins/canvas/common/lib/autocomplete.ts rename to src/plugins/presentation_util/public/components/expression_input/autocomplete.ts index 88fb6b052b957..5f0c9cab6215c 100644 --- a/x-pack/plugins/canvas/common/lib/autocomplete.ts +++ b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts @@ -1,8 +1,9 @@ /* * 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. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import { uniq } from 'lodash'; @@ -15,9 +16,9 @@ import { ExpressionFunction, ExpressionFunctionParameter, getByAlias, -} from '../../../../../src/plugins/expressions/common'; +} from '../../../../expressions/common'; -const MARKER = 'CANVAS_SUGGESTION_MARKER'; +const MARKER = 'EXPRESSIONS_SUGGESTION_MARKER'; interface BaseSuggestion { text: string; @@ -25,11 +26,6 @@ interface BaseSuggestion { end: number; } -export interface FunctionSuggestion extends BaseSuggestion { - type: 'function'; - fnDef: ExpressionFunction; -} - interface ArgSuggestionValue extends Omit { name: string; } @@ -43,8 +39,6 @@ interface ValueSuggestion extends BaseSuggestion { type: 'value'; } -export type AutocompleteSuggestion = FunctionSuggestion | ArgSuggestion | ValueSuggestion; - interface FnArgAtPosition { ast: ExpressionASTWithMeta; fnIndex: number; @@ -57,6 +51,7 @@ interface FnArgAtPosition { // If this function is a sub-expression function, we need the parent function and argument // name to determine the return type of the function parentFn?: string; + // If this function is a sub-expression function, the context could either be local or it // could be the parent's previous function. contextFn?: string | null; @@ -101,6 +96,13 @@ type ExpressionASTWithMeta = ASTMetaInformation< > >; +export interface FunctionSuggestion extends BaseSuggestion { + type: 'function'; + fnDef: ExpressionFunction; +} + +export type AutocompleteSuggestion = FunctionSuggestion | ArgSuggestion | ValueSuggestion; + // Typeguard for checking if ExpressionArg is a new expression function isExpression( maybeExpression: ExpressionArgASTWithMeta diff --git a/src/plugins/presentation_util/public/components/expression_input/constants.ts b/src/plugins/presentation_util/public/components/expression_input/constants.ts new file mode 100644 index 0000000000000..f937d55cbf9bb --- /dev/null +++ b/src/plugins/presentation_util/public/components/expression_input/constants.ts @@ -0,0 +1,28 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CodeEditorProps } from '../../../../kibana_react/public'; + +export const LANGUAGE_CONFIGURATION = { + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + ], +}; + +export const CODE_EDITOR_OPTIONS: CodeEditorProps['options'] = { + scrollBeyondLastLine: false, + quickSuggestions: true, + minimap: { + enabled: false, + }, + wordWrap: 'on', + wrappingIndent: 'indent', +}; diff --git a/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx b/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx new file mode 100644 index 0000000000000..648171959791f --- /dev/null +++ b/src/plugins/presentation_util/public/components/expression_input/expression_input.stories.tsx @@ -0,0 +1,94 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import { Meta } from '@storybook/react'; + +import { ExpressionFunction, ExpressionFunctionParameter, Style } from 'src/plugins/expressions'; +import { ExpressionInput } from '../expression_input'; +import { registerExpressionsLanguage } from './language'; + +const content: ExpressionFunctionParameter<'string'> = { + name: 'content', + required: false, + help: 'A string of text that contains Markdown. To concatenate, pass the `string` function multiple times.', + types: ['string'], + default: '', + aliases: ['_', 'expression'], + multi: true, + resolve: false, + options: [], + accepts: () => true, +}; + +const font: ExpressionFunctionParameter