From f97bf98e5e23ace85254a2bc3364786eb94ee5c4 Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Thu, 22 Sep 2022 14:14:05 +0200 Subject: [PATCH 01/29] Migrate browser-side `plugins` domain to packages (#141087) * create empty packages, start moving public types * add dependencies for public package * create internal package * start adapting usages * [CI] Auto-commit changed files from 'node scripts/generate codeowners' * fix index exports * actually export the contract types * add empty plugins packages * start moving types, add public package * first passing bazel build * update mocks * adapt usages * [CI] Auto-commit changed files from 'node scripts/generate codeowners' * create empty lifecycle mocks package * move core mocks to lifecycle mocks package * fix usages * [CI] Auto-commit changed files from 'node scripts/generate codeowners' * update readme Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 6 + package.json | 12 ++ packages/BUILD.bazel | 12 ++ .../BUILD.bazel | 116 ++++++++++++ .../core-lifecycle-browser-internal/README.md | 5 + .../core-lifecycle-browser-internal/index.ts | 9 + .../jest.config.js | 13 ++ .../kibana.jsonc | 7 + .../package.json | 9 + .../src/index.ts | 10 + .../src/internal_core_setup.ts | 17 ++ .../src/internal_core_start.ts | 17 ++ .../tsconfig.json | 18 ++ .../core-lifecycle-browser-mocks/BUILD.bazel | 142 ++++++++++++++ .../core-lifecycle-browser-mocks/README.md | 4 + .../core-lifecycle-browser-mocks/index.ts | 9 + .../jest.config.js | 13 ++ .../core-lifecycle-browser-mocks/kibana.jsonc | 7 + .../core-lifecycle-browser-mocks/package.json | 9 + .../src/core_setup.mock.ts | 51 ++++++ .../src/core_start.mock.ts | 47 +++++ .../core-lifecycle-browser-mocks/src/index.ts | 15 ++ .../tsconfig.json | 18 ++ .../core-lifecycle-browser/BUILD.bazel | 128 +++++++++++++ .../core-lifecycle-browser/README.md | 5 + .../lifecycle/core-lifecycle-browser/index.ts | 9 + .../core-lifecycle-browser/jest.config.js | 13 ++ .../core-lifecycle-browser/kibana.jsonc | 7 + .../core-lifecycle-browser/package.json | 9 + .../core-lifecycle-browser/src/core_setup.ts | 67 +++++++ .../core-lifecycle-browser/src/core_start.ts | 65 +++++++ .../core-lifecycle-browser/src/index.ts | 10 + .../core-lifecycle-browser/tsconfig.json | 18 ++ .../core-plugins-browser-internal/BUILD.bazel | 125 +++++++++++++ .../core-plugins-browser-internal/README.md | 3 + .../core-plugins-browser-internal/index.ts | 15 ++ .../jest.config.js | 13 ++ .../kibana.jsonc | 7 + .../package.json | 9 + .../src}/index.ts | 9 +- .../src}/plugin.test.mocks.ts | 0 .../src}/plugin.test.ts | 6 +- .../src}/plugin.ts | 39 +--- .../src}/plugin_context.ts | 25 +-- .../src}/plugin_reader.test.ts | 0 .../src}/plugin_reader.ts | 2 +- .../src}/plugins_service.test.mocks.ts | 4 +- .../src}/plugins_service.test.ts | 9 +- .../src}/plugins_service.ts | 2 +- .../src/test_helpers/index.ts | 9 + .../src/test_helpers/mocks.ts | 34 ++++ .../tsconfig.json | 18 ++ .../core-plugins-browser-mocks/BUILD.bazel | 114 ++++++++++++ .../core-plugins-browser-mocks/README.md | 4 + .../core-plugins-browser-mocks/index.ts | 9 + .../core-plugins-browser-mocks/jest.config.js | 13 ++ .../core-plugins-browser-mocks/kibana.jsonc | 7 + .../core-plugins-browser-mocks/package.json | 9 + .../core-plugins-browser-mocks/src/index.ts | 9 + .../src}/plugins_service.mock.ts | 29 ++- .../core-plugins-browser-mocks/tsconfig.json | 18 ++ .../plugins/core-plugins-browser/BUILD.bazel | 116 ++++++++++++ .../plugins/core-plugins-browser/README.md | 8 + .../plugins/core-plugins-browser/index.ts | 9 + .../core-plugins-browser/jest.config.js | 13 ++ .../plugins/core-plugins-browser/kibana.jsonc | 7 + .../plugins/core-plugins-browser/package.json | 9 + .../plugins/core-plugins-browser/src/index.ts | 10 + .../core-plugins-browser/src/plugin.ts | 27 +++ .../src/plugin_initializer.ts | 43 +++++ .../core-plugins-browser/tsconfig.json | 18 ++ src/core/public/core_system.test.mocks.ts | 4 +- src/core/public/core_system.ts | 24 +-- src/core/public/index.ts | 173 ++---------------- src/core/public/mocks.ts | 103 +---------- yarn.lock | 48 +++++ 76 files changed, 1706 insertions(+), 344 deletions(-) create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/BUILD.bazel create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/README.md create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/jest.config.js create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/kibana.jsonc create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/package.json create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/src/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/BUILD.bazel create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/README.md create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/jest.config.js create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/kibana.jsonc create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/package.json create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_setup.mock.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_start.mock.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/src/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser-mocks/tsconfig.json create mode 100644 packages/core/lifecycle/core-lifecycle-browser/BUILD.bazel create mode 100644 packages/core/lifecycle/core-lifecycle-browser/README.md create mode 100644 packages/core/lifecycle/core-lifecycle-browser/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser/jest.config.js create mode 100644 packages/core/lifecycle/core-lifecycle-browser/kibana.jsonc create mode 100644 packages/core/lifecycle/core-lifecycle-browser/package.json create mode 100644 packages/core/lifecycle/core-lifecycle-browser/src/core_setup.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser/src/core_start.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser/src/index.ts create mode 100644 packages/core/lifecycle/core-lifecycle-browser/tsconfig.json create mode 100644 packages/core/plugins/core-plugins-browser-internal/BUILD.bazel create mode 100644 packages/core/plugins/core-plugins-browser-internal/README.md create mode 100644 packages/core/plugins/core-plugins-browser-internal/index.ts create mode 100644 packages/core/plugins/core-plugins-browser-internal/jest.config.js create mode 100644 packages/core/plugins/core-plugins-browser-internal/kibana.jsonc create mode 100644 packages/core/plugins/core-plugins-browser-internal/package.json rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/index.ts (68%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin.test.mocks.ts (100%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin.test.ts (95%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin.ts (81%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin_context.ts (84%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin_reader.test.ts (100%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugin_reader.ts (95%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugins_service.test.mocks.ts (86%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugins_service.test.ts (97%) rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-internal/src}/plugins_service.ts (98%) create mode 100644 packages/core/plugins/core-plugins-browser-internal/src/test_helpers/index.ts create mode 100644 packages/core/plugins/core-plugins-browser-internal/src/test_helpers/mocks.ts create mode 100644 packages/core/plugins/core-plugins-browser-internal/tsconfig.json create mode 100644 packages/core/plugins/core-plugins-browser-mocks/BUILD.bazel create mode 100644 packages/core/plugins/core-plugins-browser-mocks/README.md create mode 100644 packages/core/plugins/core-plugins-browser-mocks/index.ts create mode 100644 packages/core/plugins/core-plugins-browser-mocks/jest.config.js create mode 100644 packages/core/plugins/core-plugins-browser-mocks/kibana.jsonc create mode 100644 packages/core/plugins/core-plugins-browser-mocks/package.json create mode 100644 packages/core/plugins/core-plugins-browser-mocks/src/index.ts rename {src/core/public/plugins => packages/core/plugins/core-plugins-browser-mocks/src}/plugins_service.mock.ts (66%) create mode 100644 packages/core/plugins/core-plugins-browser-mocks/tsconfig.json create mode 100644 packages/core/plugins/core-plugins-browser/BUILD.bazel create mode 100644 packages/core/plugins/core-plugins-browser/README.md create mode 100644 packages/core/plugins/core-plugins-browser/index.ts create mode 100644 packages/core/plugins/core-plugins-browser/jest.config.js create mode 100644 packages/core/plugins/core-plugins-browser/kibana.jsonc create mode 100644 packages/core/plugins/core-plugins-browser/package.json create mode 100644 packages/core/plugins/core-plugins-browser/src/index.ts create mode 100644 packages/core/plugins/core-plugins-browser/src/plugin.ts create mode 100644 packages/core/plugins/core-plugins-browser/src/plugin_initializer.ts create mode 100644 packages/core/plugins/core-plugins-browser/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dc7a6270638c..6eecf19ee57b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -753,6 +753,9 @@ packages/core/injected-metadata/core-injected-metadata-browser-mocks @elastic/ki packages/core/injected-metadata/core-injected-metadata-common-internal @elastic/kibana-core packages/core/integrations/core-integrations-browser-internal @elastic/kibana-core packages/core/integrations/core-integrations-browser-mocks @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-browser @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-browser-internal @elastic/kibana-core +packages/core/lifecycle/core-lifecycle-browser-mocks @elastic/kibana-core packages/core/logging/core-logging-server @elastic/kibana-core packages/core/logging/core-logging-server-internal @elastic/kibana-core packages/core/logging/core-logging-server-mocks @elastic/kibana-core @@ -772,6 +775,9 @@ packages/core/notifications/core-notifications-browser-mocks @elastic/kibana-cor packages/core/overlays/core-overlays-browser @elastic/kibana-core packages/core/overlays/core-overlays-browser-internal @elastic/kibana-core packages/core/overlays/core-overlays-browser-mocks @elastic/kibana-core +packages/core/plugins/core-plugins-browser @elastic/kibana-core +packages/core/plugins/core-plugins-browser-internal @elastic/kibana-core +packages/core/plugins/core-plugins-browser-mocks @elastic/kibana-core packages/core/preboot/core-preboot-server @elastic/kibana-core packages/core/preboot/core-preboot-server-internal @elastic/kibana-core packages/core/preboot/core-preboot-server-mocks @elastic/kibana-core diff --git a/package.json b/package.json index 7c8a27447d4c..ff83389b8f3f 100644 --- a/package.json +++ b/package.json @@ -230,6 +230,9 @@ "@kbn/core-injected-metadata-common-internal": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-common-internal", "@kbn/core-integrations-browser-internal": "link:bazel-bin/packages/core/integrations/core-integrations-browser-internal", "@kbn/core-integrations-browser-mocks": "link:bazel-bin/packages/core/integrations/core-integrations-browser-mocks", + "@kbn/core-lifecycle-browser": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser", + "@kbn/core-lifecycle-browser-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal", + "@kbn/core-lifecycle-browser-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks", "@kbn/core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server", "@kbn/core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal", "@kbn/core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks", @@ -249,6 +252,9 @@ "@kbn/core-overlays-browser": "link:bazel-bin/packages/core/overlays/core-overlays-browser", "@kbn/core-overlays-browser-internal": "link:bazel-bin/packages/core/overlays/core-overlays-browser-internal", "@kbn/core-overlays-browser-mocks": "link:bazel-bin/packages/core/overlays/core-overlays-browser-mocks", + "@kbn/core-plugins-browser": "link:bazel-bin/packages/core/plugins/core-plugins-browser", + "@kbn/core-plugins-browser-internal": "link:bazel-bin/packages/core/plugins/core-plugins-browser-internal", + "@kbn/core-plugins-browser-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks", "@kbn/core-preboot-server": "link:bazel-bin/packages/core/preboot/core-preboot-server", "@kbn/core-preboot-server-internal": "link:bazel-bin/packages/core/preboot/core-preboot-server-internal", "@kbn/core-preboot-server-mocks": "link:bazel-bin/packages/core/preboot/core-preboot-server-mocks", @@ -940,6 +946,9 @@ "@types/kbn__core-injected-metadata-common-internal": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-common-internal/npm_module_types", "@types/kbn__core-integrations-browser-internal": "link:bazel-bin/packages/core/integrations/core-integrations-browser-internal/npm_module_types", "@types/kbn__core-integrations-browser-mocks": "link:bazel-bin/packages/core/integrations/core-integrations-browser-mocks/npm_module_types", + "@types/kbn__core-lifecycle-browser": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser/npm_module_types", + "@types/kbn__core-lifecycle-browser-internal": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal/npm_module_types", + "@types/kbn__core-lifecycle-browser-mocks": "link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks/npm_module_types", "@types/kbn__core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server/npm_module_types", "@types/kbn__core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal/npm_module_types", "@types/kbn__core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks/npm_module_types", @@ -959,6 +968,9 @@ "@types/kbn__core-overlays-browser": "link:bazel-bin/packages/core/overlays/core-overlays-browser/npm_module_types", "@types/kbn__core-overlays-browser-internal": "link:bazel-bin/packages/core/overlays/core-overlays-browser-internal/npm_module_types", "@types/kbn__core-overlays-browser-mocks": "link:bazel-bin/packages/core/overlays/core-overlays-browser-mocks/npm_module_types", + "@types/kbn__core-plugins-browser": "link:bazel-bin/packages/core/plugins/core-plugins-browser/npm_module_types", + "@types/kbn__core-plugins-browser-internal": "link:bazel-bin/packages/core/plugins/core-plugins-browser-internal/npm_module_types", + "@types/kbn__core-plugins-browser-mocks": "link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks/npm_module_types", "@types/kbn__core-preboot-server": "link:bazel-bin/packages/core/preboot/core-preboot-server/npm_module_types", "@types/kbn__core-preboot-server-internal": "link:bazel-bin/packages/core/preboot/core-preboot-server-internal/npm_module_types", "@types/kbn__core-preboot-server-mocks": "link:bazel-bin/packages/core/preboot/core-preboot-server-mocks/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index d6994772c9ef..ea24a3a04602 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -96,6 +96,9 @@ filegroup( "//packages/core/injected-metadata/core-injected-metadata-common-internal:build", "//packages/core/integrations/core-integrations-browser-internal:build", "//packages/core/integrations/core-integrations-browser-mocks:build", + "//packages/core/lifecycle/core-lifecycle-browser:build", + "//packages/core/lifecycle/core-lifecycle-browser-internal:build", + "//packages/core/lifecycle/core-lifecycle-browser-mocks:build", "//packages/core/logging/core-logging-server:build", "//packages/core/logging/core-logging-server-internal:build", "//packages/core/logging/core-logging-server-mocks:build", @@ -115,6 +118,9 @@ filegroup( "//packages/core/overlays/core-overlays-browser:build", "//packages/core/overlays/core-overlays-browser-internal:build", "//packages/core/overlays/core-overlays-browser-mocks:build", + "//packages/core/plugins/core-plugins-browser:build", + "//packages/core/plugins/core-plugins-browser-internal:build", + "//packages/core/plugins/core-plugins-browser-mocks:build", "//packages/core/preboot/core-preboot-server:build", "//packages/core/preboot/core-preboot-server-internal:build", "//packages/core/preboot/core-preboot-server-mocks:build", @@ -419,6 +425,9 @@ filegroup( "//packages/core/injected-metadata/core-injected-metadata-common-internal:build_types", "//packages/core/integrations/core-integrations-browser-internal:build_types", "//packages/core/integrations/core-integrations-browser-mocks:build_types", + "//packages/core/lifecycle/core-lifecycle-browser:build_types", + "//packages/core/lifecycle/core-lifecycle-browser-internal:build_types", + "//packages/core/lifecycle/core-lifecycle-browser-mocks:build_types", "//packages/core/logging/core-logging-server:build_types", "//packages/core/logging/core-logging-server-internal:build_types", "//packages/core/logging/core-logging-server-mocks:build_types", @@ -438,6 +447,9 @@ filegroup( "//packages/core/overlays/core-overlays-browser:build_types", "//packages/core/overlays/core-overlays-browser-internal:build_types", "//packages/core/overlays/core-overlays-browser-mocks:build_types", + "//packages/core/plugins/core-plugins-browser:build_types", + "//packages/core/plugins/core-plugins-browser-internal:build_types", + "//packages/core/plugins/core-plugins-browser-mocks:build_types", "//packages/core/preboot/core-preboot-server:build_types", "//packages/core/preboot/core-preboot-server-internal:build_types", "//packages/core/preboot/core-preboot-server-mocks:build_types", diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-browser-internal/BUILD.bazel new file mode 100644 index 000000000000..3f1aa3eb50c4 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/BUILD.bazel @@ -0,0 +1,116 @@ +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_DIRNAME = "core-lifecycle-browser-internal" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-browser-internal" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/lifecycle/core-lifecycle-browser:npm_module_types", + "//packages/core/application/core-application-browser-internal:npm_module_types", + "//packages/core/injected-metadata/core-injected-metadata-browser-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/README.md b/packages/core/lifecycle/core-lifecycle-browser-internal/README.md new file mode 100644 index 000000000000..e25f622ea619 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/README.md @@ -0,0 +1,5 @@ +# @kbn/core-lifecycle-browser-internal + +This package contains the internal types for core's lifecycle contracts: +- `InternalCoreSetup` +- `InternalCoreStart` diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/index.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/index.ts new file mode 100644 index 000000000000..9cb96150c7f2 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/index.ts @@ -0,0 +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 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. + */ + +export type { InternalCoreSetup, InternalCoreStart } from './src'; diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/jest.config.js b/packages/core/lifecycle/core-lifecycle-browser-internal/jest.config.js new file mode 100644 index 000000000000..713613cbc6d1 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-browser-internal'], +}; diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-browser-internal/kibana.jsonc new file mode 100644 index 000000000000..c552d622aa43 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-browser-internal", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/package.json b/packages/core/lifecycle/core-lifecycle-browser-internal/package.json new file mode 100644 index 000000000000..738d3fed2bb5 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-lifecycle-browser-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/src/index.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/src/index.ts new file mode 100644 index 000000000000..fdd37f693fee --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/src/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export type { InternalCoreSetup } from './internal_core_setup'; +export type { InternalCoreStart } from './internal_core_start'; diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts new file mode 100644 index 000000000000..e844b3facf76 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_setup.ts @@ -0,0 +1,17 @@ +/* + * 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 type { CoreSetup } from '@kbn/core-lifecycle-browser'; +import type { InternalApplicationSetup } from '@kbn/core-application-browser-internal'; +import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; + +/** @internal */ +export interface InternalCoreSetup extends Omit { + application: InternalApplicationSetup; + injectedMetadata: InternalInjectedMetadataSetup; +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts new file mode 100644 index 000000000000..294c1b226b73 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/src/internal_core_start.ts @@ -0,0 +1,17 @@ +/* + * 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 type { CoreStart } from '@kbn/core-lifecycle-browser'; +import type { InternalApplicationStart } from '@kbn/core-application-browser-internal'; +import type { InternalInjectedMetadataStart } from '@kbn/core-injected-metadata-browser-internal'; + +/** @internal */ +export interface InternalCoreStart extends Omit { + application: InternalApplicationStart; + injectedMetadata: InternalInjectedMetadataStart; +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json b/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json new file mode 100644 index 000000000000..62f956eb463d --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-internal/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-browser-mocks/BUILD.bazel new file mode 100644 index 000000000000..eaf6de1d6576 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/BUILD.bazel @@ -0,0 +1,142 @@ +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_DIRNAME = "core-lifecycle-browser-mocks" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-browser-mocks" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/core/injected-metadata/core-injected-metadata-browser-mocks", + "//packages/core/doc-links/core-doc-links-browser-mocks", + "//packages/core/theme/core-theme-browser-mocks", + "//packages/core/analytics/core-analytics-browser-mocks", + "//packages/core/execution-context/core-execution-context-browser-mocks", + "//packages/core/i18n/core-i18n-browser-mocks", + "//packages/core/fatal-errors/core-fatal-errors-browser-mocks", + "//packages/core/http/core-http-browser-mocks", + "//packages/core/ui-settings/core-ui-settings-browser-mocks", + "//packages/core/deprecations/core-deprecations-browser-mocks", + "//packages/core/overlays/core-overlays-browser-mocks", + "//packages/core/saved-objects/core-saved-objects-browser-mocks", + "//packages/core/notifications/core-notifications-browser-mocks", + "//packages/core/application/core-application-browser-mocks", + "//packages/core/chrome/core-chrome-browser-mocks", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/injected-metadata/core-injected-metadata-browser-mocks:npm_module_types", + "//packages/core/doc-links/core-doc-links-browser-mocks:npm_module_types", + "//packages/core/theme/core-theme-browser-mocks:npm_module_types", + "//packages/core/analytics/core-analytics-browser-mocks:npm_module_types", + "//packages/core/execution-context/core-execution-context-browser-mocks:npm_module_types", + "//packages/core/i18n/core-i18n-browser-mocks:npm_module_types", + "//packages/core/fatal-errors/core-fatal-errors-browser-mocks:npm_module_types", + "//packages/core/http/core-http-browser-mocks:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-browser-mocks:npm_module_types", + "//packages/core/deprecations/core-deprecations-browser-mocks:npm_module_types", + "//packages/core/overlays/core-overlays-browser-mocks:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-browser-mocks:npm_module_types", + "//packages/core/notifications/core-notifications-browser-mocks:npm_module_types", + "//packages/core/application/core-application-browser-mocks:npm_module_types", + "//packages/core/chrome/core-chrome-browser-mocks:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/README.md b/packages/core/lifecycle/core-lifecycle-browser-mocks/README.md new file mode 100644 index 000000000000..c250bfc7fa02 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/README.md @@ -0,0 +1,4 @@ +# @kbn/core-lifecycle-browser-mocks + +This package contains the mocks for core's lifecycle contracts: +- `coreLifecycleMock` \ No newline at end of file diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/index.ts b/packages/core/lifecycle/core-lifecycle-browser-mocks/index.ts new file mode 100644 index 000000000000..b748940720b2 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/index.ts @@ -0,0 +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 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. + */ + +export { coreLifecycleMock } from './src'; diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/jest.config.js b/packages/core/lifecycle/core-lifecycle-browser-mocks/jest.config.js new file mode 100644 index 000000000000..1568be8604fe --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-browser-mocks'], +}; diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-browser-mocks/kibana.jsonc new file mode 100644 index 000000000000..ed65ce8dacf5 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-browser-mocks", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/package.json b/packages/core/lifecycle/core-lifecycle-browser-mocks/package.json new file mode 100644 index 000000000000..fd1224d4d078 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-lifecycle-browser-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_setup.mock.ts b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_setup.mock.ts new file mode 100644 index 000000000000..b9877891ada9 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_setup.mock.ts @@ -0,0 +1,51 @@ +/* + * 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 { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; +import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; +import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-browser-mocks'; +import { fatalErrorsServiceMock } from '@kbn/core-fatal-errors-browser-mocks'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; +import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; +import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; +import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; +import { createCoreStartMock } from './core_start.mock'; + +export function createCoreSetupMock({ + basePath = '', + pluginStartDeps = {}, + pluginStartContract, +}: { + basePath?: string; + pluginStartDeps?: object; + pluginStartContract?: any; +} = {}) { + const mock = { + analytics: analyticsServiceMock.createAnalyticsServiceSetup(), + application: applicationServiceMock.createSetupContract(), + docLinks: docLinksServiceMock.createSetupContract(), + executionContext: executionContextServiceMock.createSetupContract(), + fatalErrors: fatalErrorsServiceMock.createSetupContract(), + getStartServices: jest.fn, any, any]>, []>(() => + Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract]) + ), + http: httpServiceMock.createSetupContract({ basePath }), + notifications: notificationServiceMock.createSetupContract(), + uiSettings: uiSettingsServiceMock.createSetupContract(), + deprecations: deprecationsServiceMock.createSetupContract(), + injectedMetadata: { + getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar, + }, + theme: themeServiceMock.createSetupContract(), + }; + + return mock; +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_start.mock.ts b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_start.mock.ts new file mode 100644 index 000000000000..4fa223e05173 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/core_start.mock.ts @@ -0,0 +1,47 @@ +/* + * 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 { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; +import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; +import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; +import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; +import { executionContextServiceMock } from '@kbn/core-execution-context-browser-mocks'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; +import { fatalErrorsServiceMock } from '@kbn/core-fatal-errors-browser-mocks'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; +import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; +import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-browser-mocks'; +import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; +import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; +import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks'; + +export function createCoreStartMock({ basePath = '' } = {}) { + const mock = { + analytics: analyticsServiceMock.createAnalyticsServiceStart(), + application: applicationServiceMock.createStartContract(), + chrome: chromeServiceMock.createStartContract(), + docLinks: docLinksServiceMock.createStartContract(), + executionContext: executionContextServiceMock.createStartContract(), + http: httpServiceMock.createStartContract({ basePath }), + i18n: i18nServiceMock.createStartContract(), + notifications: notificationServiceMock.createStartContract(), + overlays: overlayServiceMock.createStartContract(), + uiSettings: uiSettingsServiceMock.createStartContract(), + savedObjects: savedObjectsServiceMock.createStartContract(), + deprecations: deprecationsServiceMock.createStartContract(), + theme: themeServiceMock.createStartContract(), + injectedMetadata: { + getInjectedVar: injectedMetadataServiceMock.createStartContract().getInjectedVar, + }, + fatalErrors: fatalErrorsServiceMock.createStartContract(), + }; + + return mock; +} diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/src/index.ts b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/index.ts new file mode 100644 index 000000000000..6d55549b4345 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/src/index.ts @@ -0,0 +1,15 @@ +/* + * 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 { createCoreSetupMock } from './core_setup.mock'; +import { createCoreStartMock } from './core_start.mock'; + +export const coreLifecycleMock = { + createCoreSetup: createCoreSetupMock, + createCoreStart: createCoreStartMock, +}; diff --git a/packages/core/lifecycle/core-lifecycle-browser-mocks/tsconfig.json b/packages/core/lifecycle/core-lifecycle-browser-mocks/tsconfig.json new file mode 100644 index 000000000000..4283cbe1b760 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser-mocks/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/packages/core/lifecycle/core-lifecycle-browser/BUILD.bazel b/packages/core/lifecycle/core-lifecycle-browser/BUILD.bazel new file mode 100644 index 000000000000..d32c12c10728 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/BUILD.bazel @@ -0,0 +1,128 @@ +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_DIRNAME = "core-lifecycle-browser" +PKG_REQUIRE_NAME = "@kbn/core-lifecycle-browser" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/injected-metadata/core-injected-metadata-browser:npm_module_types", + "//packages/core/theme/core-theme-browser:npm_module_types", + "//packages/core/analytics/core-analytics-browser:npm_module_types", + "//packages/core/execution-context/core-execution-context-browser:npm_module_types", + "//packages/core/http/core-http-browser:npm_module_types", + "//packages/core/fatal-errors/core-fatal-errors-browser:npm_module_types", + "//packages/core/ui-settings/core-ui-settings-browser:npm_module_types", + "//packages/core/notifications/core-notifications-browser:npm_module_types", + "//packages/core/application/core-application-browser:npm_module_types", + "//packages/core/doc-links/core-doc-links-browser:npm_module_types", + "//packages/core/i18n/core-i18n-browser:npm_module_types", + "//packages/core/deprecations/core-deprecations-browser:npm_module_types", + "//packages/core/overlays/core-overlays-browser:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-browser:npm_module_types", + "//packages/core/chrome/core-chrome-browser:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/lifecycle/core-lifecycle-browser/README.md b/packages/core/lifecycle/core-lifecycle-browser/README.md new file mode 100644 index 000000000000..c890d9178fe8 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/README.md @@ -0,0 +1,5 @@ +# @kbn/core-lifecycle-browser + +This package contains the public types for core's lifecycle contracts: +- `CoreSetup` +- `CoreStart` diff --git a/packages/core/lifecycle/core-lifecycle-browser/index.ts b/packages/core/lifecycle/core-lifecycle-browser/index.ts new file mode 100644 index 000000000000..22d314845830 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/index.ts @@ -0,0 +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 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. + */ + +export type { CoreSetup, CoreStart, StartServicesAccessor } from './src'; diff --git a/packages/core/lifecycle/core-lifecycle-browser/jest.config.js b/packages/core/lifecycle/core-lifecycle-browser/jest.config.js new file mode 100644 index 000000000000..0f7dc563d56e --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/lifecycle/core-lifecycle-browser'], +}; diff --git a/packages/core/lifecycle/core-lifecycle-browser/kibana.jsonc b/packages/core/lifecycle/core-lifecycle-browser/kibana.jsonc new file mode 100644 index 000000000000..e17c98379b11 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-lifecycle-browser", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/lifecycle/core-lifecycle-browser/package.json b/packages/core/lifecycle/core-lifecycle-browser/package.json new file mode 100644 index 000000000000..0e14a56f8bf1 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-lifecycle-browser", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/lifecycle/core-lifecycle-browser/src/core_setup.ts b/packages/core/lifecycle/core-lifecycle-browser/src/core_setup.ts new file mode 100644 index 000000000000..0df6e7a25086 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/src/core_setup.ts @@ -0,0 +1,67 @@ +/* + * 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 type { InjectedMetadataSetup } from '@kbn/core-injected-metadata-browser'; +import type { ThemeServiceSetup } from '@kbn/core-theme-browser'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-browser'; +import type { ExecutionContextSetup } from '@kbn/core-execution-context-browser'; +import type { HttpSetup } from '@kbn/core-http-browser'; +import type { FatalErrorsSetup } from '@kbn/core-fatal-errors-browser'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import type { NotificationsSetup } from '@kbn/core-notifications-browser'; +import type { ApplicationSetup } from '@kbn/core-application-browser'; +import type { CoreStart } from './core_start'; + +/** + * Core services exposed to the `Plugin` setup lifecycle + * + * @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same + * as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`. + * @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the + * consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`. + * + * @public + * + * @internalRemarks We document the properties with \@link tags to improve + * navigation in the generated docs until there's a fix for + * https://github.com/Microsoft/web-build-tools/issues/1237 + */ +export interface CoreSetup { + /** {@link AnalyticsServiceSetup} */ + analytics: AnalyticsServiceSetup; + /** {@link ApplicationSetup} */ + application: ApplicationSetup; + /** {@link FatalErrorsSetup} */ + fatalErrors: FatalErrorsSetup; + /** {@link HttpSetup} */ + http: HttpSetup; + /** {@link NotificationsSetup} */ + notifications: NotificationsSetup; + /** {@link IUiSettingsClient} */ + uiSettings: IUiSettingsClient; + /** {@link ExecutionContextSetup} */ + executionContext: ExecutionContextSetup; + /** {@link InjectedMetadataSetup} */ + injectedMetadata: InjectedMetadataSetup; + /** {@link ThemeServiceSetup} */ + theme: ThemeServiceSetup; + /** {@link StartServicesAccessor} */ + getStartServices: StartServicesAccessor; +} + +/** + * Allows plugins to get access to APIs available in start inside async + * handlers, such as {@link App.mount}. Promise will not resolve until Core + * and plugin dependencies have completed `start`. + * + * @public + */ +export type StartServicesAccessor< + TPluginsStart extends object = object, + TStart = unknown +> = () => Promise<[CoreStart, TPluginsStart, TStart]>; diff --git a/packages/core/lifecycle/core-lifecycle-browser/src/core_start.ts b/packages/core/lifecycle/core-lifecycle-browser/src/core_start.ts new file mode 100644 index 000000000000..9cd702645535 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/src/core_start.ts @@ -0,0 +1,65 @@ +/* + * 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 type { InjectedMetadataStart } from '@kbn/core-injected-metadata-browser'; +import type { DocLinksStart } from '@kbn/core-doc-links-browser'; +import type { ThemeServiceStart } from '@kbn/core-theme-browser'; +import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import type { ExecutionContextStart } from '@kbn/core-execution-context-browser'; +import type { HttpStart } from '@kbn/core-http-browser'; +import type { I18nStart } from '@kbn/core-i18n-browser'; +import type { FatalErrorsStart } from '@kbn/core-fatal-errors-browser'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +import type { DeprecationsServiceStart } from '@kbn/core-deprecations-browser'; +import type { OverlayStart } from '@kbn/core-overlays-browser'; +import type { SavedObjectsStart } from '@kbn/core-saved-objects-browser'; +import type { NotificationsStart } from '@kbn/core-notifications-browser'; +import type { ApplicationStart } from '@kbn/core-application-browser'; +import type { ChromeStart } from '@kbn/core-chrome-browser'; + +/** + * Core services exposed to the `Plugin` start lifecycle + * + * @public + * + * @internalRemarks We document the properties with \@link tags to improve + * navigation in the generated docs until there's a fix for + * https://github.com/Microsoft/web-build-tools/issues/1237 + */ +export interface CoreStart { + /** {@link AnalyticsServiceStart} */ + analytics: AnalyticsServiceStart; + /** {@link ApplicationStart} */ + application: ApplicationStart; + /** {@link ChromeStart} */ + chrome: ChromeStart; + /** {@link DocLinksStart} */ + docLinks: DocLinksStart; + /** {@link ExecutionContextStart} */ + executionContext: ExecutionContextStart; + /** {@link HttpStart} */ + http: HttpStart; + /** {@link SavedObjectsStart} */ + savedObjects: SavedObjectsStart; + /** {@link I18nStart} */ + i18n: I18nStart; + /** {@link NotificationsStart} */ + notifications: NotificationsStart; + /** {@link OverlayStart} */ + overlays: OverlayStart; + /** {@link IUiSettingsClient} */ + uiSettings: IUiSettingsClient; + /** {@link FatalErrorsStart} */ + fatalErrors: FatalErrorsStart; + /** {@link DeprecationsServiceStart} */ + deprecations: DeprecationsServiceStart; + /** {@link ThemeServiceStart} */ + theme: ThemeServiceStart; + /** {@link InjectedMetadataStart} */ + injectedMetadata: InjectedMetadataStart; +} diff --git a/packages/core/lifecycle/core-lifecycle-browser/src/index.ts b/packages/core/lifecycle/core-lifecycle-browser/src/index.ts new file mode 100644 index 000000000000..5d147b47ccde --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/src/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export type { CoreSetup, StartServicesAccessor } from './core_setup'; +export type { CoreStart } from './core_start'; diff --git a/packages/core/lifecycle/core-lifecycle-browser/tsconfig.json b/packages/core/lifecycle/core-lifecycle-browser/tsconfig.json new file mode 100644 index 000000000000..ae5054c1cd72 --- /dev/null +++ b/packages/core/lifecycle/core-lifecycle-browser/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/packages/core/plugins/core-plugins-browser-internal/BUILD.bazel b/packages/core/plugins/core-plugins-browser-internal/BUILD.bazel new file mode 100644 index 000000000000..734d78cce229 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/BUILD.bazel @@ -0,0 +1,125 @@ +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_DIRNAME = "core-plugins-browser-internal" +PKG_REQUIRE_NAME = "@kbn/core-plugins-browser-internal" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//react", + "@npm//rxjs", + "@npm//lodash", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//rxjs", + "@npm//lodash", + "//packages/kbn-config:npm_module_types", + "//packages/core/base/core-base-common:npm_module_types", + "//packages/core/base/core-base-browser-internal:npm_module_types", + "//packages/core/injected-metadata/core-injected-metadata-common-internal:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-browser:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-browser-internal:npm_module_types", + "//packages/core/plugins/core-plugins-browser:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-browser-internal/README.md b/packages/core/plugins/core-plugins-browser-internal/README.md new file mode 100644 index 000000000000..17891ea31421 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/README.md @@ -0,0 +1,3 @@ +# @kbn/core-plugins-browser-internal + +This package contains the internal types and implementation for Core's browser-side `plugins` service. diff --git a/packages/core/plugins/core-plugins-browser-internal/index.ts b/packages/core/plugins/core-plugins-browser-internal/index.ts new file mode 100644 index 000000000000..6f251aace7e0 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/index.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export { PluginsService } from './src'; +export type { + PluginsServiceSetup, + PluginsServiceStart, + PluginsServiceSetupDeps, + PluginsServiceStartDeps, +} from './src'; diff --git a/packages/core/plugins/core-plugins-browser-internal/jest.config.js b/packages/core/plugins/core-plugins-browser-internal/jest.config.js new file mode 100644 index 000000000000..a8bf5db34a65 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-browser-internal'], +}; diff --git a/packages/core/plugins/core-plugins-browser-internal/kibana.jsonc b/packages/core/plugins/core-plugins-browser-internal/kibana.jsonc new file mode 100644 index 000000000000..61935e6670ae --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-browser-internal", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-browser-internal/package.json b/packages/core/plugins/core-plugins-browser-internal/package.json new file mode 100644 index 000000000000..0820932cb2f9 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-plugins-browser-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/public/plugins/index.ts b/packages/core/plugins/core-plugins-browser-internal/src/index.ts similarity index 68% rename from src/core/public/plugins/index.ts rename to packages/core/plugins/core-plugins-browser-internal/src/index.ts index 976ec660ac9b..f3f78eb4708b 100644 --- a/src/core/public/plugins/index.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/index.ts @@ -7,6 +7,9 @@ */ export { PluginsService } from './plugins_service'; -export type { Plugin, PluginInitializer } from './plugin'; -export type { PluginInitializerContext } from './plugin_context'; -export type { PluginOpaqueId } from '../../server/types'; +export type { + PluginsServiceSetup, + PluginsServiceStart, + PluginsServiceSetupDeps, + PluginsServiceStartDeps, +} from './plugins_service'; diff --git a/src/core/public/plugins/plugin.test.mocks.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin.test.mocks.ts similarity index 100% rename from src/core/public/plugins/plugin.test.mocks.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin.test.mocks.ts diff --git a/src/core/public/plugins/plugin.test.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin.test.ts similarity index 95% rename from src/core/public/plugins/plugin.test.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin.test.ts index 2c3bfc6961fb..f4df372b30a0 100644 --- a/src/core/public/plugins/plugin.test.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugin.test.ts @@ -8,8 +8,8 @@ import { mockInitializer, mockPlugin, mockPluginReader } from './plugin.test.mocks'; -import { DiscoveredPlugin, PluginType } from '../../server'; -import { coreMock } from '../mocks'; +import { DiscoveredPlugin, PluginType } from '@kbn/core-base-common'; +import { createPluginInitializerContextMock } from './test_helpers'; import { PluginWrapper } from './plugin'; function createManifest( @@ -32,7 +32,7 @@ function createManifest( let plugin: PluginWrapper>; const opaqueId = Symbol(); -const initializerContext = coreMock.createPluginInitializerContext(); +const initializerContext = createPluginInitializerContextMock(); beforeEach(() => { mockPluginReader.mockClear(); diff --git a/src/core/public/plugins/plugin.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin.ts similarity index 81% rename from src/core/public/plugins/plugin.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin.ts index 8abab5081e55..c61d9afb175c 100644 --- a/src/core/public/plugins/plugin.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugin.ts @@ -7,39 +7,14 @@ */ import { firstValueFrom, Subject } from 'rxjs'; -import type { DiscoveredPlugin, PluginOpaqueId } from '../../server'; -import { PluginInitializerContext } from './plugin_context'; +import type { DiscoveredPlugin, PluginOpaqueId } from '@kbn/core-base-common'; +import type { CoreStart, CoreSetup } from '@kbn/core-lifecycle-browser'; +import type { + Plugin, + PluginInitializer, + PluginInitializerContext, +} from '@kbn/core-plugins-browser'; import { read } from './plugin_reader'; -import { CoreStart, CoreSetup } from '..'; - -/** - * The interface that should be returned by a `PluginInitializer`. - * - * @public - */ -export interface Plugin< - TSetup = void, - TStart = void, - TPluginsSetup extends object = object, - TPluginsStart extends object = object -> { - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; - start(core: CoreStart, plugins: TPluginsStart): TStart; - stop?(): void; -} - -/** - * The `plugin` export at the root of a plugin's `public` directory should conform - * to this interface. - * - * @public - */ -export type PluginInitializer< - TSetup, - TStart, - TPluginsSetup extends object = object, - TPluginsStart extends object = object -> = (core: PluginInitializerContext) => Plugin; /** * Lightweight wrapper around discovered plugin that is responsible for instantiating diff --git a/src/core/public/plugins/plugin_context.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts similarity index 84% rename from src/core/public/plugins/plugin_context.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts index e3516ce5da78..41643b0e0250 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugin_context.ts @@ -8,30 +8,11 @@ import { omit } from 'lodash'; import type { CoreContext } from '@kbn/core-base-browser-internal'; -import type { DiscoveredPlugin } from '../../server'; -import type { PluginOpaqueId, PackageInfo, EnvironmentMode } from '../../server/types'; +import type { DiscoveredPlugin, PluginOpaqueId } from '@kbn/core-base-common'; +import type { CoreSetup, CoreStart } from '@kbn/core-lifecycle-browser'; +import type { PluginInitializerContext } from '@kbn/core-plugins-browser'; import { PluginWrapper } from './plugin'; import { PluginsServiceSetupDeps, PluginsServiceStartDeps } from './plugins_service'; -import { CoreSetup, CoreStart } from '..'; - -/** - * The available core services passed to a `PluginInitializer` - * - * @public - */ -export interface PluginInitializerContext { - /** - * A symbol used to identify this plugin in the system. Needed when registering handlers or context providers. - */ - readonly opaqueId: PluginOpaqueId; - readonly env: { - mode: Readonly; - packageInfo: Readonly; - }; - readonly config: { - get: () => T; - }; -} /** * Provides a plugin-specific context passed to the plugin's constructor. This is currently diff --git a/src/core/public/plugins/plugin_reader.test.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin_reader.test.ts similarity index 100% rename from src/core/public/plugins/plugin_reader.test.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin_reader.test.ts diff --git a/src/core/public/plugins/plugin_reader.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugin_reader.ts similarity index 95% rename from src/core/public/plugins/plugin_reader.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugin_reader.ts index 24508075975d..53dd18bd6868 100644 --- a/src/core/public/plugins/plugin_reader.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugin_reader.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { PluginInitializer } from './plugin'; +import type { PluginInitializer } from '@kbn/core-plugins-browser'; /** * Unknown variant for internal use only for when plugins are not known. diff --git a/src/core/public/plugins/plugins_service.test.mocks.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.mocks.ts similarity index 86% rename from src/core/public/plugins/plugins_service.test.mocks.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.mocks.ts index 7cf65f0d37db..34198c0b35e1 100644 --- a/src/core/public/plugins/plugins_service.test.mocks.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.mocks.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { PluginName } from '../../server'; -import { Plugin } from './plugin'; +import type { PluginName } from '@kbn/core-base-common'; +import type { Plugin } from '@kbn/core-plugins-browser'; export type MockedPluginInitializer = jest.Mock>; diff --git a/src/core/public/plugins/plugins_service.test.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts similarity index 97% rename from src/core/public/plugins/plugins_service.test.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts index 78f27f0c31a5..f2023abec195 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.test.ts @@ -13,14 +13,14 @@ import { mockPluginInitializerProvider, } from './plugins_service.test.mocks'; -import { type PluginName, PluginType } from '../../server'; +import { type PluginName, PluginType } from '@kbn/core-base-common'; import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; import { executionContextServiceMock } from '@kbn/core-execution-context-browser-mocks'; import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; -import { coreMock } from '../mocks'; +import { coreContextMock } from '@kbn/core-base-browser-mocks'; import { PluginsService, @@ -36,7 +36,8 @@ import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks'; import { fatalErrorsServiceMock } from '@kbn/core-fatal-errors-browser-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import type { CoreSetup, CoreStart, PluginInitializerContext } from '..'; +import type { PluginInitializerContext } from '@kbn/core-plugins-browser'; +import type { CoreSetup, CoreStart } from '@kbn/core-lifecycle-browser'; import { savedObjectsServiceMock } from '@kbn/core-saved-objects-browser-mocks'; import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; @@ -50,7 +51,7 @@ let plugins: InjectedMetadataPlugin[]; type DeeplyMocked = { [P in keyof T]: jest.Mocked }; -const mockCoreContext = coreMock.createCoreContext(); +const mockCoreContext = coreContextMock.create(); let mockSetupDeps: DeeplyMocked; let mockSetupContext: DeeplyMocked; let mockStartDeps: DeeplyMocked; diff --git a/src/core/public/plugins/plugins_service.ts b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.ts similarity index 98% rename from src/core/public/plugins/plugins_service.ts rename to packages/core/plugins/core-plugins-browser-internal/src/plugins_service.ts index dc0a77d096ff..4e10796fd3a6 100644 --- a/src/core/public/plugins/plugins_service.ts +++ b/packages/core/plugins/core-plugins-browser-internal/src/plugins_service.ts @@ -9,13 +9,13 @@ import type { CoreService, CoreContext } from '@kbn/core-base-browser-internal'; import type { PluginName, PluginOpaqueId } from '@kbn/core-base-common'; import type { InjectedMetadataPlugin } from '@kbn/core-injected-metadata-common-internal'; +import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-browser-internal'; import { PluginWrapper } from './plugin'; import { createPluginInitializerContext, createPluginSetupContext, createPluginStartContext, } from './plugin_context'; -import { InternalCoreSetup, InternalCoreStart } from '../core_system'; /** @internal */ export type PluginsServiceSetupDeps = InternalCoreSetup; diff --git a/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/index.ts b/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/index.ts new file mode 100644 index 000000000000..ee660a8c1f8b --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/index.ts @@ -0,0 +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 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. + */ + +export { createPluginInitializerContextMock } from './mocks'; diff --git a/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/mocks.ts b/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/mocks.ts new file mode 100644 index 000000000000..fcd4e80c02de --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/src/test_helpers/mocks.ts @@ -0,0 +1,34 @@ +/* + * 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 type { PluginInitializerContext } from '@kbn/core-plugins-browser'; + +export const createPluginInitializerContextMock = (config: unknown = {}) => { + const mock: PluginInitializerContext = { + opaqueId: Symbol(), + env: { + mode: { + dev: true, + name: 'development', + prod: false, + }, + packageInfo: { + version: 'version', + branch: 'branch', + buildNum: 100, + buildSha: 'buildSha', + dist: false, + }, + }, + config: { + get: () => config as T, + }, + }; + + return mock; +}; diff --git a/packages/core/plugins/core-plugins-browser-internal/tsconfig.json b/packages/core/plugins/core-plugins-browser-internal/tsconfig.json new file mode 100644 index 000000000000..4283cbe1b760 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-internal/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/packages/core/plugins/core-plugins-browser-mocks/BUILD.bazel b/packages/core/plugins/core-plugins-browser-mocks/BUILD.bazel new file mode 100644 index 000000000000..0d334ef02a29 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/BUILD.bazel @@ -0,0 +1,114 @@ +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_DIRNAME = "core-plugins-browser-mocks" +PKG_REQUIRE_NAME = "@kbn/core-plugins-browser-mocks" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-utility-types:npm_module_types", + "//packages/core/plugins/core-plugins-browser-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-browser-mocks/README.md b/packages/core/plugins/core-plugins-browser-mocks/README.md new file mode 100644 index 000000000000..f379ef7d953e --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/README.md @@ -0,0 +1,4 @@ +# @kbn/core-plugins-browser-mocks + +This package contains mocks for Core's browser-side `plugins` service. +- `pluginsServiceMock` diff --git a/packages/core/plugins/core-plugins-browser-mocks/index.ts b/packages/core/plugins/core-plugins-browser-mocks/index.ts new file mode 100644 index 000000000000..3c9ecebdb3d1 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/index.ts @@ -0,0 +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 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. + */ + +export { pluginsServiceMock } from './src'; diff --git a/packages/core/plugins/core-plugins-browser-mocks/jest.config.js b/packages/core/plugins/core-plugins-browser-mocks/jest.config.js new file mode 100644 index 000000000000..f1072f43bde2 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-browser-mocks'], +}; diff --git a/packages/core/plugins/core-plugins-browser-mocks/kibana.jsonc b/packages/core/plugins/core-plugins-browser-mocks/kibana.jsonc new file mode 100644 index 000000000000..c451ce7aac05 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-browser-mocks", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-browser-mocks/package.json b/packages/core/plugins/core-plugins-browser-mocks/package.json new file mode 100644 index 000000000000..98090f042ab0 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-plugins-browser-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/plugins/core-plugins-browser-mocks/src/index.ts b/packages/core/plugins/core-plugins-browser-mocks/src/index.ts new file mode 100644 index 000000000000..9b04e0fbbeb4 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/src/index.ts @@ -0,0 +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 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. + */ + +export { pluginsServiceMock } from './plugins_service.mock'; diff --git a/src/core/public/plugins/plugins_service.mock.ts b/packages/core/plugins/core-plugins-browser-mocks/src/plugins_service.mock.ts similarity index 66% rename from src/core/public/plugins/plugins_service.mock.ts rename to packages/core/plugins/core-plugins-browser-mocks/src/plugins_service.mock.ts index cfc174d106a8..c1539e787368 100644 --- a/src/core/public/plugins/plugins_service.mock.ts +++ b/packages/core/plugins/core-plugins-browser-mocks/src/plugins_service.mock.ts @@ -7,7 +7,8 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { PluginsService, PluginsServiceSetup } from './plugins_service'; +import type { PluginInitializerContext } from '@kbn/core-plugins-browser'; +import type { PluginsService, PluginsServiceSetup } from '@kbn/core-plugins-browser-internal'; const createSetupContractMock = () => { const setupContract: jest.Mocked = { @@ -25,6 +26,31 @@ const createStartContractMock = () => { return startContract as PluginsServiceSetup; }; +const createPluginInitializerContextMock = (config: unknown = {}) => { + const mock: PluginInitializerContext = { + opaqueId: Symbol(), + env: { + mode: { + dev: true, + name: 'development', + prod: false, + }, + packageInfo: { + version: 'version', + branch: 'branch', + buildNum: 100, + buildSha: 'buildSha', + dist: false, + }, + }, + config: { + get: () => config as T, + }, + }; + + return mock; +}; + type PluginsServiceContract = PublicMethodsOf; const createMock = () => { const mocked: jest.Mocked = { @@ -43,4 +69,5 @@ export const pluginsServiceMock = { create: createMock, createSetupContract: createSetupContractMock, createStartContract: createStartContractMock, + createPluginInitializerContext: createPluginInitializerContextMock, }; diff --git a/packages/core/plugins/core-plugins-browser-mocks/tsconfig.json b/packages/core/plugins/core-plugins-browser-mocks/tsconfig.json new file mode 100644 index 000000000000..4283cbe1b760 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser-mocks/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/packages/core/plugins/core-plugins-browser/BUILD.bazel b/packages/core/plugins/core-plugins-browser/BUILD.bazel new file mode 100644 index 000000000000..fca01ef98d10 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/BUILD.bazel @@ -0,0 +1,116 @@ +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_DIRNAME = "core-plugins-browser" +PKG_REQUIRE_NAME = "@kbn/core-plugins-browser" + +SOURCE_FILES = glob( + [ + "**/*.ts", + "**/*.tsx", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-config:npm_module_types", + "//packages/core/base/core-base-common:npm_module_types", + "//packages/core/lifecycle/core-lifecycle-browser:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/plugins/core-plugins-browser/README.md b/packages/core/plugins/core-plugins-browser/README.md new file mode 100644 index 000000000000..a68e2ff32808 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/README.md @@ -0,0 +1,8 @@ +# @kbn/core-plugins-browser + +This package contains the public types for Core's browser-side `plugins` domain: +- `Plugin` +- `PluginInitializer` +- `PluginInitializerContext` + +Note: the `CoreSetup` and `CoreStart` types are available from the `@kbn/core-lifecycle-browser` package instead. diff --git a/packages/core/plugins/core-plugins-browser/index.ts b/packages/core/plugins/core-plugins-browser/index.ts new file mode 100644 index 000000000000..779ebe33097a --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/index.ts @@ -0,0 +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 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. + */ + +export type { Plugin, PluginInitializer, PluginInitializerContext } from './src'; diff --git a/packages/core/plugins/core-plugins-browser/jest.config.js b/packages/core/plugins/core-plugins-browser/jest.config.js new file mode 100644 index 000000000000..b53bd873d88c --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/plugins/core-plugins-browser'], +}; diff --git a/packages/core/plugins/core-plugins-browser/kibana.jsonc b/packages/core/plugins/core-plugins-browser/kibana.jsonc new file mode 100644 index 000000000000..f7457049acc0 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-plugins-browser", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/plugins/core-plugins-browser/package.json b/packages/core/plugins/core-plugins-browser/package.json new file mode 100644 index 000000000000..f03af035d223 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/core-plugins-browser", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/plugins/core-plugins-browser/src/index.ts b/packages/core/plugins/core-plugins-browser/src/index.ts new file mode 100644 index 000000000000..1e1f513981a0 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/src/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export type { Plugin } from './plugin'; +export type { PluginInitializer, PluginInitializerContext } from './plugin_initializer'; diff --git a/packages/core/plugins/core-plugins-browser/src/plugin.ts b/packages/core/plugins/core-plugins-browser/src/plugin.ts new file mode 100644 index 000000000000..676e4fec39f4 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/src/plugin.ts @@ -0,0 +1,27 @@ +/* + * 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 type { CoreStart, CoreSetup } from '@kbn/core-lifecycle-browser'; + +/** + * The interface that should be returned by a `PluginInitializer`. + * + * @public + */ +export interface Plugin< + TSetup = void, + TStart = void, + TPluginsSetup extends object = object, + TPluginsStart extends object = object +> { + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; + + start(core: CoreStart, plugins: TPluginsStart): TStart; + + stop?(): void; +} diff --git a/packages/core/plugins/core-plugins-browser/src/plugin_initializer.ts b/packages/core/plugins/core-plugins-browser/src/plugin_initializer.ts new file mode 100644 index 000000000000..14aaaff31e94 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/src/plugin_initializer.ts @@ -0,0 +1,43 @@ +/* + * 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 type { PluginOpaqueId } from '@kbn/core-base-common'; +import type { PackageInfo, EnvironmentMode } from '@kbn/config'; +import type { Plugin } from './plugin'; + +/** + * The `plugin` export at the root of a plugin's `public` directory should conform + * to this interface. + * + * @public + */ +export type PluginInitializer< + TSetup, + TStart, + TPluginsSetup extends object = object, + TPluginsStart extends object = object +> = (core: PluginInitializerContext) => Plugin; + +/** + * The available core services passed to a `PluginInitializer` + * + * @public + */ +export interface PluginInitializerContext { + /** + * A symbol used to identify this plugin in the system. Needed when registering handlers or context providers. + */ + readonly opaqueId: PluginOpaqueId; + readonly env: { + mode: Readonly; + packageInfo: Readonly; + }; + readonly config: { + get: () => T; + }; +} diff --git a/packages/core/plugins/core-plugins-browser/tsconfig.json b/packages/core/plugins/core-plugins-browser/tsconfig.json new file mode 100644 index 000000000000..4283cbe1b760 --- /dev/null +++ b/packages/core/plugins/core-plugins-browser/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ] +} diff --git a/src/core/public/core_system.test.mocks.ts b/src/core/public/core_system.test.mocks.ts index f5b0c017dcd1..69560623e163 100644 --- a/src/core/public/core_system.test.mocks.ts +++ b/src/core/public/core_system.test.mocks.ts @@ -17,7 +17,7 @@ import { httpServiceMock } from '@kbn/core-http-browser-mocks'; import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks'; -import { pluginsServiceMock } from './plugins/plugins_service.mock'; +import { pluginsServiceMock } from '@kbn/core-plugins-browser-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; import { renderingServiceMock } from '@kbn/core-rendering-browser-mocks'; import { integrationsServiceMock } from '@kbn/core-integrations-browser-mocks'; @@ -94,7 +94,7 @@ jest.doMock('@kbn/core-overlays-browser-internal', () => ({ export const MockPluginsService = pluginsServiceMock.create(); export const PluginsServiceConstructor = jest.fn().mockImplementation(() => MockPluginsService); -jest.doMock('./plugins', () => ({ +jest.doMock('@kbn/core-plugins-browser-internal', () => ({ PluginsService: PluginsServiceConstructor, })); diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 7b1e073e4b53..4381cfdd2abf 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -11,8 +11,6 @@ import type { CoreContext } from '@kbn/core-base-browser-internal'; import { InjectedMetadataService, type InjectedMetadataParams, - type InternalInjectedMetadataSetup, - type InternalInjectedMetadataStart, } from '@kbn/core-injected-metadata-browser-internal'; import { DocLinksService } from '@kbn/core-doc-links-browser-internal'; import { ThemeService } from '@kbn/core-theme-browser-internal'; @@ -32,16 +30,12 @@ import { KBN_LOAD_MARKS } from '@kbn/core-mount-utils-browser-internal'; import { SavedObjectsService } from '@kbn/core-saved-objects-browser-internal'; import { NotificationsService } from '@kbn/core-notifications-browser-internal'; import { ChromeService } from '@kbn/core-chrome-browser-internal'; -import { - ApplicationService, - type InternalApplicationSetup, - type InternalApplicationStart, -} from '@kbn/core-application-browser-internal'; +import { ApplicationService } from '@kbn/core-application-browser-internal'; import { RenderingService } from '@kbn/core-rendering-browser-internal'; import { CoreAppsService } from '@kbn/core-apps-browser-internal'; +import type { InternalCoreSetup, InternalCoreStart } from '@kbn/core-lifecycle-browser-internal'; +import { PluginsService } from '@kbn/core-plugins-browser-internal'; import { fetchOptionalMemoryInfo } from './fetch_optional_memory_info'; -import { CoreSetup, CoreStart } from '.'; -import { PluginsService } from './plugins'; import { LOAD_SETUP_DONE, @@ -59,18 +53,6 @@ interface Params { injectedMetadata: InjectedMetadataParams['injectedMetadata']; } -/** @internal */ -export interface InternalCoreSetup extends Omit { - application: InternalApplicationSetup; - injectedMetadata: InternalInjectedMetadataSetup; -} - -/** @internal */ -export interface InternalCoreStart extends Omit { - application: InternalApplicationStart; - injectedMetadata: InternalInjectedMetadataStart; -} - // Expands the definition of navigator to include experimental features interface ExtendedNavigator { connection?: { diff --git a/src/core/public/index.ts b/src/core/public/index.ts index e5c137a6d5db..ff666e0f3a18 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -26,30 +26,19 @@ import './index.scss'; -import type { - InjectedMetadataSetup, - InjectedMetadataStart, -} from '@kbn/core-injected-metadata-browser'; -import { DocLinksStart } from '@kbn/core-doc-links-browser'; -import type { ThemeServiceSetup, ThemeServiceStart } from '@kbn/core-theme-browser'; -import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; -import { ExecutionContextSetup, ExecutionContextStart } from '@kbn/core-execution-context-browser'; -import type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; -import type { I18nStart } from '@kbn/core-i18n-browser'; - -import type { +export type { DocLinksStart } from '@kbn/core-doc-links-browser'; +export type { HttpSetup, HttpStart } from '@kbn/core-http-browser'; +export type { I18nStart } from '@kbn/core-i18n-browser'; +export type { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo, } from '@kbn/core-fatal-errors-browser'; -import type { UiSettingsState, IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import type { DeprecationsServiceStart } from '@kbn/core-deprecations-browser'; -import type { Capabilities } from '@kbn/core-capabilities-common'; -import type { OverlayStart } from '@kbn/core-overlays-browser'; -import type { SavedObjectsStart } from '@kbn/core-saved-objects-browser'; -import type { NotificationsSetup, NotificationsStart } from '@kbn/core-notifications-browser'; -import type { ApplicationSetup, ApplicationStart } from '@kbn/core-application-browser'; -import type { +export type { UiSettingsState, IUiSettingsClient } from '@kbn/core-ui-settings-browser'; +export type { Capabilities } from '@kbn/core-capabilities-common'; +export type { SavedObjectsStart } from '@kbn/core-saved-objects-browser'; +export type { NotificationsSetup, NotificationsStart } from '@kbn/core-notifications-browser'; +export type { ChromeBadge, ChromeBreadcrumb, ChromeHelpExtension, @@ -70,19 +59,21 @@ import type { ChromeUserBanner, ChromeHelpMenuActions, } from '@kbn/core-chrome-browser'; -import type { +export type { Plugin, PluginInitializer, PluginInitializerContext, - PluginOpaqueId, -} from './plugins'; +} from '@kbn/core-plugins-browser'; +export type { PluginOpaqueId } from '@kbn/core-base-common'; export type { PackageInfo, EnvironmentMode } from '@kbn/config'; export type { DomainDeprecationDetails } from '@kbn/core-deprecations-common'; export type { CoreContext } from '@kbn/core-base-browser-internal'; -export { DEFAULT_APP_CATEGORIES, APP_WRAPPER_CLASS } from '@kbn/core-application-common'; -export type { CoreSystem } from './core_system'; -export type { AppCategory } from '../types'; +export { + DEFAULT_APP_CATEGORIES, + APP_WRAPPER_CLASS, + type AppCategory, +} from '@kbn/core-application-common'; export type { UiSettingsParams, PublicUiSettingsParams, @@ -233,134 +224,8 @@ export type { ExecutionContextStart, } from '@kbn/core-execution-context-browser'; -/** - * Core services exposed to the `Plugin` setup lifecycle - * - * @typeParam TPluginsStart - the type of the consuming plugin's start dependencies. Should be the same - * as the consuming {@link Plugin}'s `TPluginsStart` type. Used by `getStartServices`. - * @typeParam TStart - the type of the consuming plugin's start contract. Should be the same as the - * consuming {@link Plugin}'s `TStart` type. Used by `getStartServices`. - * - * @public - * - * @internalRemarks We document the properties with \@link tags to improve - * navigation in the generated docs until there's a fix for - * https://github.com/Microsoft/web-build-tools/issues/1237 - */ -export interface CoreSetup { - /** {@link AnalyticsServiceSetup} */ - analytics: AnalyticsServiceSetup; - /** {@link ApplicationSetup} */ - application: ApplicationSetup; - /** {@link FatalErrorsSetup} */ - fatalErrors: FatalErrorsSetup; - /** {@link HttpSetup} */ - http: HttpSetup; - /** {@link NotificationsSetup} */ - notifications: NotificationsSetup; - /** {@link IUiSettingsClient} */ - uiSettings: IUiSettingsClient; - /** {@link ExecutionContextSetup} */ - executionContext: ExecutionContextSetup; - /** {@link InjectedMetadataSetup} */ - injectedMetadata: InjectedMetadataSetup; - /** {@link ThemeServiceSetup} */ - theme: ThemeServiceSetup; - /** {@link StartServicesAccessor} */ - getStartServices: StartServicesAccessor; -} +export type { CoreSetup, CoreStart, StartServicesAccessor } from '@kbn/core-lifecycle-browser'; -/** - * Allows plugins to get access to APIs available in start inside async - * handlers, such as {@link App.mount}. Promise will not resolve until Core - * and plugin dependencies have completed `start`. - * - * @public - */ -export type StartServicesAccessor< - TPluginsStart extends object = object, - TStart = unknown -> = () => Promise<[CoreStart, TPluginsStart, TStart]>; - -/** - * Core services exposed to the `Plugin` start lifecycle - * - * @public - * - * @internalRemarks We document the properties with \@link tags to improve - * navigation in the generated docs until there's a fix for - * https://github.com/Microsoft/web-build-tools/issues/1237 - */ -export interface CoreStart { - /** {@link AnalyticsServiceStart} */ - analytics: AnalyticsServiceStart; - /** {@link ApplicationStart} */ - application: ApplicationStart; - /** {@link ChromeStart} */ - chrome: ChromeStart; - /** {@link DocLinksStart} */ - docLinks: DocLinksStart; - /** {@link ExecutionContextStart} */ - executionContext: ExecutionContextStart; - /** {@link HttpStart} */ - http: HttpStart; - /** {@link SavedObjectsStart} */ - savedObjects: SavedObjectsStart; - /** {@link I18nStart} */ - i18n: I18nStart; - /** {@link NotificationsStart} */ - notifications: NotificationsStart; - /** {@link OverlayStart} */ - overlays: OverlayStart; - /** {@link IUiSettingsClient} */ - uiSettings: IUiSettingsClient; - /** {@link FatalErrorsStart} */ - fatalErrors: FatalErrorsStart; - /** {@link DeprecationsServiceStart} */ - deprecations: DeprecationsServiceStart; - /** {@link ThemeServiceStart} */ - theme: ThemeServiceStart; - /** {@link InjectedMetadataStart} */ - injectedMetadata: InjectedMetadataStart; -} - -export type { - Capabilities, - ChromeBadge, - ChromeBreadcrumb, - ChromeHelpExtension, - ChromeHelpMenuActions, - ChromeHelpExtensionMenuLink, - ChromeHelpExtensionLinkBase, - ChromeHelpExtensionMenuCustomLink, - ChromeHelpExtensionMenuDiscussLink, - ChromeHelpExtensionMenuDocumentationLink, - ChromeHelpExtensionMenuGitHubLink, - ChromeNavControl, - ChromeNavControls, - ChromeNavLink, - ChromeNavLinks, - ChromeDocTitle, - ChromeRecentlyAccessed, - ChromeRecentlyAccessedHistoryItem, - ChromeUserBanner, - ChromeStart, - DocLinksStart, - FatalErrorInfo, - FatalErrorsSetup, - FatalErrorsStart, - HttpSetup, - HttpStart, - I18nStart, - NotificationsSetup, - NotificationsStart, - Plugin, - PluginInitializer, - PluginInitializerContext, - SavedObjectsStart, - PluginOpaqueId, - IUiSettingsClient, - UiSettingsState, -}; +export type { CoreSystem } from './core_system'; export { __kbnBootstrap__ } from './kbn_bootstrap'; diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 82c566243427..790b8ccf028c 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -7,25 +7,12 @@ */ import { createMemoryHistory } from 'history'; -import { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; -import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; import { coreContextMock } from '@kbn/core-base-browser-mocks'; -import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; -import { executionContextServiceMock } from '@kbn/core-execution-context-browser-mocks'; -import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; -import { fatalErrorsServiceMock } from '@kbn/core-fatal-errors-browser-mocks'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; -import { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; -import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks'; -import { savedObjectsServiceMock } from '@kbn/core-saved-objects-browser-mocks'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; import { CoreScopedHistory } from '@kbn/core-application-browser-internal'; import type { AppMountParameters } from '@kbn/core-application-browser'; -import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks'; -import type { PluginInitializerContext } from '.'; +import { pluginsServiceMock } from '@kbn/core-plugins-browser-mocks'; +import { coreLifecycleMock } from '@kbn/core-lifecycle-browser-mocks'; export { injectedMetadataServiceMock } from '@kbn/core-injected-metadata-browser-mocks'; export { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; @@ -46,86 +33,6 @@ export { export { applicationServiceMock, scopedHistoryMock } from '@kbn/core-application-browser-mocks'; export { deprecationsServiceMock } from '@kbn/core-deprecations-browser-mocks'; -function createCoreSetupMock({ - basePath = '', - pluginStartDeps = {}, - pluginStartContract, -}: { - basePath?: string; - pluginStartDeps?: object; - pluginStartContract?: any; -} = {}) { - const mock = { - analytics: analyticsServiceMock.createAnalyticsServiceSetup(), - application: applicationServiceMock.createSetupContract(), - docLinks: docLinksServiceMock.createSetupContract(), - executionContext: executionContextServiceMock.createSetupContract(), - fatalErrors: fatalErrorsServiceMock.createSetupContract(), - getStartServices: jest.fn, any, any]>, []>(() => - Promise.resolve([createCoreStartMock({ basePath }), pluginStartDeps, pluginStartContract]) - ), - http: httpServiceMock.createSetupContract({ basePath }), - notifications: notificationServiceMock.createSetupContract(), - uiSettings: uiSettingsServiceMock.createSetupContract(), - deprecations: deprecationsServiceMock.createSetupContract(), - injectedMetadata: { - getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar, - }, - theme: themeServiceMock.createSetupContract(), - }; - - return mock; -} - -function createCoreStartMock({ basePath = '' } = {}) { - const mock = { - analytics: analyticsServiceMock.createAnalyticsServiceStart(), - application: applicationServiceMock.createStartContract(), - chrome: chromeServiceMock.createStartContract(), - docLinks: docLinksServiceMock.createStartContract(), - executionContext: executionContextServiceMock.createStartContract(), - http: httpServiceMock.createStartContract({ basePath }), - i18n: i18nServiceMock.createStartContract(), - notifications: notificationServiceMock.createStartContract(), - overlays: overlayServiceMock.createStartContract(), - uiSettings: uiSettingsServiceMock.createStartContract(), - savedObjects: savedObjectsServiceMock.createStartContract(), - deprecations: deprecationsServiceMock.createStartContract(), - theme: themeServiceMock.createStartContract(), - injectedMetadata: { - getInjectedVar: injectedMetadataServiceMock.createStartContract().getInjectedVar, - }, - fatalErrors: fatalErrorsServiceMock.createStartContract(), - }; - - return mock; -} - -function pluginInitializerContextMock(config: any = {}) { - const mock: PluginInitializerContext = { - opaqueId: Symbol(), - env: { - mode: { - dev: true, - name: 'development', - prod: false, - }, - packageInfo: { - version: 'version', - branch: 'branch', - buildNum: 100, - buildSha: 'buildSha', - dist: false, - }, - }, - config: { - get: () => config as T, - }, - }; - - return mock; -} - function createStorageMock() { const storageMock: jest.Mocked = { getItem: jest.fn(), @@ -158,9 +65,9 @@ function createAppMountParametersMock(appBasePath = '') { export const coreMock = { createCoreContext: coreContextMock.create, - createSetup: createCoreSetupMock, - createStart: createCoreStartMock, - createPluginInitializerContext: pluginInitializerContextMock, + createSetup: coreLifecycleMock.createCoreSetup, + createStart: coreLifecycleMock.createCoreStart, + createPluginInitializerContext: pluginsServiceMock.createPluginInitializerContext, createStorage: createStorageMock, createAppMountParameters: createAppMountParametersMock, }; diff --git a/yarn.lock b/yarn.lock index 535bf43b01e1..d172285b2080 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3040,6 +3040,18 @@ version "0.0.0" uid "" +"@kbn/core-lifecycle-browser-internal@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal": + version "0.0.0" + uid "" + +"@kbn/core-lifecycle-browser-mocks@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks": + version "0.0.0" + uid "" + +"@kbn/core-lifecycle-browser@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser": + version "0.0.0" + uid "" + "@kbn/core-logging-server-internal@link:bazel-bin/packages/core/logging/core-logging-server-internal": version "0.0.0" uid "" @@ -3116,6 +3128,18 @@ version "0.0.0" uid "" +"@kbn/core-plugins-browser-internal@link:bazel-bin/packages/core/plugins/core-plugins-browser-internal": + version "0.0.0" + uid "" + +"@kbn/core-plugins-browser-mocks@link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks": + version "0.0.0" + uid "" + +"@kbn/core-plugins-browser@link:bazel-bin/packages/core/plugins/core-plugins-browser": + version "0.0.0" + uid "" + "@kbn/core-preboot-server-internal@link:bazel-bin/packages/core/preboot/core-preboot-server-internal": version "0.0.0" uid "" @@ -7093,6 +7117,18 @@ version "0.0.0" uid "" +"@types/kbn__core-lifecycle-browser-internal@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-lifecycle-browser-mocks@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-lifecycle-browser@link:bazel-bin/packages/core/lifecycle/core-lifecycle-browser/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-logging-server-internal@link:bazel-bin/packages/core/logging/core-logging-server-internal/npm_module_types": version "0.0.0" uid "" @@ -7169,6 +7205,18 @@ version "0.0.0" uid "" +"@types/kbn__core-plugins-browser-internal@link:bazel-bin/packages/core/plugins/core-plugins-browser-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-plugins-browser-mocks@link:bazel-bin/packages/core/plugins/core-plugins-browser-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-plugins-browser@link:bazel-bin/packages/core/plugins/core-plugins-browser/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-preboot-server-internal@link:bazel-bin/packages/core/preboot/core-preboot-server-internal/npm_module_types": version "0.0.0" uid "" From 7f49b9caa63db0f23c2a53f495fea4265d8a07f3 Mon Sep 17 00:00:00 2001 From: doakalexi <109488926+doakalexi@users.noreply.github.com> Date: Thu, 22 Sep 2022 08:16:05 -0400 Subject: [PATCH 02/29] =?UTF-8?q?[ResponseOps][Connectors]=20Fixing=20flak?= =?UTF-8?q?y=20connectors=C2=B7ts=20test=20(#140989)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updating skipped tests * Removing unused fields * Fixing test failure * Fixing other test failure * Fixing failure test * Cleaning up tests * Revert skip for testing * Fixing related test failures * Updating retry * Fixing tests * Fixing types * Rename function --- test/functional/services/common/find.ts | 20 +++ .../apps/triggers_actions_ui/connectors.ts | 119 +++++++++--------- 2 files changed, 82 insertions(+), 57 deletions(-) diff --git a/test/functional/services/common/find.ts b/test/functional/services/common/find.ts index ec2d5385a0a4..a7c782b23686 100644 --- a/test/functional/services/common/find.ts +++ b/test/functional/services/common/find.ts @@ -90,6 +90,26 @@ export class FindService extends FtrService { }); } + public async setValueByClass(selector: string, text: string, topOffset?: number): Promise { + this.log.debug(`Find.setValueByClass('${selector}', '${text}')`); + return await this.retry.try(async () => { + const element = await this.byClassName(selector); + await element.click(topOffset); + + // in case the input element is actually a child of the testSubject, we + // call clearValue() and type() on the element that is focused after + // clicking on the testSubject + const input = await this.activeElement(); + if (input) { + await input.clearValue(); + await input.type(text); + } else { + await element.clearValue(); + await element.type(text); + } + }); + } + public async selectValue(selector: string, value: string): Promise { this.log.debug(`Find.selectValue('${selector}', option[value="${value}"]')`); const combobox = await this.byCssSelector(selector); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 78287b57a584..0abb9bd7a395 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { findIndex } from 'lodash'; import { FtrProviderContext } from '../../ftr_provider_context'; import { ObjectRemover } from '../../lib/object_remover'; import { generateUniqueKey, getTestActionData } from '../../lib/get_test_data'; @@ -15,13 +16,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); const find = getService('find'); const retry = getService('retry'); - const comboBox = getService('comboBox'); const supertest = getService('supertest'); + const objectRemover = new ObjectRemover(supertest); - // FLAKY: https://github.com/elastic/kibana/issues/88796 - describe.skip('Connectors', function () { - const objectRemover = new ObjectRemover(supertest); - + describe('Connectors', function () { before(async () => { const { body: createdAction } = await supertest .post(`/api/actions/connector`) @@ -44,7 +42,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('.index-card'); - await find.clickByCssSelector('[data-test-subj="backButton"]'); + await find.clickByCssSelector('[data-test-subj="create-connector-flyout-back-btn"]'); await testSubjects.click('.slack-card'); @@ -68,12 +66,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { actionType: 'Slack', }, ]); + const connector = await getConnector(connectorName); + objectRemover.add(connector.id, 'action', 'actions'); }); it('should edit a connector', async () => { const connectorName = generateUniqueKey(); const updatedConnectorName = `${connectorName}updated`; - await createConnector(connectorName); + const createdAction = await createConnector(connectorName); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -107,7 +108,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should test a connector and display a successful result', async () => { const connectorName = generateUniqueKey(); const indexName = generateUniqueKey(); - await createIndexConnector(connectorName, indexName); + const createdAction = await createIndexConnector(connectorName, indexName); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -119,7 +121,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('[data-test-subj="testConnectorTab"]'); // test success - await testSubjects.setValue('documentsJsonEditor', '{ "key": "value" }'); + await find.setValueByClass('kibanaCodeEditor', '{ "key": "value" }'); await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); @@ -128,14 +130,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); await find.clickByCssSelector( - '[data-test-subj="cancelSaveEditedConnectorButton"]:not(disabled)' + '[data-test-subj="edit-connector-flyout-cancel-btn"]:not(disabled)' ); }); it('should test a connector and display a failure result', async () => { const connectorName = generateUniqueKey(); const indexName = generateUniqueKey(); - await createIndexConnector(connectorName, indexName); + const createdAction = await createIndexConnector(connectorName, indexName); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -146,25 +149,23 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('[data-test-subj="testConnectorTab"]'); - await testSubjects.setValue('documentsJsonEditor', '{ "": "value" }'); + await find.setValueByClass('kibanaCodeEditor', '"test"'); await find.clickByCssSelector('[data-test-subj="executeActionButton"]:not(disabled)'); await retry.try(async () => { - const executionFailureResultCallout = await testSubjects.find('executionFailureResult'); - expect(await executionFailureResultCallout.getVisibleText()).to.match( - /error indexing documents/ - ); + await testSubjects.find('executionFailureResult'); }); await find.clickByCssSelector( - '[data-test-subj="cancelSaveEditedConnectorButton"]:not(disabled)' + '[data-test-subj="edit-connector-flyout-cancel-btn"]:not(disabled)' ); }); it('should reset connector when canceling an edit', async () => { const connectorName = generateUniqueKey(); - await createConnector(connectorName); + const createdAction = await createConnector(connectorName); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); @@ -173,9 +174,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('[data-test-subj="connectorsTableCell-name"] button'); await testSubjects.setValue('nameInput', 'some test name to cancel'); - await testSubjects.click('cancelSaveEditedConnectorButton'); + await testSubjects.click('edit-connector-flyout-cancel-btn'); - await find.waitForDeletedByCssSelector('[data-test-subj="cancelSaveEditedConnectorButton"]'); + await find.waitForDeletedByCssSelector('[data-test-subj="edit-connector-flyout-cancel-btn"]'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -189,8 +190,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should delete a connector', async () => { const connectorName = generateUniqueKey(); await createConnector(connectorName); - - await createConnector(generateUniqueKey()); + const createdAction = await createConnector(generateUniqueKey()); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -214,8 +215,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should bulk delete connectors', async () => { const connectorName = generateUniqueKey(); await createConnector(connectorName); - - await createConnector(generateUniqueKey()); + const createdAction = await createConnector(generateUniqueKey()); + objectRemover.add(createdAction.id, 'action', 'actions'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -269,42 +270,46 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); async function createConnector(connectorName: string) { - await pageObjects.triggersActionsUI.clickCreateConnectorButton(); - - await testSubjects.click('.slack-card'); - - await testSubjects.setValue('nameInput', connectorName); - - await testSubjects.setValue('slackWebhookUrlInput', 'https://test.com'); - - await find.clickByCssSelector( - '[data-test-subj="create-connector-flyout-save-btn"]:not(disabled)' - ); - await pageObjects.common.closeToast(); + const { body: createdAction } = await supertest + .post(`/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name: connectorName, + config: {}, + secrets: { + webhookUrl: 'https://test.com', + }, + connector_type_id: '.slack', + }) + .expect(200); + await testSubjects.click('connectorsTab'); + return createdAction; } async function createIndexConnector(connectorName: string, indexName: string) { - await pageObjects.triggersActionsUI.clickCreateConnectorButton(); - - await testSubjects.click('.index-card'); - - await testSubjects.setValue('nameInput', connectorName); - - await retry.try(async () => { - // At times we find the driver controlling the ComboBox in tests - // can select the wrong item, this ensures we always select the correct index - await comboBox.set('connectorIndexesComboBox', indexName); - expect( - await comboBox.isOptionSelected( - await testSubjects.find('connectorIndexesComboBox'), - indexName - ) - ).to.be(true); - }); + const { body: createdAction } = await supertest + .post(`/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + config: { + index: indexName, + refresh: false, + }, + connector_type_id: '.index', + name: connectorName, + secrets: {}, + }) + .expect(200); + await testSubjects.click('connectorsTab'); + return createdAction; + } - await find.clickByCssSelector( - '[data-test-subj="create-connector-flyout-save-btn"]:not(disabled)' - ); - await pageObjects.common.closeToast(); + async function getConnector(name: string) { + const { body } = await supertest + .get(`/api/actions/connectors`) + .set('kbn-xsrf', 'foo') + .expect(200); + const i = findIndex(body, (c: any) => c.name === name); + return body[i]; } }; From 229dff505eca130e24ec58d07f646ad827988a23 Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Thu, 22 Sep 2022 08:25:17 -0400 Subject: [PATCH 03/29] [Synthetics] unskip edit_monitor api integration tests (#141277) * Update edit_monitor.ts * Update x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts --- x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts b/x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts index 7bcda35a892f..480d07e7144f 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/edit_monitor.ts @@ -16,8 +16,7 @@ import { getFixtureJson } from './helper/get_fixture_json'; import { PrivateLocationTestService } from './services/private_location_test_service'; export default function ({ getService }: FtrProviderContext) { - // Failing: See https://github.com/elastic/kibana/issues/140520 - describe.skip('[PUT] /internal/uptime/service/monitors', function () { + describe('[PUT] /internal/uptime/service/monitors', function () { this.tags('skipCloud'); const supertest = getService('supertest'); From aa11010f015200f43f5766cdeba656659608831e Mon Sep 17 00:00:00 2001 From: liza-mae Date: Thu, 22 Sep 2022 06:34:50 -0600 Subject: [PATCH 04/29] [dashboard controls] skip failing test on cloud (#141291) --- .../apps/dashboard_elements/controls/options_list.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/dashboard_elements/controls/options_list.ts b/test/functional/apps/dashboard_elements/controls/options_list.ts index d6f49b9b435e..56c1778d31de 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list.ts @@ -75,7 +75,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - describe('Options List Control creation and editing experience', async () => { + // Skip on cloud until issue is fixed + // Issue: https://github.com/elastic/kibana/issues/141280 + describe('Options List Control creation and editing experience', function () { + this.tags(['skipCloudFailedTest']); it('can add a new options list control from a blank state', async () => { await dashboardControls.createControl({ controlType: OPTIONS_LIST_CONTROL, From aea8a9e87ec252954535fbd1805bb6c8d8b48fb9 Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Thu, 22 Sep 2022 14:39:53 +0200 Subject: [PATCH 05/29] [SharedUX] Removing TODOs from KibanaPageTemplate (#141043) * Remove a few TODOs * Remove TODOs from page template, first pass * Removing TODOs, pass 2 * Trying to convert to emotion * Fix emotion styling * Fix emotion styling * Fix merge conflict * Updating test * Update packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx Co-authored-by: Clint Andrew Hall * Move selectors to constants Co-authored-by: Clint Andrew Hall --- .../impl/src/page_template_inner.tsx | 31 +++++++++++++------ .../shared-ux/page/solution_nav/BUILD.bazel | 1 + .../with_solution_nav.test.tsx.snap | 30 ++++++++++++++++-- .../solution_nav/src/with_solution_nav.scss | 8 ----- .../src/with_solution_nav.styles.ts | 20 ++++++++++++ .../solution_nav/src/with_solution_nav.tsx | 24 ++++++-------- 6 files changed, 79 insertions(+), 35 deletions(-) delete mode 100644 packages/shared-ux/page/solution_nav/src/with_solution_nav.scss create mode 100644 packages/shared-ux/page/solution_nav/src/with_solution_nav.styles.ts diff --git a/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx b/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx index 762435157f97..607b8fbd1776 100644 --- a/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx +++ b/packages/shared-ux/page/kibana_template/impl/src/page_template_inner.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { FC } from 'react'; +import React, { FC, useEffect, useState } from 'react'; import classNames from 'classnames'; import { EuiPageTemplate } from '@elastic/eui'; @@ -21,6 +21,9 @@ const getClasses = (template?: string, className?: string) => { ); }; +const KIBANA_CHROME_SELECTOR = '[data-test-subj="kibanaChrome"]'; +const HEADER_GLOBAL_NAV_SELECTOR = '[data-test-subj="headerGlobalNav"]'; + /** * A thin wrapper around EuiPageTemplate with a few Kibana specific additions */ @@ -35,6 +38,18 @@ export const KibanaPageTemplateInner: FC = ({ }) => { let header; + const [offset, setOffset] = useState(); + + useEffect(() => { + const kibanaChrome = document.querySelector(KIBANA_CHROME_SELECTOR) as HTMLElement; + if (kibanaChrome) { + const kibanaChromeHeader = kibanaChrome.querySelector( + HEADER_GLOBAL_NAV_SELECTOR + ) as HTMLElement; + setOffset(kibanaChromeHeader?.offsetTop + kibanaChromeHeader?.offsetHeight); + } + }, []); + if (isEmptyState && pageHeader && !children) { const { iconType, pageTitle, description, rightSideItems } = pageHeader; const title = pageTitle ?

{pageTitle}

: undefined; @@ -54,15 +69,11 @@ export const KibanaPageTemplateInner: FC = ({ let sideBar; if (pageSideBar) { - sideBar = ( - - {pageSideBar} - - ); + const sideBarProps = { ...pageSideBarProps }; + if (offset) { + sideBarProps.sticky = { offset }; + } + sideBar = {pageSideBar}; } const classes = getClasses(undefined, className); diff --git a/packages/shared-ux/page/solution_nav/BUILD.bazel b/packages/shared-ux/page/solution_nav/BUILD.bazel index d12304fcdd19..0b6b0a825802 100644 --- a/packages/shared-ux/page/solution_nav/BUILD.bazel +++ b/packages/shared-ux/page/solution_nav/BUILD.bazel @@ -78,6 +78,7 @@ TYPES_DEPS = [ "//packages/kbn-i18n-react:npm_module_types", "//packages/kbn-i18n:npm_module_types", "//packages/shared-ux/avatar/solution:npm_module_types", + "//packages/shared-ux/page/kibana_template/types" ] jsts_transpiler( diff --git a/packages/shared-ux/page/solution_nav/src/__snapshots__/with_solution_nav.test.tsx.snap b/packages/shared-ux/page/solution_nav/src/__snapshots__/with_solution_nav.test.tsx.snap index bae96ec7b65d..749d0a13ad8d 100644 --- a/packages/shared-ux/page/solution_nav/src/__snapshots__/with_solution_nav.test.tsx.snap +++ b/packages/shared-ux/page/solution_nav/src/__snapshots__/with_solution_nav.test.tsx.snap @@ -52,7 +52,20 @@ exports[`WithSolutionNav renders wrapped component 1`] = ` } pageSideBarProps={ Object { - "className": "kbnSolutionNav__sidebar kbnStickyMenu", + "className": "kbnStickyMenu", + "css": Object { + "map": undefined, + "name": "sx7fqw", + "next": undefined, + "styles": " + flex: 0 1 0%; + overflow: hidden; + @media screen and (prefers-reduced-motion: no-preference) { + transition: min-width 150ms cubic-bezier(.694, .0482, .335, 1); + } + ", + "toString": [Function], + }, "minWidth": undefined, "paddingSize": "none", } @@ -112,7 +125,20 @@ exports[`WithSolutionNav with children 1`] = ` } pageSideBarProps={ Object { - "className": "kbnSolutionNav__sidebar kbnStickyMenu", + "className": "kbnStickyMenu", + "css": Object { + "map": undefined, + "name": "sx7fqw", + "next": undefined, + "styles": " + flex: 0 1 0%; + overflow: hidden; + @media screen and (prefers-reduced-motion: no-preference) { + transition: min-width 150ms cubic-bezier(.694, .0482, .335, 1); + } + ", + "toString": [Function], + }, "minWidth": undefined, "paddingSize": "none", } diff --git a/packages/shared-ux/page/solution_nav/src/with_solution_nav.scss b/packages/shared-ux/page/solution_nav/src/with_solution_nav.scss deleted file mode 100644 index 00cfb7b9f927..000000000000 --- a/packages/shared-ux/page/solution_nav/src/with_solution_nav.scss +++ /dev/null @@ -1,8 +0,0 @@ -// TODO: Can now be converted to Emotion -.kbnSolutionNav__sidebar { - overflow: hidden; - - @include euiCanAnimate { - transition: min-width $euiAnimSpeedFast $euiAnimSlightResistance; - } -} diff --git a/packages/shared-ux/page/solution_nav/src/with_solution_nav.styles.ts b/packages/shared-ux/page/solution_nav/src/with_solution_nav.styles.ts new file mode 100644 index 000000000000..906f1fdd8e29 --- /dev/null +++ b/packages/shared-ux/page/solution_nav/src/with_solution_nav.styles.ts @@ -0,0 +1,20 @@ +/* + * 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 { css } from '@emotion/react'; +import { euiCanAnimate, EuiThemeComputed } from '@elastic/eui'; + +export const WithSolutionNavStyles = (euiTheme: EuiThemeComputed<{}>) => { + return css` + flex: 0 1 0%; + overflow: hidden; + ${euiCanAnimate} { + transition: min-width ${euiTheme.animation.fast} ${euiTheme.animation.resistance}; + } + `; +}; diff --git a/packages/shared-ux/page/solution_nav/src/with_solution_nav.tsx b/packages/shared-ux/page/solution_nav/src/with_solution_nav.tsx index a618f6d6ba41..0c3f0359c1f6 100644 --- a/packages/shared-ux/page/solution_nav/src/with_solution_nav.tsx +++ b/packages/shared-ux/page/solution_nav/src/with_solution_nav.tsx @@ -8,27 +8,20 @@ import React, { ComponentType, ReactNode, useState } from 'react'; import classNames from 'classnames'; -import { - useIsWithinBreakpoints, - useEuiTheme, - useIsWithinMinBreakpoint, - EuiPageSidebarProps, -} from '@elastic/eui'; +import { SerializedStyles } from '@emotion/serialize'; +import { KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template-types'; +import { useIsWithinBreakpoints, useEuiTheme, useIsWithinMinBreakpoint } from '@elastic/eui'; import { SolutionNav, SolutionNavProps } from './solution_nav'; - -import './with_solution_nav.scss'; +import { WithSolutionNavStyles } from './with_solution_nav.styles'; // https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging function getDisplayName(Component: ComponentType) { return Component.displayName || Component.name || 'UnnamedComponent'; } -// TODO: Would be nice to grab these from KibanaPageTemplate or vice-versa -interface TemplateProps { - pageSideBar?: ReactNode; - pageSideBarProps?: Partial; +type TemplateProps = Pick & { children?: ReactNode; -} +}; type Props

= P & TemplateProps & { @@ -58,8 +51,8 @@ export const withSolutionNav =

(WrappedComponent: Compo const { canBeCollapsed = true } = solutionNav; const isSidebarShrunk = isMediumBreakpoint || (canBeCollapsed && isLargerBreakpoint && !isSideNavOpenOnDesktop); + const withSolutionNavStyles = WithSolutionNavStyles(euiTheme); const sideBarClasses = classNames( - 'kbnSolutionNav__sidebar', 'kbnStickyMenu', { 'kbnSolutionNav__sidebar--shrink': isSidebarShrunk, @@ -75,11 +68,12 @@ export const withSolutionNav =

(WrappedComponent: Compo /> ); - const pageSideBarProps: TemplateProps['pageSideBarProps'] = { + const pageSideBarProps: TemplateProps['pageSideBarProps'] & { css: SerializedStyles } = { paddingSize: 'none' as 'none', ...props.pageSideBarProps, minWidth: isSidebarShrunk ? euiTheme.size.xxl : undefined, className: sideBarClasses, + css: withSolutionNavStyles, }; return ( From 2f00d39586f44522717bf30125ef3aff8fca1420 Mon Sep 17 00:00:00 2001 From: suchcodemuchwow Date: Thu, 22 Sep 2022 15:46:29 +0300 Subject: [PATCH 06/29] skip flaky test suit #141356 --- .../security_solution/server/lib/telemetry/helpers.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts index 330add442519..cba00773453f 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts @@ -933,7 +933,8 @@ describe('test tlog', () => { }); }); -describe('test create task metrics', () => { +// FLAKY: https://github.com/elastic/kibana/issues/141356 +describe.skip('test create task metrics', () => { test('can succeed when all parameters are given', async () => { const stubTaskName = 'test'; const stubPassed = true; From 81e973bc35e64d586fdffd3df68ee930e3b7e249 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Thu, 22 Sep 2022 09:01:18 -0400 Subject: [PATCH 07/29] Changing triggers actions ui routes to internal (#141149) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../alert_types/threshold/index_threshold_api.ts | 2 +- x-pack/plugins/triggers_actions_ui/common/index.ts | 2 +- .../public/common/lib/config_api.test.ts | 2 +- .../public/common/lib/data_apis.test.ts | 4 ++-- .../public/common/lib/data_apis.ts | 2 +- .../public/common/lib/health_api.test.ts | 2 +- .../triggers_actions_ui/server/data/README.md | 14 +++++++------- .../server/routes/config.test.ts | 4 ++-- .../index_threshold/fields_endpoint.ts | 2 +- .../index_threshold/indices_endpoint.ts | 2 +- .../index_threshold/time_series_query_endpoint.ts | 3 ++- 11 files changed, 20 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/index_threshold_api.ts b/x-pack/plugins/stack_alerts/public/alert_types/threshold/index_threshold_api.ts index a884d2230c2b..d1e5613c659f 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/index_threshold_api.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/index_threshold_api.ts @@ -9,7 +9,7 @@ import { HttpSetup } from '@kbn/core/public'; import { TimeSeriesResult } from '@kbn/triggers-actions-ui-plugin/common'; import { IndexThresholdAlertParams } from './types'; -const INDEX_THRESHOLD_DATA_API_ROOT = '/api/triggers_actions_ui/data'; +const INDEX_THRESHOLD_DATA_API_ROOT = '/internal/triggers_actions_ui/data'; export interface GetThresholdAlertVisualizationDataParams { model: IndexThresholdAlertParams; diff --git a/x-pack/plugins/triggers_actions_ui/common/index.ts b/x-pack/plugins/triggers_actions_ui/common/index.ts index bc9592a2e49f..1675dee6129d 100644 --- a/x-pack/plugins/triggers_actions_ui/common/index.ts +++ b/x-pack/plugins/triggers_actions_ui/common/index.ts @@ -9,6 +9,6 @@ /* eslint-disable @kbn/eslint/no_export_all */ export * from './data'; -export const BASE_TRIGGERS_ACTIONS_UI_API_PATH = '/api/triggers_actions_ui'; +export const BASE_TRIGGERS_ACTIONS_UI_API_PATH = '/internal/triggers_actions_ui'; export * from './parse_interval'; export * from './experimental_features'; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/config_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/config_api.test.ts index 765c6b2b7b12..9f117b51c9cf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/config_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/config_api.test.ts @@ -17,7 +17,7 @@ describe('triggersActionsUiConfig', () => { expect(http.get.mock.calls).toMatchInlineSnapshot(` Array [ Array [ - "/api/triggers_actions_ui/_config", + "/internal/triggers_actions_ui/_config", ], ] `); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.test.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.test.ts index 178c891dc3a3..3f08c3e5f844 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.test.ts @@ -38,7 +38,7 @@ describe('Data API', () => { http.post.mockResolvedValueOnce(mockFields); const fields = await getESIndexFields({ indexes, http }); - expect(http.post).toHaveBeenCalledWith('/api/triggers_actions_ui/data/_fields', { + expect(http.post).toHaveBeenCalledWith('/internal/triggers_actions_ui/data/_fields', { body: `{"indexPatterns":${JSON.stringify(indexes)}}`, }); expect(fields).toEqual(mockFields.fields); @@ -50,7 +50,7 @@ describe('Data API', () => { http.post.mockResolvedValueOnce(mockIndices); const indices = await getMatchingIndices({ pattern, http }); - expect(http.post).toHaveBeenCalledWith('/api/triggers_actions_ui/data/_indices', { + expect(http.post).toHaveBeenCalledWith('/internal/triggers_actions_ui/data/_indices', { body: `{"pattern":"*${mockPattern}*"}`, }); expect(indices).toEqual(mockIndices.indices); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts index 90f80dd3dc2f..fa4bf0a86986 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/data_apis.ts @@ -8,7 +8,7 @@ import { HttpSetup } from '@kbn/core/public'; import { DataViewsContract, DataView } from '@kbn/data-views-plugin/public'; -const DATA_API_ROOT = '/api/triggers_actions_ui/data'; +const DATA_API_ROOT = '/internal/triggers_actions_ui/data'; const formatPattern = (pattern: string) => { let formattedPattern = pattern; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts index 6454f726e934..b668d58f5b7d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts @@ -17,7 +17,7 @@ describe('triggersActionsUiHealth', () => { expect(http.get.mock.calls).toMatchInlineSnapshot(` Array [ Array [ - "/api/triggers_actions_ui/_health", + "/internal/triggers_actions_ui/_health", ], ] `); diff --git a/x-pack/plugins/triggers_actions_ui/server/data/README.md b/x-pack/plugins/triggers_actions_ui/server/data/README.md index 78577f078300..696232d5a680 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/README.md +++ b/x-pack/plugins/triggers_actions_ui/server/data/README.md @@ -6,9 +6,9 @@ The TriggersActionsUi plugin's Data Apis back the functionality needed by the In The following endpoints are provided for this alert type: -- `POST /api/triggers_actions_ui/data/_indices` -- `POST /api/triggers_actions_ui/data/_fields` -- `POST /api/triggers_actions_ui/data/_time_series_query` +- `POST /internal/triggers_actions_ui/data/_indices` +- `POST /internal/triggers_actions_ui/data/_fields` +- `POST /internal/triggers_actions_ui/data/_time_series_query` ### `POST .../_indices` @@ -79,7 +79,7 @@ provide a "preview" of the alert during creation/editing based on recent data, and could be used to show a "simulation" of the the alert over an arbitrary range of time. -The endpoint is `POST /api/triggers_actions_ui/data/_time_series_query`. +The endpoint is `POST /internal/triggers_actions_ui/data/_time_series_query`. The request and response bodies are specifed in [`lib/core_query_types.ts`][it-core-query] and @@ -93,7 +93,7 @@ for the last 10 seconds. This example uses [now-iso][] to generate iso date strings. ```console -curl -k "https://elastic:changeme@localhost:5601/api/triggers_actions_ui/data/_time_series_query" \ +curl -k "https://elastic:changeme@localhost:5601/internal/triggers_actions_ui/data/_time_series_query" \ -H "kbn-xsrf: foo" -H "content-type: application/json" -d "{ \"index\": \"es-hb-sim\", \"timeField\": \"@timestamp\", @@ -136,7 +136,7 @@ curl -k "https://elastic:changeme@localhost:5601/api/triggers_actions_ui/data/_ To get the current value of the calculated metric, you can leave off the date: ``` -curl -k "https://elastic:changeme@localhost:5601/api/triggers_actions_ui/data/_time_series_query" \ +curl -k "https://elastic:changeme@localhost:5601/internal/triggers_actions_ui/data/_time_series_query" \ -H "kbn-xsrf: foo" -H "content-type: application/json" -d '{ "index": "es-hb-sim", "timeField": "@timestamp", @@ -169,7 +169,7 @@ curl -k "https://elastic:changeme@localhost:5601/api/triggers_actions_ui/data/_ ## service functions A single service function is available that provides the functionality -of the http endpoint `POST /api/triggers_actions_ui/data/_time_series_query`, +of the http endpoint `POST /internal/triggers_actions_ui/data/_time_series_query`, but as an API for Kibana plugins. The function is available as `triggersActionsUi.data.timeSeriesQuery()` on the plugin's _Start_ contract diff --git a/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts b/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts index 79b5f6f85d4e..9c32256f91bc 100644 --- a/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts +++ b/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts @@ -12,13 +12,13 @@ describe('createConfigRoute', () => { it('registers the route', async () => { const router = httpServiceMock.createRouter(); const logger = loggingSystemMock.create().get(); - createConfigRoute(logger, router, `/api/triggers_actions_ui`, () => ({ + createConfigRoute(logger, router, `/internal/triggers_actions_ui`, () => ({ isUsingSecurity: true, minimumScheduleInterval: { value: '1m', enforce: false }, })); const [config, handler] = router.get.mock.calls[0]; - expect(config.path).toMatchInlineSnapshot(`"/api/triggers_actions_ui/_config"`); + expect(config.path).toMatchInlineSnapshot(`"/internal/triggers_actions_ui/_config"`); const mockResponse = httpServerMock.createResponseFactory(); await handler({}, httpServerMock.createKibanaRequest(), mockResponse); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts index 0a48e206e020..37e71ac0e1a1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts @@ -11,7 +11,7 @@ import { Spaces } from '../../../../scenarios'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { ESTestIndexTool, ES_TEST_INDEX_NAME, getUrlPrefix } from '../../../../../common/lib'; -const API_URI = 'api/triggers_actions_ui/data/_fields'; +const API_URI = 'internal/triggers_actions_ui/data/_fields'; // eslint-disable-next-line import/no-default-export export default function fieldsEndpointTests({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts index 894dd5848ee7..fb70420d5f45 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts @@ -13,7 +13,7 @@ import { ESTestIndexTool, ES_TEST_INDEX_NAME, getUrlPrefix } from '../../../../. import { createEsDocumentsWithGroups } from '../lib/create_test_data'; import { createDataStream, deleteDataStream } from '../lib/create_test_data'; -const API_URI = 'api/triggers_actions_ui/data/_indices'; +const API_URI = 'internal/triggers_actions_ui/data/_indices'; // eslint-disable-next-line import/no-default-export export default function indicesEndpointTests({ getService }: FtrProviderContext) { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts index 52fae5766e86..5eee05a916da 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts @@ -14,7 +14,8 @@ import { ESTestIndexTool, ES_TEST_INDEX_NAME, getUrlPrefix } from '../../../../. import { createEsDocumentsWithGroups } from '../lib/create_test_data'; -const INDEX_THRESHOLD_TIME_SERIES_QUERY_URL = 'api/triggers_actions_ui/data/_time_series_query'; +const INDEX_THRESHOLD_TIME_SERIES_QUERY_URL = + 'internal/triggers_actions_ui/data/_time_series_query'; const START_DATE_MM_DD_HH_MM_SS_MS = '01-01T00:00:00.000Z'; const START_DATE = `2020-${START_DATE_MM_DD_HH_MM_SS_MS}`; From ec1fe0a8974c8a60815380431b0ad4b93f48408d Mon Sep 17 00:00:00 2001 From: Jatin Kathuria Date: Thu, 22 Sep 2022 15:03:47 +0200 Subject: [PATCH 08/29] [Security Solution][Fix]-Issue with disabled dataProvider (#140735) Fixes : #129958 When the data provider was disabled, the final query getting created is not syntactically correct and throws a syntax error as show in the screenshot below: ![](https://user-images.githubusercontent.com/2946766/162839613-88320f35-ec0d-4df3-aa66-167593ef4955.png) --- .../public/common/components/top_n/index.tsx | 2 +- .../common/lib/{keury => kuery}/index.ts | 1 + .../components/alerts_table/actions.tsx | 2 +- .../components/alerts_table/index.tsx | 2 +- .../components/rules/query_bar/index.tsx | 2 +- .../rule_preview/use_preview_histogram.tsx | 2 +- .../detection_engine/rules/utils.ts | 2 +- .../public/hosts/pages/details/helpers.ts | 2 +- .../public/hosts/pages/details/index.tsx | 2 +- .../public/hosts/pages/hosts.tsx | 2 +- .../public/kubernetes/pages/index.tsx | 2 +- .../public/network/pages/details/index.tsx | 2 +- .../public/network/pages/network.tsx | 2 +- .../components/event_counts/index.tsx | 2 +- .../components/events_by_dataset/index.tsx | 2 +- .../components/flyout/header/index.tsx | 3 +- .../network_details/expandable_network.tsx | 2 +- .../components/timeline/helpers.test.tsx | 390 +----------------- .../timelines/components/timeline/helpers.tsx | 82 +--- .../timeline/query_bar/index.test.tsx | 2 +- .../components/timeline/query_bar/index.tsx | 2 +- .../timeline/query_tab_content/index.test.tsx | 4 +- .../timeline/query_tab_content/index.tsx | 3 +- .../public/users/pages/details/index.tsx | 2 +- .../public/users/pages/users.tsx | 2 +- .../public/components/t_grid/helpers.test.tsx | 95 +++++ .../public/components/t_grid/helpers.tsx | 49 +-- x-pack/plugins/timelines/public/index.ts | 2 + 28 files changed, 143 insertions(+), 524 deletions(-) rename x-pack/plugins/security_solution/public/common/lib/{keury => kuery}/index.ts (95%) diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx index 8771d75ccf81..589065e0812b 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx @@ -15,12 +15,12 @@ import { InputsModelId } from '../../store/inputs/constants'; import { useGlobalTime } from '../../containers/use_global_time'; import type { BrowserFields } from '../../containers/source'; import { useKibana } from '../../lib/kibana'; +import { combineQueries } from '../../lib/kuery'; import type { inputsModel, State } from '../../store'; import { inputsSelectors } from '../../store'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import { timelineSelectors } from '../../../timelines/store/timeline'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; -import { combineQueries } from '../../../timelines/components/timeline/helpers'; import { getOptions } from './helpers'; import { TopN } from './top_n'; diff --git a/x-pack/plugins/security_solution/public/common/lib/keury/index.ts b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts similarity index 95% rename from x-pack/plugins/security_solution/public/common/lib/keury/index.ts rename to x-pack/plugins/security_solution/public/common/lib/kuery/index.ts index 735996d762ff..55be876f3867 100644 --- a/x-pack/plugins/security_solution/public/common/lib/keury/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts @@ -11,4 +11,5 @@ export { convertToBuildEsQuery, escapeKuery, escapeQueryValue, + combineQueries, } from '@kbn/timelines-plugin/public'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx index 0850969019bb..6f2a0dfe0752 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx @@ -57,7 +57,7 @@ import { omitTypenameInTimeline, formatTimelineResultToModel, } from '../../../timelines/components/open_timeline/helpers'; -import { convertKueryToElasticSearchQuery } from '../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../common/lib/kuery'; import { getField, getFieldKey } from '../../../helpers'; import { replaceTemplateFieldFromQuery, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index bf183ca40572..49927599cb1e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -25,7 +25,7 @@ import { SourcererScopeName } from '../../../common/store/sourcerer/model'; import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants'; import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; -import { combineQueries } from '../../../timelines/components/timeline/helpers'; +import { combineQueries } from '../../../common/lib/kuery'; import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline'; import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx index 6d96695d3c79..a5316eabb11f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx @@ -19,7 +19,7 @@ import type { ActionTimelineToShow } from '../../../../timelines/components/open import { QueryBar } from '../../../../common/components/query_bar'; import { buildGlobalQuery } from '../../../../timelines/components/timeline/helpers'; import { getDataProviderFilter } from '../../../../timelines/components/timeline/query_bar'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { useKibana } from '../../../../common/lib/kibana'; import type { TimelineModel } from '../../../../timelines/store/timeline/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx index a0c6e706c19e..d3814fe1e8c1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/use_preview_histogram.tsx @@ -10,7 +10,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { DataViewBase } from '@kbn/es-query'; import { useMatrixHistogramCombined } from '../../../../common/containers/matrix_histogram'; import { MatrixHistogramType } from '../../../../../common/search_strategy'; -import { convertToBuildEsQuery } from '../../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../../common/lib/kuery'; import { useKibana } from '../../../../common/lib/kibana'; import { QUERY_PREVIEW_ERROR } from './translations'; import { DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts index 083b75a33c70..b4de6a95daaf 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { escapeKuery } from '../../../../common/lib/keury'; +import { escapeKuery } from '../../../../common/lib/kuery'; import type { FilterOptions } from './types'; const SEARCHABLE_RULE_PARAMS = [ diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts index 0a09c7ec6dad..99cdba73760a 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/helpers.ts @@ -6,7 +6,7 @@ */ import type { Filter } from '@kbn/es-query'; -import { escapeQueryValue } from '../../../common/lib/keury'; +import { escapeQueryValue } from '../../../common/lib/kuery'; /** Returns the kqlQueryExpression for the `Events` widget on the `Host Details` page */ export const getHostDetailsEventsKqlQueryExpression = ({ diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index fb39b402c84d..b801dd825a7a 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -40,7 +40,7 @@ import { SiemSearchBar } from '../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { setHostDetailsTablesActivePageToZero } from '../../store/actions'; import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index 3195137ca389..b9cefa660a45 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -30,7 +30,7 @@ import { useGlobalTime } from '../../common/containers/use_global_time'; import { TimelineId } from '../../../common/types/timeline'; import { LastEventIndexKey, RiskScoreEntity } from '../../../common/search_strategy'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import type { State } from '../../common/store'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; diff --git a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx index 58e0ae3914ad..d938e7a97278 100644 --- a/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/kubernetes/pages/index.tsx @@ -20,7 +20,7 @@ import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useSourcererDataView } from '../../common/containers/sourcerer'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { useDeepEqualSelector } from '../../common/hooks/use_selector'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_query'; import { SessionsView } from '../../common/components/sessions_viewer'; import { TimelineId } from '../../../common/types/timeline'; diff --git a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx index c7c435b608d7..964e660fed52 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx @@ -33,7 +33,7 @@ import { SecuritySolutionPageWrapper } from '../../../common/components/page_wra import { useNetworkDetails, ID } from '../../containers/details'; import { useKibana } from '../../../common/lib/kibana'; import { decodeIpv6 } from '../../../common/lib/helpers'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; import { setNetworkDetailsTablesActivePageToZero } from '../../store/actions'; diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx index a28f25119511..92bc47ba04c7 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx @@ -30,7 +30,7 @@ import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { LastEventIndexKey } from '../../../common/search_strategy'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; import { SpyRoute } from '../../common/utils/route/spy_routes'; diff --git a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx index 9f73cbf9a2d4..5194d697c96b 100644 --- a/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/event_counts/index.tsx @@ -14,7 +14,7 @@ import { ID as OverviewHostQueryId } from '../../containers/overview_host'; import { OverviewHost } from '../overview_host'; import { OverviewNetwork } from '../overview_network'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { diff --git a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx index 15768c635981..4e35cae87334 100644 --- a/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/events_by_dataset/index.tsx @@ -22,7 +22,7 @@ import type { MatrixHistogramConfigs, MatrixHistogramOption, } from '../../../common/components/matrix_histogram/types'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { useKibana, useUiSetting$ } from '../../../common/lib/kibana'; import { eventsStackByOptions, diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index f7e267de67d0..367a145774d7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -49,7 +49,8 @@ import { startSelector, endSelector, } from '../../../../common/components/super_date_picker/selectors'; -import { combineQueries, focusActiveTimelineButton } from '../../timeline/helpers'; +import { focusActiveTimelineButton } from '../../timeline/helpers'; +import { combineQueries } from '../../../../common/lib/kuery'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { ActiveTimelines } from './active_timelines'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx index 05421e9891e5..8841a53f43d6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx @@ -21,7 +21,7 @@ import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { networkToCriteria } from '../../../../common/components/ml/criteria/network_to_criteria'; import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; import { useKibana } from '../../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../../common/lib/kuery'; import { inputsSelectors } from '../../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx index 5f6713c82c42..4e391a95fc05 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx @@ -6,14 +6,11 @@ */ import { cloneDeep } from 'lodash/fp'; -import { mockIndexPattern } from '../../../common/mock'; import { DataProviderType } from './data_providers/data_provider'; import { mockDataProviders } from './data_providers/mock/mock_data_providers'; -import { buildGlobalQuery, combineQueries, resolverIsShowing, showGlobalFilters } from './helpers'; +import { buildGlobalQuery } from './helpers'; import { mockBrowserFields } from '../../../common/containers/source/mock'; -import type { EsQueryConfig, Filter } from '@kbn/es-query'; -import { FilterStateStore } from '@kbn/es-query'; const cleanUpKqlQuery = (str: string) => str.replace(/\n/g, '').replace(/\s\s+/g, ' '); @@ -220,388 +217,3 @@ describe('Build KQL Query', () => { ); }); }); - -describe('Combined Queries', () => { - const config: EsQueryConfig = { - allowLeadingWildcards: true, - queryStringOptions: {}, - ignoreFilterIfFieldNotInIndex: true, - dateFormatTZ: 'America/New_York', - }; - test('No Data Provider & No kqlQuery & and isEventViewer is false', () => { - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - }) - ).toBeNull(); - }); - - test('No Data Provider & No kqlQuery & isEventViewer is true', () => { - const isEventViewer = true; - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - isEventViewer, - }) - ).toEqual({ - filterQuery: '{"bool":{"must":[],"filter":[],"should":[],"must_not":[]}}', - }); - }); - - test('No Data Provider & No kqlQuery & with Filters', () => { - const isEventViewer = true; - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'event.category', - negate: false, - params: { query: 'file' }, - type: 'phrase', - }, - query: { match_phrase: { 'event.category': 'file' } }, - }, - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'host.name', - negate: false, - type: 'exists', - value: 'exists', - }, - query: { exists: { field: 'host.name' } }, - } as Filter, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - isEventViewer, - }) - ).toEqual({ - filterQuery: - '{"bool":{"must":[],"filter":[{"exists":{"field":"host.name"}}],"should":[],"must_not":[]}}', - }); - }); - - test('Only Data Provider', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with timestamp (string input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = '@timestamp'; - dataProviders[0].queryMatch.value = '2018-03-23T23:36:23.232Z'; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"range\\":{\\"@timestamp\\":{\\"gte\\":\\"1521848183232\\",\\"lte\\":\\"1521848183232\\"}}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with timestamp (numeric input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = '@timestamp'; - dataProviders[0].queryMatch.value = 1521848183232; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"range\\":{\\"@timestamp\\":{\\"gte\\":\\"1521848183232\\",\\"lte\\":\\"1521848183232\\"}}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with a date type (string input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = 'event.end'; - dataProviders[0].queryMatch.value = '2018-03-23T23:36:23.232Z'; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"event.end\\":\\"1521848183232\\"}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only Data Provider with date type (numeric input)', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - dataProviders[0].queryMatch.field = 'event.end'; - dataProviders[0].queryMatch.value = 1521848183232; - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"event.end\\":\\"1521848183232\\"}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Only KQL search/filter query', () => { - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Invalid KQL search/filter query', () => { - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toBeUndefined(); - expect(kqlError).toBeDefined(); // Not testing on the error message since we don't control changes to them - }); - - test('Data Provider & KQL search query', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"should":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}],"minimum_should_match":1}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL filter query', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'filter', - })!; - expect(filterQuery).toEqual( - '{"bool":{"must":[],"filter":[{"bool":{"filter":[{"bool":{"should":[{"match_phrase":{"name":"Provider 1"}}],"minimum_should_match":1}},{"bool":{"should":[{"match_phrase":{"host.name":"host-1"}}],"minimum_should_match":1}}]}}],"should":[],"must_not":[]}}' - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL search query multiple', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); - dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4)); - dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'search', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 3\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 4\\"}}],\\"minimum_should_match\\":1}}]}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 2\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 5\\"}}],\\"minimum_should_match\\":1}}]}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"host.name\\":\\"host-1\\"}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & KQL filter query multiple', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); - dataProviders[0].and = cloneDeep(mockDataProviders.slice(2, 4)); - dataProviders[1].and = cloneDeep(mockDataProviders.slice(4, 5)); - const { filterQuery, kqlError } = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: 'host.name: "host-1"', language: 'kuery' }, - kqlMode: 'filter', - })!; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 3\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 4\\"}}],\\"minimum_should_match\\":1}}]}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 2\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 5\\"}}],\\"minimum_should_match\\":1}}]}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"host.name\\":\\"host-1\\"}}],\\"minimum_should_match\\":1}}]}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - expect(kqlError).toBeUndefined(); - }); - - test('Data Provider & kql filter query with nested field that exists', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const query = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - meta: { - alias: null, - negate: false, - disabled: false, - type: 'exists', - key: 'nestedField.firstAttributes', - value: 'exists', - }, - query: { - exists: { - field: 'nestedField.firstAttributes', - }, - }, - $state: { - store: FilterStateStore.APP_STATE, - }, - } as Filter, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'filter', - }); - const filterQuery = query && query.filterQuery; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"exists\\":{\\"field\\":\\"nestedField.firstAttributes\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - }); - - test('Data Provider & kql filter query with nested field of a particular value', () => { - const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); - const query = combineQueries({ - config, - dataProviders, - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [ - { - $state: { store: FilterStateStore.APP_STATE }, - meta: { - alias: null, - disabled: false, - key: 'nestedField.secondAttributes', - negate: false, - params: { query: 'test' }, - type: 'phrase', - }, - query: { match_phrase: { 'nestedField.secondAttributes': 'test' } }, - }, - ], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'filter', - }); - const filterQuery = query && query.filterQuery; - expect(filterQuery).toMatchInlineSnapshot( - `"{\\"bool\\":{\\"must\\":[],\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"name\\":\\"Provider 1\\"}}],\\"minimum_should_match\\":1}},{\\"match_phrase\\":{\\"nestedField.secondAttributes\\":\\"test\\"}}],\\"should\\":[],\\"must_not\\":[]}}"` - ); - }); - - describe('resolverIsShowing', () => { - test('it returns true when graphEventId is NOT an empty string', () => { - expect(resolverIsShowing('a valid id')).toBe(true); - }); - - test('it returns false when graphEventId is undefined', () => { - expect(resolverIsShowing(undefined)).toBe(false); - }); - - test('it returns false when graphEventId is an empty string', () => { - expect(resolverIsShowing('')).toBe(false); - }); - }); - - describe('showGlobalFilters', () => { - test('it returns false when `globalFullScreen` is true and `graphEventId` is NOT an empty string, because Resolver IS showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: 'a valid id' })).toBe(false); - }); - - test('it returns true when `globalFullScreen` is true and `graphEventId` is undefined, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: undefined })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is true and `graphEventId` is an empty string, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: true, graphEventId: '' })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is NOT an empty string, because Resolver IS showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: 'a valid id' })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is undefined, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: undefined })).toBe(true); - }); - - test('it returns true when `globalFullScreen` is false and `graphEventId` is an empty string, because Resolver is NOT showing', () => { - expect(showGlobalFilters({ globalFullScreen: false, graphEventId: '' })).toBe(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx index 592130a2db17..9cb0e3d6e60b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx @@ -8,7 +8,6 @@ import { isEmpty, get } from 'lodash/fp'; import memoizeOne from 'memoize-one'; -import type { DataViewBase, EsQueryConfig, Filter, Query } from '@kbn/es-query'; import { handleSkipFocus, elementOrChildrenHasFocus, @@ -16,7 +15,7 @@ import { getTableSkipFocus, stopPropagationAndPreventDefault, } from '@kbn/timelines-plugin/public'; -import { escapeQueryValue, convertToBuildEsQuery } from '../../../common/lib/keury'; +import { escapeQueryValue } from '../../../common/lib/kuery'; import type { DataProvider, DataProvidersAnd } from './data_providers/data_provider'; import { DataProviderType, EXISTS_OPERATOR } from './data_providers/data_provider'; @@ -134,85 +133,6 @@ export const buildGlobalQuery = (dataProviders: DataProvider[], browserFields: B return !index ? `(${queryMatch})` : `${globalQuery} or (${queryMatch})`; }, ''); -export const combineQueries = ({ - config, - dataProviders, - indexPattern, - browserFields, - filters = [], - kqlQuery, - kqlMode, - isEventViewer, -}: { - config: EsQueryConfig; - dataProviders: DataProvider[]; - indexPattern: DataViewBase; - browserFields: BrowserFields; - filters: Filter[]; - kqlQuery: Query; - kqlMode: string; - isEventViewer?: boolean; -}): { filterQuery?: string; kqlError?: Error } | null => { - const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { - return null; - } else if ( - isEmpty(dataProviders) && - isEmpty(kqlQuery.query) && - (isEventViewer || !isEmpty(filters)) - ) { - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { - kuery.query = `(${kqlQuery.query})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { - kuery.query = `(${buildGlobalQuery(dataProviders, browserFields)})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; - } - const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; - kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( - kqlQuery.query as string - )})`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - return { - filterQuery, - kqlError, - }; -}; - /** * The CSS class name of a "stateful event", which appears in both * the `Timeline` and the `Events Viewer` widget diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx index 3cf7acdef93f..153b24dcf0bf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; import { DEFAULT_FROM, DEFAULT_TO } from '../../../../../common/constants'; import { mockBrowserFields } from '../../../../common/containers/source/mock'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { mockIndexPattern, TestProviders } from '../../../../common/mock'; import { QueryBar } from '../../../../common/components/query_bar'; import { FilterStateStore } from '@kbn/es-query'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx index ed5b4d6d4515..c040f0c6b1ab 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx @@ -18,7 +18,7 @@ import { InputsModelId } from '../../../../common/store/inputs/constants'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; -import { convertKueryToElasticSearchQuery } from '../../../../common/lib/keury'; +import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import type { KqlMode } from '../../../store/timeline/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index c7a30a4f501b..b610adbe6da5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -26,8 +26,8 @@ import { useTimelineEventsDetails } from '../../../containers/details'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { mockSourcererScope } from '../../../../common/containers/sourcerer/mocks'; import { Direction } from '../../../../../common/search_strategy'; -import * as helpers from '../helpers'; import { mockCasesContext } from '@kbn/cases-plugin/public/mocks/mock_cases_context'; +import * as helpers from '../../../../common/lib/kuery'; jest.mock('../../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -47,6 +47,8 @@ jest.mock('../../../../common/containers/sourcerer/use_signal_helpers', () => ({ useSignalHelpers: () => ({ signalIndexNeedsInit: false }), })); +jest.mock('../../../../common/lib/kuery'); + const mockUseResizeObserver: jest.Mock = useResizeObserver as jest.Mock; jest.mock('use-resize-observer/polyfilled'); mockUseResizeObserver.mockImplementation(() => ({})); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index 5797009535e2..c38304d79841 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -35,7 +35,8 @@ import { defaultHeaders } from '../body/column_headers/default_headers'; import { StatefulBody } from '../body'; import { Footer, footerHeight } from '../footer'; import { TimelineHeader } from '../header'; -import { calculateTotalPages, combineQueries } from '../helpers'; +import { calculateTotalPages } from '../helpers'; +import { combineQueries } from '../../../../common/lib/kuery'; import { TimelineRefetch } from '../refetch_timeline'; import type { ControlColumnProps, diff --git a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx index 4e2c09380309..906312d6e1ab 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx @@ -31,7 +31,7 @@ import { SiemSearchBar } from '../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useKibana } from '../../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../../common/lib/kuery'; import { inputsSelectors } from '../../../common/store'; import { useAlertsPrivileges } from '../../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { setUsersDetailsTablesActivePageToZero } from '../../store/actions'; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index d3140a330da6..df5b891c24e8 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -26,7 +26,7 @@ import { LastEventTime } from '../../common/components/last_event_time'; import { useGlobalFullScreen } from '../../common/containers/use_full_screen'; import { useGlobalTime } from '../../common/containers/use_global_time'; import { useKibana } from '../../common/lib/kibana'; -import { convertToBuildEsQuery } from '../../common/lib/keury'; +import { convertToBuildEsQuery } from '../../common/lib/kuery'; import type { State } from '../../common/store'; import { inputsSelectors } from '../../common/store'; import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx index d0d656d64e4d..288ad46d326f 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx @@ -526,6 +526,101 @@ describe('Combined Queries', () => { ); }); + test('Disabled Data Provider and kqlQuery', () => { + const dataProviders = cloneDeep(mockDataProviders.slice(0, 1)); + dataProviders[0].enabled = false; + const { filterQuery } = combineQueries({ + config, + dataProviders, + indexPattern: mockIndexPattern, + browserFields: mockBrowserFields, + filters: [], + kqlQuery: { query: '_id:*', language: 'kuery' }, + kqlMode: 'search', + })!; + + const expectQueryString = JSON.stringify({ + bool: { + must: [], + filter: [ + { + bool: { + should: [ + { + exists: { + field: '_id', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + should: [], + must_not: [], + }, + }); + + expect(filterQuery).toStrictEqual(expectQueryString); + }); + + test('Both disabled & enabled data provider and kqlQuery', () => { + const dataProviders = cloneDeep(mockDataProviders.slice(0, 2)); + dataProviders[0].enabled = false; + const { filterQuery } = combineQueries({ + config, + dataProviders, + indexPattern: mockIndexPattern, + browserFields: mockBrowserFields, + filters: [], + kqlQuery: { query: '_id:*', language: 'kuery' }, + kqlMode: 'search', + })!; + + const expectQueryString = JSON.stringify({ + bool: { + must: [], + filter: [ + { + bool: { + should: [ + { + bool: { + should: [ + { + match_phrase: { + [dataProviders[1].queryMatch.field]: dataProviders[1].queryMatch.value, + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + exists: { + field: '_id', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + should: [], + must_not: [], + }, + }); + + expect(filterQuery).toStrictEqual(expectQueryString); + }); + describe('resolverIsShowing', () => { test('it returns true when graphEventId is NOT an empty string', () => { expect(resolverIsShowing('a valid id')).toBe(true); diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx index 4de43ef24939..497787166510 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx @@ -144,6 +144,10 @@ interface CombineQueries { kqlMode: string; } +export const isDataProviderEmpty = (dataProviders: DataProvider[]) => { + return isEmpty(dataProviders) || isEmpty(dataProviders.filter((d) => d.enabled === true)); +}; + export const combineQueries = ({ config, dataProviders, @@ -154,9 +158,9 @@ export const combineQueries = ({ kqlMode, }: CombineQueries): { filterQuery: string | undefined; kqlError: Error | undefined } | null => { const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { + if (isDataProviderEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { return null; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { + } else if (isDataProviderEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { const [filterQuery, kqlError] = convertToBuildEsQuery({ config, queries: [kuery], @@ -168,40 +172,21 @@ export const combineQueries = ({ filterQuery, kqlError, }; - } else if (isEmpty(dataProviders) && !isEmpty(kqlQuery.query)) { - kuery.query = `(${kqlQuery.query})`; + } - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); + const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - return { - filterQuery, - kqlError, - }; - } else if (!isEmpty(dataProviders) && isEmpty(kqlQuery)) { - kuery.query = `(${buildGlobalQuery(dataProviders, browserFields)})`; + const postpend = (q: string) => `${!isEmpty(q) ? `(${q})` : ''}`; - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); + const globalQuery = buildGlobalQuery(dataProviders, browserFields); // based on Data Providers - return { - filterQuery, - kqlError, - }; - } - const operatorKqlQuery = kqlMode === 'filter' ? 'and' : 'or'; - const postpend = (q: string) => `${!isEmpty(q) ? ` ${operatorKqlQuery} (${q})` : ''}`; - kuery.query = `((${buildGlobalQuery(dataProviders, browserFields)})${postpend( - kqlQuery.query as string - )})`; + const querySuffix = postpend(kqlQuery.query as string); // based on Unified Search bar + + const queryPrefix = globalQuery ? `(${globalQuery})` : ''; + + const queryOperator = queryPrefix && querySuffix ? operatorKqlQuery : ''; + + kuery.query = `(${queryPrefix} ${queryOperator} ${querySuffix})`; const [filterQuery, kqlError] = convertToBuildEsQuery({ config, diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts index b31f01c0663c..8ed9bc7cd092 100644 --- a/x-pack/plugins/timelines/public/index.ts +++ b/x-pack/plugins/timelines/public/index.ts @@ -95,3 +95,5 @@ export { StatefulEventContext } from './components/stateful_event_context'; export { TimelineContext } from './components/t_grid/shared'; export type { AddToTimelineButtonProps } from './components/hover_actions/actions/add_to_timeline'; + +export { combineQueries } from './components/t_grid/helpers'; From 51e25878b852f14a2643f0d7bf78308794993acb Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 22 Sep 2022 09:08:33 -0400 Subject: [PATCH 09/29] Shameless copy of the retryTransientEsErrors from fleet (#141246) --- .../services/slo/transform_manager.test.ts | 30 ++++++- .../server/services/slo/transform_manager.ts | 32 ++++--- .../observability/server/utils/retry.test.ts | 87 +++++++++++++++++++ .../observability/server/utils/retry.ts | 53 +++++++++++ 4 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/observability/server/utils/retry.test.ts create mode 100644 x-pack/plugins/observability/server/utils/retry.ts diff --git a/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts b/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts index dafa4bff18a5..1badb6b08e49 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_manager.test.ts @@ -6,10 +6,14 @@ */ /* eslint-disable max-classes-per-file */ -import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; -import { ElasticsearchClient } from '@kbn/core/server'; +import { + ElasticsearchClientMock, + elasticsearchServiceMock, + loggingSystemMock, +} from '@kbn/core/server/mocks'; import { MockedLogger } from '@kbn/logging-mocks'; import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import { errors as EsErrors } from '@elastic/elasticsearch'; import { DefaultTransformManager } from './transform_manager'; import { @@ -22,7 +26,7 @@ import { createAPMTransactionErrorRateIndicator, createSLO } from './fixtures/sl const SPACE_ID = 'space-id'; describe('TransformManager', () => { - let esClientMock: jest.Mocked; + let esClientMock: ElasticsearchClientMock; let loggerMock: jest.Mocked; beforeEach(() => { @@ -158,6 +162,26 @@ describe('TransformManager', () => { expect(esClientMock.transform.deleteTransform).toHaveBeenCalledTimes(1); }); + + it('retries on transient error', async () => { + esClientMock.transform.deleteTransform.mockRejectedValueOnce( + new EsErrors.ConnectionError('irrelevant') + ); + // @ts-ignore defining only a subset of the possible SLI + const generators: Record = { + 'slo.apm.transaction_error_rate': new ApmTransactionErrorRateTransformGenerator(), + }; + const transformManager = new DefaultTransformManager( + generators, + esClientMock, + loggerMock, + SPACE_ID + ); + + await transformManager.uninstall('slo-transform-id'); + + expect(esClientMock.transform.deleteTransform).toHaveBeenCalledTimes(2); + }); }); }); diff --git a/x-pack/plugins/observability/server/services/slo/transform_manager.ts b/x-pack/plugins/observability/server/services/slo/transform_manager.ts index 178d6dacaa43..ab7799a4a00c 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_manager.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_manager.ts @@ -8,6 +8,7 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { SLO, SLITypes } from '../../types/models'; +import { retryTransientEsErrors } from '../../utils/retry'; import { TransformGenerator } from './transform_generators'; type TransformId = string; @@ -36,7 +37,9 @@ export class DefaultTransformManager implements TransformManager { const transformParams = generator.getTransformParams(slo, this.spaceId); try { - await this.esClient.transform.putTransform(transformParams); + await retryTransientEsErrors(() => this.esClient.transform.putTransform(transformParams), { + logger: this.logger, + }); } catch (err) { this.logger.error(`Cannot create transform for ${slo.indicator.type} SLO type: ${err}`); throw err; @@ -47,9 +50,10 @@ export class DefaultTransformManager implements TransformManager { async start(transformId: TransformId): Promise { try { - await this.esClient.transform.startTransform( - { transform_id: transformId }, - { ignore: [409] } + await retryTransientEsErrors( + () => + this.esClient.transform.startTransform({ transform_id: transformId }, { ignore: [409] }), + { logger: this.logger } ); } catch (err) { this.logger.error(`Cannot start transform id ${transformId}: ${err}`); @@ -59,9 +63,13 @@ export class DefaultTransformManager implements TransformManager { async stop(transformId: TransformId): Promise { try { - await this.esClient.transform.stopTransform( - { transform_id: transformId, wait_for_completion: true }, - { ignore: [404] } + await retryTransientEsErrors( + () => + this.esClient.transform.stopTransform( + { transform_id: transformId, wait_for_completion: true }, + { ignore: [404] } + ), + { logger: this.logger } ); } catch (err) { this.logger.error(`Cannot stop transform id ${transformId}: ${err}`); @@ -71,9 +79,13 @@ export class DefaultTransformManager implements TransformManager { async uninstall(transformId: TransformId): Promise { try { - await this.esClient.transform.deleteTransform( - { transform_id: transformId, force: true }, - { ignore: [404] } + await retryTransientEsErrors( + () => + this.esClient.transform.deleteTransform( + { transform_id: transformId, force: true }, + { ignore: [404] } + ), + { logger: this.logger } ); } catch (err) { this.logger.error(`Cannot delete transform id ${transformId}: ${err}`); diff --git a/x-pack/plugins/observability/server/utils/retry.test.ts b/x-pack/plugins/observability/server/utils/retry.test.ts new file mode 100644 index 000000000000..25870fd24aa7 --- /dev/null +++ b/x-pack/plugins/observability/server/utils/retry.test.ts @@ -0,0 +1,87 @@ +/* + * 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. + */ + +jest.mock('timers/promises'); +import { setTimeout } from 'timers/promises'; +import { loggerMock } from '@kbn/logging-mocks'; +import { errors as EsErrors } from '@elastic/elasticsearch'; + +import { retryTransientEsErrors } from './retry'; + +const setTimeoutMock = setTimeout as jest.Mock< + ReturnType, + Parameters +>; + +describe('retryTransientErrors', () => { + beforeEach(() => { + setTimeoutMock.mockClear(); + }); + + it("doesn't retry if operation is successful", async () => { + const esCallMock = jest.fn().mockResolvedValue('success'); + expect(await retryTransientEsErrors(esCallMock)).toEqual('success'); + expect(esCallMock).toHaveBeenCalledTimes(1); + }); + + it('logs an warning message on retry', async () => { + const logger = loggerMock.create(); + const esCallMock = jest + .fn() + .mockRejectedValueOnce(new EsErrors.ConnectionError('foo')) + .mockResolvedValue('success'); + + await retryTransientEsErrors(esCallMock, { logger }); + expect(logger.warn).toHaveBeenCalledTimes(1); + expect(logger.warn.mock.calls[0][0]).toMatch( + `Retrying Elasticsearch operation after [2s] due to error: ConnectionError: foo ConnectionError: foo` + ); + }); + + it('retries with an exponential backoff', async () => { + let attempt = 0; + const esCallMock = jest.fn(async () => { + attempt++; + if (attempt < 5) { + throw new EsErrors.ConnectionError('foo'); + } else { + return 'success'; + } + }); + + expect(await retryTransientEsErrors(esCallMock)).toEqual('success'); + expect(setTimeoutMock.mock.calls).toEqual([[2000], [4000], [8000], [16000]]); + expect(esCallMock).toHaveBeenCalledTimes(5); + }); + + it('retries each supported error type', async () => { + const errors = [ + new EsErrors.NoLivingConnectionsError('no living connection', { + warnings: [], + meta: {} as any, + }), + new EsErrors.ConnectionError('no connection'), + new EsErrors.TimeoutError('timeout'), + new EsErrors.ResponseError({ statusCode: 503, meta: {} as any, warnings: [] }), + new EsErrors.ResponseError({ statusCode: 408, meta: {} as any, warnings: [] }), + new EsErrors.ResponseError({ statusCode: 410, meta: {} as any, warnings: [] }), + ]; + + for (const error of errors) { + const esCallMock = jest.fn().mockRejectedValueOnce(error).mockResolvedValue('success'); + expect(await retryTransientEsErrors(esCallMock)).toEqual('success'); + expect(esCallMock).toHaveBeenCalledTimes(2); + } + }); + + it('does not retry unsupported errors', async () => { + const error = new Error('foo!'); + const esCallMock = jest.fn().mockRejectedValueOnce(error).mockResolvedValue('success'); + await expect(retryTransientEsErrors(esCallMock)).rejects.toThrow(error); + expect(esCallMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/plugins/observability/server/utils/retry.ts b/x-pack/plugins/observability/server/utils/retry.ts new file mode 100644 index 000000000000..421289d1c047 --- /dev/null +++ b/x-pack/plugins/observability/server/utils/retry.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { setTimeout } from 'timers/promises'; +import { errors as EsErrors } from '@elastic/elasticsearch'; +import type { Logger } from '@kbn/logging'; + +const MAX_ATTEMPTS = 5; + +const retryResponseStatuses = [ + 503, // ServiceUnavailable + 408, // RequestTimeout + 410, // Gone +]; + +const isRetryableError = (e: any) => + e instanceof EsErrors.NoLivingConnectionsError || + e instanceof EsErrors.ConnectionError || + e instanceof EsErrors.TimeoutError || + (e instanceof EsErrors.ResponseError && retryResponseStatuses.includes(e?.statusCode!)); + +/** + * Retries any transient network or configuration issues encountered from Elasticsearch with an exponential backoff. + * Should only be used to wrap operations that are idempotent and can be safely executed more than once. + */ +export const retryTransientEsErrors = async ( + esCall: () => Promise, + { logger, attempt = 0 }: { logger?: Logger; attempt?: number } = {} +): Promise => { + try { + return await esCall(); + } catch (e) { + if (attempt < MAX_ATTEMPTS && isRetryableError(e)) { + const retryCount = attempt + 1; + const retryDelaySec = Math.min(Math.pow(2, retryCount), 64); // 2s, 4s, 8s, 16s, 32s, 64s, 64s, 64s ... + + logger?.warn( + `Retrying Elasticsearch operation after [${retryDelaySec}s] due to error: ${e.toString()} ${ + e.stack + }` + ); + + await setTimeout(retryDelaySec * 1000); + return retryTransientEsErrors(esCall, { logger, attempt: retryCount }); + } + + throw e; + } +}; From 27b8e98d3efc33938a4a1a298c36a0f62a054d75 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 22 Sep 2022 09:10:13 -0400 Subject: [PATCH 10/29] [Fleet] Add experimental data stream features support to simplified package policy API (#141288) --- .../simplified_package_policy_helper.test.ts | 31 +++++++++++++++++++ .../simplified_package_policy_helper.ts | 10 +++++- .../server/routes/package_policy/handlers.ts | 7 +++-- .../server/types/models/package_policy.ts | 21 +++++++------ 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.test.ts b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.test.ts index eec59a647c39..7d5a7966f91c 100644 --- a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.test.ts +++ b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.test.ts @@ -115,5 +115,36 @@ describe('toPackagePolicy', () => { 'nginx-nginx/metrics': ['nginx.stubstatus'], }); }); + + it('should to pass experimental_data_stream_features', () => { + const res = simplifiedPackagePolicytoNewPackagePolicy( + { + name: 'nginx-1', + namespace: 'default', + policy_id: 'policy123', + description: 'Test description', + }, + nginxPackageInfo as unknown as PackageInfo, + { + experimental_data_stream_features: [ + { + data_stream: 'logs-nginx.access', + features: { + synthetic_source: true, + }, + }, + ], + } + ); + + expect(res.package?.experimental_data_stream_features).toEqual([ + { + data_stream: 'logs-nginx.access', + features: { + synthetic_source: true, + }, + }, + ]); + }); }); }); diff --git a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts index c0d05d1eeab2..aa6eb99bf360 100644 --- a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts +++ b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts @@ -11,6 +11,7 @@ import type { PackagePolicyConfigRecord, NewPackagePolicy, PackageInfo, + ExperimentalDataStreamFeature, } from '../types'; import { PackagePolicyValidationError } from '../errors'; @@ -66,7 +67,10 @@ type InputMap = Map Date: Thu, 22 Sep 2022 10:22:18 -0300 Subject: [PATCH 11/29] [Graph] Fix guidance panel appearing for a moment when saving Graph (#141228) * [Discover] Fix issue where workspace switches to uninitialized briefly when saving as copy in Graph * [Graph] Add Jest tests for Graph workspace saving bug --- .../workspace_layout.test.tsx | 49 ++++++++++++++++++- .../workspace_layout/workspace_layout.tsx | 6 ++- .../helpers/saved_workspace_utils.test.ts | 47 ++++++++++++++++++ .../public/helpers/saved_workspace_utils.ts | 28 ++++++----- 4 files changed, 115 insertions(+), 15 deletions(-) create mode 100644 x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts diff --git a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx index 57b4ff613c88..cb43b5ec5d68 100644 --- a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx +++ b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx @@ -11,9 +11,15 @@ import { WorkspaceLayoutComponent } from '.'; import { coreMock } from '@kbn/core/public/mocks'; import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; import { NavigationPublicPluginStart as NavigationStart } from '@kbn/navigation-plugin/public'; -import { GraphSavePolicy, GraphWorkspaceSavedObject, IndexPatternProvider } from '../../types'; +import { + GraphSavePolicy, + GraphWorkspaceSavedObject, + IndexPatternProvider, + Workspace, +} from '../../types'; import { OverlayStart, Capabilities } from '@kbn/core/public'; import { SharingSavedObjectProps } from '../../helpers/use_workspace_loader'; +import { GraphVisualization } from '../graph_visualization'; jest.mock('react-router-dom', () => { const useLocation = () => ({ @@ -45,6 +51,7 @@ describe('workspace_layout', () => { aliasTargetId: '', } as SharingSavedObjectProps, spaces: spacesPluginMock.createStartContract(), + workspace: {} as unknown as Workspace, }; it('should display conflict notification if outcome is conflict', () => { shallow( @@ -60,4 +67,44 @@ describe('workspace_layout', () => { otherObjectPath: '#/workspace/conflictId?query={}', }); }); + it('should not show GraphVisualization when workspaceInitialized is false, savedWorkspace.id is undefined, and savedWorkspace.isSaving is false', () => { + const component = shallow( + + ); + expect(component.find(GraphVisualization).exists()).toBe(false); + }); + it('should show GraphVisualization when workspaceInitialized is true', () => { + const component = shallow( + + ); + expect(component.find(GraphVisualization).exists()).toBe(true); + }); + it('should show GraphVisualization when savedWorkspace.id is defined', () => { + const component = shallow( + + ); + expect(component.find(GraphVisualization).exists()).toBe(true); + }); + it('should show GraphVisualization when savedWorkspace.isSaving is true', () => { + const component = shallow( + + ); + expect(component.find(GraphVisualization).exists()).toBe(true); + }); }); diff --git a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx index 6cfbbcf7d910..3eede479bd80 100644 --- a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx +++ b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx @@ -91,7 +91,11 @@ export const WorkspaceLayoutComponent = ({ const search = useLocation().search; const urlQuery = new URLSearchParams(search).get('query'); - const isInitialized = Boolean(workspaceInitialized || savedWorkspace.id); + // savedWorkspace.id gets set to null while saving a copy of an existing + // workspace, so we need to check for savedWorkspace.isSaving as well + const isInitialized = Boolean( + workspaceInitialized || savedWorkspace.id || savedWorkspace.isSaving + ); const selectSelected = useCallback((node: WorkspaceNode) => { selectedNode.current = node; diff --git a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts new file mode 100644 index 000000000000..7d4027c91858 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock } from '@kbn/core/public/mocks'; +import { GraphWorkspaceSavedObject } from '../types'; +import { saveSavedWorkspace } from './saved_workspace_utils'; + +const core = coreMock.createStart(); + +describe('saved_workspace_utils', () => { + describe('saveSavedWorkspace', () => { + it('should delete the savedWorkspace id and set isSaving to true immediately when copyOnSave is true', async () => { + const savedWorkspace = { + id: '123', + title: 'my workspace', + lastSavedTitle: 'my workspace', + migrationVersion: {}, + wsState: '{ "indexPattern": "my-index-pattern" }', + getEsType: () => 'graph-workspace', + copyOnSave: true, + isSaving: false, + } as GraphWorkspaceSavedObject; + const promise = saveSavedWorkspace( + savedWorkspace, + {}, + { + savedObjectsClient: { + ...core.savedObjects.client, + find: jest.fn().mockResolvedValue({ savedObjects: [] }), + create: jest.fn().mockResolvedValue({ id: '456' }), + }, + overlays: core.overlays, + } + ); + expect(savedWorkspace.id).toBe(undefined); + expect(savedWorkspace.isSaving).toBe(true); + const id = await promise; + expect(id).toBe('456'); + expect(savedWorkspace.id).toBe('456'); + expect(savedWorkspace.isSaving).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts index 202d13f9cd53..03e377792f1a 100644 --- a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts +++ b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts @@ -162,18 +162,6 @@ export async function saveSavedWorkspace( overlays: OverlayStart; } ) { - // Save the original id in case the save fails. - const originalId = savedObject.id; - // Read https://github.com/elastic/kibana/issues/9056 and - // https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable - // exists. - // The goal is to move towards a better rename flow, but since our users have been conditioned - // to expect a 'save as' flow during a rename, we are keeping the logic the same until a better - // UI/UX can be worked out. - if (savedObject.copyOnSave) { - delete savedObject.id; - } - let attributes: SavedObjectAttributes = {}; forOwn(mapping, (fieldType, fieldName) => { @@ -191,14 +179,28 @@ export async function saveSavedWorkspace( throw new Error('References not returned from extractReferences'); } + // Save the original id in case the save fails. + const originalId = savedObject.id; + try { + // Read https://github.com/elastic/kibana/issues/9056 and + // https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable + // exists. + // The goal is to move towards a better rename flow, but since our users have been conditioned + // to expect a 'save as' flow during a rename, we are keeping the logic the same until a better + // UI/UX can be worked out. + if (savedObject.copyOnSave) { + delete savedObject.id; + } + + savedObject.isSaving = true; + await checkForDuplicateTitle( savedObject as any, isTitleDuplicateConfirmed, onTitleDuplicate, services ); - savedObject.isSaving = true; const createOpt = { id: savedObject.id, From 15fc5b753cd56dd01d2e84f1076615e7d246c8b0 Mon Sep 17 00:00:00 2001 From: Ashokaditya <1849116+ashokaditya@users.noreply.github.com> Date: Thu, 22 Sep 2022 15:30:50 +0200 Subject: [PATCH 12/29] [Security Solution][Endpoint][Response Actions] Do fuzzy search on given usernames for Actions Log (#141239) * Do fuzzy search on given usernames fixes elastic/security-team/issues/4724 refs elastic/kibana/pull/140975 * Allow `match` searches on the API Do fuzzy search via the request review suggestions --- .../use_get_endpoint_action_list.test.ts | 2 +- .../endpoint/use_get_endpoint_action_list.ts | 10 +- .../services/actions/action_list.test.ts | 187 ++++++++++++--- .../utils/action_list_helpers.test.ts | 222 +++++++++++++++--- .../endpoint/utils/action_list_helpers.ts | 23 +- 5 files changed, 360 insertions(+), 84 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.test.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.test.ts index 328a465603e6..0afd8788ad33 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.test.ts @@ -64,7 +64,7 @@ describe('useGetEndpointActionList hook', () => { page: 2, pageSize: 20, startDate: 'now-5d', - userIds: ['elastic', 'citsale'], + userIds: ['*elastic*', '*citsale*'], }, }); }); diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.ts index 957afe5e0c15..eba9b162d67f 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_action_list.ts @@ -24,6 +24,14 @@ export const useGetEndpointActionList = ( ): UseQueryResult> => { const http = useHttp(); + // prepend and append * to userIds for fuzzy search + let userIds = query.userIds; + if (typeof query.userIds === 'string') { + userIds = `*${query.userIds}*`; + } else if (Array.isArray(query.userIds)) { + userIds = query.userIds.map((userId) => `*${userId}*`); + } + return useQuery>({ queryKey: ['get-action-list', query], ...options, @@ -37,7 +45,7 @@ export const useGetEndpointActionList = ( pageSize: query.pageSize, startDate: query.startDate, statuses: query.statuses, - userIds: query.userIds, + userIds, }, }); }, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts index b2402b968ee7..f08b82a49071 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/actions/action_list.test.ts @@ -225,53 +225,171 @@ describe('When using `getActionList()', () => { startDate: 'now-10d', endDate: 'now', commands: ['isolate', 'unisolate', 'get-file'], - userIds: ['elastic'], + userIds: ['*elastic*'], }); expect(esClient.search).toHaveBeenNthCalledWith( 1, - expect.objectContaining({ + { body: { query: { bool: { - filter: [ - { - term: { - input_type: 'endpoint', - }, - }, - { - term: { - type: 'INPUT_ACTION', - }, - }, + must: [ { - range: { - '@timestamp': { - gte: 'now-10d', - }, + bool: { + filter: [ + { + term: { + input_type: 'endpoint', + }, + }, + { + term: { + type: 'INPUT_ACTION', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-10d', + }, + }, + }, + { + range: { + '@timestamp': { + lte: 'now', + }, + }, + }, + { + terms: { + 'data.command': ['isolate', 'unisolate', 'get-file'], + }, + }, + { + terms: { + agents: ['123'], + }, + }, + ], }, }, { - range: { - '@timestamp': { - lte: 'now', - }, - }, - }, - { - terms: { - 'data.command': ['isolate', 'unisolate', 'get-file'], + bool: { + should: [ + { + query_string: { + fields: ['user_id'], + query: '*elastic*', + }, + }, + ], + minimum_should_match: 1, }, }, + ], + }, + }, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + }, + from: 0, + index: '.logs-endpoint.actions-default', + size: 20, + }, + { ignore: [404], meta: true } + ); + }); + + it('should call search with exact usernames when no wildcards are present', async () => { + // mock metadataService.findHostMetadataForFleetAgents resolved value + (endpointAppContextService.getEndpointMetadataService as jest.Mock) = jest + .fn() + .mockReturnValue({ + findHostMetadataForFleetAgents: jest.fn().mockResolvedValue([]), + }); + await getActionList({ + esClient, + logger, + metadataService: endpointAppContextService.getEndpointMetadataService(), + pageSize: 10, + startDate: 'now-1d', + endDate: 'now', + userIds: ['elastic', 'kibana'], + }); + + expect(esClient.search).toHaveBeenNthCalledWith( + 1, + { + body: { + query: { + bool: { + must: [ { - terms: { - user_id: ['elastic'], + bool: { + filter: [ + { + term: { + input_type: 'endpoint', + }, + }, + { + term: { + type: 'INPUT_ACTION', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d', + }, + }, + }, + { + range: { + '@timestamp': { + lte: 'now', + }, + }, + }, + ], }, }, { - terms: { - agents: ['123'], + bool: { + should: [ + { + bool: { + should: [ + { + match: { + user_id: 'elastic', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + match: { + user_id: 'kibana', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, }, }, ], @@ -287,12 +405,9 @@ describe('When using `getActionList()', () => { }, from: 0, index: '.logs-endpoint.actions-default', - size: 20, - }), - expect.objectContaining({ - ignore: [404], - meta: true, - }) + size: 10, + }, + { ignore: [404], meta: true } ); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts index 9ea0e66a510c..b2145bc8740f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.test.ts @@ -33,15 +33,21 @@ describe('action helpers', () => { body: { query: { bool: { - filter: [ - { - term: { - input_type: 'endpoint', - }, - }, + must: [ { - term: { - type: 'INPUT_ACTION', + bool: { + filter: [ + { + term: { + input_type: 'endpoint', + }, + }, + { + term: { + type: 'INPUT_ACTION', + }, + }, + ], }, }, ], @@ -65,6 +71,7 @@ describe('action helpers', () => { } ); }); + it('should query with additional filter options provided', async () => { const esClient = mockScopedEsClient.asInternalUser; @@ -77,7 +84,7 @@ describe('action helpers', () => { elasticAgentIds: ['agent-123', 'agent-456'], endDate: 'now', commands: ['isolate', 'unisolate', 'get-file'], - userIds: ['elastic'], + userIds: ['*elastic*', '*kibana*'], }); expect(esClient.search).toHaveBeenCalledWith( @@ -85,44 +92,180 @@ describe('action helpers', () => { body: { query: { bool: { - filter: [ + must: [ { - term: { - input_type: 'endpoint', + bool: { + filter: [ + { + term: { + input_type: 'endpoint', + }, + }, + { + term: { + type: 'INPUT_ACTION', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-10d', + }, + }, + }, + { + range: { + '@timestamp': { + lte: 'now', + }, + }, + }, + { + terms: { + 'data.command': ['isolate', 'unisolate', 'get-file'], + }, + }, + { + terms: { + agents: ['agent-123', 'agent-456'], + }, + }, + ], }, }, { - term: { - type: 'INPUT_ACTION', - }, - }, - { - range: { - '@timestamp': { - gte: 'now-10d', - }, - }, - }, - { - range: { - '@timestamp': { - lte: 'now', - }, - }, - }, - { - terms: { - 'data.command': ['isolate', 'unisolate', 'get-file'], + bool: { + should: [ + { + bool: { + should: [ + { + query_string: { + fields: ['user_id'], + query: '*elastic*', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + query_string: { + fields: ['user_id'], + query: '*kibana*', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, }, }, + ], + }, + }, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + }, + from: 5, + index: '.logs-endpoint.actions-default', + size: 20, + }, + { + ignore: [404], + meta: true, + } + ); + }); + + it('should search with exact usernames when given', async () => { + const esClient = mockScopedEsClient.asInternalUser; + + applyActionListEsSearchMock(esClient); + await getActions({ + esClient, + size: 10, + from: 1, + startDate: 'now-1d', + endDate: 'now', + userIds: ['elastic', 'kibana'], + }); + + expect(esClient.search).toHaveBeenCalledWith( + { + body: { + query: { + bool: { + must: [ { - terms: { - user_id: ['elastic'], + bool: { + filter: [ + { + term: { + input_type: 'endpoint', + }, + }, + { + term: { + type: 'INPUT_ACTION', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-1d', + }, + }, + }, + { + range: { + '@timestamp': { + lte: 'now', + }, + }, + }, + ], }, }, { - terms: { - agents: ['agent-123', 'agent-456'], + bool: { + should: [ + { + bool: { + should: [ + { + match: { + user_id: 'elastic', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + match: { + user_id: 'kibana', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, }, }, ], @@ -136,9 +279,9 @@ describe('action helpers', () => { }, ], }, - from: 5, + from: 1, index: '.logs-endpoint.actions-default', - size: 20, + size: 10, }, { ignore: [404], @@ -146,6 +289,7 @@ describe('action helpers', () => { } ); }); + it('should return expected output', async () => { const esClient = mockScopedEsClient.asInternalUser; const actionRequests = createActionRequestsEsSearchResultsMock(); diff --git a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts index a522cbde6d9e..ee0a2d6e6e2c 100644 --- a/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/utils/action_list_helpers.ts @@ -9,6 +9,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import type { SearchRequest } from '@kbn/data-plugin/public'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { TransportResult } from '@elastic/elasticsearch'; +import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { ENDPOINT_ACTIONS_INDEX } from '../../../common/endpoint/constants'; import type { @@ -49,10 +50,6 @@ export const getActions = async ({ }); } - if (userIds?.length) { - additionalFilters.push({ terms: { user_id: userIds } }); - } - if (elasticAgentIds?.length) { additionalFilters.push({ terms: { agents: elasticAgentIds } }); } @@ -70,15 +67,27 @@ export const getActions = async ({ ...additionalFilters, ]; + const must: SearchRequest = [ + { + bool: { + filter: actionsFilters, + }, + }, + ]; + + if (userIds?.length) { + const userIdsKql = userIds.map((userId) => `user_id:${userId}`).join(' or '); + const mustClause = toElasticsearchQuery(fromKueryExpression(userIdsKql)); + must.push(mustClause); + } + const actionsSearchQuery: SearchRequest = { index: ENDPOINT_ACTIONS_INDEX, size, from, body: { query: { - bool: { - filter: actionsFilters, - }, + bool: { must }, }, sort: [ { From 60fc42c62767a526f40cb304b4d15f7af766f1ca Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 22 Sep 2022 15:31:43 +0200 Subject: [PATCH 13/29] [Fleet] Update to use savedObjects bulkDelete for package policy delete (#141276) --- .../fleet/server/services/package_policy.ts | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 77c5b67d9a78..ba7e648f4c77 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -674,7 +674,9 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } - const deletePackagePolicy = async (id: string) => { + const idsToDelete: string[] = []; + + ids.forEach((id) => { try { const packagePolicy = packagePolicies.find((p) => p.id === id); @@ -694,10 +696,23 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ); } - // TODO: replace this with savedObject BulkDelete when following PR is merged - // https://github.com/elastic/kibana/pull/139680 - await soClient.delete(SAVED_OBJECT_TYPE, id); + idsToDelete.push(id); + } catch (error) { + result.push({ + id, + success: false, + ...fleetErrorToResponseOptions(error), + }); + } + }); + const { statuses } = await soClient.bulkDelete( + idsToDelete.map((id) => ({ id, type: SAVED_OBJECT_TYPE })) + ); + + statuses.forEach(({ id, success, error }) => { + const packagePolicy = packagePolicies.find((p) => p.id === id); + if (success && packagePolicy) { result.push({ id, name: packagePolicy.name, @@ -709,16 +724,17 @@ class PackagePolicyClientImpl implements PackagePolicyClient { }, policy_id: packagePolicy.policy_id, }); - } catch (error) { + } else if (!success && error) { result.push({ id, success: false, - ...fleetErrorToResponseOptions(error), + statusCode: error.statusCode, + body: { + message: error.message, + }, }); } - }; - - await pMap(ids, deletePackagePolicy, { concurrency: 1000 }); + }); if (!options?.skipUnassignFromAgentPolicies) { const uniquePolicyIdsR = [ From fcbb4e4d196c20663b61894c23ea4376d342c8e3 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 22 Sep 2022 15:33:24 +0200 Subject: [PATCH 14/29] close popover on click (#141272) --- x-pack/plugins/lens/public/app_plugin/settings_menu.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/app_plugin/settings_menu.tsx b/x-pack/plugins/lens/public/app_plugin/settings_menu.tsx index e4cd670286ef..f4447929d806 100644 --- a/x-pack/plugins/lens/public/app_plugin/settings_menu.tsx +++ b/x-pack/plugins/lens/public/app_plugin/settings_menu.tsx @@ -45,13 +45,14 @@ export function SettingsMenu({ const dispatch = useLensDispatch(); const toggleAutoApply = useCallback(() => { + onClose(); writeToStorage( new Storage(localStorage), AUTO_APPLY_DISABLED_STORAGE_KEY, String(autoApplyEnabled) ); dispatch(autoApplyEnabled ? disableAutoApply() : enableAutoApply()); - }, [dispatch, autoApplyEnabled]); + }, [dispatch, autoApplyEnabled, onClose]); return ( Date: Thu, 22 Sep 2022 15:52:09 +0200 Subject: [PATCH 15/29] [APM] Fix search bar suggestions (#141101) --- .../e2e/power_user/rules/error_count.cy.ts | 18 ++ .../e2e/power_user/rules/generate_data.ts | 50 +++++ .../apm/ftr_e2e/cypress_test_runner.ts | 10 +- .../service_inventory.stories.tsx | 2 +- .../routing/templates/apm_main_template.tsx | 15 +- .../components/shared/search_bar.test.tsx | 6 + .../apm/public/hooks/use_apm_data_view.ts | 39 +--- .../apm/server/lib/helpers/setup_request.ts | 2 +- .../data_view/create_static_data_view.test.ts | 52 +++-- .../data_view/create_static_data_view.ts | 157 ++++++++++---- .../apm/server/routes/data_view/route.ts | 20 +- x-pack/plugins/apm/server/routes/typings.ts | 10 +- .../common/apm_api_supertest.ts | 11 +- .../tests/data_view/static.spec.ts | 201 ++++++++++++------ .../test/apm_api_integration/tests/index.ts | 2 +- 15 files changed, 414 insertions(+), 181 deletions(-) create mode 100644 x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts index ec01fc2df2da..a9ba45b4ad31 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/error_count.cy.ts @@ -5,6 +5,9 @@ * 2.0. */ +import { synthtrace } from '../../../../synthtrace'; +import { generateData } from './generate_data'; + function deleteAllRules() { cy.log('Delete all rules'); cy.request({ @@ -38,6 +41,21 @@ describe('Rules', () => { deleteAllRules(); }); + before(() => { + const start = '2021-10-10T00:00:00.000Z'; + const end = '2021-10-10T00:01:00.000Z'; + synthtrace.index( + generateData({ + from: new Date(start).getTime(), + to: new Date(end).getTime(), + }) + ); + }); + + after(() => { + synthtrace.clean(); + }); + describe('Error count', () => { const ruleName = 'Error count threshold'; const comboBoxInputSelector = diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts new file mode 100644 index 000000000000..880c9d6b5944 --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/rules/generate_data.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { apm, timerange } from '@kbn/apm-synthtrace'; + +export function generateData({ from, to }: { from: number; to: number }) { + const range = timerange(from, to); + + const opbeansJava = apm + .service({ + name: 'opbeans-java', + environment: 'production', + agentName: 'java', + }) + .instance('opbeans-java-prod-1') + .podId('opbeans-java-prod-1-pod'); + + const opbeansNode = apm + .service({ + name: 'opbeans-node', + environment: 'production', + agentName: 'nodejs', + }) + .instance('opbeans-node-prod-1'); + + return range + .interval('2m') + .rate(1) + .generator((timestamp, index) => [ + opbeansJava + .transaction({ transactionName: 'GET /apple 🍎 ' }) + .timestamp(timestamp) + .duration(1000) + .success() + .errors( + opbeansJava + .error({ message: `Error ${index}`, type: `exception ${index}` }) + .timestamp(timestamp) + ), + opbeansNode + .transaction({ transactionName: 'GET /banana 🍌' }) + .timestamp(timestamp) + .duration(500) + .success(), + ]); +} diff --git a/x-pack/plugins/apm/ftr_e2e/cypress_test_runner.ts b/x-pack/plugins/apm/ftr_e2e/cypress_test_runner.ts index 9736a695e81c..8af466b87262 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress_test_runner.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress_test_runner.ts @@ -73,7 +73,7 @@ export async function cypressTestRunner({ getService }: FtrProviderContext) { return res; } -function getCypressCliArgs() { +function getCypressCliArgs(): Record { if (!process.env.CYPRESS_CLI_ARGS) { return {}; } @@ -82,5 +82,11 @@ function getCypressCliArgs() { process.env.CYPRESS_CLI_ARGS ) as Record; - return cypressCliArgs; + const spec = + typeof cypressCliArgs.spec === 'string' && + !cypressCliArgs.spec.includes('**') + ? `**/${cypressCliArgs.spec}*` + : cypressCliArgs.spec; + + return { ...cypressCliArgs, spec }; } diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.stories.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.stories.tsx index 2cd79535afac..9d547f228830 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_inventory.stories.tsx @@ -40,7 +40,7 @@ const stories: Meta<{}> = { }, notifications: { toasts: { add: () => {}, addWarning: () => {} } }, uiSettings: { get: () => [] }, - dataViews: { get: async () => {} }, + dataViews: { create: async () => {} }, } as unknown as CoreStart; const KibanaReactContext = createKibanaReactContext(coreMock); diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx index ff8442016adc..4eb7d8140fdf 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_main_template.tsx @@ -48,7 +48,7 @@ export function ApmMainTemplate({ const location = useLocation(); const { services } = useKibana(); - const { http, docLinks, observability } = services; + const { http, docLinks, observability, application } = services; const basePath = http?.basePath.get(); const ObservabilityPageTemplate = observability.navigation.PageTemplate; @@ -57,6 +57,19 @@ export function ApmMainTemplate({ return callApmApi('GET /internal/apm/has_data'); }, []); + // create static data view on inital load + useFetcher( + (callApmApi) => { + const canCreateDataView = + application?.capabilities.savedObjectsManagement.edit; + + if (canCreateDataView) { + return callApmApi('POST /internal/apm/data_view/static'); + } + }, + [application?.capabilities.savedObjectsManagement.edit] + ); + const shouldBypassNoDataScreen = bypassNoDataScreenPaths.some((path) => location.pathname.includes(path) ); diff --git a/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx b/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx index 33a3646bf752..1fb1e15a26ee 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx @@ -15,6 +15,7 @@ import { ApmServiceContextProvider } from '../../context/apm_service/apm_service import { UrlParamsProvider } from '../../context/url_params_context/url_params_context'; import type { ApmUrlParams } from '../../context/url_params_context/types'; import * as useFetcherHook from '../../hooks/use_fetcher'; +import * as useApmDataViewHook from '../../hooks/use_apm_data_view'; import * as useServiceTransactionTypesHook from '../../context/apm_service/use_service_transaction_types_fetcher'; import { renderWithTheme } from '../../utils/test_helpers'; import { fromQuery } from './links/url_helpers'; @@ -45,6 +46,11 @@ function setup({ .spyOn(useServiceTransactionTypesHook, 'useServiceTransactionTypesFetcher') .mockReturnValue(serviceTransactionTypes); + // mock transaction types + jest + .spyOn(useApmDataViewHook, 'useApmDataView') + .mockReturnValue({ dataView: undefined }); + jest.spyOn(useFetcherHook, 'useFetcher').mockReturnValue({} as any); return renderWithTheme( diff --git a/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts b/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts index 9d4ef214ff5e..63d7232128d8 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_data_view.ts @@ -7,20 +7,10 @@ import { DataView } from '@kbn/data-views-plugin/common'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; import { useEffect, useState } from 'react'; -import { APM_STATIC_DATA_VIEW_ID } from '../../common/data_view_constants'; -import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context'; import { ApmPluginStartDeps } from '../plugin'; import { callApmApi } from '../services/rest/create_call_apm_api'; -async function createStaticApmDataView() { - const res = await callApmApi('POST /internal/apm/data_view/static', { - signal: null, - }); - return res.dataView; -} - async function getApmDataViewTitle() { const res = await callApmApi('GET /internal/apm/data_view/title', { signal: null, @@ -30,37 +20,16 @@ async function getApmDataViewTitle() { export function useApmDataView() { const { services } = useKibana(); - const { core } = useApmPluginContext(); const [dataView, setDataView] = useState(); - const canCreateDataView = - core.application.capabilities.savedObjectsManagement.edit; - useEffect(() => { async function fetchDataView() { - try { - // load static data view - return await services.dataViews.get(APM_STATIC_DATA_VIEW_ID); - } catch (e) { - // re-throw if an unhandled error occurred - const notFound = e instanceof SavedObjectNotFound; - if (!notFound) { - throw e; - } - - // create static data view if user has permissions - if (canCreateDataView) { - return createStaticApmDataView(); - } else { - // or create dynamic data view if user does not have permissions to create a static - const title = await getApmDataViewTitle(); - return services.dataViews.create({ title }); - } - } + const title = await getApmDataViewTitle(); + return services.dataViews.create({ title }); } - fetchDataView().then((dv) => setDataView(dv)); - }, [canCreateDataView, services.dataViews]); + fetchDataView().then(setDataView); + }, [services.dataViews]); return { dataView }; } diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts index 9d6a716c8b3e..dc6e37936740 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts @@ -39,7 +39,7 @@ export async function setupRequest({ plugins, request, config, -}: APMRouteHandlerResources) { +}: APMRouteHandlerResources): Promise { return withApmSpan('setup_request', async () => { const { query } = params; const coreContext = await context.core; diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts index c7e22eba054b..65ecb93bcb76 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.test.ts @@ -8,8 +8,9 @@ import { createStaticDataView } from './create_static_data_view'; import { Setup } from '../../lib/helpers/setup_request'; import * as HistoricalAgentData from '../historical_data/has_historical_agent_data'; -import { APMConfig } from '../..'; import { DataViewsService } from '@kbn/data-views-plugin/common'; +import { APMRouteHandlerResources, APMCore } from '../typings'; +import { APMConfig } from '../..'; function getMockedDataViewService(existingDataViewTitle: string) { return { @@ -20,7 +21,7 @@ function getMockedDataViewService(existingDataViewTitle: string) { } as unknown as DataViewsService; } -const setup = { +const setupMock = { indices: { transaction: 'apm-*-transaction-*', span: 'apm-*-span-*', @@ -29,12 +30,28 @@ const setup = { } as APMConfig['indices'], } as unknown as Setup; +const coreMock = { + start: () => { + return { + savedObjects: { + getScopedClient: () => { + return { + updateObjectsSpaces: () => {}, + }; + }, + }, + }; + }, +} as unknown as APMCore; + describe('createStaticDataView', () => { it(`should not create data view if 'xpack.apm.autocreateApmIndexPattern=false'`, async () => { const dataViewService = getMockedDataViewService('apm-*'); await createStaticDataView({ - setup, - config: { autoCreateApmDataView: false } as APMConfig, + setup: setupMock, + resources: { + config: { autoCreateApmDataView: false }, + } as APMRouteHandlerResources, dataViewService, }); expect(dataViewService.createAndSave).not.toHaveBeenCalled(); @@ -49,8 +66,10 @@ describe('createStaticDataView', () => { const dataViewService = getMockedDataViewService('apm-*'); await createStaticDataView({ - setup, - config: { autoCreateApmDataView: true } as APMConfig, + setup: setupMock, + resources: { + config: { autoCreateApmDataView: false }, + } as APMRouteHandlerResources, dataViewService, }); expect(dataViewService.createAndSave).not.toHaveBeenCalled(); @@ -65,8 +84,11 @@ describe('createStaticDataView', () => { const dataViewService = getMockedDataViewService('apm-*'); await createStaticDataView({ - setup, - config: { autoCreateApmDataView: true } as APMConfig, + setup: setupMock, + resources: { + core: coreMock, + config: { autoCreateApmDataView: true }, + } as APMRouteHandlerResources, dataViewService, }); @@ -84,8 +106,11 @@ describe('createStaticDataView', () => { 'apm-*-transaction-*,apm-*-span-*,apm-*-error-*,apm-*-metrics-*'; await createStaticDataView({ - setup, - config: { autoCreateApmDataView: true } as APMConfig, + setup: setupMock, + resources: { + core: coreMock, + config: { autoCreateApmDataView: true }, + } as APMRouteHandlerResources, dataViewService, }); @@ -110,8 +135,11 @@ describe('createStaticDataView', () => { ); await createStaticDataView({ - setup, - config: { autoCreateApmDataView: true } as APMConfig, + setup: setupMock, + resources: { + core: coreMock, + config: { autoCreateApmDataView: true }, + } as APMRouteHandlerResources, dataViewService, }); diff --git a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts index 6142791b45cc..c2310acadcff 100644 --- a/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts +++ b/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts @@ -7,6 +7,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DataView, DataViewsService } from '@kbn/data-views-plugin/common'; +import { i18n } from '@kbn/i18n'; import { TRACE_ID, TRANSACTION_ID, @@ -15,29 +16,49 @@ import { APM_STATIC_DATA_VIEW_ID } from '../../../common/data_view_constants'; import { hasHistoricalAgentData } from '../historical_data/has_historical_agent_data'; import { withApmSpan } from '../../utils/with_apm_span'; import { getApmDataViewTitle } from './get_apm_data_view_title'; + +import { APMRouteHandlerResources } from '../typings'; import { Setup } from '../../lib/helpers/setup_request'; -import { APMConfig } from '../..'; + +export type CreateDataViewResponse = Promise< + | { created: boolean; dataView: DataView } + | { created: boolean; reason?: string } +>; export async function createStaticDataView({ dataViewService, - config, + resources, setup, }: { dataViewService: DataViewsService; - config: APMConfig; + resources: APMRouteHandlerResources; setup: Setup; -}): Promise { +}): CreateDataViewResponse { + const { config } = resources; + return withApmSpan('create_static_data_view', async () => { // don't auto-create APM data view if it's been disabled via the config if (!config.autoCreateApmDataView) { - return; + return { + created: false, + reason: i18n.translate('xpack.apm.dataView.autoCreateDisabled', { + defaultMessage: + 'Auto-creation of data views has been disabled via "autoCreateApmDataView" config option', + }), + }; } // Discover and other apps will throw errors if an data view exists without having matching indices. // The following ensures the data view is only created if APM data is found const hasData = await hasHistoricalAgentData(setup); + if (!hasData) { - return; + return { + created: false, + reason: i18n.translate('xpack.apm.dataView.noApmData', { + defaultMessage: 'No APM data', + }), + }; } const apmDataViewTitle = getApmDataViewTitle(setup.indices); @@ -47,50 +68,42 @@ export async function createStaticDataView({ }); if (!shouldCreateOrUpdate) { - return; + return { + created: false, + reason: i18n.translate( + 'xpack.apm.dataView.alreadyExistsInActiveSpace', + { defaultMessage: 'Dataview already exists in the active space' } + ), + }; } - try { - return await withApmSpan('create_data_view', async () => { - const dataView = await dataViewService.createAndSave( - { - allowNoIndex: true, - id: APM_STATIC_DATA_VIEW_ID, - name: 'APM', - title: apmDataViewTitle, - timeFieldName: '@timestamp', - - // link to APM from Discover - fieldFormats: { - [TRACE_ID]: { - id: 'url', - params: { - urlTemplate: 'apm/link-to/trace/{{value}}', - labelTemplate: '{{value}}', - }, - }, - [TRANSACTION_ID]: { - id: 'url', - params: { - urlTemplate: 'apm/link-to/transaction/{{value}}', - labelTemplate: '{{value}}', - }, - }, - }, - }, - true - ); - - return dataView; - }); - } catch (e) { - // if the data view (saved object) already exists a conflict error (code: 409) will be thrown - // that error should be silenced - if (SavedObjectsErrorHelpers.isConflictError(e)) { - return; + return await withApmSpan('create_data_view', async () => { + try { + const dataView = await createAndSaveStaticDataView({ + dataViewService, + apmDataViewTitle, + }); + + await addDataViewToAllSpaces(resources); + + return { created: true, dataView }; + } catch (e) { + // if the data view (saved object) already exists a conflict error (code: 409) will be thrown + if (SavedObjectsErrorHelpers.isConflictError(e)) { + return { + created: false, + reason: i18n.translate( + 'xpack.apm.dataView.alreadyExistsInAnotherSpace', + { + defaultMessage: + 'Dataview already exists in another space but is not made available in this space', + } + ), + }; + } + throw e; } - throw e; - } + }); }); } @@ -114,3 +127,53 @@ async function getShouldCreateOrUpdate({ throw e; } } + +async function addDataViewToAllSpaces(resources: APMRouteHandlerResources) { + const { request, core } = resources; + const startServices = await core.start(); + const scopedClient = startServices.savedObjects.getScopedClient(request); + + // make data view available across all spaces + return scopedClient.updateObjectsSpaces( + [{ id: APM_STATIC_DATA_VIEW_ID, type: 'index-pattern' }], + ['*'], + [] + ); +} + +function createAndSaveStaticDataView({ + dataViewService, + apmDataViewTitle, +}: { + dataViewService: DataViewsService; + apmDataViewTitle: string; +}) { + return dataViewService.createAndSave( + { + allowNoIndex: true, + id: APM_STATIC_DATA_VIEW_ID, + name: 'APM', + title: apmDataViewTitle, + timeFieldName: '@timestamp', + + // link to APM from Discover + fieldFormats: { + [TRACE_ID]: { + id: 'url', + params: { + urlTemplate: 'apm/link-to/trace/{{value}}', + labelTemplate: '{{value}}', + }, + }, + [TRANSACTION_ID]: { + id: 'url', + params: { + urlTemplate: 'apm/link-to/transaction/{{value}}', + labelTemplate: '{{value}}', + }, + }, + }, + }, + true + ); +} diff --git a/x-pack/plugins/apm/server/routes/data_view/route.ts b/x-pack/plugins/apm/server/routes/data_view/route.ts index a8c660c293d4..6f55f67fc9b4 100644 --- a/x-pack/plugins/apm/server/routes/data_view/route.ts +++ b/x-pack/plugins/apm/server/routes/data_view/route.ts @@ -5,21 +5,23 @@ * 2.0. */ -import { DataView } from '@kbn/data-views-plugin/common'; -import { createStaticDataView } from './create_static_data_view'; -import { setupRequest } from '../../lib/helpers/setup_request'; +import { + CreateDataViewResponse, + createStaticDataView, +} from './create_static_data_view'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getApmDataViewTitle } from './get_apm_data_view_title'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; +import { setupRequest } from '../../lib/helpers/setup_request'; const staticDataViewRoute = createApmServerRoute({ endpoint: 'POST /internal/apm/data_view/static', options: { tags: ['access:apm'] }, - handler: async (resources): Promise<{ dataView: DataView | undefined }> => { + handler: async (resources): CreateDataViewResponse => { + const { context, plugins, request } = resources; const setup = await setupRequest(resources); - const { context, plugins, request, config } = resources; - const coreContext = await context.core; + const dataViewStart = await plugins.dataViews.start(); const dataViewService = await dataViewStart.dataViewsServiceFactory( coreContext.savedObjects.client, @@ -28,13 +30,13 @@ const staticDataViewRoute = createApmServerRoute({ true ); - const dataView = await createStaticDataView({ + const res = await createStaticDataView({ dataViewService, - config, + resources, setup, }); - return { dataView }; + return res; }, }); diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts index 2e246f753d75..ff75af8f8334 100644 --- a/x-pack/plugins/apm/server/routes/typings.ts +++ b/x-pack/plugins/apm/server/routes/typings.ts @@ -47,6 +47,11 @@ export type TelemetryUsageCounter = ReturnType< UsageCollectionSetup['createUsageCounter'] >; +export interface APMCore { + setup: CoreSetup; + start: () => Promise; +} + export interface APMRouteHandlerResources { request: KibanaRequest; context: ApmPluginRequestHandlerContext; @@ -59,10 +64,7 @@ export interface APMRouteHandlerResources { }; config: APMConfig; logger: Logger; - core: { - setup: CoreSetup; - start: () => Promise; - }; + core: APMCore; plugins: { [key in keyof APMPluginSetupDependencies]: { setup: Required[key]; diff --git a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts index 86beb73d51ea..c492f7af04a6 100644 --- a/x-pack/test/apm_api_integration/common/apm_api_supertest.ts +++ b/x-pack/test/apm_api_integration/common/apm_api_supertest.ts @@ -41,10 +41,19 @@ export function createApmApiClient(st: supertest.SuperTest) { }; } +type ApiErrorResponse = Omit & { + body: { + statusCode: number; + error: string; + message: string; + attributes: object; + }; +}; + export type ApmApiSupertest = ReturnType; export class ApmApiError extends Error { - res: request.Response; + res: ApiErrorResponse; constructor(res: request.Response, endpoint: string) { super( diff --git a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts index 11bb01d3ca7b..0ed65724bfd4 100644 --- a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts +++ b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts @@ -8,30 +8,37 @@ import { apm, ApmSynthtraceEsClient, timerange } from '@kbn/apm-synthtrace'; import expect from '@kbn/expect'; import { APM_STATIC_DATA_VIEW_ID } from '@kbn/apm-plugin/common/data_view_constants'; +import { DataView } from '@kbn/data-views-plugin/common'; +import request from 'superagent'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { SupertestReturnType } from '../../common/apm_api_supertest'; +import { SupertestReturnType, ApmApiError } from '../../common/apm_api_supertest'; export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); const apmApiClient = getService('apmApiClient'); const supertest = getService('supertest'); const synthtrace = getService('synthtraceEsClient'); - const dataViewPattern = 'traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*'; - function createDataViewViaApmApi() { + function createDataViewWithWriteUser() { return apmApiClient.writeUser({ endpoint: 'POST /internal/apm/data_view/static' }); } + function createDataViewWithReadUser() { + return apmApiClient.readUser({ endpoint: 'POST /internal/apm/data_view/static' }); + } + function deleteDataView() { return supertest - .delete(`/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}`) - .set('kbn-xsrf', 'foo') - .expect(200); + .delete(`/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}?force=true`) + .set('kbn-xsrf', 'foo'); } - function getDataView() { - return supertest.get(`/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}`); + function getDataView({ space }: { space: string }) { + const spacePrefix = space !== 'default' ? `/s/${space}` : ''; + return supertest.get( + `${spacePrefix}/api/saved_objects/index-pattern/${APM_STATIC_DATA_VIEW_ID}` + ); } function getDataViewSuggestions(field: string) { @@ -43,90 +50,150 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when('no mappings exist', { config: 'basic', archives: [] }, () => { let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; - describe('when no data is generated', () => { - before(async () => { - response = await createDataViewViaApmApi(); - }); + before(async () => { + response = await createDataViewWithWriteUser(); + }); - it('does not create data view', async () => { - expect(response.status).to.be(200); - expect(response.body.dataView).to.be(undefined); + it('does not create data view', async () => { + expect(response.status).to.be(200); + expect(response.body).to.eql({ + created: false, + reason: 'No APM data', }); + }); - it('cannot fetch data view', async () => { - await getDataView().expect(404); - }); + it('cannot fetch data view', async () => { + const res = await getDataView({ space: 'default' }); + expect(res.status).to.be(404); + expect(res.body.message).to.eql( + 'Saved object [index-pattern/apm_static_index_pattern_id] not found' + ); }); }); - registry.when('mappings exists', { config: 'basic', archives: [] }, () => { - describe('when data is generated', () => { + registry.when('mappings and APM data exists', { config: 'basic', archives: [] }, () => { + before(async () => { + await generateApmData(synthtrace); + }); + + after(async () => { + await synthtrace.clean(); + }); + + afterEach(async () => { + await deleteDataView(); + }); + + describe('when creating data view with write user', () => { let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; before(async () => { - await generateApmData(synthtrace); - response = await createDataViewViaApmApi(); - }); - - after(async () => { - await deleteDataView(); - await synthtrace.clean(); + response = await createDataViewWithWriteUser(); }); it('successfully creates the apm data view', async () => { expect(response.status).to.be(200); - expect(response.body.dataView!.id).to.be('apm_static_index_pattern_id'); - expect(response.body.dataView!.name).to.be('APM'); - expect(response.body.dataView!.title).to.be( - 'traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*' - ); + // @ts-expect-error + const dataView = response.body.dataView as DataView; + + expect(dataView.id).to.be('apm_static_index_pattern_id'); + expect(dataView.name).to.be('APM'); + expect(dataView.title).to.be('traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*'); }); + }); - describe('when fetching the data view', async () => { - let resBody: any; + describe('when fetching the data view', async () => { + let dataViewResponse: request.Response; - before(async () => { - const res = await getDataView().expect(200); - resBody = res.body; - }); + before(async () => { + await createDataViewWithWriteUser(); + dataViewResponse = await getDataView({ space: 'default' }); + }); - it('has correct id', () => { - expect(resBody.id).to.be('apm_static_index_pattern_id'); - }); + it('return 200', () => { + expect(dataViewResponse.status).to.be(200); + }); - it('has correct title', () => { - expect(resBody.attributes.title).to.be(dataViewPattern); - }); + it('has correct id', () => { + expect(dataViewResponse.body.id).to.be('apm_static_index_pattern_id'); + }); - it('has correct attributes', () => { - expect(resBody.attributes.fieldFormatMap).to.be( - JSON.stringify({ - 'trace.id': { - id: 'url', - params: { - urlTemplate: 'apm/link-to/trace/{{value}}', - labelTemplate: '{{value}}', - }, + it('has correct title', () => { + expect(dataViewResponse.body.attributes.title).to.be(dataViewPattern); + }); + + it('has correct attributes', () => { + expect(dataViewResponse.body.attributes.fieldFormatMap).to.be( + JSON.stringify({ + 'trace.id': { + id: 'url', + params: { + urlTemplate: 'apm/link-to/trace/{{value}}', + labelTemplate: '{{value}}', }, - 'transaction.id': { - id: 'url', - params: { - urlTemplate: 'apm/link-to/transaction/{{value}}', - labelTemplate: '{{value}}', - }, + }, + 'transaction.id': { + id: 'url', + params: { + urlTemplate: 'apm/link-to/transaction/{{value}}', + labelTemplate: '{{value}}', }, - }) - ); - }); + }, + }) + ); + }); + + // this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past) + it('can get suggestions for `trace.id`', async () => { + const suggestions = await getDataViewSuggestions('trace.id'); + expect(suggestions.body.length).to.be(10); + }); + }); + + describe('when creating data view via read user', () => { + it('throws an error', async () => { + try { + await createDataViewWithReadUser(); + } catch (e) { + const err = e as ApmApiError; + const responseBody = err.res.body; + expect(err.res.status).to.eql(403); + expect(responseBody.statusCode).to.eql(403); + expect(responseBody.error).to.eql('Forbidden'); + expect(responseBody.message).to.eql('Unable to create index-pattern'); + } + }); + }); + + describe('when creating data view twice', () => { + it('returns 200 response with reason, if data view already exists', async () => { + await createDataViewWithWriteUser(); + const res = await createDataViewWithWriteUser(); - // this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past) - it('can get suggestions for `trace.id`', async () => { - const suggestions = await getDataViewSuggestions('trace.id'); - expect(suggestions.body.length).to.be(10); + expect(res.status).to.be(200); + expect(res.body).to.eql({ + created: false, + reason: 'Dataview already exists in the active space', }); }); }); + + describe('when creating data view in "default" space', async () => { + it('can be retrieved from the "default space"', async () => { + await createDataViewWithWriteUser(); + const res = await getDataView({ space: 'default' }); + expect(res.body.id).to.eql('apm_static_index_pattern_id'); + expect(res.body.namespaces).to.eql(['*', 'default']); + }); + + it('can be retrieved from the "foo" space', async () => { + await createDataViewWithWriteUser(); + const res = await getDataView({ space: 'foo' }); + expect(res.body.id).to.eql('apm_static_index_pattern_id'); + expect(res.body.namespaces).to.eql(['*', 'default']); + }); + }); }); } @@ -137,7 +204,7 @@ function generateApmData(synthtrace: ApmSynthtraceEsClient) { ); const instance = apm - .service({ name: 'multiple-env-service', environment: 'production', agentName: 'go' }) + .service({ name: 'my-service', environment: 'production', agentName: 'go' }) .instance('my-instance'); return synthtrace.index([ diff --git a/x-pack/test/apm_api_integration/tests/index.ts b/x-pack/test/apm_api_integration/tests/index.ts index 9f882797b0a1..53c685a07e8b 100644 --- a/x-pack/test/apm_api_integration/tests/index.ts +++ b/x-pack/test/apm_api_integration/tests/index.ts @@ -16,7 +16,7 @@ function getGlobPattern() { return '**/*.spec.ts'; } - return envGrepFiles.includes('.spec.ts') ? envGrepFiles : `**/*${envGrepFiles}*.spec.ts`; + return envGrepFiles.includes('**') ? envGrepFiles : `**/*${envGrepFiles}*`; } export default function apmApiIntegrationTests({ getService, loadTestFile }: FtrProviderContext) { From dd2cfb7ac28d753d6a829979986cb7b6a33b2ca3 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 22 Sep 2022 15:55:46 +0200 Subject: [PATCH 16/29] [ML] Explain Log Rate Spikes: Adds jest tests for query_utils/buildBaseFilterCriteria. (#141213) Adds jest tests for query_utils/buildBaseFilterCriteria. --- .../application/utils/query_utils.test.ts | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 x-pack/plugins/aiops/public/application/utils/query_utils.test.ts diff --git a/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts b/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts new file mode 100644 index 000000000000..59d680d236b1 --- /dev/null +++ b/x-pack/plugins/aiops/public/application/utils/query_utils.test.ts @@ -0,0 +1,254 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ChangePoint } from '@kbn/ml-agg-utils'; + +import type { GroupTableItem } from '../../components/spike_analysis_table/spike_analysis_table_groups'; + +import { buildBaseFilterCriteria } from './query_utils'; + +const selectedChangePointMock: ChangePoint = { + doc_count: 53408, + bg_count: 1154, + fieldName: 'meta.cloud.instance_id.keyword', + fieldValue: '1234', + normalizedScore: 1, + pValue: 0.01, + score: 708.3964185322641, + total_bg_count: 179657, + total_doc_count: 114011, +}; + +const selectedGroupMock: GroupTableItem = { + id: '21289599', + docCount: 20468, + pValue: 2.2250738585072626e-308, + group: { + 'error.message': 'rate limit exceeded', + message: 'too many requests', + 'user_agent.original.keyword': 'Mozilla/5.0', + }, + repeatedValues: { + 'beat.hostname.keyword': 'ip-192-168-1-1', + 'beat.name.keyword': 'i-1234', + 'docker.container.id.keyword': 'asdf', + }, + histogram: [], +}; + +describe('query_utils', () => { + describe('buildBaseFilterCriteria', () => { + it('returns range filter based on minimum supplied arguments', () => { + const baseFilterCriteria = buildBaseFilterCriteria('the-time-field-name', 1234, 5678); + + expect(baseFilterCriteria).toEqual([ + { + range: { + 'the-time-field-name': { + format: 'epoch_millis', + gte: 1234, + lte: 5678, + }, + }, + }, + ]); + }); + + it('returns filters including default query with supplied arguments provided via UI', () => { + const baseFilterCriteria = buildBaseFilterCriteria( + '@timestamp', + 1640082000012, + 1640103600906, + { match_all: {} } + ); + + expect(baseFilterCriteria).toEqual([ + { + range: { + '@timestamp': { + format: 'epoch_millis', + gte: 1640082000012, + lte: 1640103600906, + }, + }, + }, + { match_all: {} }, + ]); + }); + + it('includes a term filter when including a selectedChangePoint', () => { + const baseFilterCriteria = buildBaseFilterCriteria( + '@timestamp', + 1640082000012, + 1640103600906, + { match_all: {} }, + selectedChangePointMock + ); + + expect(baseFilterCriteria).toEqual([ + { + range: { + '@timestamp': { + format: 'epoch_millis', + gte: 1640082000012, + lte: 1640103600906, + }, + }, + }, + { match_all: {} }, + { term: { 'meta.cloud.instance_id.keyword': '1234' } }, + ]); + }); + + it('includes a term filter with must_not when excluding a selectedChangePoint', () => { + const baseFilterCriteria = buildBaseFilterCriteria( + '@timestamp', + 1640082000012, + 1640103600906, + { match_all: {} }, + selectedChangePointMock, + false + ); + + expect(baseFilterCriteria).toEqual([ + { + range: { + '@timestamp': { + format: 'epoch_millis', + gte: 1640082000012, + lte: 1640103600906, + }, + }, + }, + { match_all: {} }, + { bool: { must_not: [{ term: { 'meta.cloud.instance_id.keyword': '1234' } }] } }, + ]); + }); + + it('includes multiple term filters when including a selectedGroupMock', () => { + const baseFilterCriteria = buildBaseFilterCriteria( + '@timestamp', + 1640082000012, + 1640103600906, + { match_all: {} }, + undefined, + true, + selectedGroupMock + ); + + expect(baseFilterCriteria).toEqual([ + { + range: { + '@timestamp': { + format: 'epoch_millis', + gte: 1640082000012, + lte: 1640103600906, + }, + }, + }, + { match_all: {} }, + { + term: { + 'error.message': 'rate limit exceeded', + }, + }, + { + term: { + message: 'too many requests', + }, + }, + { + term: { + 'user_agent.original.keyword': 'Mozilla/5.0', + }, + }, + { + term: { + 'beat.hostname.keyword': 'ip-192-168-1-1', + }, + }, + { + term: { + 'beat.name.keyword': 'i-1234', + }, + }, + { + term: { + 'docker.container.id.keyword': 'asdf', + }, + }, + ]); + }); + + it('includes a must_not with nested term filters when excluding a selectedGroup', () => { + const baseFilterCriteria = buildBaseFilterCriteria( + '@timestamp', + 1640082000012, + 1640103600906, + { match_all: {} }, + undefined, + false, + selectedGroupMock + ); + + expect(baseFilterCriteria).toEqual([ + { + range: { + '@timestamp': { + format: 'epoch_millis', + gte: 1640082000012, + lte: 1640103600906, + }, + }, + }, + { match_all: {} }, + { + bool: { + must_not: [ + { + bool: { + filter: [ + { + term: { + 'error.message': 'rate limit exceeded', + }, + }, + { + term: { + message: 'too many requests', + }, + }, + { + term: { + 'user_agent.original.keyword': 'Mozilla/5.0', + }, + }, + { + term: { + 'beat.hostname.keyword': 'ip-192-168-1-1', + }, + }, + { + term: { + 'beat.name.keyword': 'i-1234', + }, + }, + { + term: { + 'docker.container.id.keyword': 'asdf', + }, + }, + ], + }, + }, + ], + }, + }, + ]); + }); + }); +}); From ebb8455c6b38541e05a2bf72bdb5e772b649c780 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Thu, 22 Sep 2022 09:59:21 -0400 Subject: [PATCH 17/29] [Response Ops][Alerting] Defining default action params on connector type (#141226) * Defining default action params on connector type * Fixing types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pagerduty/pagerduty.tsx | 9 ++++ .../xmatters/xmatters.tsx | 8 +++ .../get_defaults_for_action_params.test.ts | 26 ---------- .../lib/get_defaults_for_action_params.ts | 42 ---------------- .../action_connector_form/action_form.tsx | 7 ++- .../action_type_form.test.tsx | 19 ++++--- .../action_type_form.tsx | 50 +++++++++++++------ .../sections/rule_form/rule_form.tsx | 12 +---- .../triggers_actions_ui/public/types.ts | 2 + 9 files changed, 70 insertions(+), 105 deletions(-) delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.test.ts delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty.tsx index 53b41ea49a27..8c3961e6d711 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/pagerduty/pagerduty.tsx @@ -16,6 +16,7 @@ import { EventActionOptions, } from '../types'; import { hasMustacheTokens } from '../../../lib/has_mustache_tokens'; +import { AlertProvidedActionVariables } from '../../../lib/action_variables'; export function getActionType(): ActionTypeModel< PagerDutyConfig, @@ -83,6 +84,14 @@ export function getActionType(): ActionTypeModel< }, actionConnectorFields: lazy(() => import('./pagerduty_connectors')), actionParamsFields: lazy(() => import('./pagerduty_params')), + defaultActionParams: { + dedupKey: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, + eventAction: EventActionOptions.TRIGGER, + }, + defaultRecoveredActionParams: { + dedupKey: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, + eventAction: EventActionOptions.RESOLVE, + }, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/xmatters/xmatters.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/xmatters/xmatters.tsx index 2ba8d78d90ae..9f2955479d52 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/xmatters/xmatters.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/xmatters/xmatters.tsx @@ -9,6 +9,7 @@ import { lazy } from 'react'; import { i18n } from '@kbn/i18n'; import { ActionTypeModel, GenericValidationResult } from '../../../../types'; import { XmattersActionParams, XmattersConfig, XmattersSecrets } from '../types'; +import { AlertProvidedActionVariables } from '../../../lib/action_variables'; export function getActionType(): ActionTypeModel< XmattersConfig, @@ -45,5 +46,12 @@ export function getActionType(): ActionTypeModel< }, actionConnectorFields: lazy(() => import('./xmatters_connectors')), actionParamsFields: lazy(() => import('./xmatters_params')), + defaultActionParams: { + alertActionGroupName: `{{${AlertProvidedActionVariables.alertActionGroupName}}}`, + signalId: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, + ruleName: `{{${AlertProvidedActionVariables.ruleName}}}`, + date: `{{${AlertProvidedActionVariables.date}}}`, + spaceId: `{{${AlertProvidedActionVariables.ruleSpaceId}}}`, + }, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.test.ts deleted file mode 100644 index fa4a5b6b2b33..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RecoveredActionGroup } from '@kbn/alerting-plugin/common'; -import { AlertProvidedActionVariables } from './action_variables'; -import { getDefaultsForActionParams } from './get_defaults_for_action_params'; - -describe('getDefaultsForActionParams', () => { - test('pagerduty defaults', async () => { - expect(getDefaultsForActionParams('.pagerduty', 'test', false)).toEqual({ - dedupKey: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, - eventAction: 'trigger', - }); - }); - - test('pagerduty defaults for recovered action group', async () => { - expect(getDefaultsForActionParams('.pagerduty', RecoveredActionGroup.id, true)).toEqual({ - dedupKey: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, - eventAction: 'resolve', - }); - }); -}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts deleted file mode 100644 index d3f60f4c6335..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RuleActionParam } from '@kbn/alerting-plugin/common'; -import { EventActionOptions } from '../components/builtin_action_types/types'; -import { AlertProvidedActionVariables } from './action_variables'; - -export type DefaultActionParams = Record | undefined; -export type DefaultActionParamsGetter = ( - actionTypeId: string, - actionGroupId: string -) => DefaultActionParams; -export const getDefaultsForActionParams = ( - actionTypeId: string, - actionGroupId: string, - isRecoveryActionGroup: boolean -): DefaultActionParams => { - switch (actionTypeId) { - case '.pagerduty': - const pagerDutyDefaults = { - dedupKey: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, - eventAction: EventActionOptions.TRIGGER, - }; - if (isRecoveryActionGroup) { - pagerDutyDefaults.eventAction = EventActionOptions.RESOLVE; - } - return pagerDutyDefaults; - case '.xmatters': - const xmattersDefaults = { - alertActionGroupName: `{{${AlertProvidedActionVariables.alertActionGroupName}}}`, - signalId: `{{${AlertProvidedActionVariables.ruleId}}}:{{${AlertProvidedActionVariables.alertId}}}`, - ruleName: `{{${AlertProvidedActionVariables.ruleName}}}`, - date: `{{${AlertProvidedActionVariables.date}}}`, - spaceId: `{{${AlertProvidedActionVariables.ruleSpaceId}}}`, - }; - return xmattersDefaults; - } -}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index 06978dc8c13e..8f34a8ad07ed 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -37,7 +37,6 @@ import { actionTypeCompare } from '../../lib/action_type_compare'; import { checkActionFormActionTypeEnabled } from '../../lib/check_action_type_enabled'; import { VIEW_LICENSE_OPTIONS_LINK } from '../../../common/constants'; import { useKibana } from '../../../common/lib/kibana'; -import { DefaultActionParamsGetter } from '../../lib/get_defaults_for_action_params'; import { ConnectorAddModal } from '.'; import { suspendedComponentWithProps } from '../../lib/suspended_component_with_props'; import { OmitMessageVariablesType } from '../../lib/action_variables'; @@ -61,7 +60,7 @@ export interface ActionAccordionFormProps { setHasActionsDisabled?: (value: boolean) => void; setHasActionsWithBrokenConnector?: (value: boolean) => void; actionTypeRegistry: ActionTypeRegistryContract; - getDefaultActionParams?: DefaultActionParamsGetter; + recoveryActionGroup?: string; isActionGroupDisabledForActionType?: (actionGroupId: string, actionTypeId: string) => boolean; } @@ -84,7 +83,7 @@ export const ActionForm = ({ setHasActionsDisabled, setHasActionsWithBrokenConnector, actionTypeRegistry, - getDefaultActionParams, + recoveryActionGroup, isActionGroupDisabledForActionType, }: ActionAccordionFormProps) => { const { @@ -361,7 +360,7 @@ export const ActionForm = ({ messageVariables={messageVariables} actionGroups={actionGroups} defaultActionMessage={defaultActionMessage} - defaultParams={getDefaultActionParams?.(actionItem.actionTypeId, actionItem.group)} + recoveryActionGroup={recoveryActionGroup} isActionGroupDisabledForActionType={isActionGroupDisabledForActionType} setActionGroupIdByIndex={setActionGroupIdByIndex} onAddConnector={() => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index eb710b884e13..0112f2296ee0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -11,7 +11,6 @@ import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ActionConnector, ActionType, RuleAction, GenericValidationResult } from '../../../types'; import { act } from 'react-dom/test-utils'; import { EuiFieldText } from '@elastic/eui'; -import { DefaultActionParams } from '../../lib/get_defaults_for_action_params'; jest.mock('../../../common/lib/kibana'); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -43,6 +42,10 @@ describe('action_type_form', () => { }, actionConnectorFields: null, actionParamsFields: mockedActionParamsFields, + defaultActionParams: { + dedupKey: 'test', + eventAction: 'resolve', + }, }); actionTypeRegistry.get.mockReturnValue(actionType); @@ -89,6 +92,10 @@ describe('action_type_form', () => { }, actionConnectorFields: null, actionParamsFields: mockedActionParamsFields, + defaultActionParams: { + dedupKey: 'test', + eventAction: 'resolve', + }, }); actionTypeRegistry.get.mockReturnValue(actionType); @@ -134,6 +141,10 @@ describe('action_type_form', () => { }, actionConnectorFields: null, actionParamsFields: mockedActionParamsFields, + defaultActionParams: { + dedupKey: 'test', + eventAction: 'resolve', + }, }); actionTypeRegistry.get.mockReturnValue(actionType); @@ -188,7 +199,6 @@ function getActionTypeForm( defaultActionGroupId?: string, connectors?: Array, Record>>, actionTypeIndex?: Record, - defaultParams?: DefaultActionParams, onAddConnector?: () => void, onDeleteAction?: () => void, onConnectorSelected?: (id: string) => void @@ -259,10 +269,6 @@ function getActionTypeForm( }, }; - const defaultParamsDefault = { - dedupKey: `test`, - eventAction: 'resolve', - }; return ( ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index aba42984de1b..c3ca4b027561 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -42,7 +42,6 @@ import { hasSaveActionsCapability } from '../../lib/capabilities'; import { ActionAccordionFormProps, ActionGroupWithMessageVariables } from './action_form'; import { transformActionVariables } from '../../lib/action_variables'; import { useKibana } from '../../../common/lib/kibana'; -import { DefaultActionParams } from '../../lib/get_defaults_for_action_params'; import { ConnectorsSelection } from './connectors_selection'; export type ActionTypeFormProps = { @@ -56,7 +55,7 @@ export type ActionTypeFormProps = { actionTypesIndex: ActionTypeIndex; connectors: ActionConnector[]; actionTypeRegistry: ActionTypeRegistryContract; - defaultParams: DefaultActionParams; + recoveryActionGroup?: string; isActionGroupDisabledForActionType?: (actionGroupId: string, actionTypeId: string) => boolean; } & Pick< ActionAccordionFormProps, @@ -92,7 +91,7 @@ export const ActionTypeForm = ({ setActionGroupIdByIndex, actionTypeRegistry, isActionGroupDisabledForActionType, - defaultParams, + recoveryActionGroup, }: ActionTypeFormProps) => { const { application: { capabilities }, @@ -107,26 +106,47 @@ export const ActionTypeForm = ({ errors: {}, }); + const getDefaultParams = async () => { + const connectorType = await actionTypeRegistry.get(actionItem.actionTypeId); + let defaultParams; + if (actionItem.group === recoveryActionGroup) { + defaultParams = connectorType.defaultRecoveredActionParams; + } + + if (!defaultParams) { + defaultParams = connectorType.defaultActionParams; + } + + return defaultParams; + }; + useEffect(() => { - setAvailableActionVariables( - messageVariables ? getAvailableActionVariables(messageVariables, selectedActionGroup) : [] - ); - if (defaultParams) { - for (const [key, paramValue] of Object.entries(defaultParams)) { - if (actionItem.params[key] === undefined || actionItem.params[key] === null) { - setActionParamsProperty(key, paramValue, index); + (async () => { + setAvailableActionVariables( + messageVariables ? getAvailableActionVariables(messageVariables, selectedActionGroup) : [] + ); + + const defaultParams = await getDefaultParams(); + if (defaultParams) { + for (const [key, paramValue] of Object.entries(defaultParams)) { + if (actionItem.params[key] === undefined || actionItem.params[key] === null) { + setActionParamsProperty(key, paramValue, index); + } } } - } + })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [actionItem.group]); useEffect(() => { - if (defaultParams && actionGroup) { - for (const [key, paramValue] of Object.entries(defaultParams)) { - setActionParamsProperty(key, paramValue, index); + (async () => { + const defaultParams = await getDefaultParams(); + if (defaultParams && actionGroup) { + for (const [key, paramValue] of Object.entries(defaultParams)) { + setActionParamsProperty(key, paramValue, index); + } } - } + })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [actionGroup]); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx index 6d1e614c428d..9a1162b89a43 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.tsx @@ -68,7 +68,6 @@ import { SolutionFilter } from './solution_filter'; import './rule_form.scss'; import { useKibana } from '../../../common/lib/kibana'; import { recoveredActionGroupMessage } from '../../constants'; -import { getDefaultsForActionParams } from '../../lib/get_defaults_for_action_params'; import { IsEnabledResult, IsDisabledResult } from '../../lib/check_rule_type_enabled'; import { RuleNotifyWhen } from './rule_notify_when'; import { checkRuleTypeEnabled } from '../../lib/check_rule_type_enabled'; @@ -309,15 +308,6 @@ export const RuleForm = ({ const selectedRuleType = rule?.ruleTypeId ? ruleTypeIndex?.get(rule?.ruleTypeId) : undefined; const recoveryActionGroup = selectedRuleType?.recoveryActionGroup?.id; - const getDefaultActionParams = useCallback( - (actionTypeId: string, actionGroupId: string): Record | undefined => - getDefaultsForActionParams( - actionTypeId, - actionGroupId, - actionGroupId === recoveryActionGroup - ), - [recoveryActionGroup] - ); const tagsOptions = rule.tags ? rule.tags.map((label: string) => ({ label })) : []; @@ -571,7 +561,7 @@ export const RuleForm = ({ } : { ...actionGroup, defaultActionMessage: ruleTypeModel?.defaultActionMessage } )} - getDefaultActionParams={getDefaultActionParams} + recoveryActionGroup={recoveryActionGroup} setActionIdByIndex={(id: string, index: number) => setActionProperty('id', id, index)} setActionGroupIdByIndex={(group: string, index: number) => setActionProperty('group', group, index) diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index ae827a5b33f7..65b6d50e2228 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -204,6 +204,8 @@ export interface ActionTypeModel > | null; actionParamsFields: React.LazyExoticComponent>>; + defaultActionParams?: Partial; + defaultRecoveredActionParams?: Partial; customConnectorSelectItem?: CustomConnectorSelectionItem; isExperimental?: boolean; } From 8bfe338d73da999040c185c8f9311a43324042ee Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Thu, 22 Sep 2022 07:06:27 -0700 Subject: [PATCH 18/29] Documents saved objects bulk delete API (#141164) Co-authored-by: Rudolf Meijering --- docs/api/saved-objects.asciidoc | 3 + docs/api/saved-objects/bulk_delete.asciidoc | 107 ++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 docs/api/saved-objects/bulk_delete.asciidoc diff --git a/docs/api/saved-objects.asciidoc b/docs/api/saved-objects.asciidoc index 6cabbdc785db..610f18c38d62 100644 --- a/docs/api/saved-objects.asciidoc +++ b/docs/api/saved-objects.asciidoc @@ -30,6 +30,8 @@ The following saved objects APIs are available: * <> to remove {kib} saved objects +* <> to remove multiple {kib} saved objects + * <> to retrieve sets of saved objects that you want to import into {kib} * <> to create sets of {kib} saved objects from a file created by the export API @@ -46,6 +48,7 @@ include::saved-objects/bulk_create.asciidoc[] include::saved-objects/update.asciidoc[] include::saved-objects/bulk_update.asciidoc[] include::saved-objects/delete.asciidoc[] +include::saved-objects/bulk_delete.asciidoc[] include::saved-objects/export.asciidoc[] include::saved-objects/import.asciidoc[] include::saved-objects/resolve_import_errors.asciidoc[] diff --git a/docs/api/saved-objects/bulk_delete.asciidoc b/docs/api/saved-objects/bulk_delete.asciidoc new file mode 100644 index 000000000000..d08c5874477b --- /dev/null +++ b/docs/api/saved-objects/bulk_delete.asciidoc @@ -0,0 +1,107 @@ +[[saved-objects-api-bulk-delete]] +=== Bulk delete object API +++++ +Bulk delete objects +++++ + +experimental[] Remove multiple {kib} saved objects. + +WARNING: Once you delete a saved object, _it cannot be recovered_. + +==== Request + +`POST :/api/saved_objects/_bulk_delete` + +`POST :/s//api/saved_objects/_bulk_delete` + +==== Path parameters + +`space_id`:: + (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. + +==== Request body + +`type`:: + (Required, string) Valid options include `visualization`, `dashboard`, `search`, `index-pattern`, `config`. + +`id`:: + (Required, string) The object ID to remove. + +==== Query parameters + +`force`:: + (Optional, boolean) When true, force delete objects that exist in multiple namespaces. Note that the option applies to the whole request. Use the <> to specify per-object delete behavior. ++ +TIP: Use this if you attempted to delete objects and received an HTTP 400 error with the following message: _"Unable to delete saved object that exists in multiple namespaces, use the `force` option to delete it anyway"_ ++ +WARNING: When you bulk delete objects that exist in multiple namespaces, the API also deletes <> that reference the object. These requests are batched to minimise the impact but they can place a heavy load on {kib}. Make sure you limit the number of objects that exist in multiple namespaces in a single bulk delete operation. + +==== Response code +`200`:: + Indicates a successful call. Note, this HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual + objects will be returned in the response body. Refer to the example below for details. + +==== Response body + +`statuses`:: + (array) Top-level property that contains objects that represent the response for each of the requested objects. The order of the objects in the response is identical to the order of the objects in the request. + +Saved objects that cannot be removed will include an error object. + +==== Example + +Delete three saved objects, where one of them does not exist and one exists in multiple namespaces: + +[source,sh] +-------------------------------------------------- +$ curl -X POST api/saved_objects/_bulk_delete +[ + { + type: 'visualization', + id: 'not an id', + }, + { + type: 'dashboard', + id: 'be3733a0-9efe-11e7-acb3-3dab96693fab', + { + type: 'index-pattern', + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + } +] +-------------------------------------------------- +// KIBANA + +The API returns the following: + +[source,sh] +-------------------------------------------------- +{ + "statuses": [ + { + "success": false, + "id": "not an id", + "type": "visualization", + "error": { + "statusCode": 404, + "error": "Not Found", + "message": "Saved object [visualization/not an id] not found", + }, + }, + { + "success": true, + "id": "be3733a0-9efe-11e7-acb3-3dab96693fab", + "type": "dashboard", + }, + { + "success": false, + "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", + "type": "index-pattern", + "error": { + "statusCode": 400, + "error": "Bad Request", + "message": "Unable to delete saved object id: d3d7af60-4c81-11e8-b3d7-01146121b73d, type: index-pattern that exists in multiple namespaces, use the \"force\" option to delete all saved objects: Bad Request", + }, + } + ] +} +-------------------------------------------------- From 13c46d62254105bedbb995fe165dcbbcd9990bc0 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 22 Sep 2022 08:33:48 -0600 Subject: [PATCH 19/29] skip failing test suite (#138776) --- .../security_solution_endpoint/apps/endpoint/policy_details.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index 12ea3e745250..443170a43215 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -25,7 +25,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const policyTestResources = getService('policyTestResources'); const endpointTestResources = getService('endpointTestResources'); - describe('When on the Endpoint Policy Details Page', function () { + // Failing: See https://github.com/elastic/kibana/issues/138776 + describe.skip('When on the Endpoint Policy Details Page', function () { let indexedData: IndexedHostsAndAlertsResponse; before(async () => { From 837da729bd27883fd4cea18939a5bd9fa167aa48 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 22 Sep 2022 08:34:11 -0600 Subject: [PATCH 20/29] skip failing test suite (#140797) --- .../security_and_spaces/group1/tests/alerting/disable.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts index 2f452a54927b..860576f806e3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts @@ -26,7 +26,8 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('disable', () => { + // Failing: See https://github.com/elastic/kibana/issues/140797 + describe.skip('disable', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); From 37d6b9d38ab78ea3c5d795fcc76e318abe5f91dd Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 22 Sep 2022 09:58:01 -0500 Subject: [PATCH 21/29] [journeys] add a short delay after loading data (#141437) --- .../journey/journey_ftr_harness.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/kbn-journeys/journey/journey_ftr_harness.ts b/packages/kbn-journeys/journey/journey_ftr_harness.ts index 672b14f0e1a8..952017492e07 100644 --- a/packages/kbn-journeys/journey/journey_ftr_harness.ts +++ b/packages/kbn-journeys/journey/journey_ftr_harness.ts @@ -120,12 +120,19 @@ export class JourneyFtrHarness { await Promise.all([ this.setupApm(), this.setupBrowserAndPage(), - asyncForEach(this.journeyConfig.getEsArchives(), async (esArchive) => { - await this.esArchiver.load(esArchive); - }), - asyncForEach(this.journeyConfig.getKbnArchives(), async (kbnArchive) => { - await this.kibanaServer.importExport.load(kbnArchive); - }), + (async () => { + await Promise.all([ + asyncForEach(this.journeyConfig.getEsArchives(), async (esArchive) => { + await this.esArchiver.load(esArchive); + }), + asyncForEach(this.journeyConfig.getKbnArchives(), async (kbnArchive) => { + await this.kibanaServer.importExport.load(kbnArchive); + }), + ]); + + // wait after loading the data, before doing any querying in tests + await setTimeout(10_000); + })(), ]); } From 585d51444e7301b392ec9228d62811a33cb0690b Mon Sep 17 00:00:00 2001 From: Abdul Wahab Zahid Date: Thu, 22 Sep 2022 17:09:54 +0200 Subject: [PATCH 22/29] Fix Next and Previous button on step screenshot carousel. (#141422) --- .../ping_list/columns/ping_timestamp/ping_timestamp.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx index 1eef87ed9efc..4cee2eb9bfca 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor/ping_list/columns/ping_timestamp/ping_timestamp.tsx @@ -63,8 +63,11 @@ export const PingTimestamp = ({ const [screenshotRef, setScreenshotRef] = useState(undefined); + const isScreenshotRefValid = Boolean( + screenshotRef && screenshotRef?.ref?.screenshotRef?.synthetics?.step?.index === stepNumber + ); const { data, loading } = useInProgressImage({ - hasImage: Boolean(stepImages[stepNumber - 1]) || Boolean(screenshotRef), + hasImage: Boolean(stepImages[stepNumber - 1]) || isScreenshotRefValid, hasIntersected: Boolean(intersection && intersection.intersectionRatio === 1), stepStatus, imgPath, From fa661a445b6fa4a56bfdce4bb8acc06bb5b32da5 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Thu, 22 Sep 2022 17:13:41 +0200 Subject: [PATCH 23/29] [Lens][Aggs] Gracefully handle the case of missing extended_stats for std_deviation operation (#141248) * :bug: Make getValue return undefined if no extended_object is present * :white_check_mark: Add unit test --- .../search/aggs/metrics/std_deviation.test.ts | 16 ++++++++++++++-- .../common/search/aggs/metrics/std_deviation.ts | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts index 38e0ca8c3975..3e9ba6c9ecfa 100644 --- a/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts @@ -13,7 +13,10 @@ import { METRIC_TYPES } from './metric_agg_types'; describe('AggTypeMetricStandardDeviationProvider class', () => { const typesRegistry = mockAggTypesRegistry(); - const getAggConfigs = (customLabel?: string) => { + const getAggConfigs = ({ + customLabel, + showBounds, + }: { customLabel?: string; showBounds?: boolean } = {}) => { const field = { name: 'memory', }; @@ -38,6 +41,7 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { displayName: 'memory', }, customLabel, + ...(showBounds != null ? { showBounds } : {}), }, }, ], @@ -47,7 +51,7 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { }; it('uses the custom label if it is set', () => { - const aggConfigs = getAggConfigs('custom label'); + const aggConfigs = getAggConfigs({ customLabel: 'custom label' }); const responseAggs: any = getStdDeviationMetricAgg().getResponseAggs( aggConfigs.aggs[0] as IStdDevAggConfig ); @@ -102,4 +106,12 @@ describe('AggTypeMetricStandardDeviationProvider class', () => { } `); }); + + it('returns null without throwing if no "extended_stats" is returned', () => { + const aggConfigs = getAggConfigs({ showBounds: false }); + + expect(() => + getStdDeviationMetricAgg().getValue(aggConfigs.aggs[0] as IStdDevAggConfig, {}) + ).not.toThrow(); + }); }); diff --git a/src/plugins/data/common/search/aggs/metrics/std_deviation.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation.ts index 8bc1af26509d..c64ba8ed22c6 100644 --- a/src/plugins/data/common/search/aggs/metrics/std_deviation.ts +++ b/src/plugins/data/common/search/aggs/metrics/std_deviation.ts @@ -117,7 +117,7 @@ export const getStdDeviationMetricAgg = () => { getValue(agg, bucket) { const showBounds = agg.getParam('showBounds'); if (showBounds === false) { - return bucket[agg.id].std_deviation; + return bucket[agg.id]?.std_deviation; } return get(bucket[agg.parentId], agg.valProp()); }, From e8e1203e5ea8e014effa31cc132f0e23be58164b Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 22 Sep 2022 11:42:16 -0400 Subject: [PATCH 24/29] [Fleet] Do not set ignore_above for index:false (#141442) --- .../__snapshots__/template.test.ts.snap | 176 +++++++++--------- .../epm/elasticsearch/template/mappings.ts | 25 +++ .../elasticsearch/template/template.test.ts | 1 - .../epm/elasticsearch/template/template.ts | 24 +-- 4 files changed, 116 insertions(+), 110 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap index 758d0e6d1bc1..da068809234f 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/__snapshots__/template.test.ts.snap @@ -6,12 +6,12 @@ exports[`EPM template tests loading base.yml: base.yml 1`] = ` "user": { "properties": { "auid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "euid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -32,12 +32,12 @@ exports[`EPM template tests loading base.yml: base.yml 1`] = ` "nested": { "properties": { "bar": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "baz": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -115,8 +115,8 @@ exports[`EPM template tests loading coredns.logs.yml: coredns.logs.yml 1`] = ` "coredns": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "query": { "properties": { @@ -124,28 +124,28 @@ exports[`EPM template tests loading coredns.logs.yml: coredns.logs.yml 1`] = ` "type": "long" }, "class": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "response": { "properties": { "code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "flags": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "size": { "type": "long" @@ -439,12 +439,12 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "diskio": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "serial_number": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "read": { "properties": { @@ -573,16 +573,16 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "type": "long" }, "device_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "mount_point": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "files": { "type": "long" @@ -797,8 +797,8 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "network": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "out": { "properties": { @@ -876,12 +876,12 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "process": { "properties": { "state": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "cmdline": { - "ignore_above": 2048, - "type": "keyword" + "type": "keyword", + "ignore_above": 2048 }, "cpu": { "properties": { @@ -967,22 +967,22 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "cgroup": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "cpu": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "cfs": { "properties": { @@ -1045,12 +1045,12 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "cpuacct": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "total": { "properties": { @@ -1082,12 +1082,12 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "memory": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "mem": { "properties": { @@ -1306,12 +1306,12 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "blkio": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "total": { "properties": { @@ -1360,20 +1360,20 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "raid": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "status": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "level": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sync_action": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "disks": { "properties": { @@ -1424,24 +1424,24 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "type": "long" }, "host": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "etld_plus_one": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "host_error": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "process": { "properties": { "cmdline": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1536,42 +1536,42 @@ exports[`EPM template tests loading system.yml: system.yml 1`] = ` "users": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "seat": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "service": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "remote": { "type": "boolean" }, "state": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "scope": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "leader": { "type": "long" }, "remote_host": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } } diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/mappings.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/mappings.ts index a398f4fde99d..85b8691f148c 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/mappings.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/mappings.ts @@ -8,6 +8,7 @@ import type { Field } from '../../fields/field'; const DEFAULT_SCALING_FACTOR = 1000; +const DEFAULT_IGNORE_ABOVE = 1024; interface Properties { [key: string]: any; @@ -46,3 +47,27 @@ export function histogram(field: Field): Properties { return fieldProps; } + +export function keyword(field: Field): Properties { + const fieldProps = getDefaultProperties(field); + fieldProps.type = 'keyword'; + + if (field.ignore_above) { + fieldProps.ignore_above = field.ignore_above; + } else { + fieldProps.ignore_above = DEFAULT_IGNORE_ABOVE; + } + if (field.normalizer) { + fieldProps.normalizer = field.normalizer; + } + if (field.dimension) { + fieldProps.time_series_dimension = field.dimension; + delete fieldProps.ignore_above; + } + + if (field.index === false || field.doc_values === false) { + delete fieldProps.ignore_above; + } + + return fieldProps; +} diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index 5cd0081d20cd..0d26984c55be 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -177,7 +177,6 @@ describe('EPM template', () => { const keywordWithIndexFalseMapping = { properties: { keywordIndexFalse: { - ignore_above: 1024, type: 'keyword', doc_values: false, }, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index e0ea50b6420d..5605125bd4ff 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -24,7 +24,7 @@ import { import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; -import { getDefaultProperties, histogram, scaledFloat } from './mappings'; +import { getDefaultProperties, histogram, keyword, scaledFloat } from './mappings'; interface Properties { [key: string]: any; @@ -261,8 +261,7 @@ function _generateMappings( fieldProps = { ...fieldProps, ...generateDynamicAndEnabled(field), type: 'object' }; break; case 'keyword': - const keywordMapping = generateKeywordMapping(field); - fieldProps = { ...fieldProps, ...keywordMapping, type: 'keyword' }; + fieldProps = keyword(field); if (field.multi_fields) { fieldProps.fields = generateMultiFields(field.multi_fields); } @@ -359,7 +358,7 @@ function generateMultiFields(fields: Fields): MultiFields { multiFields[f.name] = { ...generateTextMapping(f), type: f.type }; break; case 'keyword': - multiFields[f.name] = { ...generateKeywordMapping(f), type: f.type }; + multiFields[f.name] = keyword(f); break; case 'long': case 'double': @@ -372,23 +371,6 @@ function generateMultiFields(fields: Fields): MultiFields { return multiFields; } -function generateKeywordMapping(field: Field): IndexTemplateMapping { - const mapping: IndexTemplateMapping = { - ignore_above: DEFAULT_IGNORE_ABOVE, - }; - if (field.ignore_above) { - mapping.ignore_above = field.ignore_above; - } - if (field.normalizer) { - mapping.normalizer = field.normalizer; - } - if (field.dimension) { - mapping.time_series_dimension = field.dimension; - delete mapping.ignore_above; - } - return mapping; -} - function generateTextMapping(field: Field): IndexTemplateMapping { const mapping: IndexTemplateMapping = {}; if (field.analyzer) { From da8eb44f92ea42aa0b76b816e9ae1ae7ea54148a Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 22 Sep 2022 10:57:46 -0500 Subject: [PATCH 25/29] revert #141437 and switch back to fixed journey ordering --- .../functional/performance_playwright.sh | 4 +++- .../journey/journey_ftr_harness.ts | 19 ++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.buildkite/scripts/steps/functional/performance_playwright.sh b/.buildkite/scripts/steps/functional/performance_playwright.sh index cdf2e449f7a6..189791cae3e3 100644 --- a/.buildkite/scripts/steps/functional/performance_playwright.sh +++ b/.buildkite/scripts/steps/functional/performance_playwright.sh @@ -46,7 +46,9 @@ unset ELASTIC_APM_SERVER_URL unset ELASTIC_APM_SECRET_TOKEN unset ELASTIC_APM_GLOBAL_LABELS -for journey in x-pack/performance/journeys/*; do +journeys=("login" "ecommerce_dashboard" "flight_dashboard" "web_logs_dashboard" "promotion_tracking_dashboard" "many_fields_discover" "data_stress_test_lens") + +for journey in "${journeys[@]}"; do set +e phases=("WARMUP" "TEST") diff --git a/packages/kbn-journeys/journey/journey_ftr_harness.ts b/packages/kbn-journeys/journey/journey_ftr_harness.ts index 952017492e07..672b14f0e1a8 100644 --- a/packages/kbn-journeys/journey/journey_ftr_harness.ts +++ b/packages/kbn-journeys/journey/journey_ftr_harness.ts @@ -120,19 +120,12 @@ export class JourneyFtrHarness { await Promise.all([ this.setupApm(), this.setupBrowserAndPage(), - (async () => { - await Promise.all([ - asyncForEach(this.journeyConfig.getEsArchives(), async (esArchive) => { - await this.esArchiver.load(esArchive); - }), - asyncForEach(this.journeyConfig.getKbnArchives(), async (kbnArchive) => { - await this.kibanaServer.importExport.load(kbnArchive); - }), - ]); - - // wait after loading the data, before doing any querying in tests - await setTimeout(10_000); - })(), + asyncForEach(this.journeyConfig.getEsArchives(), async (esArchive) => { + await this.esArchiver.load(esArchive); + }), + asyncForEach(this.journeyConfig.getKbnArchives(), async (kbnArchive) => { + await this.kibanaServer.importExport.load(kbnArchive); + }), ]); } From a5afcd7ae9684ad1ea97ba26f654cf70624cd70c Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 22 Sep 2022 11:00:30 -0500 Subject: [PATCH 26/29] [ftr/startServers] resolve relative config arguments at CLI (#141450) --- .../start_servers/flags.test.ts | 25 ++++++++++++++++++- .../functional_tests/start_servers/flags.ts | 4 +-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/kbn-test/src/functional_tests/start_servers/flags.test.ts b/packages/kbn-test/src/functional_tests/start_servers/flags.test.ts index 5f40b2ae6682..a8498d9e4e49 100644 --- a/packages/kbn-test/src/functional_tests/start_servers/flags.test.ts +++ b/packages/kbn-test/src/functional_tests/start_servers/flags.test.ts @@ -6,13 +6,19 @@ * Side Public License, v 1. */ +import Path from 'path'; + import { getFlags, FlagsReader } from '@kbn/dev-cli-runner'; import { createAnyInstanceSerializer, createAbsolutePathSerializer } from '@kbn/jest-serializers'; +import { REPO_ROOT } from '@kbn/utils'; + import { EsVersion } from '../../functional_test_runner'; import { parseFlags, FLAG_OPTIONS } from './flags'; jest.mock('uuid', () => ({ v4: () => 'some-uuid' })); +const cwdMock = (process.cwd = jest.fn().mockReturnValue(REPO_ROOT)); + expect.addSnapshotSerializer( createAnyInstanceSerializer(EsVersion, (v: EsVersion) => `EsVersion ${v.toString()}`) ); @@ -23,10 +29,27 @@ const defaults = getFlags(['--config=foo'], FLAG_OPTIONS); const test = (opts: Record) => parseFlags(new FlagsReader({ ...defaults, ...opts })); +beforeEach(() => { + cwdMock.mockReturnValue(REPO_ROOT); +}); + it('parses a subset of the flags from runTests', () => { expect(test({ config: 'foo' })).toMatchInlineSnapshot(` Object { - "config": "foo", + "config": /foo, + "esFrom": undefined, + "esVersion": , + "installDir": undefined, + "logsDir": undefined, + } + `); +}); + +it('respects the cwd of the script', () => { + cwdMock.mockReturnValue(Path.resolve(REPO_ROOT, 'x-pack')); + expect(test({ config: 'foo' })).toMatchInlineSnapshot(` + Object { + "config": /x-pack/foo, "esFrom": undefined, "esVersion": , "installDir": undefined, diff --git a/packages/kbn-test/src/functional_tests/start_servers/flags.ts b/packages/kbn-test/src/functional_tests/start_servers/flags.ts index 8ce3af9f5917..99c7de9e53ea 100644 --- a/packages/kbn-test/src/functional_tests/start_servers/flags.ts +++ b/packages/kbn-test/src/functional_tests/start_servers/flags.ts @@ -31,8 +31,8 @@ export const FLAG_OPTIONS: FlagOptions = { export function parseFlags(flags: FlagsReader) { const configs = [ - ...(flags.arrayOfStrings('config') ?? []), - ...(flags.arrayOfStrings('journey') ?? []), + ...(flags.arrayOfPaths('config') ?? []), + ...(flags.arrayOfPaths('journey') ?? []), ]; if (configs.length !== 1) { throw createFlagError(`expected exactly one --config or --journey flag`); From d8f83051d595b8a7dd66b80f4032aa5410c06c8c Mon Sep 17 00:00:00 2001 From: Maryna Cherniavska Date: Thu, 22 Sep 2022 18:08:48 +0200 Subject: [PATCH 27/29] MongoDB Native Connector sync failing - Direct_connection configurable field missing on Kibana side #2839 (#141457) --- .../components/search_index/connector/constants.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/constants.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/constants.ts index 7cb12fc5f2ed..37d0318325f9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/constants.ts @@ -57,6 +57,15 @@ export const NATIVE_CONNECTORS: NativeConnector[] = [ } ), }, + direct_connection: { + value: '', + label: i18n.translate( + 'xpack.enterpriseSearch.content.nativeConnectors.mongodb.configuration.directConnectionLabel', + { + defaultMessage: 'Use direct connection (true/false)', + } + ), + }, }, name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.mongodb.name', { defaultMessage: 'MongoDB', From d868f2c12c86374c267ded0ed3691eb0df30a69c Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Thu, 22 Sep 2022 12:12:11 -0400 Subject: [PATCH 28/29] [ResponseOps][Cases] Fix duplicate alerts test (#141445) * Trying fix * Removing flaky test only --- .../security_and_spaces/tests/common/cases/find_cases.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts index df0fdaeba697..3c076d4e3514 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts @@ -55,8 +55,7 @@ export default ({ getService }: FtrProviderContext): void => { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); - // Failing: See https://github.com/elastic/kibana/issues/139626 - describe.skip('find_cases', () => { + describe('find_cases', () => { describe('basic tests', () => { afterEach(async () => { await deleteAllCaseItems(es); @@ -369,6 +368,11 @@ export default ({ getService }: FtrProviderContext): void => { owner: 'securitySolutionFixture', }, }); + + // There is potential for the alert index to not be refreshed by the time the second comment is created + // which could attempt to update the alert status again and will encounter a conflict so this will + // ensure that the index is up to date before we try to update the next alert status + await es.indices.refresh({ index: defaultSignalsIndex }); } const patchedCase = await createComment({ From 0fcfaec2dd1d7acc598467e88e10e4acbbba67b1 Mon Sep 17 00:00:00 2001 From: Wafaa Nasr Date: Thu, 22 Sep 2022 18:16:31 +0200 Subject: [PATCH 29/29] remove alignCenter to prevent the icon from adjusting (#141365) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../exceptions/components/builder/entry_delete_button.tsx | 2 +- .../exceptions/components/builder/exception_item_renderer.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx index b30bcd9ae162..3bc0f6c60c35 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_delete_button.tsx @@ -11,7 +11,7 @@ import styled from 'styled-components'; import type { BuilderEntry } from '@kbn/securitysolution-list-utils'; const MyFirstRowContainer = styled(EuiFlexItem)` - padding-top: 20px; + padding-top: 25px; `; interface BuilderEntryDeleteButtonProps { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx index d55289d01688..84c18baf5156 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/exception_item_renderer.tsx @@ -136,7 +136,7 @@ export const BuilderExceptionListItemComponent = React.memo - + {item.nested === 'child' && }