diff --git a/.buildkite/pipelines/pull_request/osquery_cypress.yml b/.buildkite/pipelines/pull_request/osquery_cypress.yml new file mode 100644 index 000000000000..766d28e0877c --- /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 d0f38dc77335..ab125d4f7337 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 000000000000..a23d41c4f8d4 --- /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 0201c7774f85..5d955c789dde 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/package.json b/package.json index 1e5a135b723e..374ccee71ec6 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", @@ -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,8 @@ "@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", "@types/license-checker": "15.0.0", @@ -694,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", @@ -749,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", @@ -786,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 8208496f7d80..96b184614768 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -84,6 +84,8 @@ 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 c6611e71e35a..66e00706e9e5 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 70de78b7617c..ed6082527bab 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 a3b6880c3293..d6a0e91b9b42 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 8635421beb0a..f9db84f255ec 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 c0b75ab491ac..0353b2d16be7 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-crypto/BUILD.bazel b/packages/kbn-crypto/BUILD.bazel index 0f35aab46107..81ee6d770103 100644 --- a/packages/kbn-crypto/BUILD.bazel +++ b/packages/kbn-crypto/BUILD.bazel @@ -1,10 +1,11 @@ -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-crypto" PKG_REQUIRE_NAME = "@kbn/crypto" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__crypto" SOURCE_FILES = glob( [ @@ -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-crypto/package.json b/packages/kbn-crypto/package.json index 8fa6cd3c232f..96bf21906ed4 100644 --- a/packages/kbn-crypto/package.json +++ b/packages/kbn-crypto/package.json @@ -3,6 +3,5 @@ "version": "1.0.0", "private": true, "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "./target_node/index.js", - "types": "./target_types/index.d.ts" + "main": "./target_node/index.js" } diff --git a/packages/kbn-docs-utils/src/api_docs/README.md b/packages/kbn-docs-utils/src/api_docs/README.md index f980fe83b959..728cb0690834 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 26d2030d1b0b..70d8d659c99f 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 e5f1de4d07f6..dd81e8318e9d 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 cc03c8107074..a389086c9ee3 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 609fe6d00f17..be74c363a7ac 100644 --- a/packages/kbn-server-http-tools/BUILD.bazel +++ b/packages/kbn-server-http-tools/BUILD.bazel @@ -37,8 +37,8 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-config-schema", - "//packages/kbn-crypto", + "//packages/kbn-config-schema:npm_module_types", + "//packages/kbn-crypto:npm_module_types", "@npm//@hapi/hapi", "@npm//@hapi/hoek", "@npm//joi", diff --git a/packages/kbn-server-route-repository/BUILD.bazel b/packages/kbn-server-route-repository/BUILD.bazel index 9f8a9f34061d..6e7e10d4dd81 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 c2f82d65d331..c4d256e7672a 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/packages/kbn-utils/src/path/index.test.ts b/packages/kbn-utils/src/path/index.test.ts index 307d47af9ac5..e4c80a0783b5 100644 --- a/packages/kbn-utils/src/path/index.test.ts +++ b/packages/kbn-utils/src/path/index.test.ts @@ -7,10 +7,17 @@ */ import { accessSync, constants } from 'fs'; -import { createAbsolutePathSerializer } from '@kbn/dev-utils'; import { getConfigPath, getDataPath, getLogsPath, getConfigDirectory } from './'; - -expect.addSnapshotSerializer(createAbsolutePathSerializer()); +import { REPO_ROOT } from '../repo_root'; + +expect.addSnapshotSerializer( + ((rootPath: string = REPO_ROOT, replacement = '') => { + return { + test: (value: any) => typeof value === 'string' && value.startsWith(rootPath), + serialize: (value: string) => value.replace(rootPath, replacement).replace(/\\/g, '/'), + }; + })() +); describe('Default path finder', () => { it('should expose a path to the config directory', () => { diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index d4393791a74f..c599b2f71940 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 0e006856dac9..866e19a1d0d3 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 c6c8bb4d26f9..3d2300940ac0 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 dfcd1b12cb62..de32836ced12 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 d2fd10f14b63..1785e55acc79 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 6729025943b9..c4b39773c440 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 f34f32a0bff9..6c7d08a4f2b5 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 1afd2d98782a..87e249acab8b 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 a3979ffa6e94..3ac6b623fbc8 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 c411e53abfcd..acfdf1726316 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 a54a9c7f35e3..567a0b1d8c6d 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 2cd7993e3b18..810436dc30b9 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 b4006a691afc..e14ae252da95 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_reveal_image/kibana.json b/src/plugins/expression_reveal_image/kibana.json index dad7fdfe2bc5..5fb13ce31247 100755 --- a/src/plugins/expression_reveal_image/kibana.json +++ b/src/plugins/expression_reveal_image/kibana.json @@ -11,5 +11,5 @@ "ui": true, "requiredPlugins": ["expressions", "presentationUtil"], "optionalPlugins": [], - "requiredBundles": [] + "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/expression_reveal_image/public/expression_renderers/__stories__/reveal_image_renderer.stories.tsx b/src/plugins/expression_reveal_image/public/expression_renderers/__stories__/reveal_image_renderer.stories.tsx index 863d8d1000f3..22dd2ef4156d 100644 --- a/src/plugins/expression_reveal_image/public/expression_renderers/__stories__/reveal_image_renderer.stories.tsx +++ b/src/plugins/expression_reveal_image/public/expression_renderers/__stories__/reveal_image_renderer.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; -import { revealImageRenderer } from '../'; +import { getRevealImageRenderer } from '../'; import { getElasticOutline, getElasticLogo } from '../../../../presentation_util/public'; import { Render, waitFor } from '../../../../presentation_util/public/__stories__'; import { Origin } from '../../../common/types/expression_functions'; @@ -26,7 +26,7 @@ const Renderer = ({ origin: Origin.LEFT, percent: 0.45, }; - return ; + return ; }; storiesOf('renderers/revealImage', module).add( diff --git a/src/plugins/expression_reveal_image/public/expression_renderers/index.ts b/src/plugins/expression_reveal_image/public/expression_renderers/index.ts index 433a81884f15..959a630b08b5 100644 --- a/src/plugins/expression_reveal_image/public/expression_renderers/index.ts +++ b/src/plugins/expression_reveal_image/public/expression_renderers/index.ts @@ -6,8 +6,4 @@ * Side Public License, v 1. */ -import { revealImageRenderer } from './reveal_image_renderer'; - -export const renderers = [revealImageRenderer]; - -export { revealImageRenderer }; +export { revealImageRendererFactory, getRevealImageRenderer } from './reveal_image_renderer'; diff --git a/src/plugins/expression_reveal_image/public/expression_renderers/reveal_image_renderer.tsx b/src/plugins/expression_reveal_image/public/expression_renderers/reveal_image_renderer.tsx index d4dec3a8a582..6bdd01429641 100644 --- a/src/plugins/expression_reveal_image/public/expression_renderers/reveal_image_renderer.tsx +++ b/src/plugins/expression_reveal_image/public/expression_renderers/reveal_image_renderer.tsx @@ -7,10 +7,14 @@ */ import React, { lazy } 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 { RevealImageRendererConfig } from '../../common/types'; export const strings = { @@ -27,25 +31,32 @@ export const strings = { const LazyRevealImageComponent = lazy(() => import('../components/reveal_image_component')); const RevealImageComponent = withSuspense(LazyRevealImageComponent, null); -export const revealImageRenderer = (): ExpressionRenderDefinition => ({ - name: 'revealImage', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render: ( - domNode: HTMLElement, - config: RevealImageRendererConfig, - handlers: IInterpreterRenderHandlers - ) => { - handlers.onDestroy(() => { - unmountComponentAtNode(domNode); - }); +export const getRevealImageRenderer = + (theme$: Observable = defaultTheme$) => + (): ExpressionRenderDefinition => ({ + name: 'revealImage', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: ( + domNode: HTMLElement, + config: RevealImageRendererConfig, + handlers: IInterpreterRenderHandlers + ) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); - render( - - - , - domNode - ); - }, -}); + render( + + + + + , + domNode + ); + }, + }); + +export const revealImageRendererFactory = (core: CoreSetup) => + getRevealImageRenderer(core.theme.theme$); diff --git a/src/plugins/expression_reveal_image/public/index.ts b/src/plugins/expression_reveal_image/public/index.ts index 66512a1126b0..736e062475e6 100755 --- a/src/plugins/expression_reveal_image/public/index.ts +++ b/src/plugins/expression_reveal_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 { ExpressionRevealImagePlugin } from './plugin'; export type { ExpressionRevealImagePluginSetup, ExpressionRevealImagePluginStart } from './plugin'; @@ -17,4 +14,4 @@ export function plugin() { return new ExpressionRevealImagePlugin(); } -export * from './expression_renderers'; +export { revealImageRendererFactory, getRevealImageRenderer } from './expression_renderers'; diff --git a/src/plugins/expression_reveal_image/public/plugin.ts b/src/plugins/expression_reveal_image/public/plugin.ts index c5e1b5c8d916..17bff3f33e8a 100755 --- a/src/plugins/expression_reveal_image/public/plugin.ts +++ b/src/plugins/expression_reveal_image/public/plugin.ts @@ -8,7 +8,7 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { ExpressionsStart, ExpressionsSetup } from '../../expressions/public'; -import { revealImageRenderer } from './expression_renderers'; +import { revealImageRendererFactory } from './expression_renderers'; import { revealImageFunction } from '../common/expression_functions'; interface SetupDeps { @@ -33,7 +33,7 @@ export class ExpressionRevealImagePlugin { public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionRevealImagePluginSetup { expressions.registerFunction(revealImageFunction); - expressions.registerRenderer(revealImageRenderer); + expressions.registerRenderer(revealImageRendererFactory(core)); } public start(core: CoreStart): ExpressionRevealImagePluginStart {} 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 940bf2221fb9..87dec8b1d9a2 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 342e05460b8f..39c5f259c273 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 4510a0aac5a0..a84a78c823a5 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 210937b335e5..32460a845515 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 88fb6b052b95..5f0c9cab6215 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 000000000000..f937d55cbf9b --- /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 000000000000..648171959791 --- /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