diff --git a/.ci/Dockerfile b/.ci/Dockerfile index 6eddcd20609224..e1ff9099bfb4bd 100644 --- a/.ci/Dockerfile +++ b/.ci/Dockerfile @@ -1,7 +1,7 @@ # NOTE: This Dockerfile is ONLY used to run certain tasks in CI. It is not used to run Kibana or as a distributable. # If you're looking for the Kibana Docker image distributable, please see: src/dev/build/tasks/os_packages/docker_generator/templates/dockerfile.template.ts -ARG NODE_VERSION=16.19.0 +ARG NODE_VERSION=16.19.1 FROM node:${NODE_VERSION} AS base diff --git a/.eslintrc.js b/.eslintrc.js index c011bbe6636c04..221453e3828023 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -183,50 +183,49 @@ const DEV_PATTERNS = [ const RESTRICTED_IMPORTS = [ { name: 'lodash', - importNames: ['set', 'setWith'], - message: 'Please use @kbn/safer-lodash-set instead', + importNames: ['set', 'setWith', 'template'], + message: + 'lodash.set/setWith: Please use @kbn/safer-lodash-set instead.\n' + + 'lodash.template: Function is unsafe, and not compatible with our content security policy.', }, { name: 'lodash.set', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/set instead', }, { name: 'lodash.setwith', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/setWith instead', }, { name: 'lodash/set', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/set instead', }, { name: 'lodash/setWith', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/setWith instead', }, { name: 'lodash/fp', - importNames: ['set', 'setWith', 'assoc', 'assocPath'], - message: 'Please use @kbn/safer-lodash-set instead', + importNames: ['set', 'setWith', 'assoc', 'assocPath', 'template'], + message: + 'lodash.set/setWith/assoc/assocPath: Please use @kbn/safer-lodash-set/fp instead\n' + + 'lodash.template: Function is unsafe, and not compatible with our content security policy.', }, { name: 'lodash/fp/set', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/fp/set instead', }, { name: 'lodash/fp/setWith', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/fp/setWith instead', }, { name: 'lodash/fp/assoc', - message: 'Please use @kbn/safer-lodash-set instead', + message: 'Please use @kbn/safer-lodash-set/fp/assoc instead', }, { name: 'lodash/fp/assocPath', - message: 'Please use @kbn/safer-lodash-set instead', - }, - { - name: 'lodash', - importNames: ['template'], - message: 'lodash.template is unsafe, and not compatible with our content security policy.', + message: 'Please use @kbn/safer-lodash-set/fp/assocPath instead', }, { name: 'lodash.template', @@ -236,11 +235,6 @@ const RESTRICTED_IMPORTS = [ name: 'lodash/template', message: 'lodash.template is unsafe, and not compatible with our content security policy.', }, - { - name: 'lodash/fp', - importNames: ['template'], - message: 'lodash.template is unsafe, and not compatible with our content security policy.', - }, { name: 'lodash/fp/template', message: 'lodash.template is unsafe, and not compatible with our content security policy.', @@ -744,47 +738,54 @@ module.exports = { { files: ['**/*.{js,mjs,ts,tsx}'], rules: { - 'no-restricted-imports': [ - 2, + 'no-restricted-imports': ['error', ...RESTRICTED_IMPORTS], + 'no-restricted-modules': [ + 'error', { - paths: RESTRICTED_IMPORTS, + name: 'lodash.set', + message: 'Please use @kbn/safer-lodash-set instead', }, - ], - 'no-restricted-modules': [ - 2, { - paths: [ - { - name: 'lodash.set', - message: 'Please use @kbn/safer-lodash-set instead', - }, - { - name: 'lodash.setwith', - message: 'Please use @kbn/safer-lodash-set instead', - }, - { - name: 'lodash.template', - message: - 'lodash.template is unsafe, and not compatible with our content security policy.', - }, - { - name: 'lodash/set', - message: 'Please use @kbn/safer-lodash-set instead', - }, - { - name: 'lodash/setWith', - message: 'Please use @kbn/safer-lodash-set instead', - }, - { - name: 'lodash/template', - message: - 'lodash.template is unsafe, and not compatible with our content security policy.', - }, - ], + name: 'lodash.setwith', + message: 'Please use @kbn/safer-lodash-set instead', + }, + { + name: 'lodash.template', + message: + 'lodash.template is unsafe, and not compatible with our content security policy.', + }, + { + name: 'lodash/set', + message: 'Please use @kbn/safer-lodash-set/set instead', + }, + { + name: 'lodash/setWith', + message: 'Please use @kbn/safer-lodash-set/setWith instead', + }, + { + name: 'lodash/fp/set', + message: 'Please use @kbn/safer-lodash-set/fp/set instead', + }, + { + name: 'lodash/fp/setWith', + message: 'Please use @kbn/safer-lodash-set/fp/setWith instead', + }, + { + name: 'lodash/fp/assoc', + message: 'Please use @kbn/safer-lodash-set/fp/assoc instead', + }, + { + name: 'lodash/fp/assocPath', + message: 'Please use @kbn/safer-lodash-set/fp/assocPath instead', + }, + { + name: 'lodash/template', + message: + 'lodash.template is unsafe, and not compatible with our content security policy.', }, ], 'no-restricted-properties': [ - 2, + 'error', { object: 'lodash', property: 'set', @@ -795,18 +796,6 @@ module.exports = { property: 'set', message: 'Please use @kbn/safer-lodash-set instead', }, - { - object: 'lodash', - property: 'template', - message: - 'lodash.template is unsafe, and not compatible with our content security policy.', - }, - { - object: '_', - property: 'template', - message: - 'lodash.template is unsafe, and not compatible with our content security policy.', - }, { object: 'lodash', property: 'setWith', @@ -837,6 +826,18 @@ module.exports = { property: 'assocPath', message: 'Please use @kbn/safer-lodash-set instead', }, + { + object: 'lodash', + property: 'template', + message: + 'lodash.template is unsafe, and not compatible with our content security policy.', + }, + { + object: '_', + property: 'template', + message: + 'lodash.template is unsafe, and not compatible with our content security policy.', + }, ], }, }, @@ -844,15 +845,11 @@ module.exports = { files: ['**/common/**/*.{js,mjs,ts,tsx}', '**/public/**/*.{js,mjs,ts,tsx}'], rules: { 'no-restricted-imports': [ - 2, + 'error', + ...RESTRICTED_IMPORTS, { - paths: [ - ...RESTRICTED_IMPORTS, - { - name: 'semver', - message: 'Please use "semver/*/{function}" instead', - }, - ], + name: 'semver', + message: 'Please use "semver/*/{function}" instead', }, ], }, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f2d11bf493d948..ca7c43c33ec46f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -461,7 +461,7 @@ src/plugins/newsfeed @elastic/kibana-core test/common/plugins/newsfeed @elastic/kibana-core x-pack/plugins/notifications @elastic/appex-sharedux x-pack/test/cases_api_integration/common/plugins/observability @elastic/response-ops -x-pack/plugins/observability @elastic/observability-ui +x-pack/plugins/observability @elastic/actionable-observability x-pack/test/security_api_integration/plugins/oidc_provider @elastic/kibana-security test/common/plugins/otel_metrics @elastic/infra-monitoring-ui packages/kbn-optimizer @elastic/kibana-operations @@ -759,25 +759,13 @@ packages/kbn-yarn-lock-validator @elastic/kibana-operations # /x-pack/test/observability_functional @elastic/unified-observability # Home/Overview/Landing Pages -/x-pack/plugins/observability/public/pages/home @elastic/observability-design -/x-pack/plugins/observability/public/pages/landing @elastic/observability-design -/x-pack/plugins/observability/public/pages/overview @elastic/observability-design @elastic/actionable-observability +/x-pack/plugins/observability/public/pages/home @elastic/observability-design @elastic/observability-ui +/x-pack/plugins/observability/public/pages/landing @elastic/observability-design @elastic/observability-ui +/x-pack/plugins/observability/public/pages/overview @elastic/observability-design @elastic/observability-ui # Actionable Observability -/x-pack/plugins/observability/common/rules @elastic/actionable-observability -/x-pack/plugins/observability/public/rules @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/alerts @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/cases @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/rules @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/rule_details @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/slos @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/slo_edit @elastic/actionable-observability -/x-pack/plugins/observability/public/pages/slo_details @elastic/actionable-observability /x-pack/test/observability_functional @elastic/actionable-observability -# keep it below actionable observability -x-pack/plugins/observability @elastic/observability-ui - # Infra Monitoring /x-pack/test/functional/apps/infra @elastic/infra-monitoring-ui /x-pack/test/api_integration/apis/infra @elastic/infra-monitoring-ui @@ -884,13 +872,13 @@ x-pack/plugins/observability @elastic/observability-ui /kbn_pm/ @elastic/kibana-operations # Quality Assurance -/src/dev/code_coverage @elastic/kibana-qa -/vars/*Coverage.groovy @elastic/kibana-qa -/test/functional/services/common @elastic/kibana-qa -/test/functional/services/lib @elastic/kibana-qa -/test/functional/services/remote @elastic/kibana-qa -/test/visual_regression @elastic/kibana-qa -/x-pack/test/visual_regression @elastic/kibana-qa +/src/dev/code_coverage @elastic/appex-qa +/vars/*Coverage.groovy @elastic/appex-qa +/test/functional/services/common @elastic/appex-qa +/test/functional/services/lib @elastic/appex-qa +/test/functional/services/remote @elastic/appex-qa +/test/visual_regression @elastic/appex-qa +/x-pack/test/visual_regression @elastic/appex-qa # Core /config/kibana.yml @elastic/kibana-core diff --git a/.node-version b/.node-version index e65243f2ea3795..8b3ed1b235e334 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16.19.0 +16.19.1 diff --git a/.nvmrc b/.nvmrc index e65243f2ea3795..8b3ed1b235e334 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.19.0 +16.19.1 diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index f097ad8152a59b..d32fec9840d16e 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -22,13 +22,13 @@ load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install # Setup the Node.js toolchain for the architectures we want to support node_repositories( node_repositories = { - "16.19.0-darwin_amd64": ("node-v16.19.0-darwin-x64.tar.gz", "node-v16.19.0-darwin-x64", "491e5a5592eca1961dcbb1fae28567428ce56ce9cc7977b04041e163e0c1670c"), - "16.19.0-darwin_arm64": ("node-v16.19.0-darwin-arm64.tar.gz", "node-v16.19.0-darwin-arm64", "5c9434fbb0f323fecf3d261b23a2e544919380c5043d0046d9745682fefd9cde"), - "16.19.0-linux_arm64": ("node-v16.19.0-linux-arm64.tar.xz", "node-v16.19.0-linux-arm64", "9072c995052f832678fe8fab18e960bd9853f30e481787e53f8dd1ec8aaa3bb6"), - "16.19.0-linux_amd64": ("node-v16.19.0-linux-x64.tar.xz", "node-v16.19.0-linux-x64", "c88b52497ab38a3ddf526e5b46a41270320409109c3f74171b241132984fd08f"), - "16.19.0-windows_amd64": ("node-v16.19.0-win-x64.zip", "node-v16.19.0-win-x64", "534ca7a24e999c81cec847a498cc43d47e2bb158f6edf639e5297f2718350e96"), + "16.19.1-darwin_amd64": ("node-v16.19.1-darwin-x64.tar.gz", "node-v16.19.1-darwin-x64", "d7f683b2a8f78db8a28235a175e130c760f0d3cd335404e02f223e3a9adc30c7"), + "16.19.1-darwin_arm64": ("node-v16.19.1-darwin-arm64.tar.gz", "node-v16.19.1-darwin-arm64", "168f787f457bf645f3fc41e7419b62071db7d42519ce461b1d7ebfc0acbdbfb1"), + "16.19.1-linux_arm64": ("node-v16.19.1-linux-arm64.tar.xz", "node-v16.19.1-linux-arm64", "042b3ae7e994a77bfdb0e366d0389c1b7602bb744830da15f9325f404f979ce2"), + "16.19.1-linux_amd64": ("node-v16.19.1-linux-x64.tar.xz", "node-v16.19.1-linux-x64", "fa796a23837dc5c22914b1349b6117df4d497e2001a4cd7b28b0767e22f3bb51"), + "16.19.1-windows_amd64": ("node-v16.19.1-win-x64.zip", "node-v16.19.1-win-x64", "77e0198497fee24552d6a6f1737eed595b619af1b749ee0bee4b938026e55f73"), }, - node_version = "16.19.0", + node_version = "16.19.1", node_urls = [ "https://nodejs.org/dist/v{version}/{filename}", ], diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 01796d9d6e216a..3e926c99476ef4 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 6660f43f9fc044..8b7c1387882a89 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 459b12ad51964f..c0df2688bc3504 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 772cc263ceccfc..fb58dd319eb7a8 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -24,14 +24,7 @@ "section": "def-common.SanitizedRule", "text": "SanitizedRule" }, - ") => string | ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.JsonObject", - "text": "JsonObject" - } + ") => string" ], "path": "x-pack/plugins/alerting/public/alert_navigation_registry/types.ts", "deprecated": false, @@ -106,7 +99,7 @@ "section": "def-common.RuleLastRun", "text": "RuleLastRun" }, - " | null | undefined; nextRun?: Date | null | undefined; running?: boolean | null | undefined; }" + " | null | undefined; nextRun?: Date | null | undefined; running?: boolean | null | undefined; viewInAppRelativeUrl?: string | undefined; }" ], "path": "x-pack/plugins/alerting/public/alert_navigation_registry/types.ts", "deprecated": false, @@ -133,7 +126,8 @@ "id": "def-public.PluginSetupContract.registerNavigation", "type": "Function", "tags": [ - "throws" + "throws", + "deprecated" ], "label": "registerNavigation", "description": [ @@ -151,8 +145,18 @@ ") => void" ], "path": "x-pack/plugins/alerting/public/plugin.ts", - "deprecated": false, + "deprecated": true, "trackAdoption": false, + "references": [ + { + "plugin": "ml", + "path": "x-pack/plugins/ml/public/alerting/register_ml_alerts.ts" + }, + { + "plugin": "stackAlerts", + "path": "x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts" + } + ], "children": [ { "parentPluginId": "alerting", @@ -218,7 +222,9 @@ "parentPluginId": "alerting", "id": "def-public.PluginSetupContract.registerDefaultNavigation", "type": "Function", - "tags": [], + "tags": [ + "deprecated" + ], "label": "registerDefaultNavigation", "description": [ "\nRegister a customized view for all rule types with this application id. Stack Management provides a generic overview, but a developer can register a\ncustom navigation to provide the user an extra link to a more curated view. The alerting plugin doesn't actually do\nanything with this information, but it can be used by other plugins via the `getNavigation` functionality. Currently\nthe trigger_actions_ui plugin uses it to expose the link from the generic rule details view in Stack Management.\n" @@ -235,8 +241,9 @@ ") => void" ], "path": "x-pack/plugins/alerting/public/plugin.ts", - "deprecated": false, + "deprecated": true, "trackAdoption": false, + "references": [], "children": [ { "parentPluginId": "alerting", @@ -304,15 +311,7 @@ "label": "getNavigation", "description": [], "signature": [ - "(ruleId: string) => Promise<", - { - "pluginId": "alerting", - "scope": "common", - "docId": "kibAlertingPluginApi", - "section": "def-common.RuleNavigation", - "text": "RuleNavigation" - }, - " | undefined>" + "(ruleId: string) => Promise" ], "path": "x-pack/plugins/alerting/public/plugin.ts", "deprecated": false, @@ -2986,6 +2985,21 @@ "path": "x-pack/plugins/alerting/server/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-server.RuleType.getViewInAppRelativeUrl", + "type": "Function", + "tags": [], + "label": "getViewInAppRelativeUrl", + "description": [], + "signature": [ + "GetViewInAppRelativeUrlFn", + " | undefined" + ], + "path": "x-pack/plugins/alerting/server/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -5945,6 +5959,20 @@ "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-common.Rule.viewInAppRelativeUrl", + "type": "string", + "tags": [], + "label": "viewInAppRelativeUrl", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/alerting/common/rule.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -6957,40 +6985,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.RuleStateNavigation", - "type": "Interface", - "tags": [], - "label": "RuleStateNavigation", - "description": [], - "path": "x-pack/plugins/alerting/common/rule_navigation.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "alerting", - "id": "def-common.RuleStateNavigation.state", - "type": "Object", - "tags": [], - "label": "state", - "description": [], - "signature": [ - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.JsonObject", - "text": "JsonObject" - } - ], - "path": "x-pack/plugins/alerting/common/rule_navigation.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.RuleType", @@ -7209,31 +7203,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "alerting", - "id": "def-common.RuleUrlNavigation", - "type": "Interface", - "tags": [], - "label": "RuleUrlNavigation", - "description": [], - "path": "x-pack/plugins/alerting/common/rule_navigation.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "alerting", - "id": "def-common.RuleUrlNavigation.path", - "type": "string", - "tags": [], - "label": "path", - "description": [], - "path": "x-pack/plugins/alerting/common/rule_navigation.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false } ], "enums": [ @@ -7890,35 +7859,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-common.RuleNavigation", - "type": "Type", - "tags": [], - "label": "RuleNavigation", - "description": [], - "signature": [ - { - "pluginId": "alerting", - "scope": "common", - "docId": "kibAlertingPluginApi", - "section": "def-common.RuleUrlNavigation", - "text": "RuleUrlNavigation" - }, - " | ", - { - "pluginId": "alerting", - "scope": "common", - "docId": "kibAlertingPluginApi", - "section": "def-common.RuleStateNavigation", - "text": "RuleStateNavigation" - } - ], - "path": "x-pack/plugins/alerting/common/rule_navigation.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-common.RuleNotifyWhenType", @@ -8162,7 +8102,7 @@ "section": "def-common.RuleLastRun", "text": "RuleLastRun" }, - " | null | undefined; nextRun?: Date | null | undefined; running?: boolean | null | undefined; }" + " | null | undefined; nextRun?: Date | null | undefined; running?: boolean | null | undefined; viewInAppRelativeUrl?: string | undefined; }" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 045fc7332d186a..adada612c63f62 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 489 | 1 | 478 | 39 | +| 486 | 1 | 475 | 40 | ## Client diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index b874620614d438..0a1ea8fbc3f594 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 1e0d6b35b0cab2..390aea6cfea56a 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 2cf6be5ee966b6..bd2371a5e5b5e0 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index a5774ff145599f..2eb95893c4fb77 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 864b7b1fcbc37d..1a59ab69ccccf3 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index bda164b248d358..419e785e6fa232 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 228b64499a587c..f0eeee257c0765 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index 1585c8444b6f0b..1b66211c3606ae 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index fc56cff42156bf..15a13dd2ba2ade 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 1dcbe975bc599b..1d37f83f96702e 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index daadccc54a7793..bb69cb33d23192 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index bb9678e4df83a4..bb9ab23be40319 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 54db6d38fa9b3c..e7214f8f32f322 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.devdocs.json b/api_docs/content_management.devdocs.json index e07703f73f764c..779fcfac4f5729 100644 --- a/api_docs/content_management.devdocs.json +++ b/api_docs/content_management.devdocs.json @@ -145,21 +145,21 @@ }, "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/create.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "contentManagement", - "id": "def-common.CreateIn.contentType", + "id": "def-common.CreateIn.contentTypeId", "type": "Uncategorized", "tags": [], - "label": "contentType", + "label": "contentTypeId", "description": [], "signature": [ "T" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/create.ts", "deprecated": false, "trackAdoption": false }, @@ -173,7 +173,7 @@ "signature": [ "Data" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/create.ts", "deprecated": false, "trackAdoption": false }, @@ -187,7 +187,7 @@ "signature": [ "Options | undefined" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/create.ts", "deprecated": false, "trackAdoption": false } @@ -209,37 +209,34 @@ "section": "def-common.DeleteIn", "text": "DeleteIn" }, - "" + "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/delete.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "contentManagement", - "id": "def-common.DeleteIn.contentType", + "id": "def-common.DeleteIn.contentTypeId", "type": "Uncategorized", "tags": [], - "label": "contentType", + "label": "contentTypeId", "description": [], "signature": [ "T" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/delete.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "contentManagement", - "id": "def-common.DeleteIn.data", - "type": "Uncategorized", + "id": "def-common.DeleteIn.id", + "type": "string", "tags": [], - "label": "data", + "label": "id", "description": [], - "signature": [ - "Data" - ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/delete.ts", "deprecated": false, "trackAdoption": false }, @@ -253,7 +250,7 @@ "signature": [ "Options | undefined" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/delete.ts", "deprecated": false, "trackAdoption": false } @@ -275,9 +272,9 @@ "section": "def-common.GetIn", "text": "GetIn" }, - "" + "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/get.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -288,18 +285,21 @@ "tags": [], "label": "id", "description": [], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/get.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "contentManagement", - "id": "def-common.GetIn.contentType", - "type": "string", + "id": "def-common.GetIn.contentTypeId", + "type": "Uncategorized", "tags": [], - "label": "contentType", + "label": "contentTypeId", "description": [], - "path": "src/plugins/content_management/common/rpc.ts", + "signature": [ + "T" + ], + "path": "src/plugins/content_management/common/rpc/get.ts", "deprecated": false, "trackAdoption": false }, @@ -313,7 +313,7 @@ "signature": [ "Options | undefined" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/get.ts", "deprecated": false, "trackAdoption": false } @@ -327,7 +327,7 @@ "tags": [], "label": "ProcedureSchemas", "description": [], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -347,9 +347,9 @@ "section": "def-common.Type", "text": "Type" }, - " | undefined" + "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/types.ts", "deprecated": false, "trackAdoption": false }, @@ -369,9 +369,9 @@ "section": "def-common.Type", "text": "Type" }, - " | undefined" + "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/types.ts", "deprecated": false, "trackAdoption": false } @@ -393,37 +393,37 @@ "section": "def-common.SearchIn", "text": "SearchIn" }, - "" + "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/search.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "contentManagement", - "id": "def-common.SearchIn.contentType", + "id": "def-common.SearchIn.contentTypeId", "type": "Uncategorized", "tags": [], - "label": "contentType", + "label": "contentTypeId", "description": [], "signature": [ "T" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/search.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "contentManagement", - "id": "def-common.SearchIn.params", + "id": "def-common.SearchIn.query", "type": "Uncategorized", "tags": [], - "label": "params", + "label": "query", "description": [], "signature": [ - "Params" + "Query" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/search.ts", "deprecated": false, "trackAdoption": false }, @@ -437,45 +437,7 @@ "signature": [ "Options | undefined" ], - "path": "src/plugins/content_management/common/rpc.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "contentManagement", - "id": "def-common.SearchOut", - "type": "Interface", - "tags": [], - "label": "SearchOut", - "description": [], - "signature": [ - { - "pluginId": "contentManagement", - "scope": "common", - "docId": "kibContentManagementPluginApi", - "section": "def-common.SearchOut", - "text": "SearchOut" - }, - "" - ], - "path": "src/plugins/content_management/common/rpc.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "contentManagement", - "id": "def-common.SearchOut.hits", - "type": "Array", - "tags": [], - "label": "hits", - "description": [], - "signature": [ - "Data[]" - ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/search.ts", "deprecated": false, "trackAdoption": false } @@ -499,21 +461,32 @@ }, "" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/update.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "contentManagement", - "id": "def-common.UpdateIn.contentType", + "id": "def-common.UpdateIn.contentTypeId", "type": "Uncategorized", "tags": [], - "label": "contentType", + "label": "contentTypeId", "description": [], "signature": [ "T" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/update.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "contentManagement", + "id": "def-common.UpdateIn.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "path": "src/plugins/content_management/common/rpc/update.ts", "deprecated": false, "trackAdoption": false }, @@ -527,7 +500,7 @@ "signature": [ "Data" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/update.ts", "deprecated": false, "trackAdoption": false }, @@ -541,7 +514,7 @@ "signature": [ "Options | undefined" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/update.ts", "deprecated": false, "trackAdoption": false } @@ -591,7 +564,7 @@ "signature": [ "\"create\" | \"update\" | \"get\" | \"delete\" | \"search\"" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -608,7 +581,7 @@ "signature": [ "readonly [\"get\", \"create\", \"update\", \"delete\", \"search\"]" ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -620,7 +593,7 @@ "tags": [], "label": "schemas", "description": [], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -640,7 +613,7 @@ "text": "ProcedureSchemas" } ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false }, @@ -660,7 +633,7 @@ "text": "ProcedureSchemas" } ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false }, @@ -680,7 +653,7 @@ "text": "ProcedureSchemas" } ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false }, @@ -700,7 +673,7 @@ "text": "ProcedureSchemas" } ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false }, @@ -720,7 +693,7 @@ "text": "ProcedureSchemas" } ], - "path": "src/plugins/content_management/common/rpc.ts", + "path": "src/plugins/content_management/common/rpc/rpc.ts", "deprecated": false, "trackAdoption": false } diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index ac8dc97d4332b5..de9413917e3c19 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 42 | 0 | 42 | 3 | +| 41 | 0 | 41 | 3 | ## Client diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index c5d69a448ec3b0..2031219295dc04 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 28bf4b9cf34e0e..a498d9daf12156 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index a1cf418f9a407d..47ccf22f1d4c0f 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 27a7bee70ea33d..5ae45f329d207d 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 6130c361475734..b1841ff331163b 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 75a57004aebdea..0bcaf823d10531 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 0adfe5be982049..2928c1d74b0723 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index db68fbd49a2572..1dcd1ce588b5a8 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index f587f3f68875f4..06034d231565cf 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 2f3dc1c92f60d6..93c19543506a53 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 938ca42f41987e..de2998519b208b 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index fc85563f7f3102..c1ce80e4c5782b 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 7e487d52132f89..b1c36f670e74f8 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -16,28 +16,34 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Referencing plugin(s) | Remove By | | ---------------|-----------|-----------| -| | alerting, discover, securitySolution | - | +| | ml, stackAlerts | - | +| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, dataViews, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover, data | - | +| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, dataViews, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover, data | - | +| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, data, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover | - | +| | home, data, esUiShared, spaces, savedObjectsManagement, fleet, observability, ml, apm, enterpriseSearch, indexLifecycleManagement, synthetics, upgradeAssistant, ux, kibanaOverview | - | +| | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | +| | actions, ml, savedObjectsTagging, enterpriseSearch | - | +| | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, cases, fileUpload, maps, ml, infra, fleet, canvas, dashboardEnhanced, graph, monitoring, synthetics, transform, watcher, dataVisualizer, cloudSecurityPosture, securitySolution | - | +| | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, graph, securitySolution, synthetics, watcher, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | +| | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, presentationUtil, savedSearch, visualizations, dashboard, lens, savedObjectsFinder, cases, maps, ml, infra, cloudSecurityPosture, dashboardEnhanced, graph, securitySolution, synthetics, @kbn/core-saved-objects-browser-internal | - | +| | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, visualizations, dashboard, ml, infra, cloudSecurityPosture, dashboardEnhanced, monitoring, synthetics, @kbn/core-saved-objects-browser-internal | - | +| | @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, savedObjects, embeddable, presentationUtil, visualizations, dashboard, lens, savedObjectsFinder, aiops, ml, cases, maps, dataVisualizer, infra, fleet, cloudSecurityPosture, dashboardEnhanced, graph, synthetics, securitySolution, @kbn/core-saved-objects-browser-mocks | - | +| | @kbn/core-lifecycle-browser-mocks, @kbn/core, ml, dashboard, dataViews, savedSearch, @kbn/core-plugins-browser-internal | - | +| | @kbn/core, savedObjects, embeddable, visualizations, dashboard, fleet, infra, canvas, graph, ml, @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, actions, alerting, enterpriseSearch, securitySolution, taskManager, savedSearch, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | -| | alerting, discover, securitySolution | - | +| | infra, graph, stackAlerts, inputControlVis, securitySolution, savedObjects | - | +| | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | +| | alerting, discover, securitySolution | - | +| | alerting, discover, securitySolution | - | | | actions, alerting | - | -| | @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, @kbn/core, actions, alerting, canvas, enterpriseSearch, securitySolution, taskManager, dashboard, savedSearch, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server, savedObjects, embeddable, visualizations, fleet, infra, graph, ml | - | | | @kbn/core-saved-objects-migration-server-internal, actions, dataViews, data, alerting, savedObjectsTagging, canvas, lens, cases, graph, lists, maps, securitySolution, dashboard, savedSearch, visualizations, @kbn/core-test-helpers-so-type-serializer | - | | | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, discover, savedObjectsTagging, savedObjectsFinder, fleet, canvas, osquery, securitySolution, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, apm, savedObjectsTaggingOss, cases, lists, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, dashboard | - | | | @kbn/core-saved-objects-common, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, home, dataViews, discover, savedObjectsTagging, savedObjectsFinder, fleet, canvas, osquery, securitySolution, synthetics, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-import-export-server-internal, apm, savedObjectsTaggingOss, cases, lists, upgradeAssistant, savedObjectsManagement, @kbn/core-ui-settings-server-internal, data | - | -| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, dataViews, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover, data | - | | | discover | - | -| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, dataViews, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover, data | - | -| | @kbn/es-query, securitySolution, timelines, lists, threatIntelligence, data, unifiedSearch, triggersActionsUi, savedObjectsManagement, controls, unifiedFieldList, lens, aiops, ml, infra, visTypeTimeseries, apm, observability, dataVisualizer, fleet, canvas, graph, stackAlerts, synthetics, transform, upgradeAssistant, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, discover | - | | | data, discover, imageEmbeddable, embeddable | - | -| | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, embeddable, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, cases, fileUpload, maps, ml, infra, fleet, canvas, dashboardEnhanced, graph, monitoring, synthetics, transform, watcher, dataVisualizer, cloudSecurityPosture, securitySolution | - | | | advancedSettings, discover | - | -| | infra, graph, stackAlerts, inputControlVis, securitySolution, savedObjects | - | | | securitySolution | - | -| | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | -| | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, graph, securitySolution, synthetics, watcher, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | -| | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, presentationUtil, savedSearch, visualizations, dashboard, lens, savedObjectsFinder, cases, maps, ml, infra, cloudSecurityPosture, dashboardEnhanced, graph, securitySolution, synthetics, @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, savedObjects, embeddable, presentationUtil, visualizations, dashboard, lens, savedObjectsFinder, aiops, ml, cases, maps, dataVisualizer, infra, fleet, cloudSecurityPosture, dashboardEnhanced, graph, synthetics, securitySolution, @kbn/core-saved-objects-browser-mocks | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | @@ -50,9 +56,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | securitySolution | - | | | securitySolution | - | | | securitySolution | - | -| | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | monitoring | - | -| | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, visualizations, dashboard, ml, infra, cloudSecurityPosture, dashboardEnhanced, monitoring, synthetics, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjects, savedObjectsManagement, visualizations, savedObjectsTagging, lens, fleet, graph, dashboard, savedObjectsTaggingOss, kibanaUtils, expressions, dataViews, data, embeddable, controls, uiActionsEnhanced, maps, canvas, cases, dashboardEnhanced, globalSearchProviders, infra | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, savedSearch, visualizations, dashboard, lens, maps, infra, graph, synthetics | - | | | @kbn/core-saved-objects-browser-mocks, home, @kbn/core-saved-objects-browser-internal | - | @@ -76,15 +80,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-lifecycle-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, savedSearch, visualizations, dashboard, lens, savedObjectsFinder, observability, canvas, transform, @kbn/core-saved-objects-browser-mocks | - | +| | @kbn/core-lifecycle-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, savedSearch, visualizations, dashboard, lens, savedObjectsFinder, observability, canvas, transform, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core | - | | | @kbn/core | - | -| | @kbn/core-lifecycle-browser-mocks, @kbn/core, ml, dashboard, dataViews, savedSearch, @kbn/core-plugins-browser-internal | - | | | @kbn/core, lens, savedObjects, visualizations | - | | | @kbn/core | - | | | @kbn/core, advancedSettings, triggersActionsUi, visualizations | - | | | home, canvas, osquery | - | -| | home, data, esUiShared, spaces, savedObjectsManagement, fleet, observability, ml, apm, enterpriseSearch, indexLifecycleManagement, synthetics, upgradeAssistant, ux, kibanaOverview | - | | | dataViews, maps | - | | | dataViewManagement, dataViews | - | | | visTypeTimeseries, graph, dataViewManagement, dataViews | - | @@ -93,7 +95,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | dataViewManagement, dataViews | - | | | visTypeTimeseries, graph, dataViewManagement, dataViews | - | | | dataViews, dataViewManagement | - | -| | actions, ml, savedObjectsTagging, enterpriseSearch | - | | | observability, dataVisualizer, fleet, cloudSecurityPosture, discoverEnhanced, osquery, synthetics | - | | | canvas | - | | | canvas | - | @@ -120,8 +121,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | encryptedSavedObjects | - | | | @kbn/core-elasticsearch-server-internal, @kbn/core-plugins-server-internal, console | - | | | @kbn/core-plugins-server-internal | - | -| | spaces, security, alerting | 8.8.0 | +| | security, licenseManagement, ml, apm, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | 8.8.0 | | | spaces, security, actions, alerting, ml, remoteClusters, graph, indexLifecycleManagement, mapsEms, painlessLab, rollup, searchprofiler, securitySolution, snapshotRestore, transform, upgradeAssistant | 8.8.0 | +| | spaces, security, alerting | 8.8.0 | | | embeddable, presentationUtil, dashboard, discover, graph | 8.8.0 | | | apm, security, securitySolution | 8.8.0 | | | apm, security, securitySolution | 8.8.0 | @@ -131,7 +133,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | security, fleet | 8.8.0 | | | security, fleet | 8.8.0 | | | apm | 8.8.0 | -| | security, licenseManagement, ml, apm, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | 8.8.0 | | | security | 8.8.0 | | | mapsEms | 8.8.0 | | | security | 8.8.0 @@ -150,6 +151,7 @@ Safe to remove. | Deprecated API | Plugin Id | | ---------------|------------| +| | alerting | | | data | | | data | | | data | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index ec2e386d2715a8..ef311a52fa2a8a 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -339,7 +339,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [create_static_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts#:~:text=title), [create_static_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts#:~:text=title) | - | | | [create_static_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts#:~:text=title) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/plugin.ts#:~:text=environment) | 8.8.0 | -| | [app_root.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root.tsx#:~:text=RedirectAppLinks), [app_root.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root.tsx#:~:text=RedirectAppLinks), [app_root.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root.tsx#:~:text=RedirectAppLinks) | - | +| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root/index.tsx#:~:text=RedirectAppLinks), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root/index.tsx#:~:text=RedirectAppLinks), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/components/routing/app_root/index.tsx#:~:text=RedirectAppLinks) | - | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | | | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/public/context/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | @@ -446,7 +446,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/data/types.ts#:~:text=fieldFormats), [data_service.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/data/data_service.ts#:~:text=fieldFormats) | - | | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_container/embeddable/api/overlays/save_modal.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | | | [clone_panel_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx#:~:text=SavedObject), [clone_panel_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx#:~:text=SavedObject), [clone_panel_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx#:~:text=SavedObject) | 8.8.0 | -| | [dashboard_saved_object_service.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/dashboard_saved_object_service.ts#:~:text=savedObjects), [index.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/index.ts#:~:text=savedObjects), [index.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/index.ts#:~:text=savedObjects) | - | +| | [dashboard_saved_object_service.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/dashboard_saved_object_service.ts#:~:text=savedObjects), [index.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/index.ts#:~:text=savedObjects) | - | | | [load_dashboard_state_from_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/load_dashboard_state_from_saved_object.ts#:~:text=SavedObjectsClientContract), [load_dashboard_state_from_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/load_dashboard_state_from_saved_object.ts#:~:text=SavedObjectsClientContract), [save_dashboard_state_to_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/save_dashboard_state_to_saved_object.ts#:~:text=SavedObjectsClientContract), [save_dashboard_state_to_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/save_dashboard_state_to_saved_object.ts#:~:text=SavedObjectsClientContract), [find_dashboard_saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/find_dashboard_saved_objects.ts#:~:text=SavedObjectsClientContract), [find_dashboard_saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/find_dashboard_saved_objects.ts#:~:text=SavedObjectsClientContract), [find_dashboard_saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/find_dashboard_saved_objects.ts#:~:text=SavedObjectsClientContract), [find_dashboard_saved_objects.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/find_dashboard_saved_objects.ts#:~:text=SavedObjectsClientContract), [check_for_duplicate_dashboard_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/check_for_duplicate_dashboard_title.ts#:~:text=SavedObjectsClientContract), [check_for_duplicate_dashboard_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/check_for_duplicate_dashboard_title.ts#:~:text=SavedObjectsClientContract)+ 4 more | - | | | [save_dashboard_state_to_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/services/dashboard_saved_object/lib/save_dashboard_state_to_saved_object.ts#:~:text=create), [clone_panel_action.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx#:~:text=create) | - | | | [dashboard_listing.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/dashboard/public/dashboard_app/listing/dashboard_listing.tsx#:~:text=delete) | - | @@ -592,7 +592,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | ---------------|-----------|-----------| | | [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal), [attribute_service.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | | | [container.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/tests/container.test.ts#:~:text=executeTriggerActions), [container.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/tests/container.test.ts#:~:text=executeTriggerActions), [container.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/tests/container.test.ts#:~:text=executeTriggerActions), [container.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/tests/container.test.ts#:~:text=executeTriggerActions), [explicit_input.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/tests/explicit_input.test.ts#:~:text=executeTriggerActions) | - | -| | [plugin.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/plugin.tsx#:~:text=savedObjects) | - | | | [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SimpleSavedObject), [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SimpleSavedObject), [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SimpleSavedObject) | - | | | [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SavedObjectAttributes), [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SavedObjectAttributes), [add_panel_flyout.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx#:~:text=SavedObjectAttributes), [default_embeddable_factory_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/embeddables/default_embeddable_factory_provider.ts#:~:text=SavedObjectAttributes), [default_embeddable_factory_provider.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/lib/embeddables/default_embeddable_factory_provider.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/public/types.ts#:~:text=SavedObjectAttributes) | - | | | [migrate_base_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/common/lib/migrate_base_input.ts#:~:text=SavedObjectReference), [migrate_base_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/common/lib/migrate_base_input.ts#:~:text=SavedObjectReference), [migrate_base_input.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/common/lib/migrate_base_input.ts#:~:text=SavedObjectReference), [inject.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/common/lib/inject.ts#:~:text=SavedObjectReference), [inject.ts](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable/common/lib/inject.ts#:~:text=SavedObjectReference) | - | @@ -696,7 +695,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [deserialize.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.ts#:~:text=getNonScriptedFields), [datasource.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/datasource.test.ts#:~:text=getNonScriptedFields), [deserialize.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.test.ts#:~:text=getNonScriptedFields), [deserialize.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.test.ts#:~:text=getNonScriptedFields) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/server/plugin.ts#:~:text=license%24) | 8.8.0 | | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/save_modal.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | -| | [source_picker.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/source_picker.tsx#:~:text=savedObjects), [source_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/source_modal.tsx#:~:text=savedObjects), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/plugin.ts#:~:text=savedObjects), [search_bar.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/search_bar.tsx#:~:text=savedObjects), [guidance_panel.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx#:~:text=savedObjects) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/plugin.ts#:~:text=savedObjects) | - | | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/save_modal.tsx#:~:text=SavedObjectsClientContract), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/save_modal.tsx#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/store.ts#:~:text=SavedObjectsClientContract), [store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/store.ts#:~:text=SavedObjectsClientContract), [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=SavedObjectsClientContract)+ 5 more | - | | | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=create), [saved_workspace_utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts#:~:text=create) | - | | | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=delete) | - | @@ -892,6 +891,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| +| | [register_ml_alerts.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts#:~:text=registerNavigation) | - | | | [index_patterns.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts#:~:text=title), [rollup.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts#:~:text=title), [alerting_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts#:~:text=title), [data_recognizer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts#:~:text=title), [configuration_step_details.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_details.tsx#:~:text=title), [data_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title)+ 40 more | - | | | [index_patterns.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts#:~:text=title), [rollup.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts#:~:text=title), [alerting_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts#:~:text=title), [data_recognizer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts#:~:text=title), [configuration_step_details.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_details.tsx#:~:text=title), [data_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title)+ 40 more | - | | | [index_patterns.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_frame_analytics/index_patterns.ts#:~:text=title), [rollup.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts#:~:text=title), [alerting_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts#:~:text=title), [data_recognizer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts#:~:text=title), [configuration_step_details.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_details.tsx#:~:text=title), [data_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title), [use_index_data.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts#:~:text=title)+ 15 more | - | @@ -900,11 +900,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/plugin.ts#:~:text=license%24) | 8.8.0 | | | [annotations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/routes/annotations.ts#:~:text=authc) | - | | | [initialization.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/saved_objects/initialization/initialization.ts#:~:text=authz), [sync_task.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/saved_objects/sync_task.ts#:~:text=authz), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/plugin.ts#:~:text=authz), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/server/plugin.ts#:~:text=authz) | - | -| | [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/app.tsx#:~:text=savedObjects), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/app.tsx#:~:text=savedObjects), [page.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx#:~:text=savedObjects), [change_data_view.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx#:~:text=savedObjects), [source_selection.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx#:~:text=savedObjects), [dashboard_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.ts#:~:text=savedObjects) | - | +| | [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/app.tsx#:~:text=savedObjects), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/app.tsx#:~:text=savedObjects), [dashboard_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.ts#:~:text=savedObjects) | - | | | [dependency_cache.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/util/dependency_cache.ts#:~:text=SavedObjectsClientContract), [dependency_cache.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/util/dependency_cache.ts#:~:text=SavedObjectsClientContract), [use_resolver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/routing/use_resolver.ts#:~:text=SavedObjectsClientContract), [use_resolver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/routing/use_resolver.ts#:~:text=SavedObjectsClientContract), [use_resolver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/routing/use_resolver.ts#:~:text=SavedObjectsClientContract), [dashboard_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.ts#:~:text=SavedObjectsClientContract), [dashboard_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.ts#:~:text=SavedObjectsClientContract), [router.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/routing/router.tsx#:~:text=SavedObjectsClientContract), [router.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/routing/router.tsx#:~:text=SavedObjectsClientContract) | - | | | [index_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/util/index_utils.ts#:~:text=find), [resolvers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts#:~:text=find), [dashboard_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.ts#:~:text=find), [dashboard_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts#:~:text=find) | - | | | [index_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/util/index_utils.ts#:~:text=get), [route_resolver.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/route_resolver.ts#:~:text=get) | - | -| | [kibana.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/kibana.ts#:~:text=SimpleSavedObject), [kibana.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/kibana.ts#:~:text=SimpleSavedObject), [source_selection.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx#:~:text=SimpleSavedObject), [source_selection.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx#:~:text=SimpleSavedObject) | - | +| | [kibana.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/kibana.ts#:~:text=SimpleSavedObject), [kibana.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/kibana.ts#:~:text=SimpleSavedObject) | - | | | [dashboard_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts#:~:text=savedObjectsServiceMock), [dashboard_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts#:~:text=savedObjectsServiceMock) | - | | | [modules.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/modules.ts#:~:text=SavedObjectAttributes), [modules.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/ml/common/types/modules.ts#:~:text=SavedObjectAttributes) | - | @@ -991,17 +991,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject) | - | | | [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=indexPatterns), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=indexPatterns) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObject) | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/plugin.ts#:~:text=savedObjects), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=savedObjects) | - | +| | [plugin.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/plugin.ts#:~:text=savedObjects) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectsClientContract), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectsClientContract), [initialize_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#:~:text=SavedObjectsClientContract), [initialize_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SavedObjectsClientContract), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=SavedObjectsClientContract), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=SavedObjectsClientContract)+ 5 more | - | | | [create_source.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/create_source.ts#:~:text=create), [create_source.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/create_source.ts#:~:text=create), [save_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts#:~:text=create), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=create), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=create), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=create), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=create), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=create), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=create), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=create)+ 9 more | - | | | [build_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts#:~:text=delete) | - | -| | [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=find), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=find), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=find), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=find), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=find) | - | +| | [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=find), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=find), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=find), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=find) | - | | | [initialize_saved_object.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/initialize_saved_object.ts#:~:text=get), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=get) | - | | | [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=bulkGet) | - | | | [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=update) | - | -| | [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SimpleSavedObject)+ 15 more | - | +| | [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject), [saved_object.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/saved_object.test.ts#:~:text=SimpleSavedObject)+ 4 more | - | | | [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions) | - | -| | [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SavedObjectsStart), [saved_object_finder.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/finder/saved_object_finder.tsx#:~:text=SavedObjectsStart) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectAttributes), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectAttributes), [create_source.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/create_source.ts#:~:text=SavedObjectAttributes), [create_source.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/create_source.ts#:~:text=SavedObjectAttributes), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SavedObjectAttributes), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts#:~:text=SavedObjectAttributes), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.ts#:~:text=SavedObjectAttributes)+ 15 more | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects/public/types.ts#:~:text=SavedObjectReference) | - | @@ -1172,6 +1171,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts#:~:text=registerNavigation) | - | | | [fetch_search_source_query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts#:~:text=fetch), [rule_type.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts#:~:text=fetch), [rule_type.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts#:~:text=fetch) | - | | | [boundary_index_expression.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/query_builder/expressions/boundary_index_expression.tsx#:~:text=indexPatterns), [entity_index_expression.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/query_builder/expressions/entity_index_expression.tsx#:~:text=indexPatterns), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/query_builder/index.tsx#:~:text=indexPatterns), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/query_builder/index.tsx#:~:text=indexPatterns), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/geo_containment/query_builder/index.tsx#:~:text=indexPatterns) | - | | | [expression.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/stack_alerts/public/rule_types/threshold/expression.tsx#:~:text=fieldFormats) | - | @@ -1388,7 +1388,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.test.ts#:~:text=SavedObjectsCreateOptions) | - | | | [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectsFindOptions), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectsFindOptions) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/types.ts#:~:text=ResolvedSimpleSavedObject) | - | -| | [services.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectsStart), [services.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectsStart), [search_selection.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx#:~:text=SavedObjectsStart), [search_selection.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx#:~:text=SavedObjectsStart), [new_vis_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/wizard/new_vis_modal.tsx#:~:text=SavedObjectsStart), [new_vis_modal.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/wizard/new_vis_modal.tsx#:~:text=SavedObjectsStart) | - | +| | [services.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectsStart), [services.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/services.ts#:~:text=SavedObjectsStart) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock) | - | | | [saved_visualization_references.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts#:~:text=SavedObjectAttribute), [saved_visualization_references.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts#:~:text=SavedObjectAttribute) | - | | | [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectAttributes), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectAttributes), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/find_object_by_title.ts#:~:text=SavedObjectAttributes), [find_object_by_title.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_objects_utils/find_object_by_title.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes), [saved_visualize_utils.ts](https://github.com/elastic/kibana/tree/main/src/plugins/visualizations/public/utils/saved_visualize_utils.ts#:~:text=SavedObjectAttributes)+ 11 more | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 1c7ec65271f44f..9a3512c26dfa5f 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 19c685f5d07f50..e19682fd4a70f2 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 676ad6ce01b701..c4945141138088 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -240,70 +240,6 @@ } ], "interfaces": [ - { - "parentPluginId": "discover", - "id": "def-public.DiscoverGridSettings", - "type": "Interface", - "tags": [], - "label": "DiscoverGridSettings", - "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "discover", - "id": "def-public.DiscoverGridSettings.columns", - "type": "Object", - "tags": [], - "label": "columns", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "discover", - "id": "def-public.DiscoverGridSettingsColumn", - "type": "Interface", - "tags": [], - "label": "DiscoverGridSettingsColumn", - "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "discover", - "id": "def-public.DiscoverGridSettingsColumn.width", - "type": "number", - "tags": [], - "label": "width", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "discover", "id": "def-public.ISearchEmbeddable", @@ -376,543 +312,36 @@ "tags": [], "label": "SavedSearch", "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.searchSource", - "type": "Object", - "tags": [], - "label": "searchSource", - "description": [], - "signature": [ - "{ create: () => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; fetch: (options?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceSearchOptions", - "text": "SearchSourceSearchOptions" - }, - ") => Promise<", - "SearchResponse", - ">>; history: ", - "SearchRequest", - "[]; setOverwriteDataViewType: (overwriteType: string | false | undefined) => void; setField: (field: K, value: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceFields", - "text": "SearchSourceFields" - }, - "[K]) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; removeField: (field: K) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; setFields: (newFields: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceFields", - "text": "SearchSourceFields" - }, - ") => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; getId: () => string; getFields: () => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceFields", - "text": "SearchSourceFields" - }, - "; getField: (field: K, recurse?: boolean) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceFields", - "text": "SearchSourceFields" - }, - "[K]; getActiveIndexFilter: () => any[]; getOwnField: (field: K) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceFields", - "text": "SearchSourceFields" - }, - "[K]; createCopy: () => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; createChild: (options?: {}) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; setParent: (parent?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.ISearchSource", - "text": "ISearchSource" - }, - " | undefined, options?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceOptions", - "text": "SearchSourceOptions" - }, - ") => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - "; getParent: () => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - " | undefined; fetch$: (options?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceSearchOptions", - "text": "SearchSourceSearchOptions" - }, - ") => ", - "Observable", - "<", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.IKibanaSearchResponse", - "text": "IKibanaSearchResponse" - }, - "<", - "SearchResponse", - ">>>; onRequestStart: (handler: (searchSource: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSource", - "text": "SearchSource" - }, - ", options?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSourceSearchOptions", - "text": "SearchSourceSearchOptions" - }, - " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean, includeFields?: boolean) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SerializedSearchSourceFields", - "text": "SerializedSearchSourceFields" - }, - "; serialize: () => { searchSourceJSON: string; references: ", - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[]; }; toExpressionAst: ({ asDatatable }?: ExpressionAstOptions) => ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.ExpressionAstExpression", - "text": "ExpressionAstExpression" - }, - "; parseActiveIndexPatternFromQueryString: (queryString: string) => string[]; }" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.sort", - "type": "Array", - "tags": [], - "label": "sort", - "description": [], - "signature": [ - "SortOrder", - "[] | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.columns", - "type": "Array", - "tags": [], - "label": "columns", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.tags", - "type": "Array", - "tags": [], - "label": "tags", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.grid", - "type": "Object", - "tags": [], - "label": "grid", - "description": [], - "signature": [ - "{ columns?: Record | undefined; } | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.hideChart", - "type": "CompoundType", - "tags": [], - "label": "hideChart", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.sharingSavedObjectProps", - "type": "Object", - "tags": [], - "label": "sharingSavedObjectProps", - "description": [], - "signature": [ - "{ outcome?: \"conflict\" | \"exactMatch\" | \"aliasMatch\" | undefined; aliasTargetId?: string | undefined; aliasPurpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; errorJSON?: string | undefined; } | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.viewMode", - "type": "CompoundType", - "tags": [], - "label": "viewMode", - "description": [], - "signature": [ - { - "pluginId": "savedSearch", - "scope": "public", - "docId": "kibSavedSearchPluginApi", - "section": "def-public.VIEW_MODE", - "text": "VIEW_MODE" - }, - " | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.hideAggregatedPreview", - "type": "CompoundType", - "tags": [], - "label": "hideAggregatedPreview", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.rowHeight", - "type": "number", - "tags": [], - "label": "rowHeight", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.isTextBasedQuery", - "type": "CompoundType", - "tags": [], - "label": "isTextBasedQuery", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.usesAdHocDataView", - "type": "CompoundType", - "tags": [], - "label": "usesAdHocDataView", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.timeRestore", - "type": "CompoundType", - "tags": [], - "label": "timeRestore", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.timeRange", - "type": "Object", - "tags": [], - "label": "timeRange", - "description": [], - "signature": [ - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataQueryPluginApi", - "section": "def-common.TimeRange", - "text": "TimeRange" - }, - " | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "signature": [ { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.refreshInterval", - "type": "Object", - "tags": [], - "label": "refreshInterval", - "description": [], - "signature": [ - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataQueryPluginApi", - "section": "def-common.RefreshInterval", - "text": "RefreshInterval" - }, - " | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearch", + "text": "SavedSearch" }, + " extends ", { - "parentPluginId": "discover", - "id": "def-public.SavedSearch.rowsPerPage", - "type": "number", - "tags": [], - "label": "rowsPerPage", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "pluginId": "savedSearch", + "scope": "common", + "docId": "kibSavedSearchPluginApi", + "section": "def-common.SavedSearch", + "text": "SavedSearch" + } + ], + "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "discover", - "id": "def-public.SavedSearch.breakdownField", - "type": "string", + "id": "def-public.SavedSearch.sharingSavedObjectProps", + "type": "Object", "tags": [], - "label": "breakdownField", + "label": "sharingSavedObjectProps", "description": [], "signature": [ - "string | undefined" + "{ outcome?: \"conflict\" | \"exactMatch\" | \"aliasMatch\" | undefined; aliasTargetId?: string | undefined; aliasPurpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; errorJSON?: string | undefined; } | undefined" ], "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", "deprecated": false, @@ -1094,20 +523,7 @@ "initialIsOpen": false } ], - "enums": [ - { - "parentPluginId": "discover", - "id": "def-public.VIEW_MODE", - "type": "Enum", - "tags": [], - "label": "VIEW_MODE", - "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "enums": [], "misc": [ { "parentPluginId": "discover", @@ -1224,10 +640,306 @@ "server": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginLocatorService", + "type": "Interface", + "tags": [], + "label": "DiscoverServerPluginLocatorService", + "description": [], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginLocatorService.asScopedClient", + "type": "Function", + "tags": [], + "label": "asScopedClient", + "description": [], + "signature": [ + "(req: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + ") => Promise<", + { + "pluginId": "discover", + "scope": "server", + "docId": "kibDiscoverPluginApi", + "section": "def-server.LocatorServiceScopedClient", + "text": "LocatorServiceScopedClient" + }, + ">" + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginLocatorService.asScopedClient.$1", + "type": "Object", + "tags": [], + "label": "req", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "common", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-common.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginStartDeps", + "type": "Interface", + "tags": [], + "label": "DiscoverServerPluginStartDeps", + "description": [], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginStartDeps.data", + "type": "Object", + "tags": [], + "label": "data", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "server", + "docId": "kibDataPluginApi", + "section": "def-server.DataPluginStart", + "text": "DataPluginStart" + } + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient", + "type": "Interface", + "tags": [], + "label": "LocatorServiceScopedClient", + "description": [], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.columnsFromLocator", + "type": "Function", + "tags": [], + "label": "columnsFromLocator", + "description": [], + "signature": [ + "(params: ", + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + }, + ") => Promise" + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.columnsFromLocator.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + } + ], + "path": "src/plugins/discover/server/locator/columns_from_locator.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.searchSourceFromLocator", + "type": "Function", + "tags": [], + "label": "searchSourceFromLocator", + "description": [], + "signature": [ + "(params: ", + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + }, + ") => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSource", + "text": "SearchSource" + }, + ">" + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.searchSourceFromLocator.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + } + ], + "path": "src/plugins/discover/server/locator/searchsource_from_locator.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.titleFromLocator", + "type": "Function", + "tags": [], + "label": "titleFromLocator", + "description": [], + "signature": [ + "(params: ", + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + }, + ") => Promise" + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.LocatorServiceScopedClient.titleFromLocator.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + } + ], + "path": "src/plugins/discover/server/locator/title_from_locator.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [], - "objects": [] + "objects": [], + "start": { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginStart", + "type": "Interface", + "tags": [], + "label": "DiscoverServerPluginStart", + "description": [], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-server.DiscoverServerPluginStart.locator", + "type": "Object", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "server", + "docId": "kibDiscoverPluginApi", + "section": "def-server.DiscoverServerPluginLocatorService", + "text": "DiscoverServerPluginLocatorService" + } + ], + "path": "src/plugins/discover/server/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "lifecycle": "start", + "initialIsOpen": true + } }, "common": { "classes": [ diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 8a6210844db85e..6af7f3c703902b 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 107 | 0 | 88 | 7 | +| 97 | 0 | 78 | 7 | ## Client @@ -37,12 +37,17 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k ### Interfaces -### Enums - - ### Consts, variables and types +## Server + +### Start + + +### Interfaces + + ## Common ### Classes diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index b4551b83e1726e..14819947d3e54a 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 53b17c01735eed..1e6a21f7c81711 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 2912d2b5985538..161766f380f10c 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 82c1486689a802..efe75258646d6b 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 561e5511d4f8af..4d58390c80b3c2 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 5d733937366968..8184578800fdf1 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index a11bb262d597b4..722fe7bde8d818 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 307341e1df79e4..d2f42a849ddb1f 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index f3b90aefa2917e..c0d159cf945b00 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 125882023b0c2e..80baa289f0e2ed 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 3d1e900efdc637..b9dccdadd3bc39 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index 8317a90f00b9c1..5811a29f8bfadd 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 84335fca321f14..88bdd4792667ec 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 7d2a39d25068c9..a6caeb0d77c18a 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 5f56c15876bf5c..f43139104ef14d 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index be0ea397efef9b..93a50653e87f8a 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 8c3f99da4e44f5..56a58c391c3752 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 231d4bfd3ee604..362ca0c24aea24 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index bde358a7e3d111..72fdf146aa4417 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index a3137a10e5a543..ddbaeb42b1332c 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index fdb7580f7242a1..10a0bcb9bf6ad6 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 06ca3e0a50bed0..a5797770c3a7c5 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index facc3ced120158..f43af727a8cc1b 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 7a7b44331611fe..9e3bba7f9e3073 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 7d81280fae05d8..5b0aacb51f4ea8 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 11ba5bd516c9c0..3d3220e6d71d5f 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 66f541c80817c9..5e5cbfb19c6e9d 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 8df86ca78898fe..675ad45079f839 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 214d8176f9d541..283f0825aebf70 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -5481,6 +5481,17 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "fleet", + "id": "def-server.MessageSigningServiceInterface.isEncryptionAvailable", + "type": "boolean", + "tags": [], + "label": "isEncryptionAvailable", + "description": [], + "path": "x-pack/plugins/fleet/server/services/security/message_signing_service.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-server.MessageSigningServiceInterface.generateKeyPair", @@ -5489,7 +5500,7 @@ "label": "generateKeyPair", "description": [], "signature": [ - "(providedPassphrase?: string | undefined) => Promise" + "(providedPassphrase?: string | undefined) => Promise<{ privateKey: string; publicKey: string; passphrase: string; }>" ], "path": "x-pack/plugins/fleet/server/services/security/message_signing_service.ts", "deprecated": false, @@ -5521,7 +5532,7 @@ "label": "sign", "description": [], "signature": [ - "(serializedMessage: object | Buffer) => Promise<{ data: Buffer; signature: string; }>" + "(message: Record | Buffer) => Promise<{ data: Buffer; signature: string; }>" ], "path": "x-pack/plugins/fleet/server/services/security/message_signing_service.ts", "deprecated": false, @@ -5532,10 +5543,10 @@ "id": "def-server.MessageSigningServiceInterface.sign.$1", "type": "CompoundType", "tags": [], - "label": "serializedMessage", + "label": "message", "description": [], "signature": [ - "object | Buffer" + "Record | Buffer" ], "path": "x-pack/plugins/fleet/server/services/security/message_signing_service.ts", "deprecated": false, @@ -17698,7 +17709,21 @@ "label": "agent", "description": [], "signature": [ - "{ monitoring: { namespace?: string | undefined; use_output?: string | undefined; enabled: boolean; metrics: boolean; logs: boolean; }; download: { sourceURI: string; }; features: Record; } | undefined" + "{ monitoring: { namespace?: string | undefined; use_output?: string | undefined; enabled: boolean; metrics: boolean; logs: boolean; }; download: { sourceURI: string; }; features: Record; protection?: { enabled: boolean; uninstall_token_hash: string; signing_key: string; } | undefined; } | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.FullAgentPolicy.signed", + "type": "Object", + "tags": [], + "label": "signed", + "description": [], + "signature": [ + "{ data: string; signature: string; } | undefined" ], "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 104b2550f6c8d1..953b463a745487 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1077 | 3 | 972 | 26 | +| 1079 | 3 | 974 | 26 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 937f7ac4b119fe..6202396e1e7cb7 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 4f4fe8e1456a58..7bbd0b618c9083 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 474bcb99cb0628..b1940dbc190b28 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 53b82662e70ac0..231db4c6bebdbd 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 173f639693ca27..c6c75389f83a3b 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 4f8d00209d4c0e..ea16aa53a349b2 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index cf1fdb6cd1dbf6..704f12fc8722c8 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 51e4f190a255e2..bca3c119936516 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index e0fff424e74a4d..17875d743a453e 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index ca1b4c40d2f7f1..f9b3a60039b241 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 1606fb0e50684a..c9696a8715dbc1 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 6fba76a809cd2e..ab74febebf3dae 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 82f35c41759dc9..427b8b5e49ce6b 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 5fdb1e6590ba67..e216fcc07dda8c 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index f35a33e3b53ca4..f635927f86b0b7 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 59fd65a0247f4f..e2d5952a3729fb 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index cfa2f738df4918..f02f5e1c1c212a 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index d82f788dae55da..e5d41537a41fd0 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 4712186a07c5a1..5c5ef1306ffec5 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 8ffb3c3bc5fe10..d9b6680f5bc8f7 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 3e438262ecca9d..4d3dff27228a7d 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 18a19762249958..635d6bd97cbb28 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 227c058ff12ee1..fafa6c8e15455e 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index b4d728183292c7..4fb46699074496 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 779dc409d9d707..0fe3cdd8230a99 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index f475efa0992182..2db64454f2fed7 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 041a9e55d93cfd..2df6c87d68c6d5 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index da4ff62497a805..4095c4a302ca31 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 17064fabba6b5c..3fc4f3a6dfbfa2 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index a60e53f32a4cd0..cb0ec12455375a 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 68de0b62c5a18f..cbbaab83c591df 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 0e23290944f235..7b27011a7c775c 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 7eaab16696ac0e..7cc043207929fe 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index e813b270b05ad4..32ef0cd5402a52 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 8335aa8cff0db6..b732297b203fce 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index a76d50d334c99f..3af81131ee414a 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 9cab1e3bdd9e18..dd9ec036c7ca74 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 5075ef437b7f41..4482c7f5dff183 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index 07d4a5ad4cb324..e1ee7cdc865a91 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 831b6c4fcdb46f..0aa3db7aff995c 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index e3861fec754c96..02cf81a71786b7 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index affaac3e161a18..ea0f9f2e35dc98 100644 --- a/api_docs/kbn_content_management_table_list.mdx +++ b/api_docs/kbn_content_management_table_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list title: "@kbn/content-management-table-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list'] --- import kbnContentManagementTableListObj from './kbn_content_management_table_list.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index a09d2e8bea242b..966d45b50d6650 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index f5219f7fc0df87..39288e860fd133 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 12aadc3f5deed8..fa4f7b3aa11127 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 444b341061a62a..66d85ba70e6ac2 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 7a4e26b857c356..1c99d0541add89 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index c4cecd592eaccf..7d80eb71e06eee 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index f05396da060f6e..e940ee965a1191 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 660446ef7de3a4..6c2c21928f147b 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index 58c0e76feab1c8..68468e5fb340b6 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 8bd8e48fd4d406..72ee977d01ee9d 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 8f4ab9c447eb11..3d2f5364882b44 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 9bbe05de78d9ce..3710af98fb3484 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index 05d50e1f0ffc2f..e880d11da6141e 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 1a8ca86255726b..9ee2552a2662bd 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 8e40919cc1bf50..412fdaf7d49567 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 1693575cbe2c5c..da8667ec9f4a53 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index f702115a5ac99d..d6b453ce2cdff9 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 3f06a33b7dcf7c..6cf8d2552bcbbe 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 58fd806777089d..4a0d4e62fcdcbc 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 5f93533d4d4752..8e0e23e4a006f5 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 79e1e625d5b0bb..8da4a0abfb4f64 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index ea47ce0af36779..8220f61b3b7602 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index af1a5a0dafe599..b6abbdc10bce1c 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 6362f2d68afa5b..dee1ad581964d2 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 751b8ceb6997ed..1ef5500a4a1127 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 0970bfed9dfd17..0d1bfd645fd6b8 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 242cc78e194e4c..41652a24b2de27 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index cb104de0f3a910..510c39c7640016 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 4548203f354380..41c69f6a08c325 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index 34f15270bcc594..bc2b2aff1d9afe 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index 4f135027be15b7..627967fc335b42 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 5e435db4ed9f2b..8ef75740987ebd 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index 67dd2b40c88499..7901f9a98a7e43 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index 6d42570d313d9e..e2d7bcda0a2a9a 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index a36203ad8d7e8e..40bb2bbfc1b856 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index e04f2c8cbf322c..27b6d914c85f67 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index 439a58d3a11c0f..bc66b55f84bc69 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 6a563922f9daa7..8a9ccdacf34fe4 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 75c5f7bb938b77..32f0252b272b99 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 44840c821f5e55..c525c3a50c64d7 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 64969c735503da..abb6ba6f2cfecf 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 2dd8383a610d56..e3b7db75215b8f 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 38966007acf5bb..ac9a8ab04a956b 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 3bd1df9846b8ba..1b841b939d0685 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 631f9c532d6307..ff9026332740a6 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index b818d2619b912e..ff08543c85012e 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 5123ca8672c484..b489cb0a0e5fc1 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index d4e4417a37bf98..41eb176aeb1b19 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index cf67ec9c49b6ed..da9070bbd9d5b3 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 6fa0f62e7c061d..91a1eb7e95d141 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 2c0c51bbb9fa92..4ac62f82f9a47c 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 72467bb10b4687..5a3747e4e07f2d 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index a10a0976d2a253..0732a260a34ce0 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 634c603bb37364..20f52ba6731eb4 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 37f5bbcfce1104..124a09ff699067 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 99060386eabee8..f519ee25f8939c 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index d8d41b071e5cb4..affcecc3d105c1 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 6ca44e245f46ec..09744283fb9958 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index d87730c83727f3..9ae008e7d011ae 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 705c70bb5e5ab4..24b19ae8f1d733 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index f9133dc61749e0..0dc8effe9371bb 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index c7259953ec24d4..193eb2c930e792 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 78f90f7282dd95..5ce70258f0b49b 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 27dbea18682810..144b306e158945 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 99113071382213..a83b82030ec1cf 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 78bdee40138a61..c1ae8be00852ab 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index eb27ccf7cbc01f..ec2499cd82c663 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 173c69eddff16a..0e95e8581367eb 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index fc9226ec23be35..292c9086ece262 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 7ce0427e580c1d..d06fc41f1decbb 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 59a8a8a986d602..5f70eaeac64017 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 9a9f3a39d847f8..6812b745be87e4 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 56435821ea3690..b51b90da236ea1 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 0e1d73497c91e4..f0197ce673b94f 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index 4283549d44b6a6..bc9fbd36bef6d1 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index dbae1eb5468c43..5608bbe4928309 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 1fead6619e9bfa..0396bf48da5d14 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 1b23e10c1806e6..179135ccbfd407 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 1070e020a552b1..d459bf1aeaa3a0 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index d5d61b95e8a64a..205ac88f5e4702 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.devdocs.json b/api_docs/kbn_core_lifecycle_browser.devdocs.json index 69669e96d4319b..bd667ba0286a28 100644 --- a/api_docs/kbn_core_lifecycle_browser.devdocs.json +++ b/api_docs/kbn_core_lifecycle_browser.devdocs.json @@ -577,14 +577,6 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/plugin.ts" }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "embeddable", - "path": "src/plugins/embeddable/public/plugin.tsx" - }, { "plugin": "unifiedSearch", "path": "src/plugins/unified_search/public/types.ts" @@ -633,10 +625,6 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_actions/index.ts" }, - { - "plugin": "dashboard", - "path": "src/plugins/dashboard/public/dashboard_actions/index.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/lens_attribute_service.ts" @@ -777,14 +765,6 @@ "plugin": "dashboardEnhanced", "path": "x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/components/collect_config_container.tsx" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/components/source_picker.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/services/source_modal.tsx" - }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/plugin.ts" @@ -865,18 +845,6 @@ "plugin": "dataVisualizer", "path": "x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx" }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx" - }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx" - }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx" - }, { "plugin": "ml", "path": "x-pack/plugins/ml/public/application/services/dashboard_service.ts" @@ -885,14 +853,6 @@ "plugin": "cloudSecurityPosture", "path": "x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_rules.ts" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/components/search_bar.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/hooks/use_dashboard_button_href.ts" diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index ec5a983e343d24..6d6d9a2bb00f24 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index b462c1a7b87848..306399cce59292 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index de0633c626b8c3..c53509c3542d86 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index c1bc57c3c55ef9..b08743a11140ac 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 2a2be06bffdf30..b6e432314e9bba 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index 694bff205ef67b..c78fcd55ebefc3 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index fa6b6deac04e7f..939b44ee1b714e 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 28a3dfe8e7b6ab..8053ab596c4785 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 914ad4cbd97799..140fd197caed0f 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 7ad9c4c8578232..d36475ee881a3b 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 916241b138610c..1daf6aad8e8fee 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index b397d7e6d42fc5..10e6282332ea74 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 7559367cad6e64..43685ad91870f0 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index c3b34f91967fac..069d9964aaae0f 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 8059612a8bd692..8acfeb3f25e3cd 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 4530ad8ae700e7..4c64ebacd23f6d 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index c0c54e87c07f5d..6e24319a666e3a 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 70edb49e359261..c65c52f49f4730 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index bb1d3ec670f6bc..77a16b07643c21 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index c759d1dbe23065..26a3363d26fbce 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 21f5e0487657fb..47a67777326239 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 49cdf84b8a81d6..46f1c5fc8196c0 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index d2f6135b86b98e..fade1b5a20320f 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 3662d97f6916fb..339686def13c02 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 735deb2923ddc3..92bea55f56f76e 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index da0ef8f5cbf4d1..33347b183b6a76 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 7f05061343161e..4ff83cf8191d26 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 1bb5d6f6bda0e4..dc367f111add37 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 978edbf1e331e2..e0d550041cfc50 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 0d641275140a54..e4b629ab32037f 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 238337e8755346..2b735abc2620bf 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 207c50bbbb8c77..8c265cb3c7e6ca 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 9ed3166096ace5..06b40ffd1cdb3d 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 6aabab831ddcbd..a060864d5066e3 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index c2152fcd5914f0..35826ef8cc505a 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -2207,10 +2207,6 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts" }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, { "plugin": "presentationUtil", "path": "src/plugins/presentation_util/public/services/dashboards/dashboards_service.ts" @@ -3916,50 +3912,6 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/find_object_by_title.ts" }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, { "plugin": "embeddable", "path": "src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx" @@ -4152,14 +4104,6 @@ "plugin": "dataVisualizer", "path": "x-pack/plugins/data_visualizer/common/types/index.ts" }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx" - }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx" - }, { "plugin": "infra", "path": "x-pack/plugins/infra/public/hooks/use_create_saved_object.tsx" diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index ecbeabe4e3065a..f0edb4776f5ad7 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index dbc1314565879e..a7cde7f878840d 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_internal.mdx b/api_docs/kbn_core_saved_objects_api_server_internal.mdx index 8772394c5e46fe..8b9e4f3ba610b0 100644 --- a/api_docs/kbn_core_saved_objects_api_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-internal title: "@kbn/core-saved-objects-api-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-internal'] --- import kbnCoreSavedObjectsApiServerInternalObj from './kbn_core_saved_objects_api_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 9c4fa5819cce4e..f73eab4ae5a5b5 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index 23c6c35c2039cc..3a7bbd2e549773 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 651e7e4097aa47..1bfa37135bf738 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.devdocs.json b/api_docs/kbn_core_saved_objects_browser.devdocs.json index d40aa8ce76ba92..ee794076334b80 100644 --- a/api_docs/kbn_core_saved_objects_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_browser.devdocs.json @@ -57,14 +57,6 @@ "plugin": "@kbn/core", "path": "src/core/public/index.ts" }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, - { - "plugin": "savedObjects", - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx" - }, { "plugin": "savedSearch", "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts" @@ -81,22 +73,6 @@ "plugin": "visualizations", "path": "src/plugins/visualizations/public/services.ts" }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx" - }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx" - }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/wizard/new_vis_modal.tsx" - }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/public/wizard/new_vis_modal.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx" diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index c154f02694307f..c9f7d61a8cd39b 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 5ae5a82ee42372..50387786c60ff0 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index fdcf9166372ff6..8605324724902f 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index b7b195fba35285..0e20bceeb25569 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index a38e20bace754f..9284ecaae1c2e1 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index 549bf381786d72..7b3b9b8536d31a 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 8c20317335a2ca..32f3c5b7b66551 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index 6a8c24a0190d1d..a1d597c1c6fe5f 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 48022a5f10927b..3d87c55f1428c3 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 77b2f3e60023e8..d56b7f4bbfd159 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index c85ff0bd026e4c..4404fda72564c7 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 759fcc31b19dc8..7ce5cb45bdeb15 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index f766dbf91f4ed5..9c64990d286b00 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index a32de019c776b9..424888c8aa2b6d 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 1438b8b6b16db3..6477075fa3bfc0 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index f033238f498116..6782772b8c2281 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 61067f029fc723..4b77a88937a30e 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 0fc6c866a1a8a4..ae5239538d38d0 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 2120cc7ec4efcb..f70e4c3534ed7a 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 9458a3945d4c7a..14d9281233b2e3 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 65aab7d20315ac..0270000c32ef3b 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 310aa92948b17a..996595528a76e9 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 035f88057b053b..68891b4c19a723 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index d06104243dc199..ec326db54267f2 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 5fbcd1be9692a7..12ceb96f1f9530 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index a83b90b2748f78..1433e8e0b8451b 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 5aba39e5b836e3..ce0be9d0eecfc1 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index c5c4cf61ca2a65..b56e363c1707b0 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index ca30857413d36a..4383dc30150f4c 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 9c9484b7afee94..141a3b67487b16 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index c01ad7d6eb83b7..0b18ce294fb2ec 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index e2a042fd221373..cb352de9c7071f 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 6c65a8c2676473..4a7b514af95dd3 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 1ed33d3489b681..0ba98d7e113778 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 97cf81dd6cf19c..e711636756b4a7 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 414ef07a41bb81..0eb371a73845be 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 93230a78f1ae12..ed21fc5391ab50 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 775e7af2567b6e..ea9449b2b1c964 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 9a50676c8844e3..3908f6b4f82045 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index c968e5a148c346..3cfd155383384e 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 38771fed3d0cbd..37baabb24a6eb7 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 13e93db2762186..33e17e03beb133 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 8b774dbe02cd8b..e44589c5ad5c81 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index b4f574a854eeac..004ce641602e4d 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 208971474ba686..ed1b9fa7f8442e 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 9560edf50e575e..49148bf13e43ed 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index cbcddb5c265722..488cebb89a3b67 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 2379c28b2290da..f0092b0f8bb116 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index ae60f75644b935..de79ec32efbca8 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 195d55a5fefcd6..2f5e0c942eb0f0 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index cfd05a29100559..93fa195ba86cd6 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index d96ebe475c3a85..22bee16d0585ce 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 85e37890b4f816..16e8ec6d3ae5c5 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index f1e05ee91a52ac..0837f234cf3605 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 46f49d6f3a4408..8213f9ee28f668 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 7b1c5c2782229a..68e4f0d3116fbd 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 99459b2724e4ce..affa92183f4930 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index b62d5eae0ceacd..3fd8dc4fad5c37 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 3046a4c6ca1393..5e2a8257212e66 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index d076ef6209022f..dfcaeb8177ede9 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index d18719c1a1c52c..d832fa1f088929 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index c7caf7e1381c42..904c8e9030cd95 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index b3bd82323024e5..64a8be7ee09a6a 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 46a7f6f0fd6d93..6055316ebaff3f 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 49d48495b2a096..2cb9c9a8cfa3af 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 7de7fb437791c4..9ff4b65f97fcc6 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 8408f5eaecc804..40b31612ad9514 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 822131c4358c64..abc36c4c5455c2 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 80860d0973c1ec..1e18a8d3b75868 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 42bf5e30df1730..234d28e295b15a 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.devdocs.json b/api_docs/kbn_journeys.devdocs.json index a367aafa2dd815..d06f674126af23 100644 --- a/api_docs/kbn_journeys.devdocs.json +++ b/api_docs/kbn_journeys.devdocs.json @@ -422,6 +422,22 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/journeys", + "id": "def-common.JourneyConfig.getFtrConfigPath", + "type": "Function", + "tags": [], + "label": "getFtrConfigPath", + "description": [], + "signature": [ + "() => string | undefined" + ], + "path": "packages/kbn-journeys/journey/journey_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "@kbn/journeys", "id": "def-common.JourneyConfig.getEsArchives", diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index 208d175598ba2f..c85a757c4ed593 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 67 | 0 | 62 | 5 | +| 68 | 0 | 63 | 5 | ## Common diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index ca4312aa608d60..97a034693722ea 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 2355effaa4338b..ae7075c556124f 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index db40623912faae..78b6689e3620b4 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 206189b5817eae..b52baaa9500736 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index d0c35339b28592..0f17dea4d52886 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 0bc1e9c2a083fb..09afe4a5314702 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 67d80d955891f0..87352e3142191f 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 94823871e3f66f..0b2ad6dcde0230 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 5155e41df91ac2..b5a408b845b238 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index 044d9fe5c5d5d9..a17bf71066b85c 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 7bc8836029023f..de78d68d1e53e9 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index d9dfb7bbdc992d..41209eacc44a6f 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index c2e53093736716..9e80df4909ede2 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 1b16e64a1b48f8..6bc362697e9a2b 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 510c572fe1d488..596fe6523a2d27 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 0d531d2730049d..99b64dfadbf3aa 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index ff84137fdd118c..9a2501165adadf 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index c9639f1afba8ca..447ef2dddf8e11 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 33f62f4a233069..b1f02f021a94e6 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 9bc705ebc0cf26..f12bb05c5e02a6 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 57c232ed410bca..bc4d50e4a8ec04 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 6c4b9093948ad6..6b2260140b27b0 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index eee4f24cb91f09..0b7384d58217fa 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 2c07170eaf526e..e38e032918779b 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 36a3dcdd58e817..18856c87584dfb 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index d636dc99094dc1..139bc59f09efd5 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 2a373c86eb76f2..450ab51bb769e6 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 2b12d25b3fede7..a3afc7e6e394c7 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index ac42537054b41f..ef8fbeddce1b61 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.devdocs.json b/api_docs/kbn_rule_data_utils.devdocs.json index 8e15b282dd6c89..51429bd28d4a49 100644 --- a/api_docs/kbn_rule_data_utils.devdocs.json +++ b/api_docs/kbn_rule_data_utils.devdocs.json @@ -1266,7 +1266,7 @@ "label": "AlertConsumers", "description": [], "signature": [ - "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\"" + "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\" | \"slo\"" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts", "deprecated": false, @@ -1521,7 +1521,7 @@ "label": "ValidFeatureId", "description": [], "signature": [ - "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\"" + "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\" | \"slo\"" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts", "deprecated": false, @@ -1570,7 +1570,7 @@ "\nregistering a new instance of the rule data client\nin a new plugin will require updating the below data structure\nto include the index name where the alerts as data will be written to." ], "signature": [ - "{ readonly APM: \"apm\"; readonly LOGS: \"logs\"; readonly INFRASTRUCTURE: \"infrastructure\"; readonly OBSERVABILITY: \"observability\"; readonly SIEM: \"siem\"; readonly UPTIME: \"uptime\"; }" + "{ readonly APM: \"apm\"; readonly LOGS: \"logs\"; readonly INFRASTRUCTURE: \"infrastructure\"; readonly OBSERVABILITY: \"observability\"; readonly SLO: \"slo\"; readonly SIEM: \"siem\"; readonly UPTIME: \"uptime\"; }" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts", "deprecated": false, diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index a4afd817ac65f3..ce2c207c44cb90 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 020034226e817e..213798600769aa 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 5fa83b8867d0bf..add3cfd3ddcb2c 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 20c071e13c5108..e1e4d7c386a6a0 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index fd52fef164cba2..4a2c126f2c3f44 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index f38890ce0c0b03..741e6e52093bc7 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 524ad7930f21da..d64bd39381a14b 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index dc368dc60e47bf..c1933b1d716a95 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index ef2c040d9d90c4..d18659ef45b364 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 62474c089a86eb..7830db8ad32bf1 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 6377a0b56da96a..959df4c94ed3de 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 6561acaa7e1e3f..edfb2c6cdcc37f 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 6eee665ab24219..8fa3a18ea5633b 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index d917da592a381d..a93c450c85fcfc 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 9e377e1046d91a..940401dcb19666 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index e3c1636d2583e5..455c90cf9eae37 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index aa69ead0f2a80d..ee287d3470065b 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 2bf10235381386..1b5ebe0ee3ab92 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 8052a0c477ce24..20564c2a15c2c4 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 7ec8ecebf808e2..8dd64775f30e89 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 748523e2b6decb..6cfe61898f43f6 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index a54eda90599213..af72da48648c7e 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index b53d63937bad52..9a1487ae5aca8b 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 90aad6717ab26c..8b7a45e1884080 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 448f01ef24cb16..84d5531642146e 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index c112d796888b70..d6b422d9375359 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index e0775860046a79..08f0073f79005a 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 184df4d0dfb4a3..98e19c9f6c08e7 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index cb15f3227f5963..e0f939a4b42ac6 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 2eec94a8e6cf09..bfd3ddd58aef3d 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 1e37bcb30956ab..0e75a42baf3a8e 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.devdocs.json b/api_docs/kbn_shared_ux_file_picker.devdocs.json index c291b1d0ee29de..0838853073257a 100644 --- a/api_docs/kbn_shared_ux_file_picker.devdocs.json +++ b/api_docs/kbn_shared_ux_file_picker.devdocs.json @@ -247,6 +247,22 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/shared-ux-file-picker", + "id": "def-common.Props.uploadMeta", + "type": "Unknown", + "tags": [], + "label": "uploadMeta", + "description": [ + "\n`meta` value to be used for file uploads" + ], + "signature": [ + "unknown" + ], + "path": "packages/shared-ux/file/file_picker/impl/src/file_picker.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/shared-ux-file-picker", "id": "def-common.Props.pageSize", diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 9d4ae20f6a40db..98cc4fdf9bf717 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 13 | 0 | 6 | 0 | +| 14 | 0 | 6 | 0 | ## Common diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 89aeea69347026..0a87ef2e49859b 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 63ac5a36f3d390..41a8a4bc379895 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 334c1cd62f96d1..b925d3df6c55e4 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index c4db69beafd2ca..c01f812af5a4b8 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 2fae876b533799..4b68fa6dc58caf 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 128ea8e8df9ef7..1c703a2369b3cd 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 8f7b75ddf4c75c..3768fbcd49cc68 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index c5b2c4f5789fa9..6b1e2b8a5984b0 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index da29f12b225957..ec00c6ac80b1aa 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index a7e4c290cbeda2..42ab9f9f06b3bb 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index c84b324f13ed51..16b4ac7220b908 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 623f8e5f6072f4..bdb90364b95ee8 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index 237333dead873c..120916cd68c1de 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 3e9711497a8a2c..eb96fd40af5731 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 774024740a0a10..b6d1deae0b9304 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 01d3b6085c13e1..f427553fea3031 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 5a1d052961b550..d3cedcf51828ee 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index a7277b6729192e..26a062a60edee1 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 804f45a24e3342..b39d624eb71e4a 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index ecc7eda56ae9f6..66fac2533b311b 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 26fc8e4dd82b45..35cc667e36f5a7 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 2bc966fafaaeaf..049ebcb17cb979 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 8d66ebbd7ab5db..be11e8095ce12e 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 4a63da3314288b..0d993dc36582b1 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 4437e5bd930fb7..08ebaf46f88dc7 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 506bf83435e557..3c3692c8491726 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 8cfc9af4765fb2..471d20db13daff 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index e7b44a0595f2bf..6af2033dfd0e73 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 639033423f7823..2fa8c47bf0f20c 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 71fa66aa5cd722..013b04a6ab6a30 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index f34f4e79b477ca..6487d555a588c3 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 7ad93b1efc6419..0e7fb7d9c2538f 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 547a3531cc3cab..355290bae78bff 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 4c08f55f95facf..5443337f7498c9 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index d53ba028587f84..1987689104e196 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 7cf648110f7bb2..5b5f0020329165 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index af6e4c619a7756..e8c2d9140e38dc 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index c9c179c190b3de..4f630f5bb6c265 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 86665a71a6590f..590c9f141a32c5 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index cb914af3063158..2d95a6167fe2bd 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 92ec8131e2e491..9c162f36e195cd 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 73effc933ae1c7..9e569eb13c66f3 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 8151013e564781..28c69ad56caa38 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 32dc2d89e7ebb0..a81f4e3a573cbe 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 526c731c0dd80d..0c8e51749bce73 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 537a58309875bb..471920263bfcaf 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 2ed468ecd418cf..3569fa25e46b48 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -1354,15 +1354,15 @@ }, { "plugin": "apm", - "path": "x-pack/plugins/apm/public/components/routing/app_root.tsx" + "path": "x-pack/plugins/apm/public/components/routing/app_root/index.tsx" }, { "plugin": "apm", - "path": "x-pack/plugins/apm/public/components/routing/app_root.tsx" + "path": "x-pack/plugins/apm/public/components/routing/app_root/index.tsx" }, { "plugin": "apm", - "path": "x-pack/plugins/apm/public/components/routing/app_root.tsx" + "path": "x-pack/plugins/apm/public/components/routing/app_root/index.tsx" }, { "plugin": "enterpriseSearch", diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 34e2f7e1ee6d5f..a1cd10b5d2323f 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 73999ea92082c1..443a6f043921b8 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index a60441eb5d287e..16cacfa3257734 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 3292575c90c535..b5294a551334ee 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 0a02ad7af5723e..40ce8a38d116e9 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 29ec9594da5567..77bedb1b11517c 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 1b015c35b488bb..8ebf24f36e2e5b 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index fe9acfdd27fde2..561435c2be514e 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 98da0947c88eeb..6d6bbc6a02f262 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 6ebdfb4285516b..f02a89ac26fcb3 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index ff1f9c17c21365..3eb4448752b3e8 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index d670b1b24d7f67..6635a01a23bb77 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index a09fb315e1d15a..228899752c821e 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 979e298e20962b..76588c2a1f27a6 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 2580638a9ee21a..c1ef320f6acc15 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index bb76a13d3448bc..9a21cb27a02d12 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 7f5e095373c879..9c86e4b570f5f9 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 777c50843ad4f6..9c56b9606c241c 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -14157,6 +14157,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-common.sloFeatureId", + "type": "string", + "tags": [], + "label": "sloFeatureId", + "description": [], + "signature": [ + "\"slo\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-common.SYNTHETICS_BLOCKED_TIMINGS", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 7a7ffa9c14ca15..920856da040cad 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 614 | 43 | 608 | 32 | +| 615 | 43 | 609 | 32 | ## Client diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 138fd3b29816f0..18a3338a0bd363 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 4c5a4a5c99f3d5..c859b841720ff8 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 67630 | 515 | 58461 | 1230 | +| 67651 | 515 | 58481 | 1232 | ## Plugin Directory @@ -30,7 +30,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 256 | 8 | 251 | 24 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 1 | 32 | 2 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 12 | 0 | 1 | 2 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 489 | 1 | 478 | 39 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 486 | 1 | 475 | 40 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 42 | 0 | 42 | 65 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 89 | 1 | 74 | 2 | @@ -47,7 +47,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | cloudLinks | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Adds the links to the Elastic Cloud console | 0 | 0 | 0 | 0 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | The cloud security posture plugin | 17 | 0 | 2 | 2 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 13 | 0 | 13 | 1 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Content management app | 42 | 0 | 42 | 3 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Content management app | 41 | 0 | 41 | 3 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 270 | 0 | 266 | 9 | | crossClusterReplication | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | customBranding | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Enables customization of Kibana | 0 | 0 | 0 | 0 | @@ -61,7 +61,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 1028 | 0 | 243 | 2 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 28 | 3 | 24 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 10 | 0 | 8 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 107 | 0 | 88 | 7 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 97 | 0 | 78 | 7 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 532 | 8 | 430 | 4 | @@ -90,7 +90,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 62 | 0 | 62 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 254 | 1 | 45 | 5 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 2 | 1 | 2 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1077 | 3 | 972 | 26 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1079 | 3 | 974 | 26 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -127,7 +127,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 0 | 34 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 614 | 43 | 608 | 32 | +| | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 615 | 43 | 609 | 32 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | | painlessLab | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 219 | 7 | 163 | 12 | @@ -137,12 +137,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 21 | 0 | 21 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 257 | 0 | 228 | 13 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 24 | 0 | 19 | 2 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 196 | 2 | 155 | 5 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 216 | 2 | 175 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 16 | 0 | 16 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 154 | 0 | 140 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 79 | 0 | 73 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 100 | 0 | 52 | 1 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the definition and helper methods around saved searches, used by discover and visualizations. | 45 | 0 | 45 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the definition and helper methods around saved searches, used by discover and visualizations. | 55 | 0 | 55 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 13 | 0 | | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 4 | | searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | @@ -418,7 +418,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 12 | 43 | 0 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 24 | 0 | 24 | 3 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 0 | 13 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 67 | 0 | 62 | 5 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 68 | 0 | 63 | 5 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 35 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 108 | 0 | 107 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 7 | 0 | 5 | 0 | @@ -479,7 +479,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 1 | 0 | 1 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 13 | 0 | 6 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 14 | 0 | 6 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 7 | 0 | 7 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 17 | 0 | 15 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 17 | 0 | 9 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index f9b865ff8cbcff..b9618c23b8f656 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index e6001e7201715b..db28fdc75ba510 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 1548c3dfb2d53f..df53b30d642e5b 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index d0a51aedf8ce50..9cb366395527dd 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index a21729e4639b79..a253b1d85aad9a 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index b098acea5fb038..9e7abc70765805 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -1943,7 +1943,9 @@ "section": "def-common.SavedObjectReference", "text": "SavedObjectReference" }, - "[]) => TParams; } | undefined; isExportable: boolean; defaultScheduleInterval?: string | undefined; ruleTaskTimeout?: string | undefined; doesSetRecoveryContext?: boolean | undefined; autoRecoverAlerts?: boolean | undefined; }" + "[]) => TParams; } | undefined; isExportable: boolean; defaultScheduleInterval?: string | undefined; ruleTaskTimeout?: string | undefined; doesSetRecoveryContext?: boolean | undefined; autoRecoverAlerts?: boolean | undefined; getViewInAppRelativeUrl?: ", + "GetViewInAppRelativeUrlFn", + " | undefined; }" ], "path": "x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts", "deprecated": false, @@ -2157,7 +2159,7 @@ "\nID of the Kibana feature associated with the index.\nUsed by alerts-as-data RBAC.\n\nNote from @dhurley14\nThe purpose of the `feature` param is to force the user to update\nthe data structure which contains the mapping of consumers to alerts\nas data indices. The idea is it is typed such that it forces the\nuser to go to the code and modify it. At least until a better system\nis put in place or we move the alerts as data client out of rule registry.\n" ], "signature": [ - "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\"" + "\"uptime\" | \"siem\" | \"apm\" | \"logs\" | \"infrastructure\" | \"observability\" | \"slo\"" ], "path": "x-pack/plugins/rule_registry/server/rule_data_plugin_service/index_options.ts", "deprecated": false, diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 21a9aee8492cda..ba86ab2579e905 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index 4d44041e9be5c0..d99378636a54d0 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.devdocs.json b/api_docs/saved_objects.devdocs.json index 594d2fc7d11ccc..b6ed1819ec6845 100644 --- a/api_docs/saved_objects.devdocs.json +++ b/api_docs/saved_objects.devdocs.json @@ -889,15 +889,7 @@ "label": "getSavedObjectFinder", "description": [], "signature": [ - "(savedObject: ", - { - "pluginId": "@kbn/core-saved-objects-browser", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsBrowserPluginApi", - "section": "def-common.SavedObjectsStart", - "text": "SavedObjectsStart" - }, - ", uiSettings: ", + "(uiSettings: ", { "pluginId": "@kbn/core-ui-settings-browser", "scope": "common", @@ -905,6 +897,14 @@ "section": "def-common.IUiSettingsClient", "text": "IUiSettingsClient" }, + ", http: ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + }, ") => (props: ", "SavedObjectFinderProps", ") => JSX.Element" @@ -918,15 +918,15 @@ "id": "def-public.getSavedObjectFinder.$1", "type": "Object", "tags": [], - "label": "savedObject", + "label": "uiSettings", "description": [], "signature": [ { - "pluginId": "@kbn/core-saved-objects-browser", + "pluginId": "@kbn/core-ui-settings-browser", "scope": "common", - "docId": "kibKbnCoreSavedObjectsBrowserPluginApi", - "section": "def-common.SavedObjectsStart", - "text": "SavedObjectsStart" + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-common.IUiSettingsClient", + "text": "IUiSettingsClient" } ], "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", @@ -939,15 +939,15 @@ "id": "def-public.getSavedObjectFinder.$2", "type": "Object", "tags": [], - "label": "uiSettings", + "label": "http", "description": [], "signature": [ { - "pluginId": "@kbn/core-ui-settings-browser", + "pluginId": "@kbn/core-http-browser", "scope": "common", - "docId": "kibKbnCoreUiSettingsBrowserPluginApi", - "section": "def-common.IUiSettingsClient", - "text": "IUiSettingsClient" + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" } ], "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", @@ -1329,7 +1329,7 @@ "tags": [], "label": "FinderAttributes", "description": [], - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", + "path": "src/plugins/saved_objects/common/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1343,7 +1343,7 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", + "path": "src/plugins/saved_objects/common/types.ts", "deprecated": false, "trackAdoption": false }, @@ -1357,7 +1357,7 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", + "path": "src/plugins/saved_objects/common/types.ts", "deprecated": false, "trackAdoption": false }, @@ -1368,7 +1368,7 @@ "tags": [], "label": "type", "description": [], - "path": "src/plugins/saved_objects/public/finder/saved_object_finder.tsx", + "path": "src/plugins/saved_objects/common/types.ts", "deprecated": false, "trackAdoption": false } @@ -2816,11 +2816,11 @@ "signature": [ "(savedObject: ", { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, ") => ", "IconType" @@ -2838,11 +2838,11 @@ "description": [], "signature": [ { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, "" ], @@ -2864,11 +2864,11 @@ "signature": [ "((savedObject: ", { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, ") => string) | undefined" ], @@ -2885,11 +2885,11 @@ "description": [], "signature": [ { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, "" ], @@ -2911,11 +2911,11 @@ "signature": [ "((savedObject: ", { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, ") => boolean) | undefined" ], @@ -2932,11 +2932,11 @@ "description": [], "signature": [ { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, "" ], @@ -2958,11 +2958,11 @@ "signature": [ "((savedObject: ", { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, ") => string) | undefined" ], @@ -2979,11 +2979,11 @@ "description": [], "signature": [ { - "pluginId": "@kbn/core-saved-objects-api-browser", + "pluginId": "savedObjects", "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiBrowserPluginApi", - "section": "def-common.SimpleSavedObject", - "text": "SimpleSavedObject" + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" }, "" ], @@ -3261,15 +3261,7 @@ "label": "SavedObjectFinderUiProps", "description": [], "signature": [ - "{ savedObjects: ", - { - "pluginId": "@kbn/core-saved-objects-browser", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsBrowserPluginApi", - "section": "def-common.SavedObjectsStart", - "text": "SavedObjectsStart" - }, - "; uiSettings: ", + "{ uiSettings: ", { "pluginId": "@kbn/core-ui-settings-browser", "scope": "common", @@ -3277,6 +3269,14 @@ "section": "def-common.IUiSettingsClient", "text": "IUiSettingsClient" }, + "; http: ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "common", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-common.HttpSetup", + "text": "HttpSetup" + }, "; } & ", "SavedObjectFinderProps" ], @@ -3445,7 +3445,279 @@ "common": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "savedObjects", + "id": "def-common.FinderAttributes", + "type": "Interface", + "tags": [], + "label": "FinderAttributes", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedObjects", + "id": "def-common.FinderAttributes.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FinderAttributes.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FinderAttributes.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP", + "type": "Interface", + "tags": [], + "label": "FindQueryHTTP", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.perPage", + "type": "number", + "tags": [], + "label": "perPage", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.page", + "type": "number", + "tags": [], + "label": "page", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.type", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.search", + "type": "string", + "tags": [], + "label": "search", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.searchFields", + "type": "Array", + "tags": [], + "label": "searchFields", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.defaultSearchOperator", + "type": "CompoundType", + "tags": [], + "label": "defaultSearchOperator", + "description": [], + "signature": [ + "\"AND\" | \"OR\" | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.sortField", + "type": "string", + "tags": [], + "label": "sortField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.sortOrder", + "type": "CompoundType", + "tags": [], + "label": "sortOrder", + "description": [], + "signature": [ + "\"asc\" | \"desc\" | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindQueryHTTP.fields", + "type": "CompoundType", + "tags": [], + "label": "fields", + "description": [], + "signature": [ + "string | string[] | undefined" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindResponseHTTP", + "type": "Interface", + "tags": [], + "label": "FindResponseHTTP", + "description": [], + "signature": [ + { + "pluginId": "savedObjects", + "scope": "common", + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.FindResponseHTTP", + "text": "FindResponseHTTP" + }, + "" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedObjects", + "id": "def-common.FindResponseHTTP.saved_objects", + "type": "Array", + "tags": [], + "label": "saved_objects", + "description": [], + "signature": [ + { + "pluginId": "savedObjects", + "scope": "common", + "docId": "kibSavedObjectsPluginApi", + "section": "def-common.SavedObjectCommon", + "text": "SavedObjectCommon" + }, + "[]" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindResponseHTTP.total", + "type": "number", + "tags": [], + "label": "total", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindResponseHTTP.page", + "type": "number", + "tags": [], + "label": "page", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.FindResponseHTTP.per_page", + "type": "number", + "tags": [], + "label": "per_page", + "description": [], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ { @@ -3477,6 +3749,28 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "savedObjects", + "id": "def-common.SavedObjectCommon", + "type": "Type", + "tags": [], + "label": "SavedObjectCommon", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObject", + "text": "SavedObject" + }, + "" + ], + "path": "src/plugins/saved_objects/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 29d5b2a6ec11d3..55e0c212706fa8 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 196 | 2 | 155 | 5 | +| 216 | 2 | 175 | 5 | ## Client @@ -45,6 +45,9 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core ## Common +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 8917557f4c7b0b..e6dbc3297abf62 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 77a441c39dc962..a35cca4bae9ab1 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index a2340928add9ed..d00586ff065d21 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 70ef0ecfd6823a..074359af3e0aab 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.devdocs.json b/api_docs/saved_search.devdocs.json index f2630166f76f19..8599dfd744e064 100644 --- a/api_docs/saved_search.devdocs.json +++ b/api_docs/saved_search.devdocs.json @@ -223,18 +223,376 @@ "interfaces": [ { "parentPluginId": "savedSearch", - "id": "def-public.DiscoverGridSettings", + "id": "def-public.SavedSearch", "type": "Interface", "tags": [], - "label": "DiscoverGridSettings", + "label": "SavedSearch", "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearch", + "text": "SavedSearch" + }, + " extends ", + { + "pluginId": "savedSearch", + "scope": "common", + "docId": "kibSavedSearchPluginApi", + "section": "def-common.SavedSearch", + "text": "SavedSearch" + } + ], "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "savedSearch", - "id": "def-public.DiscoverGridSettings.columns", + "id": "def-public.SavedSearch.sharingSavedObjectProps", + "type": "Object", + "tags": [], + "label": "sharingSavedObjectProps", + "description": [], + "signature": [ + "{ outcome?: \"conflict\" | \"exactMatch\" | \"aliasMatch\" | undefined; aliasTargetId?: string | undefined; aliasPurpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; errorJSON?: string | undefined; } | undefined" + ], + "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "savedSearch", + "id": "def-public.SaveSavedSearchOptions", + "type": "Interface", + "tags": [], + "label": "SaveSavedSearchOptions", + "description": [], + "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-public.SaveSavedSearchOptions.onTitleDuplicate", + "type": "Function", + "tags": [], + "label": "onTitleDuplicate", + "description": [], + "signature": [ + "(() => void) | undefined" + ], + "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "savedSearch", + "id": "def-public.SaveSavedSearchOptions.isTitleDuplicateConfirmed", + "type": "CompoundType", + "tags": [], + "label": "isTitleDuplicateConfirmed", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "savedSearch", + "id": "def-public.SaveSavedSearchOptions.copyOnSave", + "type": "CompoundType", + "tags": [], + "label": "copyOnSave", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [ + { + "parentPluginId": "savedSearch", + "id": "def-public.VIEW_MODE", + "type": "Enum", + "tags": [], + "label": "VIEW_MODE", + "description": [], + "path": "src/plugins/saved_search/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "savedSearch", + "id": "def-server.getSavedSearch", + "type": "Function", + "tags": [], + "label": "getSavedSearch", + "description": [], + "signature": [ + "(savedSearchId: string, deps: GetSavedSearchDependencies) => Promise<", + { + "pluginId": "savedSearch", + "scope": "common", + "docId": "kibSavedSearchPluginApi", + "section": "def-common.SavedSearch", + "text": "SavedSearch" + }, + ">" + ], + "path": "src/plugins/saved_search/server/services/saved_searches/get_saved_searches.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-server.getSavedSearch.$1", + "type": "string", + "tags": [], + "label": "savedSearchId", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/saved_search/server/services/saved_searches/get_saved_searches.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "savedSearch", + "id": "def-server.getSavedSearch.$2", + "type": "Object", + "tags": [], + "label": "deps", + "description": [], + "signature": [ + "GetSavedSearchDependencies" + ], + "path": "src/plugins/saved_search/server/services/saved_searches/get_saved_searches.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.fromSavedSearchAttributes", + "type": "Function", + "tags": [], + "label": "fromSavedSearchAttributes", + "description": [], + "signature": [ + "(id: string, attributes: ", + "SavedSearchAttributes", + ", tags: string[] | undefined, searchSource: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ISearchSource", + "text": "ISearchSource" + }, + ") => ", + { + "pluginId": "savedSearch", + "scope": "common", + "docId": "kibSavedSearchPluginApi", + "section": "def-common.SavedSearch", + "text": "SavedSearch" + } + ], + "path": "src/plugins/saved_search/common/saved_searches_utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.fromSavedSearchAttributes.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/saved_search/common/saved_searches_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "savedSearch", + "id": "def-common.fromSavedSearchAttributes.$2", + "type": "Object", + "tags": [], + "label": "attributes", + "description": [], + "signature": [ + "SavedSearchAttributes" + ], + "path": "src/plugins/saved_search/common/saved_searches_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "savedSearch", + "id": "def-common.fromSavedSearchAttributes.$3", + "type": "Array", + "tags": [], + "label": "tags", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "src/plugins/saved_search/common/saved_searches_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "savedSearch", + "id": "def-common.fromSavedSearchAttributes.$4", + "type": "Object", + "tags": [], + "label": "searchSource", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ISearchSource", + "text": "ISearchSource" + } + ], + "path": "src/plugins/saved_search/common/saved_searches_utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "savedSearch", + "id": "def-common.getSavedSearchFullPathUrl", + "type": "Function", + "tags": [], + "label": "getSavedSearchFullPathUrl", + "description": [], + "signature": [ + "(id?: string | undefined) => string" + ], + "path": "src/plugins/saved_search/common/saved_searches_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.getSavedSearchFullPathUrl.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_search/common/saved_searches_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "savedSearch", + "id": "def-common.getSavedSearchUrl", + "type": "Function", + "tags": [], + "label": "getSavedSearchUrl", + "description": [], + "signature": [ + "(id?: string | undefined) => string" + ], + "path": "src/plugins/saved_search/common/saved_searches_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.getSavedSearchUrl.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_search/common/saved_searches_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.DiscoverGridSettings", + "type": "Interface", + "tags": [], + "label": "DiscoverGridSettings", + "description": [], + "path": "src/plugins/saved_search/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "savedSearch", + "id": "def-common.DiscoverGridSettings.columns", "type": "Object", "tags": [], "label": "columns", @@ -243,14 +601,14 @@ "Record | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false } @@ -259,18 +617,18 @@ }, { "parentPluginId": "savedSearch", - "id": "def-public.DiscoverGridSettingsColumn", + "id": "def-common.DiscoverGridSettingsColumn", "type": "Interface", "tags": [], "label": "DiscoverGridSettingsColumn", "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "savedSearch", - "id": "def-public.DiscoverGridSettingsColumn.width", + "id": "def-common.DiscoverGridSettingsColumn.width", "type": "number", "tags": [], "label": "width", @@ -278,7 +636,7 @@ "signature": [ "number | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false } @@ -287,18 +645,18 @@ }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch", + "id": "def-common.SavedSearch", "type": "Interface", "tags": [], "label": "SavedSearch", "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.searchSource", + "id": "def-common.SavedSearch.searchSource", "type": "Object", "tags": [], "label": "searchSource", @@ -534,13 +892,13 @@ }, "; parseActiveIndexPatternFromQueryString: (queryString: string) => string[]; }" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.id", + "id": "def-common.SavedSearch.id", "type": "string", "tags": [], "label": "id", @@ -548,13 +906,13 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.title", + "id": "def-common.SavedSearch.title", "type": "string", "tags": [], "label": "title", @@ -562,13 +920,13 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.sort", + "id": "def-common.SavedSearch.sort", "type": "Array", "tags": [], "label": "sort", @@ -577,13 +935,13 @@ "SortOrder", "[] | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.columns", + "id": "def-common.SavedSearch.columns", "type": "Array", "tags": [], "label": "columns", @@ -591,13 +949,13 @@ "signature": [ "string[] | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.description", + "id": "def-common.SavedSearch.description", "type": "string", "tags": [], "label": "description", @@ -605,13 +963,13 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.tags", + "id": "def-common.SavedSearch.tags", "type": "Array", "tags": [], "label": "tags", @@ -619,13 +977,13 @@ "signature": [ "string[] | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.grid", + "id": "def-common.SavedSearch.grid", "type": "Object", "tags": [], "label": "grid", @@ -634,20 +992,20 @@ "{ columns?: Record | undefined; } | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.hideChart", + "id": "def-common.SavedSearch.hideChart", "type": "CompoundType", "tags": [], "label": "hideChart", @@ -655,27 +1013,13 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.sharingSavedObjectProps", - "type": "Object", - "tags": [], - "label": "sharingSavedObjectProps", - "description": [], - "signature": [ - "{ outcome?: \"conflict\" | \"exactMatch\" | \"aliasMatch\" | undefined; aliasTargetId?: string | undefined; aliasPurpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; errorJSON?: string | undefined; } | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.viewMode", + "id": "def-common.SavedSearch.viewMode", "type": "CompoundType", "tags": [], "label": "viewMode", @@ -683,20 +1027,20 @@ "signature": [ { "pluginId": "savedSearch", - "scope": "public", + "scope": "common", "docId": "kibSavedSearchPluginApi", - "section": "def-public.VIEW_MODE", + "section": "def-common.VIEW_MODE", "text": "VIEW_MODE" }, " | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.hideAggregatedPreview", + "id": "def-common.SavedSearch.hideAggregatedPreview", "type": "CompoundType", "tags": [], "label": "hideAggregatedPreview", @@ -704,13 +1048,13 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.rowHeight", + "id": "def-common.SavedSearch.rowHeight", "type": "number", "tags": [], "label": "rowHeight", @@ -718,13 +1062,13 @@ "signature": [ "number | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.isTextBasedQuery", + "id": "def-common.SavedSearch.isTextBasedQuery", "type": "CompoundType", "tags": [], "label": "isTextBasedQuery", @@ -732,13 +1076,13 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.usesAdHocDataView", + "id": "def-common.SavedSearch.usesAdHocDataView", "type": "CompoundType", "tags": [], "label": "usesAdHocDataView", @@ -746,13 +1090,13 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.timeRestore", + "id": "def-common.SavedSearch.timeRestore", "type": "CompoundType", "tags": [], "label": "timeRestore", @@ -760,13 +1104,13 @@ "signature": [ "boolean | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.timeRange", + "id": "def-common.SavedSearch.timeRange", "type": "Object", "tags": [], "label": "timeRange", @@ -781,13 +1125,13 @@ }, " | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.refreshInterval", + "id": "def-common.SavedSearch.refreshInterval", "type": "Object", "tags": [], "label": "refreshInterval", @@ -802,13 +1146,13 @@ }, " | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.rowsPerPage", + "id": "def-common.SavedSearch.rowsPerPage", "type": "number", "tags": [], "label": "rowsPerPage", @@ -816,13 +1160,13 @@ "signature": [ "number | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "savedSearch", - "id": "def-public.SavedSearch.breakdownField", + "id": "def-common.SavedSearch.breakdownField", "type": "string", "tags": [], "label": "breakdownField", @@ -830,65 +1174,7 @@ "signature": [ "string | undefined" ], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "savedSearch", - "id": "def-public.SaveSavedSearchOptions", - "type": "Interface", - "tags": [], - "label": "SaveSavedSearchOptions", - "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedSearch", - "id": "def-public.SaveSavedSearchOptions.onTitleDuplicate", - "type": "Function", - "tags": [], - "label": "onTitleDuplicate", - "description": [], - "signature": [ - "(() => void) | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "savedSearch", - "id": "def-public.SaveSavedSearchOptions.isTitleDuplicateConfirmed", - "type": "CompoundType", - "tags": [], - "label": "isTitleDuplicateConfirmed", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "savedSearch", - "id": "def-public.SaveSavedSearchOptions.copyOnSave", - "type": "CompoundType", - "tags": [], - "label": "copyOnSave", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts", + "path": "src/plugins/saved_search/common/types.ts", "deprecated": false, "trackAdoption": false } @@ -899,100 +1185,17 @@ "enums": [ { "parentPluginId": "savedSearch", - "id": "def-public.VIEW_MODE", + "id": "def-common.VIEW_MODE", "type": "Enum", "tags": [], "label": "VIEW_MODE", "description": [], - "path": "src/plugins/saved_search/public/services/saved_searches/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [ - { - "parentPluginId": "savedSearch", - "id": "def-common.getSavedSearchFullPathUrl", - "type": "Function", - "tags": [], - "label": "getSavedSearchFullPathUrl", - "description": [], - "signature": [ - "(id?: string | undefined) => string" - ], - "path": "src/plugins/saved_search/common/saved_searches_url.ts", + "path": "src/plugins/saved_search/common/index.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedSearch", - "id": "def-common.getSavedSearchFullPathUrl.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/saved_search/common/saved_searches_url.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "savedSearch", - "id": "def-common.getSavedSearchUrl", - "type": "Function", - "tags": [], - "label": "getSavedSearchUrl", - "description": [], - "signature": [ - "(id?: string | undefined) => string" - ], - "path": "src/plugins/saved_search/common/saved_searches_url.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "savedSearch", - "id": "def-common.getSavedSearchUrl.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/saved_search/common/saved_searches_url.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], "initialIsOpen": false } ], - "interfaces": [], - "enums": [], "misc": [], "objects": [] } diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index c2ebc14e8045f2..e78551708a4c24 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 45 | 0 | 45 | 1 | +| 55 | 0 | 55 | 2 | ## Client @@ -34,8 +34,19 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k ### Enums +## Server + +### Functions + + ## Common ### Functions +### Interfaces + + +### Enums + + diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 6deb948aaf4171..a7f7297614f91e 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index f8dd9e4134c52a..2c15986ab2c9e6 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 481609084643f1..70191ab01dddd0 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 7409186cd5c152..7d8ff51f0d821a 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 3ebbcad1a0d98c..753021b212885d 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index f4cac153343a41..0a2150f3472a81 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 9f39e867b3ac62..a07946b0b092d5 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 899655b26377c9..cc10d7b96133a3 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 6be96495a6d336..fba351dcf90a64 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index fa6fed03d9ff23..1e632a9600bba7 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 21b5f8640f8661..8e881116157f58 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 690bf19a1c0290..8a6bbb9e3cbaab 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index bb6944c6d589a2..0c6893e47cc3a0 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index d8fbe62929d290..58d6865457bffb 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 5400f5c7eaeb17..8d75936a263a89 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 4d86b62d3cacac..6349f41c5699bf 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 9ccf2cc5d0c7c5..de4bac799f58ac 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 6cede0d49e2ec6..76a65f5eb8c926 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 6e557911abdf9f..688489bebe219a 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -4975,7 +4975,7 @@ "label": "setRuleProperty", "description": [], "signature": [ - "(key: Prop, value: ", + "(key: Prop, value: ", "SanitizedRule", "[Prop] | null) => void" ], diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 06cfebed3d937f..0cd2f8955e1a11 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 95084fa2aaccb1..4125cdb045e350 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index ce00787df34176..eea96407dace66 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_field_list.mdx b/api_docs/unified_field_list.mdx index c3cd14977ac0b0..34d2c09362829c 100644 --- a/api_docs/unified_field_list.mdx +++ b/api_docs/unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedFieldList title: "unifiedFieldList" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedFieldList plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedFieldList'] --- import unifiedFieldListObj from './unified_field_list.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 6d456394e388c1..ddc71d4cfd0b3e 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 313872400971cf..651e8c93786c9a 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 30b971c6f7ef32..e5bcf93633d3f0 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 12c2643b3c7078..73feec578abc99 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 6fd51629aa3779..35aae853c2e12e 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 2a714d235182c4..3b184cd0f3e926 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index d71de853a8536b..c1909f3b2ff58a 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 5e59b27ff0f429..d0eb416f6c0b01 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 1792dfa1faa54e..e12b5502a0c0f0 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index e74951ff16de7e..444127e1ec2860 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 4c9bbedccb11a5..8b4667ed7e8b32 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 964b6dda69e49a..72a47efd044dd9 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index b4619e59ea04b1..e45229f25e0884 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 2e13178b31acb9..10248e6aa1b28a 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 7dd061e5875ba1..f1761d76647b80 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index cd9a8760c91971..01232bd409ecd8 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index b30d9665b309ef..fb6fa4c55159ca 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2023-02-16 +date: 2023-02-21 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/action-type-template.asciidoc b/docs/action-type-template.asciidoc index f477fb06c007f2..8ff643c883a40c 100644 --- a/docs/action-type-template.asciidoc +++ b/docs/action-type-template.asciidoc @@ -1,16 +1,25 @@ [[-action-type]] -=== connector and action +== connector and action ++++ ++++ Include a short description of the connector type. +[float] +[[define--ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. + +// Optionally add a screenshot + [float] [[-connector-configuration]] ==== Connector configuration - connectors have the following configuration properties. + connectors have the following configuration properties: //// List of user-facing connector configurations. This should align with the fields available in the Create connector flyout form for this connector type. @@ -20,8 +29,12 @@ Property1:: A short description of this property. Property2:: A short description of this property with format hints. This can be specified in `this specific format`. [float] -[[Preconfigured--configuration]] -==== Preconfigured connector type +[[preconfigured--configuration]] +=== Create preconfigured connectors + +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: //// Example preconfigured format for this connector type @@ -29,14 +42,15 @@ Example preconfigured format for this connector type [source,text] -- - my-: - name: preconfigured--connector-type - actionTypeId: . - config: - property1: value1 - property2: value2 - secrets: - property3: value3 +xpack.actions.preconfigured: + my-: + name: preconfigured--connector-type + actionTypeId: . + config: + property1: value1 + property2: value2 + secrets: + property3: value3 -- //// @@ -53,7 +67,10 @@ Secrets defines sensitive information for the connector type. [float] [[-action-configuration]] -==== Action configuration +=== Test connectors + +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. actions have the following properties. diff --git a/docs/developer/advanced/upgrading-nodejs.asciidoc b/docs/developer/advanced/upgrading-nodejs.asciidoc index babfee1cc9c125..a6d2d1af77b59a 100644 --- a/docs/developer/advanced/upgrading-nodejs.asciidoc +++ b/docs/developer/advanced/upgrading-nodejs.asciidoc @@ -17,7 +17,7 @@ These files must be updated when upgrading Node.js: - {kib-repo}blob/{branch}/WORKSPACE.bazel[`WORKSPACE.bazel`] - The version is specified in the `node_version` property. Besides this property, the list of files under `node_repositories` must be updated along with their respective SHA256 hashes. These can be found on the https://nodejs.org[nodejs.org] website. - Example for Node.js v16.19.0: https://nodejs.org/dist/v16.19.0/SHASUMS256.txt.asc + Example for Node.js v16.19.1: https://nodejs.org/dist/v16.19.1/SHASUMS256.txt.asc See PR {kib-repo}pull/128123[#128123] for an example of how the Node.js version has been upgraded previously. diff --git a/docs/management/connectors/action-types/cases-webhook.asciidoc b/docs/management/connectors/action-types/cases-webhook.asciidoc index 22c01b78c43000..d2d72fddb33481 100644 --- a/docs/management/connectors/action-types/cases-webhook.asciidoc +++ b/docs/management/connectors/action-types/cases-webhook.asciidoc @@ -7,9 +7,19 @@ The {webhook-cm} connector uses https://github.com/axios/axios[axios] to send POST, PUT, and GET requests to a case management RESTful API web service. +[float] +[[define-cases-webhook-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/cases-webhook-connector.gif[{webhook-cm} connector] + [float] [[cases-webhook-connector-configuration]] -=== Connector configuration +==== Connector configuration {webhook-cm} connectors have the following configuration properties: @@ -96,39 +106,38 @@ Create comment object:: (Optional) A JSON payload sent to the create comment URL NOTE: Due to Mustache template variables (the text enclosed in triple braces, for example, `{{{case.title}}}`), the JSON is not validated in this step. The JSON is validated once the mustache variables have been placed and when REST method runs. We recommend manually ensuring that the JSON is valid, disregarding the Mustache variables, so the later validation will pass. [float] -[[cases-webhook-connector-networking-configuration]] -=== Connector networking configuration +[[preconfigured-cases-webhook-configuration]] +=== Create preconfigured connectors -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. - -[float] -[[Preconfigured-cases-webhook-configuration]] -=== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-case-management-webhook: - name: Case Management Webhook Connector - actionTypeId: .cases-webhook - config: - hasAuth: true - headers: - 'content-type': 'application/json' - createIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue' - createIncidentMethod: 'post' - createIncidentJson: '{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}}' - getIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}' - getIncidentResponseExternalTitleKey: 'key' - viewIncidentUrl: 'https://testing-jira.atlassian.net/browse/{{{external.system.title}}}' - updateIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}' - updateIncidentMethod: 'put' - updateIncidentJson: '{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}}' - createCommentMethod: 'post', - createCommentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment', - createCommentJson: '{"body": {{{case.comment}}}}', - secrets: - user: testuser - password: passwordvalue +xpack.actions.preconfigured: + my-case-management-webhook: + name: Case Management Webhook Connector + actionTypeId: .cases-webhook + config: + hasAuth: true + headers: + 'content-type': 'application/json' + createIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue' + createIncidentMethod: 'post' + createIncidentJson: '{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}}' + getIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}' + getIncidentResponseExternalTitleKey: 'key' + viewIncidentUrl: 'https://testing-jira.atlassian.net/browse/{{{external.system.title}}}' + updateIncidentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}' + updateIncidentMethod: 'put' + updateIncidentJson: '{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}}' + createCommentMethod: 'post', + createCommentUrl: 'https://testing-jira.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment', + createCommentJson: '{"body": {{{case.comment}}}}', + secrets: + user: testuser + password: passwordvalue -- `config`:: Defines information for the connector type. @@ -153,23 +162,15 @@ Use the <> to customize connector `password`::: A string that corresponds to *Password*. Required if `hasAuth` is set to `true`. [float] -[[define-cases-webhook-ui]] -=== Define connector in {stack-manage-app} - -Define {webhook-cm} connector properties: - -[role="screenshot"] -image::management/connectors/images/cases-webhook-connector.gif[{webhook-cm} connector] +[[cases-webhook-action-configuration]] +=== Test connectors -Test {webhook-cm} action parameters: +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/cases-webhook-test.gif[{webhook-cm} params test] -[float] -[[cases-webhook-action-configuration]] -=== Action configuration - {webhook-cm} actions have the following configuration properties: Title:: A title for the issue, which is used for searching the contents of the knowledge base. @@ -177,6 +178,12 @@ Description:: The details about the incident. Labels:: The labels for the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. +[float] +[[cases-webhook-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + //// [float] [[cases-webhook-connector-full-example]] diff --git a/docs/management/connectors/action-types/email.asciidoc b/docs/management/connectors/action-types/email.asciidoc index d348ede2f84e1d..6b2684c1a15b42 100644 --- a/docs/management/connectors/action-types/email.asciidoc +++ b/docs/management/connectors/action-types/email.asciidoc @@ -1,6 +1,5 @@ -[role="xpack"] [[email-action-type]] -=== Email connector and action +== Email connector and action ++++ Email ++++ @@ -22,11 +21,21 @@ configuration setting is used, the email addresses used for all of the Sender configuration setting. ==== +[float] +[[define-email-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/email-connector.png[Email connector] + [float] [[email-connector-configuration]] ==== Connector configuration -Email connectors have the following configuration properties. +Email connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the @@ -87,33 +96,29 @@ Username for login type authentication. Password:: Password for login type authentication. -[float] -[[email-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize -connector networking configurations, such as proxies, certificates, or TLS -settings. You can set configurations that apply to all your connectors or use -`xpack.actions.customHostSettings` to set per-host configurations. - [float] [[preconfigured-email-configuration]] -==== Preconfigured connector type +=== Create preconfigured connectors + +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-email: - name: preconfigured-email-connector-type - actionTypeId: .email - config: - service: other - from: testsender@test.com - host: validhostname - port: 8080 - secure: false - secrets: - user: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-email: + name: preconfigured-email-connector-type + actionTypeId: .email + config: + service: other + from: testsender@test.com + host: validhostname + port: 8080 + secure: false + secrets: + user: testuser + password: passwordkeystorevalue -- Config defines information for the connector type. @@ -169,23 +174,15 @@ A string that corresponds to *Client Secret*. Should be stored in the `exchange_server`, which uses OAuth 2.0 Client Credentials Authentication. [float] -[[define-email-ui]] -==== Define connector in {stack-manage-app} - -Define email connector properties. - -[role="screenshot"] -image::management/connectors/images/email-connector.png[Email connector] +[[email-action-configuration]] +=== Test connectors -Test email action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/email-params-test.png[Email params test] -[float] -[[email-action-configuration]] -==== Action configuration - Email actions have the following configuration properties. To, CC, BCC:: @@ -199,9 +196,19 @@ The subject line of the email. Message:: The message text of the email. Markdown format is supported. + +[float] +[[email-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize +connector networking configurations, such as proxies, certificates, or TLS +settings. You can set configurations that apply to all your connectors or use +`xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-email]] -==== Configuring email accounts for well-known services +=== Configure email accounts for well-known services The email connector can send email using many popular SMTP email services and the Microsoft Exchange Graph API. diff --git a/docs/management/connectors/action-types/index.asciidoc b/docs/management/connectors/action-types/index.asciidoc index 0cc306765f077b..d674ba868686ec 100644 --- a/docs/management/connectors/action-types/index.asciidoc +++ b/docs/management/connectors/action-types/index.asciidoc @@ -11,14 +11,6 @@ You can create index connectors in {kib} or by using the If you are running {kib} on-prem, you can also create more preconfigured index connectors. -[float] -[[index-connector-configuration]] -=== Connector configuration - -Index connectors must have a name and an {es} index. You can optionally set the -{ref}/docs-refresh.html[refresh] policy and the time field, which contains the -details about when each alert condition was detected. - [float] [[define-index-ui]] === Create connectors in {kib} @@ -30,6 +22,14 @@ or as needed when you're creating a rule. For example: image::management/connectors/images/index-connector.png[Index connector] // NOTE: This is an autogenerated screenshot. Do not edit it directly. +[float] +[[index-connector-configuration]] +==== Connector configuration + +Index connectors must have a name and an {es} index. You can optionally set the +{ref}/docs-refresh.html[refresh] policy and the time field, which contains the +details about when each alert condition was detected. + [float] [[preconfigured-index-configuration]] === Create preconfigured connectors diff --git a/docs/management/connectors/action-types/jira.asciidoc b/docs/management/connectors/action-types/jira.asciidoc index b85e1361844e28..cfa6f7f7eec89e 100644 --- a/docs/management/connectors/action-types/jira.asciidoc +++ b/docs/management/connectors/action-types/jira.asciidoc @@ -1,17 +1,26 @@ -[role="xpack"] [[jira-action-type]] -=== Jira connector and action +== Jira connector and action ++++ Jira ++++ The Jira connector uses the https://developer.atlassian.com/cloud/jira/platform/rest/v2/[REST API v2] to create Jira issues. +[float] +[[define-jira-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/jira-connector.png[Jira connector] + [float] [[jira-connector-configuration]] ==== Connector configuration -Jira connectors have the following configuration properties. +Jira connectors have the following configuration properties: Name:: The name of the connector. URL:: Jira instance URL. @@ -20,26 +29,25 @@ Email:: The account email for HTTP Basic authentication. API token:: Jira API authentication token for HTTP Basic authentication. [float] -[[jira-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-jira-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-jira-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-jira: - name: preconfigured-jira-connector-type - actionTypeId: .jira - config: - apiUrl: https://elastic.atlassian.net - projectKey: ES - secrets: - email: testuser - apiToken: tokenkeystorevalue +xpack.actions.preconfigured: + my-jira: + name: preconfigured-jira-connector-type + actionTypeId: .jira + config: + apiUrl: https://elastic.atlassian.net + projectKey: ES + secrets: + email: testuser + apiToken: tokenkeystorevalue -- Config defines information for the connector type. @@ -53,23 +61,16 @@ Secrets defines sensitive information for the connector type. `apiToken`:: A string that corresponds to *API Token*. Should be stored in the <>. [float] -[[define-jira-ui]] -==== Define connector in {stack-manage-app} - -Define Jira connector properties. +[[jira-action-configuration]] +=== Test connectors -[role="screenshot"] -image::management/connectors/images/jira-connector.png[Jira connector] +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: -Test Jira action parameters. [role="screenshot"] image::management/connectors/images/jira-params-test.png[Jira params test] -[float] -[[jira-action-configuration]] -==== Action configuration - Jira actions have the following configuration properties. Issue type:: The type of the issue. @@ -80,8 +81,14 @@ Description:: The details about the incident. Parent:: The ID or key of the parent issue. Only for `Subtask` issue types. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. +[float] +[[jira-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-jira]] -==== Configure Jira +=== Configure Jira Jira offers free https://www.atlassian.com/software/jira/free[Instances], which you can use to test incidents. diff --git a/docs/management/connectors/action-types/opsgenie.asciidoc b/docs/management/connectors/action-types/opsgenie.asciidoc index 6f96933c59bf87..453aa8c00b8115 100644 --- a/docs/management/connectors/action-types/opsgenie.asciidoc +++ b/docs/management/connectors/action-types/opsgenie.asciidoc @@ -1,17 +1,26 @@ -[role="xpack"] [[opsgenie-action-type]] -=== Opsgenie connector and action +== Opsgenie connector and action ++++ Opsgenie ++++ The Opsgenie connector uses the https://docs.opsgenie.com/docs/alert-api[Opsgenie alert API]. +[float] +[[define-opsgenie-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/opsgenie-connector.png[Opsgenie connector] + [float] [[opsgenie-connector-configuration]] ==== Connector configuration -Opsgenie connectors have the following configuration properties. +Opsgenie connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. URL:: The Opsgenie URL. For example, https://api.opsgenie.com or https://api.eu.opsgenie.com. @@ -20,24 +29,23 @@ NOTE: If you are using the <> set API Key:: The Opsgenie API authentication key for HTTP Basic authentication. For more details about generating Opsgenie API keys, refer to https://support.atlassian.com/opsgenie/docs/create-a-default-api-integration/[Opsgenie documentation]. [float] -[[opgenie-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-opsgenie-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-opsgenie-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-opsgenie: - name: preconfigured-opsgenie-connector-type - actionTypeId: .opsgenie - config: - apiUrl: https://api.opsgenie.com - secrets: - apiKey: apikey +xpack.actions.preconfigured: + my-opsgenie: + name: preconfigured-opsgenie-connector-type + actionTypeId: .opsgenie + config: + apiUrl: https://api.opsgenie.com + secrets: + apiKey: apikey -- Config defines information for the connector type. @@ -49,23 +57,15 @@ Secrets defines sensitive information for the connector type. `apiKey`:: A string that corresponds to *API Key*. [float] -[[define-opsgenie-ui]] -==== Define connector in {stack-manage-app} - -Define Opsgenie connector properties. - -[role="screenshot"] -image::management/connectors/images/opsgenie-connector.png[Opsgenie connector] +[[opsgenie-action-configuration]] +=== Test connectors -Test Opsgenie action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/opsgenie-params-test.png[Opsgenie params test] -[float] -[[opsgenie-action-configuration]] -==== Action configuration - The Opsgenie connector supports two types of actions: Create alert and Close alert. The properties supported for each action are different because Opsgenie defines different properties for each operation. When testing the Opsgenie connector, choose the appropriate action from the selector. Each action has different properties that can be configured. @@ -74,13 +74,13 @@ Action:: Select *Create alert* to configure the actions that occur when a rule's [float] [[opsgenie-action-create-alert-configuration]] -===== Configure the create alert action +==== Configure the create alert action You can configure the create alert action through the form view or using a JSON editor. [float] [[opsgenie-action-create-alert-form-configuration]] -====== Form view +===== Form view The create alert action form has the following configuration properties. @@ -96,7 +96,7 @@ Note:: Additional information for the alert (optional). [float] [[opsgenie-action-create-alert-json-configuration]] -====== JSON editor +===== JSON editor A JSON editor is provided as an alternative to the form view and supports additional fields not shown in the form view. The JSON editor supports all of the forms configuration properties but as lowercase keys as https://docs.opsgenie.com/docs/alert-api#create-alert[described in the Opsgenie API documentation]. The JSON editor supports the following additional properties: @@ -141,7 +141,7 @@ Example JSON editor contents [float] [[opsgenie-action-close-alert-configuration]] -===== Close alert configuration +==== Close alert configuration The close alert action has the following configuration properties. @@ -150,9 +150,16 @@ Note:: Additional information for the alert (optional). Source:: The display name of the source (optional). User:: The display name of the owner (optional). +[float] +[[opgenie-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + + [float] [[configuring-opsgenie]] -==== Configure an Opsgenie account +=== Configure an Opsgenie account After obtaining an Opsgenie instance, configure the API integration. For details, refer to the https://support.atlassian.com/opsgenie/docs/create-a-default-api-integration/[Opsgenie documentation]. diff --git a/docs/management/connectors/action-types/pagerduty.asciidoc b/docs/management/connectors/action-types/pagerduty.asciidoc index aba9db8f997f74..ed98e4259d0eba 100644 --- a/docs/management/connectors/action-types/pagerduty.asciidoc +++ b/docs/management/connectors/action-types/pagerduty.asciidoc @@ -1,41 +1,49 @@ -[role="xpack"] [[pagerduty-action-type]] -=== PagerDuty connector and action +== PagerDuty connector and action ++++ PagerDuty ++++ The PagerDuty connector uses the https://v2.developer.pagerduty.com/docs/events-api-v2[v2 Events API] to trigger, acknowledge, and resolve PagerDuty alerts. +[float] +[[define-pagerduty-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/pagerduty-connector.png[PagerDuty connector] + [float] [[pagerduty-connector-configuration]] ==== Connector configuration -PagerDuty connectors have the following configuration properties. +PagerDuty connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is added to the allowed hosts. Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. [float] -[[pagerduty-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-pagerduty-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-pagerduty-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-pagerduty: - name: preconfigured-pagerduty-connector-type - actionTypeId: .pagerduty - config: - apiUrl: https://test.host - secrets: - routingKey: testroutingkey +xpack.actions.preconfigured: + my-pagerduty: + name: preconfigured-pagerduty-connector-type + actionTypeId: .pagerduty + config: + apiUrl: https://test.host + secrets: + routingKey: testroutingkey -- Config defines information for the connector type. @@ -47,23 +55,15 @@ Secrets defines sensitive information for the connector type. `routingKey`:: A string that corresponds to *Integration Key*. [float] -[[define-pagerduty-ui]] -==== Define connector in {stack-manage-app} - -Define PagerDuty connector properties. - -[role="screenshot"] -image::management/connectors/images/pagerduty-connector.png[PagerDuty connector] +[[pagerduty-action-configuration]] +=== Test connectors -Test PagerDuty action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/pagerduty-params-test.png[PagerDuty params test] -[float] -[[pagerduty-action-configuration]] -==== Action configuration - PagerDuty actions have the following properties. Severity:: The perceived severity of on the affected system. This can be one of `Critical`, `Error`, `Warning` or `Info`(default). @@ -78,9 +78,16 @@ Class:: An *optional* value indicating the class/type of the event, for For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. +[float] +[[pagerduty-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + + [float] [[pagerduty-benefits]] -==== Configure PagerDuty +=== Configure PagerDuty By integrating PagerDuty with rules, you can: @@ -90,14 +97,14 @@ By integrating PagerDuty with rules, you can: [float] [[pagerduty-support]] -==== Support +=== Support If you need help with this integration, get in touch with the {kib} team by visiting https://support.elastic.co[support.elastic.co] or by using the *Ask Elastic* option in the {kib} Help menu. You can also select the {kib} category at https://discuss.elastic.co/[discuss.elastic.co]. [float] [[pagerduty-integration-walkthrough]] -==== Integration with PagerDuty walkthrough +=== Integration with PagerDuty walkthrough [[pagerduty-in-pagerduty]] *In PagerDuty* @@ -145,8 +152,8 @@ See <> for how to obtain the endpoint and k . Set up an action using your PagerDuty connector, by determining: + -* The action’s type: Trigger, Resolve, or Acknowledge. -* The event’s severity: Info, warning, error, or critical. +* The action's type: Trigger, Resolve, or Acknowledge. +* The event's severity: Info, warning, error, or critical. * An array of different fields, including the timestamp, group, class, component, and your dedup key. By default, the dedup is configured to create a new PagerDuty incident for each alert and reuse the incident when a recovered alert reactivates. Depending on your custom needs, assign them variables from the rule context. To see the available context variables, click on the *Add variable* icon next diff --git a/docs/management/connectors/action-types/resilient.asciidoc b/docs/management/connectors/action-types/resilient.asciidoc index 3ba0e8e701dfdc..a317adf3bfe3e6 100644 --- a/docs/management/connectors/action-types/resilient.asciidoc +++ b/docs/management/connectors/action-types/resilient.asciidoc @@ -1,17 +1,26 @@ -[role="xpack"] [[resilient-action-type]] -=== IBM Resilient connector and action +== IBM Resilient connector and action ++++ IBM Resilient ++++ The IBM Resilient connector uses the https://developer.ibm.com/security/resilient/rest/[RESILIENT REST v2] to create IBM Resilient incidents. +[float] +[[define-resilient-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/resilient-connector.png[IBM Resilient connector] + [float] [[resilient-connector-configuration]] ==== Connector configuration -IBM Resilient connectors have the following configuration properties. +IBM Resilient connectors have the following configuration properties: Name:: The name of the connector. URL:: IBM Resilient instance URL. @@ -20,26 +29,25 @@ API key ID:: The authentication key ID for HTTP Basic authentication. API key secret:: The authentication key secret for HTTP Basic authentication. [float] -[[resilient-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-resilient-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-resilient-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-resilient: - name: preconfigured-resilient-connector-type - actionTypeId: .resilient - config: - apiUrl: https://elastic.resilient.net - orgId: ES - secrets: - apiKeyId: testuser - apiKeySecret: tokenkeystorevalue +xpack.actions.preconfigured: + my-resilient: + name: preconfigured-resilient-connector-type + actionTypeId: .resilient + config: + apiUrl: https://elastic.resilient.net + orgId: ES + secrets: + apiKeyId: testuser + apiKeySecret: tokenkeystorevalue -- Config defines information for the connector type. @@ -53,22 +61,15 @@ Secrets defines sensitive information for the connector type. `apiKeySecret`:: A string that corresponds to *API Key secret*. Should be stored in the <>. [float] -[[define-resilient-ui]] -==== Define connector in {stack-manage-app} - -Define IBM Resilient connector properties. - -[role="screenshot"] -image::management/connectors/images/resilient-connector.png[IBM Resilient connector] +[[resilient-action-configuration]] +=== Test connectors -Test IBM Resilient action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/resilient-params-test.png[IBM Resilient params test] -[float] -[[resilient-action-configuration]] -==== Action configuration IBM Resilient actions have the following configuration properties. @@ -78,8 +79,14 @@ Name:: A name for the issue, used for searching the contents of the knowledge ba Description:: The details about the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. +[float] +[[resilient-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-resilient]] -==== Configure IBM Resilient +=== Configure IBM Resilient IBM Resilient offers https://www.ibm.com/security/intelligent-orchestration/resilient[Instances], which you can use to test incidents. diff --git a/docs/management/connectors/action-types/server-log.asciidoc b/docs/management/connectors/action-types/server-log.asciidoc index a7568acfdf3db6..964d8300761a36 100644 --- a/docs/management/connectors/action-types/server-log.asciidoc +++ b/docs/management/connectors/action-types/server-log.asciidoc @@ -10,12 +10,6 @@ You can create a server log connectors in {kib} or by using the <>. If you are running {kib} on-prem, you can also create preconfigured server log connectors. -[float] -[[server-log-connector-configuration]] -=== Connector configuration - -Server log connectors do not have any configuration properties other than a name. - [float] [[define-serverlog-ui]] === Create connectors in {kib} @@ -27,6 +21,12 @@ or as needed when you're creating a rule. For example: image::management/connectors/images/serverlog-connector.png[Server log connector] // NOTE: This is an autogenerated screenshot. Do not edit it directly. +[float] +[[server-log-connector-configuration]] +==== Connector configuration + +Server log connectors do not have any configuration properties other than a name. + [float] [[preconfigured-server-log-configuration]] === Create preconfigured connectors diff --git a/docs/management/connectors/action-types/servicenow-itom.asciidoc b/docs/management/connectors/action-types/servicenow-itom.asciidoc index 6016ee3d6f8c7b..1549949cd23b9d 100644 --- a/docs/management/connectors/action-types/servicenow-itom.asciidoc +++ b/docs/management/connectors/action-types/servicenow-itom.asciidoc @@ -48,11 +48,24 @@ include::servicenow.asciidoc[tag=servicenow-certificate] include::servicenow.asciidoc[tag=servicenow-endpoint] +[float] +[[define-servicenow-itom-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. You must choose whether to use OAuth for authentication. + +[role="screenshot"] +image::management/connectors/images/servicenow-itom-connector-basic.png[{sn-itom} connector using basic auth] + +[role="screenshot"] +image::management/connectors/images/servicenow-itom-connector-oauth.png[{sn-itom} connector using OAuth] + [float] [[servicenow-itom-connector-configuration]] -=== Connector configuration +==== Connector configuration -{sn-itom} connectors have the following configuration properties. +{sn-itom} connectors have the following configuration properties: Name:: The name of the connector. Is OAuth:: The type of authentication to use. @@ -67,26 +80,25 @@ Private Key:: The RSA private key generated during setup. Private Key Password:: The password for the RSA private key generated during setup, if set. [float] -[[servicenow-itom-connector-networking-configuration]] -=== Connector networking configuration +[[preconfigured-servicenow-itom-configuration]] +=== Create preconfigured connectors -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. - -[float] -[[Preconfigured-servicenow-itom-configuration]] -=== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: Connector using Basic Authentication [source,text] -- - my-servicenow-itom: - name: preconfigured-servicenow-connector-type - actionTypeId: .servicenow-itom - config: - apiUrl: https://example.service-now.com/ - secrets: - username: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-servicenow-itom: + name: preconfigured-servicenow-connector-type + actionTypeId: .servicenow-itom + config: + apiUrl: https://example.service-now.com/ + secrets: + username: testuser + password: passwordkeystorevalue -- Connector using OAuth @@ -124,26 +136,15 @@ Secrets defines sensitive information for the connector type. `privateKeyPassword`:: A string that corresponds to *Private Key Password*. [float] -[[define-servicenow-itom-ui]] -=== Define connector in {stack-manage-app} - -Define {sn-itom} connector properties. Choose whether to use OAuth for authentication. - -[role="screenshot"] -image::management/connectors/images/servicenow-itom-connector-basic.png[{sn-itom} connector using basic auth] - -[role="screenshot"] -image::management/connectors/images/servicenow-itom-connector-oauth.png[{sn-itom} connector using OAuth] +[[servicenow-itom-action-configuration]] +=== Test connectors -Test {sn-itom} action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/servicenow-itom-params-test.png[{sn-itom} params test] -[float] -[[servicenow-itom-action-configuration]] -=== Action configuration - {sn-itom} actions have the following configuration properties. Source:: The name of the event source type. @@ -158,6 +159,12 @@ Description:: The details about the event. Refer to https://docs.servicenow.com/bundle/rome-it-operations-management/page/product/event-management/task/send-events-via-web-service.html[{sn} documentation] for more information about the properties. +[float] +[[servicenow-itom-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-servicenow-itom]] === Configure {sn-itom} diff --git a/docs/management/connectors/action-types/servicenow-sir.asciidoc b/docs/management/connectors/action-types/servicenow-sir.asciidoc index e9a9c80b13a454..56f1ccef67ac74 100644 --- a/docs/management/connectors/action-types/servicenow-sir.asciidoc +++ b/docs/management/connectors/action-types/servicenow-sir.asciidoc @@ -91,11 +91,24 @@ To update a deprecated connector: .. Enter the username and password of your {sn} instance. . Click *Update*. +[float] +[[define-servicenow-sir-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. You must choose whether to use OAuth for authentication. + +[role="screenshot"] +image::management/connectors/images/servicenow-sir-connector-basic.png[{sn-sir} connector using basic auth] + +[role="screenshot"] +image::management/connectors/images/servicenow-sir-connector-oauth.png[{sn-sir} connector using OAuth] + [float] [[servicenow-sir-connector-configuration]] -=== Connector configuration +==== Connector configuration -{sn-sir} connectors have the following configuration properties. +{sn-sir} connectors have the following configuration properties: Name:: The name of the connector. Is OAuth:: The type of authentication to use. @@ -110,45 +123,45 @@ Private Key:: The RSA private key generated during setup. Private Key Password:: The password for the RSA private key generated during setup, if set. [float] -[[servicenow-sir-connector-networking-configuration]] -=== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-servicenow-sir-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-servicenow-sir-configuration]] -=== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: Connector using Basic Authentication [source,text] -- - my-servicenow-sir: - name: preconfigured-servicenow-connector-type - actionTypeId: .servicenow-sir - config: - apiUrl: https://example.service-now.com/ - usesTableApi: false - secrets: - username: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-servicenow-sir: + name: preconfigured-servicenow-connector-type + actionTypeId: .servicenow-sir + config: + apiUrl: https://example.service-now.com/ + usesTableApi: false + secrets: + username: testuser + password: passwordkeystorevalue -- Connector using OAuth [source,text] -- - my-servicenow: - name: preconfigured-oauth-servicenow-connector-type - actionTypeId: .servicenow-sir - config: - apiUrl: https://example.service-now.com/ - usesTableApi: false - isOAuth: true - userIdentifierValue: testuser@email.com - clientId: abcdefghijklmnopqrstuvwxyzabcdef - jwtKeyId: fedcbazyxwvutsrqponmlkjihgfedcba - secrets: - clientSecret: secretsecret - privateKey: -----BEGIN RSA PRIVATE KEY-----\nprivatekeyhere\n-----END RSA PRIVATE KEY----- +xpack.actions.preconfigured: + my-servicenow: + name: preconfigured-oauth-servicenow-connector-type + actionTypeId: .servicenow-sir + config: + apiUrl: https://example.service-now.com/ + usesTableApi: false + isOAuth: true + userIdentifierValue: testuser@email.com + clientId: abcdefghijklmnopqrstuvwxyzabcdef + jwtKeyId: fedcbazyxwvutsrqponmlkjihgfedcba + secrets: + clientSecret: secretsecret + privateKey: -----BEGIN RSA PRIVATE KEY-----\nprivatekeyhere\n-----END RSA PRIVATE KEY----- -- Config defines information for the connector type. @@ -172,26 +185,15 @@ Secrets defines sensitive information for the connector type. `privateKeyPassword`:: A string that corresponds to *Private Key Password*. [float] -[[define-servicenow-sir-ui]] -=== Define connector in {stack-manage-app} - -Define {sn} SecOps connector properties. Choose whether to use OAuth for authentication. - -[role="screenshot"] -image::management/connectors/images/servicenow-sir-connector-basic.png[{sn-sir} connector using basic auth] - -[role="screenshot"] -image::management/connectors/images/servicenow-sir-connector-oauth.png[{sn-sir} connector using OAuth] +[[servicenow-sir-action-configuration]] +=== Test connectors -Test {sn-sir} action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/servicenow-sir-params-test.png[{sn-sir} params test] -[float] -[[servicenow-sir-action-configuration]] -=== Action configuration - {sn-sir} actions have the following configuration properties. Short description:: A short description for the incident, used for searching the contents of the knowledge base. @@ -206,6 +208,12 @@ Correlation Display:: A descriptive label of the alert for correlation purposes Description:: The details about the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. +[float] +[[servicenow-sir-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-servicenow-sir]] === Configure {sn-sir} diff --git a/docs/management/connectors/action-types/servicenow.asciidoc b/docs/management/connectors/action-types/servicenow.asciidoc index b5c5bcecc1800d..b1ad3be504af46 100644 --- a/docs/management/connectors/action-types/servicenow.asciidoc +++ b/docs/management/connectors/action-types/servicenow.asciidoc @@ -175,11 +175,24 @@ To update a deprecated connector: .. Enter the username and password of your {sn} instance. . Click *Update*. +[float] +[[define-servicenow-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. You must choose whether to use OAuth for authentication. + +[role="screenshot"] +image::management/connectors/images/servicenow-connector-basic.png[ServiceNow connector using basic auth] + +[role="screenshot"] +image::management/connectors/images/servicenow-connector-oauth.png[ServiceNow connector using OAuth] + [float] [[servicenow-connector-configuration]] -=== Connector configuration +==== Connector configuration -{sn-itsm} connectors have the following configuration properties. +{sn-itsm} connectors have the following configuration properties: Name:: The name of the connector. Is OAuth:: The type of authentication to use. @@ -194,45 +207,45 @@ Private Key:: The RSA private key generated during setup. Private Key Password:: The password for the RSA private key generated during setup, if set. [float] -[[servicenow-connector-networking-configuration]] -=== Connector networking configuration +[[preconfigured-servicenow-configuration]] +=== Create preconfigured connectors -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. - -[float] -[[Preconfigured-servicenow-configuration]] -=== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: Connector using Basic Authentication [source,text] -- - my-servicenow: - name: preconfigured-servicenow-connector-type - actionTypeId: .servicenow - config: - apiUrl: https://example.service-now.com/ - usesTableApi: false - secrets: - username: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-servicenow: + name: preconfigured-servicenow-connector-type + actionTypeId: .servicenow + config: + apiUrl: https://example.service-now.com/ + usesTableApi: false + secrets: + username: testuser + password: passwordkeystorevalue -- Connector using OAuth [source,text] -- - my-servicenow: - name: preconfigured-oauth-servicenow-connector-type - actionTypeId: .servicenow - config: - apiUrl: https://example.service-now.com/ - usesTableApi: false - isOAuth: true - userIdentifierValue: testuser@email.com - clientId: abcdefghijklmnopqrstuvwxyzabcdef - jwtKeyId: fedcbazyxwvutsrqponmlkjihgfedcba - secrets: - clientSecret: secretsecret - privateKey: -----BEGIN RSA PRIVATE KEY-----\nprivatekeyhere\n-----END RSA PRIVATE KEY----- +xpack.actions.preconfigured: + my-servicenow: + name: preconfigured-oauth-servicenow-connector-type + actionTypeId: .servicenow + config: + apiUrl: https://example.service-now.com/ + usesTableApi: false + isOAuth: true + userIdentifierValue: testuser@email.com + clientId: abcdefghijklmnopqrstuvwxyzabcdef + jwtKeyId: fedcbazyxwvutsrqponmlkjihgfedcba + secrets: + clientSecret: secretsecret + privateKey: -----BEGIN RSA PRIVATE KEY-----\nprivatekeyhere\n-----END RSA PRIVATE KEY----- -- Config defines information for the connector type. @@ -256,25 +269,15 @@ Secrets defines sensitive information for the connector type. `privateKeyPassword`:: A string that corresponds to *Private Key Password*. [float] -[[define-servicenow-ui]] -=== Define connector in {stack-manage-app} - -Define {sn-itsm} connector properties. Choose whether to use OAuth for authentication. - -[role="screenshot"] -image::management/connectors/images/servicenow-connector-basic.png[ServiceNow connector using basic auth] - -[role="screenshot"] -image::management/connectors/images/servicenow-connector-oauth.png[ServiceNow connector using OAuth] +[[servicenow-action-configuration]] +=== Test connectors -Test {sn-itsm} action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/servicenow-params-test.png[ServiceNow params test] -[float] -[[servicenow-action-configuration]] -=== Action configuration {sn-itsm} actions have the following configuration properties. @@ -292,6 +295,12 @@ Short description:: A short description for the incident, used for searching Description:: The details about the incident. Additional comments:: Additional information for the client, such as how to troubleshoot the issue. +[float] +[[servicenow-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-servicenow]] === Configure {sn} diff --git a/docs/management/connectors/action-types/slack.asciidoc b/docs/management/connectors/action-types/slack.asciidoc index cd6860d6d3027d..140ea742692b90 100644 --- a/docs/management/connectors/action-types/slack.asciidoc +++ b/docs/management/connectors/action-types/slack.asciidoc @@ -1,38 +1,46 @@ -[role="xpack"] [[slack-action-type]] -=== Slack connector and action +== Slack connector and action ++++ Slack ++++ The Slack connector uses https://api.slack.com/incoming-webhooks[Slack Incoming Webhooks]. +[float] +[[define-slack-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/slack-connector.png[Slack connector] + [float] [[slack-connector-configuration]] ==== Connector configuration -Slack connectors have the following configuration properties. +Slack connectors have the following configuration properties: Name:: The name of the connector. Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messaging/webhooks#getting_started[Slack Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. [float] -[[slack-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-slack-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-slack-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-slack: - name: preconfigured-slack-connector-type - actionTypeId: .slack - secrets: - webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz' +xpack.actions.preconfigured: + my-slack: + name: preconfigured-slack-connector-type + actionTypeId: .slack + secrets: + webhookUrl: 'https://hooks.slack.com/services/abcd/efgh/ijklmnopqrstuvwxyz' -- Secrets defines sensitive information for the connector type. @@ -40,26 +48,24 @@ Secrets defines sensitive information for the connector type. `webhookUrl`:: A string that corresponds to *Webhook URL*. [float] -[[define-slack-ui]] -==== Define connector in {stack-manage-app} +[[slack-action-configuration]] +=== Test connectors -Define Slack connector properties. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] -image::management/connectors/images/slack-connector.png[Slack connector] +image::management/connectors/images/slack-params-test.png[Slack params test] -Test Slack action parameters. +Slack actions have the following properties: -[role="screenshot"] -image::management/connectors/images/slack-params-test.png[Slack params test] +Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. [float] -[[slack-action-configuration]] -==== Action configuration - -Slack actions have the following properties. +[[slack-connector-networking-configuration]] +=== Connector networking configuration -Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. [float] [[configuring-slack]] diff --git a/docs/management/connectors/action-types/swimlane.asciidoc b/docs/management/connectors/action-types/swimlane.asciidoc index ff4f1bcb05fe00..18e05b04eca51e 100644 --- a/docs/management/connectors/action-types/swimlane.asciidoc +++ b/docs/management/connectors/action-types/swimlane.asciidoc @@ -1,73 +1,88 @@ -[role="xpack"] [[swimlane-action-type]] -=== Swimlane connector and action +== Swimlane connector and action ++++ Swimlane ++++ The Swimlane connector uses the https://swimlane.com/knowledge-center/docs/developer-guide/rest-api/[Swimlane REST API] to create Swimlane records. +[float] +[[define-swimlane-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/swimlane-connector.png[Swimlane connector] + [float] [[swimlane-connector-configuration]] ==== Connector configuration -Swimlane connectors have the following configuration properties. +Swimlane connectors have the following configuration properties: Name:: The name of the connector. URL:: Swimlane instance URL. Application ID:: Swimlane application ID. API token:: Swimlane API authentication token for HTTP Basic authentication. + [float] -[[Preconfigured-swimlane-configuration]] -==== Preconfigured connector type +[[preconfigured-swimlane-configuration]] +=== Create preconfigured connectors + +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-swimlane: - name: preconfigured-swimlane-connector-type - actionTypeId: .swimlane - config: - apiUrl: https://elastic.swimlaneurl.us - appId: app-id - mappings: - alertIdConfig: - fieldType: text - id: agp4s - key: alert-id - name: Alert ID - caseIdConfig: - fieldType: text - id: ae1mi - key: case-id - name: Case ID - caseNameConfig: - fieldType: text - id: anxnr - key: case-name - name: Case Name - commentsConfig: - fieldType: comments - id: au18d - key: comments - name: Comments - descriptionConfig: - fieldType: text - id: ae1gd - key: description - name: Description - ruleNameConfig: - fieldType: text - id: avfsl - key: rule-name - name: Rule Name - severityConfig: - fieldType: text - id: a71ik - key: severity - name: severity - secrets: - apiToken: tokenkeystorevalue +xpack.actions.preconfigured: + my-swimlane: + name: preconfigured-swimlane-connector-type + actionTypeId: .swimlane + config: + apiUrl: https://elastic.swimlaneurl.us + appId: app-id + mappings: + alertIdConfig: + fieldType: text + id: agp4s + key: alert-id + name: Alert ID + caseIdConfig: + fieldType: text + id: ae1mi + key: case-id + name: Case ID + caseNameConfig: + fieldType: text + id: anxnr + key: case-name + name: Case Name + commentsConfig: + fieldType: comments + id: au18d + key: comments + name: Comments + descriptionConfig: + fieldType: text + id: ae1gd + key: description + name: Description + ruleNameConfig: + fieldType: text + id: avfsl + key: rule-name + name: Rule Name + severityConfig: + fieldType: text + id: a71ik + key: severity + name: severity + secrets: + apiToken: tokenkeystorevalue -- Config defines information for the connector type. @@ -80,23 +95,15 @@ Secrets defines sensitive information for the connector type. `apiToken`:: A string that corresponds to *API Token*. Should be stored in the <>. [float] -[[define-swimlane-ui]] -==== Define connector in {stack-manage-app} - -Define Swimlane connector properties. - -[role="screenshot"] -image::management/connectors/images/swimlane-connector.png[Swimlane connector] +[[swimlane-action-configuration]] +=== Test connectors -Test Swimlane action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/swimlane-params-test.png[Swimlane params test] -[float] -[[swimlane-action-configuration]] -==== Action configuration - Swimlane actions have the following configuration properties. Comments:: Additional information for the client, such as how to troubleshoot the issue. diff --git a/docs/management/connectors/action-types/teams.asciidoc b/docs/management/connectors/action-types/teams.asciidoc index f80e3e010f995b..fd4798be97e563 100644 --- a/docs/management/connectors/action-types/teams.asciidoc +++ b/docs/management/connectors/action-types/teams.asciidoc @@ -1,38 +1,46 @@ -[role="xpack"] [[teams-action-type]] -=== Microsoft Teams connector and action +== Microsoft Teams connector and action ++++ Microsoft Teams ++++ The Microsoft Teams connector uses https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook[Incoming Webhooks]. +[float] +[[define-teams-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/teams-connector.png[Teams connector] + [float] [[teams-connector-configuration]] ==== Connector configuration -Microsoft Teams connectors have the following configuration properties. +Microsoft Teams connectors have the following configuration properties: Name:: The name of the connector. Webhook URL:: The URL of the incoming webhook. See https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#add-an-incoming-webhook-to-a-teams-channel[Add Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. [float] -[[teams-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-teams-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-teams-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-teams: - name: preconfigured-teams-connector-type - actionTypeId: .teams - secrets: - webhookUrl: 'https://outlook.office.com/webhook/abcd@0123456/IncomingWebhook/abcdefgh/ijklmnopqrstuvwxyz' +xpack.actions.preconfigured: + my-teams: + name: preconfigured-teams-connector-type + actionTypeId: .teams + secrets: + webhookUrl: 'https://outlook.office.com/webhook/abcd@0123456/IncomingWebhook/abcdefgh/ijklmnopqrstuvwxyz' -- Secrets defines sensitive information for the connector type. @@ -40,30 +48,28 @@ Secrets defines sensitive information for the connector type. `webhookUrl`:: A string that corresponds to *Webhook URL*. [float] -[[define-teams-ui]] -==== Define connector in {stack-manage-app} - -Define Teams connector properties. - -[role="screenshot"] -image::management/connectors/images/teams-connector.png[Teams connector] +[[teams-action-configuration]] +=== Test connectors -Test Teams action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/teams-params-test.png[Teams params test] -[float] -[[teams-action-configuration]] -==== Action configuration - Microsoft Teams actions have the following properties. Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. +[float] +[[teams-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[configuring-teams]] -==== Configure a Microsoft Teams account +=== Configure a Microsoft Teams account You need a https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook[Microsoft Teams webhook URL] to configure a Microsoft Teams action. To create a webhook diff --git a/docs/management/connectors/action-types/tines.asciidoc b/docs/management/connectors/action-types/tines.asciidoc index 70a36c070b0412..218de7cb960f20 100644 --- a/docs/management/connectors/action-types/tines.asciidoc +++ b/docs/management/connectors/action-types/tines.asciidoc @@ -1,4 +1,3 @@ -[role="xpack"] [[tines-action-type]] == Tines connector ++++ @@ -7,33 +6,46 @@ The Tines connector uses Tines's https://www.tines.com/docs/actions/types/webhook[Webhook actions] to send events via POST request. +[float] +[[define-tines-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/tines-connector.png[Tines connector] + [float] [[tines-connector-configuration]] -=== Connector configuration +==== Connector configuration -Tines connectors have the following configuration properties. +Tines connectors have the following configuration properties: URL:: The Tines tenant URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. Email:: The email used to sign in to Tines. API Token:: A Tines API token created by the user. For more information, refer to the https://www.tines.com/api/authentication#generate-api-token[Tines documentation]. -[role="screenshot"] -image::management/connectors/images/tines-connector.png[Tines connector] [float] -[[Preconfigured-tines-configuration]] -==== Preconfigured connector type +[[preconfigured-tines-configuration]] +=== Create preconfigured connectors + +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-tines: - name: preconfigured-tines-connector-type - actionTypeId: .tines - config: - url: https://some-tenant-2345.tines.com - secrets: - email: some.address@test.com - token: ausergeneratedapitoken +xpack.actions.preconfigured: + my-tines: + name: preconfigured-tines-connector-type + actionTypeId: .tines + config: + url: https://some-tenant-2345.tines.com + secrets: + email: some.address@test.com + token: ausergeneratedapitoken -- Config defines information for the connector type. @@ -47,22 +59,19 @@ Secrets defines sensitive information for the connector type. [float] [[tines-action-parameters]] -=== Action parameters +=== Test connectors -Tines action have the following parameters. +Tines actions have the following parameters. Story:: The Story to send the events to. Webhook:: The Webhook action from the previous story that will receive the events, it is the data entry point. -Test Tines action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/tines-params-test.png[Tines params test] -[float] -[[tines-action-format]] -=== Actions - Once the Tines connector has been configured in an alerting rule: [role="screenshot"] @@ -94,6 +103,8 @@ image::management/connectors/images/tines_elastic_stories.png[Tines Elastic stor They can be imported directly into your Tines tenant. +[float] +[[tines-format]] === Format Tines connector will send the data in JSON format. diff --git a/docs/management/connectors/action-types/torq.asciidoc b/docs/management/connectors/action-types/torq.asciidoc index 70ac19be25ec3b..39ef2585e62b9c 100644 --- a/docs/management/connectors/action-types/torq.asciidoc +++ b/docs/management/connectors/action-types/torq.asciidoc @@ -1,16 +1,25 @@ -[role="xpack"] [[torq-action-type]] -=== Torq connector and action +== Torq connector and action ++++ Torq ++++ The Torq connector uses a Torq webhook to trigger workflows with Kibana actions. +[float] +[[define-torq-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/torq-configured-connector.png[configured Torq connector] + [float] [[torq-connector-configuration]] ==== Connector configuration -Torq connectors have the following configuration properties. +Torq connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the Stack Management UI connector listing, and in the connector list when configuring an action. @@ -19,18 +28,23 @@ Torq endpoint URL:: Endpoint URL (webhook) of the Elastic Security integration y Torq authentication header secret:: Secret of the webhook authentication header. [float] -[[Preconfigured-torq-configuration]] -==== Preconfigured connector type +[[preconfigured-torq-configuration]] +=== Create preconfigured connectors + +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,yaml] -- - my-torq: - name: preconfigured-torq-connector-type - actionTypeId: .torq - config: - webhookIntegrationUrl: https://hooks.torq.io/v1/somehook - secrets: - token: mytorqtoken +xpack.actions.preconfigured: + my-torq: + name: preconfigured-torq-connector-type + actionTypeId: .torq + config: + webhookIntegrationUrl: https://hooks.torq.io/v1/somehook + secrets: + token: mytorqtoken -- Config defines information for the connector type. @@ -42,24 +56,16 @@ Secrets defines sensitive information for the connector type. `token`:: A string that corresponds to **Torq authentication header secret**. [float] -[[define-torq-ui]] -==== Define connector in Stack Management - -Define Torq connector properties. - -[role="screenshot"] -image::management/connectors/images/torq-configured-connector.png[configured Torq connector] +[[torq-action-configuration]] +=== Test connectors -Test Torq action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/torq-connector-test.png[Torq connector test] -[float] -[[torq-action-configuration]] -==== Action configuration - - Torq actions have the following configuration properties. +Torq actions have the following configuration properties. - Body:: JSON payload to send to Torq. +Body:: JSON payload to send to Torq. diff --git a/docs/management/connectors/action-types/webhook.asciidoc b/docs/management/connectors/action-types/webhook.asciidoc index 9f6d41c8cb85b1..5424eb87c3ae42 100644 --- a/docs/management/connectors/action-types/webhook.asciidoc +++ b/docs/management/connectors/action-types/webhook.asciidoc @@ -1,17 +1,26 @@ -[role="xpack"] [[webhook-action-type]] -=== Webhook connector and action +== Webhook connector and action ++++ Webhook ++++ The Webhook connector uses https://github.com/axios/axios[axios] to send a POST or PUT request to a web service. +[float] +[[define-webhook-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. For example: + +[role="screenshot"] +image::management/connectors/images/webhook-connector.png[Webhook connector] + [float] [[webhook-connector-configuration]] ==== Connector configuration -Webhook connectors have the following configuration properties. +Webhook connectors have the following configuration properties: Name:: The name of the connector. URL:: The request URL. If you are using the <> setting, make sure the hostname is added to the allowed hosts. @@ -22,28 +31,27 @@ Username:: Username for HTTP basic authentication. Password:: Password for HTTP basic authentication. [float] -[[webhook-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-webhook-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-webhook-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: [source,text] -- - my-webhook: - name: preconfigured-webhook-connector-type - actionTypeId: .webhook - config: - url: https://test.host - method: post - headers: - testheader: testvalue - secrets: - user: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-webhook: + name: preconfigured-webhook-connector-type + actionTypeId: .webhook + config: + url: https://test.host + method: post + headers: + testheader: testvalue + secrets: + user: testuser + password: passwordkeystorevalue -- Config defines information for the connector type. @@ -59,23 +67,15 @@ Secrets defines sensitive information for the connector type. `password`:: A string that corresponds to *Password*. Should be stored in the <>. Required if `hasAuth` is set to `true`. [float] -[[define-webhook-ui]] -==== Define connector in {stack-manage-app} - -Define Webhook connector properties. - -[role="screenshot"] -image::management/connectors/images/webhook-connector.png[Webhook connector] +[[webhook-action-configuration]] +=== Test connectors -Test Webhook action parameters. +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/webhook-params-test.png[Webhook params test] -[float] -[[webhook-action-configuration]] -==== Action configuration - Webhook actions have the following properties. Body:: A JSON payload sent to the request URL. For example: @@ -92,3 +92,9 @@ Body:: A JSON payload sent to the request URL. For example: Mustache template variables (the text enclosed in double braces, for example, `context.rule.name`) have their values escaped, so that the final JSON will be valid (escaping double quote characters). For more information on Mustache template variables, refer to <>. + +[float] +[[webhook-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. \ No newline at end of file diff --git a/docs/management/connectors/action-types/xmatters.asciidoc b/docs/management/connectors/action-types/xmatters.asciidoc index e4ad978dc35dd2..fce6edd35ab8ba 100644 --- a/docs/management/connectors/action-types/xmatters.asciidoc +++ b/docs/management/connectors/action-types/xmatters.asciidoc @@ -1,11 +1,24 @@ [[xmatters-action-type]] -=== xMatters connector and action +== xMatters connector and action ++++ xMatters ++++ The xMatters connector uses the https://help.xmatters.com/integrations/#cshid=Elastic[xMatters Workflow for Elastic] to send actionable alerts to on-call xMatters resources. +[float] +[[define-xmatters-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}* +or as needed when you're creating a rule. You must choose between basic and URL authentication for the requests. + +[role="screenshot"] +image::management/connectors/images/xmatters-connector-basic.png[xMatters connector with basic authentication] + +[role="screenshot"] +image::management/connectors/images/xmatters-connector-url.png[xMatters connector with url authentication] + [float] [[xmatters-connector-configuration]] ==== Connector configuration @@ -19,39 +32,39 @@ Username:: Username for HTTP Basic Authentication. Password:: Password for HTTP Basic Authentication. [float] -[[xmatters-connector-networking-configuration]] -==== Connector networking configuration - -Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. +[[preconfigured-xmatters-configuration]] +=== Create preconfigured connectors -[float] -[[Preconfigured-xmatters-configuration]] -==== Preconfigured connector type +If you are running {kib} on-prem, you can define connectors by +adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. +For example: Connector using Basic Authentication [source,text] -- - my-xmatters: - name: preconfigured-xmatters-connector-type - actionTypeId: .xmatters - config: - configUrl: https://test.host - usesBasic: true - secrets: - user: testuser - password: passwordkeystorevalue +xpack.actions.preconfigured: + my-xmatters: + name: preconfigured-xmatters-connector-type + actionTypeId: .xmatters + config: + configUrl: https://test.host + usesBasic: true + secrets: + user: testuser + password: passwordkeystorevalue -- Connector using URL Authentication [source,text] -- - my-xmatters: - name: preconfigured-xmatters-connector-type - actionTypeId: .xmatters - config: - usesBasic: false - secrets: - secretsUrl: https://test.host?apiKey=1234-abcd +xpack.actions.preconfigured: + my-xmatters: + name: preconfigured-xmatters-connector-type + actionTypeId: .xmatters + config: + usesBasic: false + secrets: + secretsUrl: https://test.host?apiKey=1234-abcd -- Config defines information for the connector type: @@ -69,34 +82,29 @@ Secrets defines sensitive information for the connector type: `secretsUrl`:: A URL string that corresponds to *URL*. Only used if `usesBasic` is false, indicating the API key is included in the URL. [float] -[[define-xmatters-ui]] -==== Define connector in {stack-manage-app} - -Define xMatters connector properties. Choose between basic and URL authentication for the requests: - -[role="screenshot"] -image::management/connectors/images/xmatters-connector-basic.png[xMatters connector with basic authentication] - -[role="screenshot"] -image::management/connectors/images/xmatters-connector-url.png[xMatters connector with url authentication] +[[xmatters-action-configuration]] +=== Test connectors -Test xMatters rule parameters: +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: [role="screenshot"] image::management/connectors/images/xmatters-params-test.png[xMatters params test] -[float] -[[xmatters-action-configuration]] -==== Action configuration - xMatters rules have the following properties: Severity:: Severity of the rule. Tags:: Comma-separated list of tags for the rule as provided by the user in Elastic. +[float] +[[xmatters-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. + [float] [[xmatters-benefits]] -==== Configure xMatters +=== Configure xMatters By integrating with xMatters, you can: diff --git a/docs/management/connectors/index.asciidoc b/docs/management/connectors/index.asciidoc index 513b4b99d45627..86adf5d49581b2 100644 --- a/docs/management/connectors/index.asciidoc +++ b/docs/management/connectors/index.asciidoc @@ -1,19 +1,19 @@ -include::action-types/email.asciidoc[] -include::action-types/resilient.asciidoc[] +include::action-types/email.asciidoc[leveloffset=+1] +include::action-types/resilient.asciidoc[leveloffset=+1] include::action-types/index.asciidoc[leveloffset=+1] -include::action-types/jira.asciidoc[] -include::action-types/teams.asciidoc[] -include::action-types/opsgenie.asciidoc[] -include::action-types/pagerduty.asciidoc[] +include::action-types/jira.asciidoc[leveloffset=+1] +include::action-types/teams.asciidoc[leveloffset=+1] +include::action-types/opsgenie.asciidoc[leveloffset=+1] +include::action-types/pagerduty.asciidoc[leveloffset=+1] include::action-types/server-log.asciidoc[leveloffset=+1] include::action-types/servicenow.asciidoc[leveloffset=+1] include::action-types/servicenow-sir.asciidoc[leveloffset=+1] include::action-types/servicenow-itom.asciidoc[leveloffset=+1] -include::action-types/swimlane.asciidoc[] -include::action-types/slack.asciidoc[] +include::action-types/swimlane.asciidoc[leveloffset=+1] +include::action-types/slack.asciidoc[leveloffset=+1] include::action-types/tines.asciidoc[leveloffset=+1] -include::action-types/torq.asciidoc[] -include::action-types/webhook.asciidoc[] +include::action-types/torq.asciidoc[leveloffset=+1] +include::action-types/webhook.asciidoc[leveloffset=+1] include::action-types/cases-webhook.asciidoc[leveloffset=+1] -include::action-types/xmatters.asciidoc[] +include::action-types/xmatters.asciidoc[leveloffset=+1] include::pre-configured-connectors.asciidoc[leveloffset=+1] diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 941cfca92e603e..98d7b13a1122bd 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -210,6 +210,12 @@ Sets the interval at which {kib} tries to remove expired and invalid sessions fr + TIP: Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w'). +xpack.security.session.сoncurrentSessions.maxSessions:: +Set the maximum number of sessions each user is allowed to have active at any given time. +By default, no limit is applied. +If set, the value of this option should be an integer between `1` and `1000`. +When the limit is exceeded, the oldest session is automatically invalidated. + [[security-encrypted-saved-objects-settings]] ==== Encrypted saved objects settings diff --git a/docs/user/ml/images/ml-change-point-detection.png b/docs/user/ml/images/ml-change-point-detection.png new file mode 100644 index 00000000000000..b964f7aa3b214a Binary files /dev/null and b/docs/user/ml/images/ml-change-point-detection.png differ diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index 7467d99ca22efe..65aa1ea3d74f9f 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -165,4 +165,36 @@ Select a field for categorization and optionally apply any filters that you want, then start the analysis. The analysis uses the same algorithms as a {ml} categorization job. The results of the analysis are shown in a table that makes it possible to open **Discover** and show or filter out the given category -there, which helps you to further examine your log messages. \ No newline at end of file +there, which helps you to further examine your log messages. + + +[discrete] +[[change-point-detection]] +=== Change point detection + +preview::[] + +Change point detection uses the +{ref}/search-aggregations-change-point-aggregation.html[change point aggregation] +to detect distribution changes, trend changes, and other statistically +significant change points in a metric of your time series data. + +You can find change point detection under **{ml-app}** > **AIOps Labs** where +you can select the {data-source} or saved search that you want to analyze. + +[role="screenshot"] +image::user/ml/images/ml-change-point-detection.png[Change point detection UI] + +Select a function and a metric field, then pick a date range to start detecting +change points in the defined range. Optionally, you can split the data by a +field. If the cardinality of the split field is greater than 10,000, then only +the first 10,000, sorted by document count, are analyzed. + +If a change point is detected, a chart visualizes where the change point was identified in +the time window analyzed, making the interpretation easier. If you split the analysis by a +field, a separate chart is displayed for every partition with a detected change +point. You can view the type of change point in the chart as well as its value +and the time when the change happened. The corresponding `p-value` indicates how +extreme the change is; lower values mark more significant changes. You can use +the change point type selector to filter the results by specific types of change +points. \ No newline at end of file diff --git a/docs/user/security/session-management.asciidoc b/docs/user/security/session-management.asciidoc index 45e3d479858ba4..01b5693d1b0b32 100644 --- a/docs/user/security/session-management.asciidoc +++ b/docs/user/security/session-management.asciidoc @@ -49,3 +49,18 @@ You can configure the interval at which {kib} tries to remove expired and invali xpack.security.session.cleanupInterval: "1d" -------------------------------------------------------------------------------- -- + +[[session-max-sessions]] +==== Maximum number of concurrent sessions +By default, there is no limit to the maximum number of concurrent sessions each user can have in {kib}. +To add a limit, use the `xpack.security.session.сoncurrentSessions.maxSessions` configuration option. +If set, the value of this option should be an integer between `1` and `1000`. +When the limit is exceeded, the oldest session is automatically invalidated. + +-- +[source,yaml] +-------------------------------------------------------------------------------- +xpack.security.session.сoncurrentSessions: + maxSessions: 3 +-------------------------------------------------------------------------------- +-- diff --git a/fleet_packages.json b/fleet_packages.json index 0f148d6899bbcd..0585444fd00488 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -10,6 +10,10 @@ will fetch the latest available version of the package from EPR (including prerelease versions), download that version, and rewrite its version to align with Kibana's. + The `allowSyncToPrerelease` option is available for packages who wish to opt into allowing sync + "bundled" packages whose version contain prerelease tags (e.g. 8.4.3-beta.1). By default, it just + updates to stable versions. + Packages will be fetched from https://epr-snapshot.elastic.co by default. This can be overridden via the `--epr-registry=production` command line argument when building Kibana. Fetching from the snapshot registry allows Kibana to bundle packages that have yet to be published to production in @@ -20,8 +24,9 @@ [ { "name": "apm", - "version": "8.8.0-preview-1675842740", - "forceAlignStackVersion": true + "version": "8.8.0-preview-1676887316", + "forceAlignStackVersion": true, + "allowSyncToPrerelease": true }, { "name": "elastic_agent", @@ -41,6 +46,6 @@ }, { "name": "security_detection_engine", - "version": "8.4.2" + "version": "8.7.1" } ] \ No newline at end of file diff --git a/package.json b/package.json index 85892dfa5e0e3a..62f48220cd2cdd 100644 --- a/package.json +++ b/package.json @@ -71,22 +71,17 @@ "url": "https://github.com/elastic/kibana.git" }, "engines": { - "node": "16.19.0", + "node": "16.19.1", "yarn": "^1.22.19" }, "resolutions": { "**/@types/node": "16.11.68", "**/chokidar": "^3.5.3", - "**/deepmerge": "^4.2.2", - "**/fast-deep-equal": "^3.1.1", "**/globule/minimatch": "^3.1.2", "**/hoist-non-react-statics": "^3.3.2", "**/isomorphic-fetch/node-fetch": "^2.6.7", - "**/istanbul-lib-coverage": "^3.2.0", - "**/trim": "1.0.1", + "**/remark-parse/trim": "1.0.1", "**/typescript": "4.6.3", - "**/use-composed-ref": "^1.3.0", - "**/use-latest": "^1.2.1", "globby/fast-glob": "^3.2.11" }, "dependencies": { @@ -97,7 +92,7 @@ "@dnd-kit/utilities": "^2.0.0", "@elastic/apm-rum": "^5.12.0", "@elastic/apm-rum-react": "^1.4.2", - "@elastic/charts": "52.0.0", + "@elastic/charts": "53.1.0", "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.6.0-canary.3", "@elastic/ems-client": "8.4.0", @@ -732,7 +727,7 @@ "compare-versions": "3.5.1", "constate": "^3.3.2", "copy-to-clipboard": "^3.0.8", - "core-js": "^3.27.2", + "core-js": "^3.28.0", "cronstrue": "^1.51.0", "cuid": "^2.1.8", "cytoscape": "^3.10.0", @@ -890,7 +885,7 @@ "redux-thunk": "^2.4.1", "redux-thunks": "^1.0.0", "remark-gfm": "1.0.0", - "remark-parse": "^8.0.3", + "remark-parse-no-trim": "^8.0.4", "remark-stringify": "^8.0.3", "require-in-the-middle": "^6.0.0", "reselect": "^4.1.6", @@ -1170,7 +1165,7 @@ "@types/file-saver": "^2.0.0", "@types/flot": "^0.0.31", "@types/fnv-plus": "^1.3.0", - "@types/geojson": "7946.0.7", + "@types/geojson": "^7946.0.10", "@types/getos": "^3.0.0", "@types/gulp": "^4.0.6", "@types/gulp-zip": "^4.0.1", @@ -1252,7 +1247,7 @@ "@types/redux-logger": "^3.0.8", "@types/resolve": "^1.20.1", "@types/seedrandom": ">=2.0.0 <4.0.0", - "@types/selenium-webdriver": "^4.1.10", + "@types/selenium-webdriver": "^4.1.11", "@types/semver": "^7", "@types/set-value": "^2.0.0", "@types/sharp": "^0.30.4", diff --git a/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap b/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap index 36fd4b605e579d..01ffd79b0b87f5 100644 --- a/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap +++ b/packages/core/logging/core-logging-server-internal/src/__snapshots__/logging_system.test.ts.snap @@ -16,7 +16,7 @@ exports[`asLoggerFactory() only allows to create new loggers. 1`] = ` Object { "@timestamp": "2012-01-30T22:33:22.011-05:00", "ecs": Object { - "version": "8.6.0", + "version": "8.6.1", }, "log": Object { "level": "TRACE", @@ -33,7 +33,7 @@ exports[`asLoggerFactory() only allows to create new loggers. 2`] = ` Object { "@timestamp": "2012-01-30T17:33:22.011-05:00", "ecs": Object { - "version": "8.6.0", + "version": "8.6.1", }, "log": Object { "level": "INFO", @@ -51,7 +51,7 @@ exports[`asLoggerFactory() only allows to create new loggers. 3`] = ` Object { "@timestamp": "2012-01-30T12:33:22.011-05:00", "ecs": Object { - "version": "8.6.0", + "version": "8.6.1", }, "log": Object { "level": "FATAL", @@ -68,7 +68,7 @@ exports[`flushes memory buffer logger and switches to real logger once config is Object { "@timestamp": "2012-02-01T09:33:22.011-05:00", "ecs": Object { - "version": "8.6.0", + "version": "8.6.1", }, "log": Object { "level": "INFO", @@ -86,7 +86,7 @@ exports[`flushes memory buffer logger and switches to real logger once config is Object { "@timestamp": "2012-01-31T23:33:22.011-05:00", "ecs": Object { - "version": "8.6.0", + "version": "8.6.1", }, "log": Object { "level": "INFO", diff --git a/packages/kbn-apm-synthtrace-client/src/lib/utils/dedot.ts b/packages/kbn-apm-synthtrace-client/src/lib/utils/dedot.ts index 5d0f57fb5840b6..3c0d3974d67591 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/utils/dedot.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/utils/dedot.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; export function dedot(source: Record, target: Record) { // eslint-disable-next-line guard-for-in diff --git a/packages/kbn-apm-synthtrace-client/tsconfig.json b/packages/kbn-apm-synthtrace-client/tsconfig.json index 8286fda7455b07..5e9a9c6cc2bcaa 100644 --- a/packages/kbn-apm-synthtrace-client/tsconfig.json +++ b/packages/kbn-apm-synthtrace-client/tsconfig.json @@ -14,5 +14,6 @@ ], "kbn_references": [ "@kbn/datemath", + "@kbn/safer-lodash-set", ] } diff --git a/packages/kbn-babel-preset/node_preset.js b/packages/kbn-babel-preset/node_preset.js index 0d8173308bd784..70195764d44fa2 100644 --- a/packages/kbn-babel-preset/node_preset.js +++ b/packages/kbn-babel-preset/node_preset.js @@ -31,7 +31,7 @@ module.exports = (_, options = {}) => { // Because of that we should use for that value the same version we install // in the package.json in order to have the same polyfills between the environment // and the tests - corejs: '3.27.2', + corejs: '3.28.0', bugfixes: true, ...(options['@babel/preset-env'] || {}), diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js index ddcc165c5a9e2c..b9e92d9e08722a 100644 --- a/packages/kbn-babel-preset/webpack_preset.js +++ b/packages/kbn-babel-preset/webpack_preset.js @@ -19,7 +19,7 @@ module.exports = (api, options = {}) => { modules: false, // Please read the explanation for this // in node_preset.js - corejs: '3.27.2', + corejs: '3.28.0', bugfixes: true, browserslistEnv: api.env('production') ? 'production' : 'dev', }, diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 566cedce41a876..430ab629307cd1 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -473,6 +473,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { createAlerts: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/create-alerts.html`, syntheticsCommandReference: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/synthetics-configuration.html#synthetics-configuration-playwright-options`, syntheticsProjectMonitors: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/synthetic-run-tests.html#synthetic-monitor-choose-project`, + syntheticsMigrateFromIntegration: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/synthetics-migrate-from-integration.html`, }, alerting: { guide: `${KIBANA_DOCS}create-and-manage-rules.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index d94665a5abadc6..f6b8ffd3038831 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -355,6 +355,7 @@ export interface DocLinks { createAlerts: string; syntheticsCommandReference: string; syntheticsProjectMonitors: string; + syntheticsMigrateFromIntegration: string; }>; readonly alerting: Readonly<{ guide: string; diff --git a/packages/kbn-ecs/generated/ecs.ts b/packages/kbn-ecs/generated/ecs.ts index 995c86f910e043..be166fca73f6cc 100644 --- a/packages/kbn-ecs/generated/ecs.ts +++ b/packages/kbn-ecs/generated/ecs.ts @@ -14,5 +14,5 @@ export interface EcsEcs { * ECS version this event conforms to. `ecs.version` is a required field and must exist in all events. * When querying across multiple indices -- which may conform to slightly different ECS versions -- this field lets integrations adjust to the schema version of the events. */ - version: '8.6.0'; + version: '8.6.1'; } diff --git a/packages/kbn-ecs/generated/ecs_flat.ts b/packages/kbn-ecs/generated/ecs_flat.ts index 63ce568d0d6f52..8c230c07e6460b 100644 --- a/packages/kbn-ecs/generated/ecs_flat.ts +++ b/packages/kbn-ecs/generated/ecs_flat.ts @@ -13765,14 +13765,27 @@ export const EcsFlat = { short: 'Date/time indicator was last reported.', type: 'date', }, - 'threat.enrichments.indicator.marking.tlp.version': { + 'threat.enrichments.indicator.marking.tlp': { + dashed_name: 'threat-enrichments-indicator-marking-tlp', + description: 'Traffic Light Protocol sharing markings.', + example: 'CLEAR', + expected_values: ['WHITE', 'CLEAR', 'GREEN', 'AMBER', 'AMBER+STRICT', 'RED'], + flat_name: 'threat.enrichments.indicator.marking.tlp', + ignore_above: 1024, + level: 'extended', + name: 'enrichments.indicator.marking.tlp', + normalize: [], + short: 'Indicator TLP marking', + type: 'keyword', + }, + 'threat.enrichments.indicator.marking.tlp_version': { dashed_name: 'threat-enrichments-indicator-marking-tlp-version', description: 'Traffic Light Protocol version.', example: 2, - flat_name: 'threat.enrichments.indicator.marking.tlp.version', + flat_name: 'threat.enrichments.indicator.marking.tlp_version', ignore_above: 1024, level: 'extended', - name: 'enrichments.indicator.marking.tlp.version', + name: 'enrichments.indicator.marking.tlp_version', normalize: [], short: 'Indicator TLP version', type: 'keyword', @@ -16202,6 +16215,18 @@ export const EcsFlat = { short: 'Indicator TLP marking', type: 'keyword', }, + 'threat.indicator.marking.tlp_version': { + dashed_name: 'threat-indicator-marking-tlp-version', + description: 'Traffic Light Protocol version.', + example: 2, + flat_name: 'threat.indicator.marking.tlp_version', + ignore_above: 1024, + level: 'extended', + name: 'indicator.marking.tlp_version', + normalize: [], + short: 'Indicator TLP version', + type: 'keyword', + }, 'threat.indicator.modified_at': { dashed_name: 'threat-indicator-modified-at', description: @@ -17129,18 +17154,6 @@ export const EcsFlat = { short: 'Threat subtechnique URL reference.', type: 'keyword', }, - 'threat.threat.indicator.marking.tlp.version': { - dashed_name: 'threat-threat-indicator-marking-tlp-version', - description: 'Traffic Light Protocol version.', - example: 2, - flat_name: 'threat.threat.indicator.marking.tlp.version', - ignore_above: 1024, - level: 'extended', - name: 'threat.indicator.marking.tlp.version', - normalize: [], - short: 'Indicator TLP version', - type: 'keyword', - }, 'tls.cipher': { dashed_name: 'tls-cipher', description: 'String indicating the cipher used during the current connection.', diff --git a/packages/kbn-ecs/generated/ecs_nested.ts b/packages/kbn-ecs/generated/ecs_nested.ts index 761b4b46430490..4ebcb5f4ef5659 100644 --- a/packages/kbn-ecs/generated/ecs_nested.ts +++ b/packages/kbn-ecs/generated/ecs_nested.ts @@ -15969,14 +15969,27 @@ export const EcsNested = { short: 'Date/time indicator was last reported.', type: 'date', }, - 'threat.enrichments.indicator.marking.tlp.version': { + 'threat.enrichments.indicator.marking.tlp': { + dashed_name: 'threat-enrichments-indicator-marking-tlp', + description: 'Traffic Light Protocol sharing markings.', + example: 'CLEAR', + expected_values: ['WHITE', 'CLEAR', 'GREEN', 'AMBER', 'AMBER+STRICT', 'RED'], + flat_name: 'threat.enrichments.indicator.marking.tlp', + ignore_above: 1024, + level: 'extended', + name: 'enrichments.indicator.marking.tlp', + normalize: [], + short: 'Indicator TLP marking', + type: 'keyword', + }, + 'threat.enrichments.indicator.marking.tlp_version': { dashed_name: 'threat-enrichments-indicator-marking-tlp-version', description: 'Traffic Light Protocol version.', example: 2, - flat_name: 'threat.enrichments.indicator.marking.tlp.version', + flat_name: 'threat.enrichments.indicator.marking.tlp_version', ignore_above: 1024, level: 'extended', - name: 'enrichments.indicator.marking.tlp.version', + name: 'enrichments.indicator.marking.tlp_version', normalize: [], short: 'Indicator TLP version', type: 'keyword', @@ -18414,6 +18427,18 @@ export const EcsNested = { short: 'Indicator TLP marking', type: 'keyword', }, + 'threat.indicator.marking.tlp_version': { + dashed_name: 'threat-indicator-marking-tlp-version', + description: 'Traffic Light Protocol version.', + example: 2, + flat_name: 'threat.indicator.marking.tlp_version', + ignore_above: 1024, + level: 'extended', + name: 'indicator.marking.tlp_version', + normalize: [], + short: 'Indicator TLP version', + type: 'keyword', + }, 'threat.indicator.modified_at': { dashed_name: 'threat-indicator-modified-at', description: @@ -19344,18 +19369,6 @@ export const EcsNested = { short: 'Threat subtechnique URL reference.', type: 'keyword', }, - 'threat.threat.indicator.marking.tlp.version': { - dashed_name: 'threat-threat-indicator-marking-tlp-version', - description: 'Traffic Light Protocol version.', - example: 2, - flat_name: 'threat.threat.indicator.marking.tlp.version', - ignore_above: 1024, - level: 'extended', - name: 'threat.indicator.marking.tlp.version', - normalize: [], - short: 'Indicator TLP version', - type: 'keyword', - }, }, group: 2, name: 'threat', diff --git a/packages/kbn-ecs/generated/index.ts b/packages/kbn-ecs/generated/index.ts index 7b6b198cf2c379..bd3cd6a3a7eacd 100644 --- a/packages/kbn-ecs/generated/index.ts +++ b/packages/kbn-ecs/generated/index.ts @@ -57,7 +57,7 @@ import { EcsVlan } from './vlan'; import { EcsVulnerability } from './vulnerability'; import { EcsX509 } from './x509'; -export const EcsVersion = '8.6.0' as const; +export const EcsVersion = '8.6.1' as const; /** * Exporting raw schema files for easy programmatic use diff --git a/packages/kbn-ecs/generated/threat.ts b/packages/kbn-ecs/generated/threat.ts index afa74f8fe3bfba..4f3072236008a4 100644 --- a/packages/kbn-ecs/generated/threat.ts +++ b/packages/kbn-ecs/generated/threat.ts @@ -554,6 +554,10 @@ export interface EcsThreat { * Traffic Light Protocol sharing markings. */ tlp?: string; + /** + * Traffic Light Protocol version. + */ + tlp_version?: string; }; /** @@ -875,17 +879,4 @@ export interface EcsThreat { reference?: string[]; }; }; - - threat?: { - indicator?: { - marking?: { - tlp?: { - /** - * Traffic Light Protocol version. - */ - version?: string; - }; - }; - }; - }; } diff --git a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts index f2fc685b2e1806..aca38ba285b273 100644 --- a/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts +++ b/packages/kbn-es-query/src/filters/build_filters/phrase_filter.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { buildInlineScriptForPhraseFilter, buildPhraseFilter, diff --git a/packages/kbn-es-query/src/filters/helpers/only_disabled.ts b/packages/kbn-es-query/src/filters/helpers/only_disabled.ts index d605d8b0be628a..5a9ca76646eb4a 100644 --- a/packages/kbn-es-query/src/filters/helpers/only_disabled.ts +++ b/packages/kbn-es-query/src/filters/helpers/only_disabled.ts @@ -8,6 +8,7 @@ import { filter } from 'lodash'; import type { Filter } from '..'; +import type { FilterCompareOptions } from './compare_filters'; import { compareFilters, COMPARE_ALL_OPTIONS } from './compare_filters'; const isEnabled = (f: Filter) => f && f.meta && !f.meta.disabled; @@ -18,10 +19,15 @@ const isEnabled = (f: Filter) => f && f.meta && !f.meta.disabled; * * @public */ -export const onlyDisabledFiltersChanged = (newFilters?: Filter[], oldFilters?: Filter[]) => { +export const onlyDisabledFiltersChanged = ( + newFilters?: Filter[], + oldFilters?: Filter[], + comparatorOptions?: FilterCompareOptions +) => { // If it's the same - compare only enabled filters const newEnabledFilters = filter(newFilters || [], isEnabled); const oldEnabledFilters = filter(oldFilters || [], isEnabled); + const options = comparatorOptions ?? COMPARE_ALL_OPTIONS; - return compareFilters(oldEnabledFilters, newEnabledFilters, COMPARE_ALL_OPTIONS); + return compareFilters(oldEnabledFilters, newEnabledFilters, options); }; diff --git a/packages/kbn-es-query/tsconfig.json b/packages/kbn-es-query/tsconfig.json index 07000887f13f8b..9dda3fcbcc2cf3 100644 --- a/packages/kbn-es-query/tsconfig.json +++ b/packages/kbn-es-query/tsconfig.json @@ -15,6 +15,7 @@ "kbn_references": [ "@kbn/utility-types", "@kbn/i18n", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js b/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js index 98d2cfa1153f21..e97d64abc640ce 100644 --- a/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js +++ b/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js @@ -7,7 +7,8 @@ */ import { toExpression } from './to_expression'; -import { cloneDeep, set, unset } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep, unset } from 'lodash'; describe('toExpression', () => { describe('single expression', () => { diff --git a/packages/kbn-interpreter/tsconfig.json b/packages/kbn-interpreter/tsconfig.json index 8af1ae01dce1be..dc10af2e6fba6e 100644 --- a/packages/kbn-interpreter/tsconfig.json +++ b/packages/kbn-interpreter/tsconfig.json @@ -13,6 +13,7 @@ "**/*.js" ], "kbn_references": [ + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts b/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts index c0ab8322eb363e..06fe06c63b4b9d 100644 --- a/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts +++ b/packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts @@ -20,6 +20,7 @@ export const AlertConsumers = { LOGS: 'logs', INFRASTRUCTURE: 'infrastructure', OBSERVABILITY: 'observability', + SLO: 'slo', SIEM: 'siem', UPTIME: 'uptime', } as const; diff --git a/packages/kbn-safer-lodash-set/README.md b/packages/kbn-safer-lodash-set/README.md index 08df12ff01ec37..823b1acff3b013 100644 --- a/packages/kbn-safer-lodash-set/README.md +++ b/packages/kbn-safer-lodash-set/README.md @@ -7,7 +7,7 @@ Lodash v4.x. ## Example Usage ```js -const { set } = require('@elastic/safer-loadsh-set'); +const { set } = require('@kbn/safer-lodash-set'); const object = { a: [{ b: { c: 3 } }] }; diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx index adae9ac5cd9ca7..29d29f087c4817 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx @@ -214,7 +214,10 @@ export const AutocompleteFieldMatchComponent: React.FC { return ( diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index be38a8225d0f44..571c2fe18fd6ab 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -143,8 +143,8 @@ describe('checking migration metadata changes on all registered SO types', () => "task": "ebcc113df12f14bf627dbd335ba78507187b48a3", "telemetry": "561b329aaed3c15b91aaf2075645be3097247612", "ui-metric": "410a8ad28e0f44b161c960ff0ce950c712b17c52", - "upgrade-assistant-ml-upgrade-operation": "e20ff1efa3c4757f5e7ff5fb897c557b08524c3a", - "upgrade-assistant-reindex-operation": "c7442ffe34954c117a74bf138e48e4c25095a6cf", + "upgrade-assistant-ml-upgrade-operation": "d8816e5ce32649e7a3a43e2c406c632319ff84bb", + "upgrade-assistant-reindex-operation": "09ac8ed9c9acf7e8ece8eafe47d7019ea1472144", "upgrade-assistant-telemetry": "12bcbfc4e4ce64d2ca7c24f9acccd331a2bd2ab6", "uptime-dynamic-settings": "9a63ce80904a04be114749e426882dc3ff011137", "uptime-synthetics-api-key": "599319bedbfa287e8761e1ba49d536417a33fa13", diff --git a/src/dev/build/tasks/fleet/bundle_packages.ts b/src/dev/build/tasks/fleet/bundle_packages.ts index 93b73fa528dcc1..73366a201c66f9 100644 --- a/src/dev/build/tasks/fleet/bundle_packages.ts +++ b/src/dev/build/tasks/fleet/bundle_packages.ts @@ -23,6 +23,7 @@ interface FleetPackage { name: string; version: string; forceAlignStackVersion?: boolean; + allowSyncToPrerelease?: boolean; } export async function bundleFleetPackages(pkgDir: string, log: ToolingLog, config: Config) { diff --git a/src/dev/chromium_version.ts b/src/dev/chromium_version.ts index f2cbab5e7a5168..aabdba9360c808 100644 --- a/src/dev/chromium_version.ts +++ b/src/dev/chromium_version.ts @@ -46,7 +46,7 @@ async function getChromiumRevision( kibanaPuppeteerVersion: PuppeteerRelease, log: ToolingLog ): Promise { - const url = `https://raw.githubusercontent.com/puppeteer/puppeteer/v${kibanaPuppeteerVersion}/src/revisions.ts`; + const url = `https://raw.githubusercontent.com/puppeteer/puppeteer/puppeteer-v${kibanaPuppeteerVersion}/packages/puppeteer-core/src/revisions.ts`; let body: string; try { log.info(`Fetching code from Puppeteer source: ${url}`); diff --git a/src/dev/performance/run_scalability_cli.ts b/src/dev/performance/run_scalability_cli.ts index 86f8c70a11ab94..61a40de35a55bf 100644 --- a/src/dev/performance/run_scalability_cli.ts +++ b/src/dev/performance/run_scalability_cli.ts @@ -40,13 +40,36 @@ run( }) : [{ name: path.parse(journeyPath).name, path: journeyPath }]; + const skippedFilePath = 'x-pack/test/scalability/disabled_scalability_tests.json'; + const skipped: string[] = JSON.parse( + fs.readFileSync(path.resolve(REPO_ROOT, skippedFilePath), 'utf8') + ).map((relativePath: string) => path.resolve(REPO_ROOT, relativePath)); + let filtered: Journey[] = []; + + if (skipped.length === 0) { + filtered = journeys; + } else { + for (const journey of journeys) { + if (skipped.includes(journey.path)) { + log.warning(`Journey '${journey.name} is skipped'`); + } else { + filtered.push(journey); + } + } + } + + if (filtered.length === 0) { + log.info(`No journeys found, check skipped list in '${skippedFilePath}'`); + return; + } + log.info( - `Found ${journeys.length} journeys to run: ${JSON.stringify(journeys.map((j) => j.name))}` + `Found ${filtered.length} journeys to run: ${JSON.stringify(filtered.map((j) => j.name))}` ); const failedJourneys = []; - for (const journey of journeys) { + for (const journey of filtered) { try { process.stdout.write(`--- Running scalability journey: ${journey.name}\n`); await runScalabilityJourney(journey.path, kibanaInstallDir); diff --git a/src/plugins/content_management/common/index.ts b/src/plugins/content_management/common/index.ts index 1670078ae8d790..0bc6549a1681b2 100644 --- a/src/plugins/content_management/common/index.ts +++ b/src/plugins/content_management/common/index.ts @@ -7,14 +7,16 @@ */ export { PLUGIN_ID, API_ENDPOINT } from './constants'; + export type { ProcedureSchemas, ProcedureName, GetIn, + BulkGetIn, CreateIn, - SearchIn, - SearchOut, - DeleteIn, UpdateIn, + DeleteIn, + SearchIn, } from './rpc'; + export { procedureNames, schemas as rpcSchemas } from './rpc'; diff --git a/src/plugins/content_management/common/rpc.ts b/src/plugins/content_management/common/rpc.ts deleted file mode 100644 index aa0d6a3b2e2c8d..00000000000000 --- a/src/plugins/content_management/common/rpc.ts +++ /dev/null @@ -1,148 +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 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 { schema, Type } from '@kbn/config-schema'; - -export interface ProcedureSchemas { - in?: Type | false; - out?: Type | false; -} - -export const procedureNames = ['get', 'create', 'update', 'delete', 'search'] as const; - -export type ProcedureName = typeof procedureNames[number]; - -// --------------------------------- -// API -// --------------------------------- - -// ------- GET -------- -const getSchemas: ProcedureSchemas = { - in: schema.object( - { - contentType: schema.string(), - id: schema.string(), - options: schema.maybe(schema.object({}, { unknowns: 'allow' })), - }, - { unknowns: 'forbid' } - ), - // --> "out" will be specified by each storage layer - out: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}; - -export interface GetIn { - id: string; - contentType: string; - options?: Options; -} - -// -- Create content -const createSchemas: ProcedureSchemas = { - in: schema.object( - { - contentType: schema.string(), - data: schema.object({}, { unknowns: 'allow' }), - options: schema.maybe(schema.object({}, { unknowns: 'allow' })), - }, - { unknowns: 'forbid' } - ), - // Here we could enforce that an "id" field is returned - out: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}; - -export interface CreateIn< - T extends string = string, - Data extends object = Record, - Options extends object = any -> { - contentType: T; - data: Data; - options?: Options; -} - -// -- Update content -const updateSchemas: ProcedureSchemas = { - in: schema.object( - { - contentType: schema.string(), - data: schema.object({}, { unknowns: 'allow' }), - options: schema.maybe(schema.object({}, { unknowns: 'allow' })), - }, - { unknowns: 'forbid' } - ), - out: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}; - -export interface UpdateIn< - T extends string = string, - Data extends object = Record, - Options extends object = any -> { - contentType: T; - data: Data; - options?: Options; -} - -// -- Delete content -const deleteSchemas: ProcedureSchemas = { - in: schema.object( - { - contentType: schema.string(), - data: schema.object({}, { unknowns: 'allow' }), - options: schema.maybe(schema.object({}, { unknowns: 'allow' })), - }, - { unknowns: 'forbid' } - ), - out: schema.maybe(schema.object({}, { unknowns: 'allow' })), -}; - -export interface DeleteIn< - T extends string = string, - Data extends object = Record, - Options extends object = any -> { - contentType: T; - data: Data; - options?: Options; -} - -// -- Search content -const searchSchemas: ProcedureSchemas = { - in: schema.object( - { - contentType: schema.string(), - data: schema.object({}, { unknowns: 'allow' }), - options: schema.maybe(schema.object({}, { unknowns: 'allow' })), - }, - { unknowns: 'forbid' } - ), - out: schema.object({ hits: schema.arrayOf(schema.object({}, { unknowns: 'allow' })) }), -}; - -export interface SearchIn< - T extends string = string, - Params extends object = Record, - Options extends object = any -> { - contentType: T; - params: Params; - options?: Options; -} - -export interface SearchOut> { - hits: Data[]; -} - -export const schemas: { - [key in ProcedureName]: ProcedureSchemas; -} = { - get: getSchemas, - create: createSchemas, - update: updateSchemas, - delete: deleteSchemas, - search: searchSchemas, -}; diff --git a/src/plugins/content_management/common/rpc/bulk_get.ts b/src/plugins/content_management/common/rpc/bulk_get.ts new file mode 100644 index 00000000000000..c3764ff5199c72 --- /dev/null +++ b/src/plugins/content_management/common/rpc/bulk_get.ts @@ -0,0 +1,31 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const bulkGetSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + ids: schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + out: schema.oneOf([ + schema.object({}, { unknowns: 'allow' }), + schema.arrayOf(schema.object({}, { unknowns: 'allow' })), + ]), +}; + +export interface BulkGetIn { + contentTypeId: T; + ids: string[]; + options?: Options; +} diff --git a/src/plugins/content_management/common/rpc/constants.ts b/src/plugins/content_management/common/rpc/constants.ts new file mode 100644 index 00000000000000..a0f00a600eef6b --- /dev/null +++ b/src/plugins/content_management/common/rpc/constants.ts @@ -0,0 +1,11 @@ +/* + * 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 const procedureNames = ['get', 'bulkGet', 'create', 'update', 'delete', 'search'] as const; + +export type ProcedureName = typeof procedureNames[number]; diff --git a/src/plugins/content_management/common/rpc/create.ts b/src/plugins/content_management/common/rpc/create.ts new file mode 100644 index 00000000000000..b5a7cfa7cd0e80 --- /dev/null +++ b/src/plugins/content_management/common/rpc/create.ts @@ -0,0 +1,33 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const createSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + // --> "data" to create a content will be defined by each content type + data: schema.recordOf(schema.string(), schema.any()), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + out: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}; + +export interface CreateIn< + T extends string = string, + Data extends object = object, + Options extends object = object +> { + contentTypeId: T; + data: Data; + options?: Options; +} diff --git a/src/plugins/content_management/common/rpc/delete.ts b/src/plugins/content_management/common/rpc/delete.ts new file mode 100644 index 00000000000000..261c6397ab5783 --- /dev/null +++ b/src/plugins/content_management/common/rpc/delete.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const deleteSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + id: schema.string({ minLength: 1 }), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + out: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}; + +export interface DeleteIn { + contentTypeId: T; + id: string; + options?: Options; +} diff --git a/src/plugins/content_management/common/rpc/get.ts b/src/plugins/content_management/common/rpc/get.ts new file mode 100644 index 00000000000000..a408a5f1afe833 --- /dev/null +++ b/src/plugins/content_management/common/rpc/get.ts @@ -0,0 +1,29 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const getSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + id: schema.string({ minLength: 1 }), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + // --> "out" will be (optionally) specified by each storage layer + out: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}; + +export interface GetIn { + id: string; + contentTypeId: T; + options?: Options; +} diff --git a/src/plugins/content_management/common/rpc/index.ts b/src/plugins/content_management/common/rpc/index.ts new file mode 100644 index 00000000000000..d078d6dffbc60a --- /dev/null +++ b/src/plugins/content_management/common/rpc/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { schemas } from './rpc'; +export { procedureNames } from './constants'; + +export type { GetIn } from './get'; +export type { BulkGetIn } from './bulk_get'; +export type { CreateIn } from './create'; +export type { UpdateIn } from './update'; +export type { DeleteIn } from './delete'; +export type { SearchIn } from './search'; +export type { ProcedureSchemas } from './types'; +export type { ProcedureName } from './constants'; diff --git a/src/plugins/content_management/common/rpc/rpc.ts b/src/plugins/content_management/common/rpc/rpc.ts new file mode 100644 index 00000000000000..4b497d4e7cc254 --- /dev/null +++ b/src/plugins/content_management/common/rpc/rpc.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 { ProcedureName } from './constants'; +import type { ProcedureSchemas } from './types'; +import { getSchemas } from './get'; +import { bulkGetSchemas } from './bulk_get'; +import { createSchemas } from './create'; +import { updateSchemas } from './update'; +import { deleteSchemas } from './delete'; +import { searchSchemas } from './search'; + +export const schemas: { + [key in ProcedureName]: ProcedureSchemas; +} = { + get: getSchemas, + bulkGet: bulkGetSchemas, + create: createSchemas, + update: updateSchemas, + delete: deleteSchemas, + search: searchSchemas, +}; diff --git a/src/plugins/content_management/common/rpc/search.ts b/src/plugins/content_management/common/rpc/search.ts new file mode 100644 index 00000000000000..9e86b2e8a0fa2d --- /dev/null +++ b/src/plugins/content_management/common/rpc/search.ts @@ -0,0 +1,36 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const searchSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + // --> "query" that can be executed will be defined by each content type + query: schema.recordOf(schema.string(), schema.any()), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + out: schema.oneOf([ + schema.object({}, { unknowns: 'allow' }), + schema.arrayOf(schema.object({}, { unknowns: 'allow' })), + ]), +}; + +export interface SearchIn< + T extends string = string, + Query extends object = object, + Options extends object = object +> { + contentTypeId: T; + query: Query; + options?: Options; +} diff --git a/src/plugins/content_management/common/rpc/types.ts b/src/plugins/content_management/common/rpc/types.ts new file mode 100644 index 00000000000000..6a19a80956708c --- /dev/null +++ b/src/plugins/content_management/common/rpc/types.ts @@ -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. + */ +import type { Type } from '@kbn/config-schema'; + +export interface ProcedureSchemas { + in: Type | false; + out: Type | false; +} diff --git a/src/plugins/content_management/common/rpc/update.ts b/src/plugins/content_management/common/rpc/update.ts new file mode 100644 index 00000000000000..a523822377eb37 --- /dev/null +++ b/src/plugins/content_management/common/rpc/update.ts @@ -0,0 +1,35 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import type { ProcedureSchemas } from './types'; + +export const updateSchemas: ProcedureSchemas = { + in: schema.object( + { + contentTypeId: schema.string(), + id: schema.string({ minLength: 1 }), + // --> "data" to update a content will be defined by each content type + data: schema.recordOf(schema.string(), schema.any()), + options: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + { unknowns: 'forbid' } + ), + out: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}; + +export interface UpdateIn< + T extends string = string, + Data extends object = object, + Options extends object = object +> { + contentTypeId: T; + id: string; + data: Data; + options?: Options; +} diff --git a/src/plugins/content_management/public/content_client/content_client.test.ts b/src/plugins/content_management/public/content_client/content_client.test.ts index 02bd67a1da8daf..238570aeb3f49b 100644 --- a/src/plugins/content_management/public/content_client/content_client.test.ts +++ b/src/plugins/content_management/public/content_client/content_client.test.ts @@ -10,7 +10,7 @@ import { lastValueFrom } from 'rxjs'; import { takeWhile, toArray } from 'rxjs/operators'; import { createCrudClientMock } from '../crud_client/crud_client.mock'; import { ContentClient } from './content_client'; -import type { GetIn, CreateIn, UpdateIn, DeleteIn, SearchIn, SearchOut } from '../../common'; +import type { GetIn, CreateIn, UpdateIn, DeleteIn, SearchIn } from '../../common'; const setup = () => { const crudClient = createCrudClientMock(); @@ -21,7 +21,7 @@ const setup = () => { describe('#get', () => { it('calls rpcClient.get with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: GetIn = { id: 'test', contentType: 'testType' }; + const input: GetIn = { id: 'test', contentTypeId: 'testType' }; const output = { test: 'test' }; crudClient.get.mockResolvedValueOnce(output); expect(await contentClient.get(input)).toEqual(output); @@ -30,7 +30,7 @@ describe('#get', () => { it('calls rpcClient.get$ with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: GetIn = { id: 'test', contentType: 'testType' }; + const input: GetIn = { id: 'test', contentTypeId: 'testType' }; const output = { test: 'test' }; crudClient.get.mockResolvedValueOnce(output); const get$ = contentClient.get$(input).pipe( @@ -53,7 +53,7 @@ describe('#get', () => { describe('#create', () => { it('calls rpcClient.create with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: CreateIn = { contentType: 'testType', data: { foo: 'bar' } }; + const input: CreateIn = { contentTypeId: 'testType', data: { foo: 'bar' } }; const output = { test: 'test' }; crudClient.create.mockResolvedValueOnce(output); @@ -65,7 +65,7 @@ describe('#create', () => { describe('#update', () => { it('calls rpcClient.update with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: UpdateIn = { contentType: 'testType', data: { id: 'test', foo: 'bar' } }; + const input: UpdateIn = { contentTypeId: 'testType', id: 'test', data: { foo: 'bar' } }; const output = { test: 'test' }; crudClient.update.mockResolvedValueOnce(output); @@ -77,7 +77,7 @@ describe('#update', () => { describe('#delete', () => { it('calls rpcClient.delete with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: DeleteIn = { contentType: 'testType', data: { id: 'test' } }; + const input: DeleteIn = { contentTypeId: 'testType', id: 'test' }; const output = { test: 'test' }; crudClient.delete.mockResolvedValueOnce(output); @@ -89,8 +89,8 @@ describe('#delete', () => { describe('#search', () => { it('calls rpcClient.search with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: SearchIn = { contentType: 'testType', params: {} }; - const output: SearchOut = { hits: [{ test: 'test' }] }; + const input: SearchIn = { contentTypeId: 'testType', query: {} }; + const output = { hits: [{ id: 'test' }] }; crudClient.search.mockResolvedValueOnce(output); expect(await contentClient.search(input)).toEqual(output); expect(crudClient.search).toBeCalledWith(input); @@ -98,8 +98,8 @@ describe('#search', () => { it('calls rpcClient.search$ with input and returns output', async () => { const { crudClient, contentClient } = setup(); - const input: SearchIn = { contentType: 'testType', params: {} }; - const output: SearchOut = { hits: [{ test: 'test' }] }; + const input: SearchIn = { contentTypeId: 'testType', query: {} }; + const output = { hits: [{ id: 'test' }] }; crudClient.search.mockResolvedValueOnce(output); const search$ = contentClient.search$(input).pipe( takeWhile((result) => { diff --git a/src/plugins/content_management/public/content_client/content_client.tsx b/src/plugins/content_management/public/content_client/content_client.tsx index 4a4952a0820605..149e509ae95108 100644 --- a/src/plugins/content_management/public/content_client/content_client.tsx +++ b/src/plugins/content_management/public/content_client/content_client.tsx @@ -9,7 +9,7 @@ import { QueryClient } from '@tanstack/react-query'; import { createQueryObservable } from './query_observable'; import type { CrudClient } from '../crud_client'; -import type { CreateIn, GetIn, UpdateIn, DeleteIn, SearchIn, SearchOut } from '../../common'; +import type { CreateIn, GetIn, UpdateIn, DeleteIn, SearchIn } from '../../common'; const queryKeyBuilder = { all: (type: string) => [type] as const, @@ -29,14 +29,14 @@ const createQueryOptionBuilder = ({ return { get: (input: I) => { return { - queryKey: queryKeyBuilder.item(input.contentType, input.id), - queryFn: () => crudClientProvider(input.contentType).get(input), + queryKey: queryKeyBuilder.item(input.contentTypeId, input.id), + queryFn: () => crudClientProvider(input.contentTypeId).get(input), }; }, - search: (input: I) => { + search: (input: I) => { return { - queryKey: queryKeyBuilder.search(input.contentType, input.params), - queryFn: () => crudClientProvider(input.contentType).search(input), + queryKey: queryKeyBuilder.search(input.contentTypeId, input.query), + queryFn: () => crudClientProvider(input.contentTypeId).search(input), }; }, }; @@ -62,22 +62,22 @@ export class ContentClient { } create(input: I): Promise { - return this.crudClientProvider(input.contentType).create(input); + return this.crudClientProvider(input.contentTypeId).create(input); } update(input: I): Promise { - return this.crudClientProvider(input.contentType).update(input); + return this.crudClientProvider(input.contentTypeId).update(input); } delete(input: I): Promise { - return this.crudClientProvider(input.contentType).delete(input); + return this.crudClientProvider(input.contentTypeId).delete(input); } - search(input: I): Promise { - return this.crudClientProvider(input.contentType).search(input); + search(input: I): Promise { + return this.crudClientProvider(input.contentTypeId).search(input); } - search$(input: I) { + search$(input: I) { return createQueryObservable(this.queryClient, this.queryOptionBuilder.search(input)); } } diff --git a/src/plugins/content_management/public/content_client/content_client_mutation_hooks.test.tsx b/src/plugins/content_management/public/content_client/content_client_mutation_hooks.test.tsx index ca1d8fe8f8e29a..7a19cf2dae7a9b 100644 --- a/src/plugins/content_management/public/content_client/content_client_mutation_hooks.test.tsx +++ b/src/plugins/content_management/public/content_client/content_client_mutation_hooks.test.tsx @@ -36,7 +36,7 @@ const setup = () => { describe('useCreateContentMutation', () => { test('should call rpcClient.create with input and resolve with output', async () => { const { Wrapper, crudClient } = setup(); - const input: CreateIn = { contentType: 'testType', data: { foo: 'bar' } }; + const input: CreateIn = { contentTypeId: 'testType', data: { foo: 'bar' } }; const output = { test: 'test' }; crudClient.create.mockResolvedValueOnce(output); const { result, waitFor } = renderHook(() => useCreateContentMutation(), { wrapper: Wrapper }); @@ -51,7 +51,7 @@ describe('useCreateContentMutation', () => { describe('useUpdateContentMutation', () => { test('should call rpcClient.update with input and resolve with output', async () => { const { Wrapper, crudClient } = setup(); - const input: UpdateIn = { contentType: 'testType', data: { foo: 'bar' } }; + const input: UpdateIn = { contentTypeId: 'testType', id: 'test', data: { foo: 'bar' } }; const output = { test: 'test' }; crudClient.update.mockResolvedValueOnce(output); const { result, waitFor } = renderHook(() => useUpdateContentMutation(), { wrapper: Wrapper }); @@ -66,7 +66,7 @@ describe('useUpdateContentMutation', () => { describe('useDeleteContentMutation', () => { test('should call rpcClient.delete with input and resolve with output', async () => { const { Wrapper, crudClient } = setup(); - const input: DeleteIn = { contentType: 'testType', data: { foo: 'bar' } }; + const input: DeleteIn = { contentTypeId: 'testType', id: 'test' }; const output = { test: 'test' }; crudClient.delete.mockResolvedValueOnce(output); const { result, waitFor } = renderHook(() => useDeleteContentMutation(), { wrapper: Wrapper }); diff --git a/src/plugins/content_management/public/content_client/content_client_query_hooks.test.tsx b/src/plugins/content_management/public/content_client/content_client_query_hooks.test.tsx index 7ed1ff8412a455..a716831efc3ad5 100644 --- a/src/plugins/content_management/public/content_client/content_client_query_hooks.test.tsx +++ b/src/plugins/content_management/public/content_client/content_client_query_hooks.test.tsx @@ -12,7 +12,7 @@ import { ContentClientProvider } from './content_client_context'; import { ContentClient } from './content_client'; import { createCrudClientMock } from '../crud_client/crud_client.mock'; import { useGetContentQuery, useSearchContentQuery } from './content_client_query_hooks'; -import type { GetIn, SearchIn, SearchOut } from '../../common'; +import type { GetIn, SearchIn } from '../../common'; const setup = () => { const crudClient = createCrudClientMock(); @@ -32,7 +32,7 @@ const setup = () => { describe('useGetContentQuery', () => { test('should call rpcClient.get with input and resolve with output', async () => { const { crudClient, Wrapper } = setup(); - const input: GetIn = { id: 'test', contentType: 'testType' }; + const input: GetIn = { id: 'test', contentTypeId: 'testType' }; const output = { test: 'test' }; crudClient.get.mockResolvedValueOnce(output); const { result, waitFor } = renderHook(() => useGetContentQuery(input), { wrapper: Wrapper }); @@ -44,8 +44,8 @@ describe('useGetContentQuery', () => { describe('useSearchContentQuery', () => { test('should call rpcClient.search with input and resolve with output', async () => { const { crudClient, Wrapper } = setup(); - const input: SearchIn = { contentType: 'testType', params: {} }; - const output: SearchOut = { hits: [{ test: 'test' }] }; + const input: SearchIn = { contentTypeId: 'testType', query: {} }; + const output = { hits: [{ id: 'test' }] }; crudClient.search.mockResolvedValueOnce(output); const { result, waitFor } = renderHook(() => useSearchContentQuery(input), { wrapper: Wrapper, diff --git a/src/plugins/content_management/public/content_client/content_client_query_hooks.tsx b/src/plugins/content_management/public/content_client/content_client_query_hooks.tsx index 8231d7bfc9390c..3549b2489b27d7 100644 --- a/src/plugins/content_management/public/content_client/content_client_query_hooks.tsx +++ b/src/plugins/content_management/public/content_client/content_client_query_hooks.tsx @@ -8,7 +8,7 @@ import { useQuery, QueryObserverOptions } from '@tanstack/react-query'; import { useContentClient } from './content_client_context'; -import type { GetIn, SearchIn, SearchOut } from '../../common'; +import type { GetIn, SearchIn } from '../../common'; /** * Exposed `useQuery` options @@ -36,10 +36,7 @@ export const useGetContentQuery = ( * @param input - get content identifier like "id" and "contentType" * @param queryOptions - query options */ -export const useSearchContentQuery = < - I extends SearchIn = SearchIn, - O extends SearchOut = SearchOut ->( +export const useSearchContentQuery = ( input: I, queryOptions?: QueryOptions ) => { diff --git a/src/plugins/content_management/public/crud_client/crud_client.ts b/src/plugins/content_management/public/crud_client/crud_client.ts index e2c5fd8fb86a51..094703a97d0c0f 100644 --- a/src/plugins/content_management/public/crud_client/crud_client.ts +++ b/src/plugins/content_management/public/crud_client/crud_client.ts @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import type { GetIn, CreateIn, UpdateIn, DeleteIn, SearchIn, SearchOut } from '../../common'; +import type { GetIn, CreateIn, UpdateIn, DeleteIn, SearchIn } from '../../common'; export interface CrudClient { get(input: I): Promise; create(input: I): Promise; update(input: I): Promise; delete(input: I): Promise; - search(input: I): Promise; + search(input: I): Promise; } diff --git a/src/plugins/content_management/public/rpc_client/rpc_client.test.ts b/src/plugins/content_management/public/rpc_client/rpc_client.test.ts new file mode 100644 index 00000000000000..3a76b355795edb --- /dev/null +++ b/src/plugins/content_management/public/rpc_client/rpc_client.test.ts @@ -0,0 +1,52 @@ +/* + * 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 { procedureNames, API_ENDPOINT } from '../../common'; + +import { RpcClient } from './rpc_client'; + +describe('RpcClient', () => { + test('should expose a handler to call each of the procedures', async () => { + /** + * This test ensure that there is a public method on the RpcClient to call every procedure + * on the server. + */ + + const proceduresSpys = procedureNames.reduce<{ + [key: string]: { name: string; spy: jest.Mock }; + }>( + (acc, name) => ({ + ...acc, + [name]: { + name, + spy: jest.fn(), + }, + }), + {} + ); + + const post = jest.fn(async (endPoint: string, data: any) => { + const [_, name] = endPoint.split(`${API_ENDPOINT}/`); + proceduresSpys[name]?.spy(endPoint, data); + return { result: `${name}mockedResponse` }; + }); + + const rpcClient = new RpcClient({ post: post as any }); + + await rpcClient.get({ contentTypeId: 'foo', id: '123' }); + await rpcClient.bulkGet({ contentTypeId: 'foo', ids: ['123'] }); + await rpcClient.create({ contentTypeId: 'foo', data: {} }); + await rpcClient.update({ contentTypeId: 'foo', id: '123', data: {} }); + await rpcClient.delete({ contentTypeId: 'foo', id: '123' }); + await rpcClient.search({ contentTypeId: 'foo', query: {} }); + + Object.values(proceduresSpys).forEach(({ name, spy }) => { + expect(spy).toHaveBeenCalledWith(`${API_ENDPOINT}/${name}`, { body: expect.any(String) }); + }); + }); +}); diff --git a/src/plugins/content_management/public/rpc_client/rpc_client.ts b/src/plugins/content_management/public/rpc_client/rpc_client.ts index 5ce2e781dcbb1f..2d3e6d1ed1ccee 100644 --- a/src/plugins/content_management/public/rpc_client/rpc_client.ts +++ b/src/plugins/content_management/public/rpc_client/rpc_client.ts @@ -10,11 +10,11 @@ import { HttpSetup } from '@kbn/core/public'; import { API_ENDPOINT } from '../../common'; import type { GetIn, + BulkGetIn, CreateIn, UpdateIn, DeleteIn, SearchIn, - SearchOut, ProcedureName, } from '../../common'; import type { CrudClient } from '../crud_client/crud_client'; @@ -26,6 +26,10 @@ export class RpcClient implements CrudClient { return this.sendMessage('get', input); } + public bulkGet(input: I): Promise { + return this.sendMessage('bulkGet', input); + } + public create(input: I): Promise { return this.sendMessage('create', input); } @@ -38,9 +42,7 @@ export class RpcClient implements CrudClient { return this.sendMessage('delete', input); } - public search( - input: I - ): Promise { + public search(input: I): Promise { return this.sendMessage('search', input); } diff --git a/src/plugins/content_management/server/core/core.test.ts b/src/plugins/content_management/server/core/core.test.ts index 19670740290f8e..074f62ebc07b3f 100644 --- a/src/plugins/content_management/server/core/core.test.ts +++ b/src/plugins/content_management/server/core/core.test.ts @@ -5,15 +5,20 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +import { schema } from '@kbn/config-schema'; + import { loggingSystemMock } from '@kbn/core/server/mocks'; import { Core } from './core'; -import { createMemoryStorage, MockContent } from './mocks'; +import { createMemoryStorage, FooContent } from './mocks'; import { ContentRegistry } from './registry'; import { ContentCrud } from './crud'; import type { GetItemStart, GetItemSuccess, GetItemError, + BulkGetItemStart, + BulkGetItemSuccess, + BulkGetItemError, CreateItemStart, CreateItemSuccess, CreateItemError, @@ -23,20 +28,34 @@ import type { DeleteItemStart, DeleteItemSuccess, DeleteItemError, + SearchItemStart, + SearchItemSuccess, + SearchItemError, } from './event_types'; +import { ContentTypeDefinition, StorageContext } from './types'; const logger = loggingSystemMock.createLogger(); const FOO_CONTENT_ID = 'foo'; +const fooSchema = schema.object({ title: schema.string() }); const setup = ({ registerFooType = false }: { registerFooType?: boolean } = {}) => { - const ctx = {}; + const ctx: StorageContext = { + requestHandlerContext: {} as any, + }; const core = new Core({ logger }); const coreSetup = core.setup(); - const contentDefinition = { + const contentDefinition: ContentTypeDefinition = { id: FOO_CONTENT_ID, storage: createMemoryStorage(), + schemas: { + content: { + create: { in: { data: fooSchema } }, + update: { in: { data: fooSchema } }, + search: { in: { query: schema.any() } }, + }, + }, }; const cleanUp = () => { coreSetup.api.eventBus.stop(); @@ -119,12 +138,43 @@ describe('Content Core', () => { cleanUp(); }); + test('bulkGet()', async () => { + const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); + + const res = await fooContentCrud!.bulkGet(ctx, ['1', '2']); + expect(res.items).toEqual([]); + + cleanUp(); + }); + + test('bulkGet() - options are forwared to storage layer', async () => { + const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); + + const res = await fooContentCrud!.bulkGet(ctx, ['1', '2'], { + forwardInResponse: { foo: 'bar' }, + }); + + expect(res).toEqual({ + contentTypeId: FOO_CONTENT_ID, + items: [ + { + options: { foo: 'bar' }, // Options forwared in response + }, + { + options: { foo: 'bar' }, // Options forwared in response + }, + ], + }); + + cleanUp(); + }); + test('create()', async () => { const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); const res = await fooContentCrud!.get(ctx, '1234'); expect(res.item).toBeUndefined(); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } // We send this "id" option to specify the id of the content created @@ -143,12 +193,12 @@ describe('Content Core', () => { test('update()', async () => { const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } ); - await fooContentCrud!.update>(ctx, '1234', { title: 'changed' }); + await fooContentCrud!.update>(ctx, '1234', { title: 'changed' }); expect(fooContentCrud!.get(ctx, '1234')).resolves.toEqual({ contentTypeId: FOO_CONTENT_ID, item: { @@ -163,12 +213,12 @@ describe('Content Core', () => { test('update() - options are forwared to storage layer', async () => { const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } ); - const res = await fooContentCrud!.update>( + const res = await fooContentCrud!.update>( ctx, '1234', { title: 'changed' }, @@ -199,7 +249,7 @@ describe('Content Core', () => { test('delete()', async () => { const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } @@ -220,7 +270,7 @@ describe('Content Core', () => { test('delete() - options are forwared to storage layer', async () => { const { fooContentCrud, ctx, cleanUp } = setup({ registerFooType: true }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } @@ -311,7 +361,7 @@ describe('Content Core', () => { register(contentDefinition); - await crud(FOO_CONTENT_ID).create, { id: string }>( + await crud(FOO_CONTENT_ID).create, { id: string }>( ctx, { title: 'Hello' }, { id: '1234' } @@ -351,7 +401,7 @@ describe('Content Core', () => { const data = { title: 'Hello' }; - await fooContentCrud!.create, { id: string }>(ctx, data, { + await fooContentCrud!.create, { id: string }>(ctx, data, { id: '1234', }); @@ -379,6 +429,7 @@ describe('Content Core', () => { ...data, }, contentTypeId: FOO_CONTENT_ID, + options: { someOption: 'baz' }, }; expect(listener).toHaveBeenCalledWith(getItemSuccess); @@ -406,6 +457,80 @@ describe('Content Core', () => { cleanUp(); }); + test('bulkGet()', async () => { + const { fooContentCrud, eventBus, ctx, cleanUp } = setup({ + registerFooType: true, + }); + + const data = { title: 'Hello' }; + + await fooContentCrud!.create, { id: string }>(ctx, data, { + id: '1234', + }); + await fooContentCrud!.create, { id: string }>(ctx, data, { + id: '5678', + }); + + const listener = jest.fn(); + const sub = eventBus.events$.subscribe(listener); + + const promise = fooContentCrud!.bulkGet(ctx, ['1234', '5678'], { someOption: 'baz' }); + + const bulkGetItemStart: BulkGetItemStart = { + type: 'bulkGetItemStart', + ids: ['1234', '5678'], + contentTypeId: FOO_CONTENT_ID, + options: { someOption: 'baz' }, + }; + + expect(listener).toHaveBeenCalledWith(bulkGetItemStart); + + await promise; + + const bulkGetItemSuccess: BulkGetItemSuccess = { + type: 'bulkGetItemSuccess', + ids: ['1234', '5678'], + data: [ + { + id: '1234', + ...data, + }, + { + id: '5678', + ...data, + }, + ], + contentTypeId: FOO_CONTENT_ID, + options: { someOption: 'baz' }, + }; + + expect(listener).toHaveBeenCalledWith(bulkGetItemSuccess); + + listener.mockReset(); + + const errorMessage = 'Ohhh no!'; + const reject = jest.fn(); + await fooContentCrud! + .bulkGet(ctx, ['1234', '5678'], { errorToThrow: errorMessage }) + .catch(reject); + + const bulkGetItemError: BulkGetItemError = { + type: 'bulkGetItemError', + ids: ['1234', '5678'], + contentTypeId: FOO_CONTENT_ID, + error: errorMessage, + options: { errorToThrow: errorMessage }, + }; + + expect(listener).toHaveBeenLastCalledWith(bulkGetItemError); + + expect(reject).toHaveBeenCalledWith(new Error(errorMessage)); + + sub.unsubscribe(); + + cleanUp(); + }); + test('create()', async () => { const { fooContentCrud, ctx, eventBus, cleanUp } = setup({ registerFooType: true, @@ -416,7 +541,7 @@ describe('Content Core', () => { const listener = jest.fn(); const sub = eventBus.events$.subscribe(listener); - const promise = fooContentCrud!.create, { id: string }>( + const promise = fooContentCrud!.create, { id: string }>( ctx, data, { @@ -452,7 +577,7 @@ describe('Content Core', () => { const errorMessage = 'Ohhh no!'; const reject = jest.fn(); await fooContentCrud! - .create, { id: string; errorToThrow: string }>(ctx, data, { + .create, { id: string; errorToThrow: string }>(ctx, data, { id: '1234', errorToThrow: errorMessage, }) @@ -479,7 +604,7 @@ describe('Content Core', () => { registerFooType: true, }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { @@ -551,7 +676,7 @@ describe('Content Core', () => { registerFooType: true, }); - await fooContentCrud!.create, { id: string }>( + await fooContentCrud!.create, { id: string }>( ctx, { title: 'Hello' }, { @@ -609,6 +734,71 @@ describe('Content Core', () => { sub.unsubscribe(); cleanUp(); }); + + test('search()', async () => { + const { fooContentCrud, ctx, eventBus, cleanUp } = setup({ + registerFooType: true, + }); + + const myContent = { title: 'Hello' }; + + await fooContentCrud!.create, { id: string }>(ctx, myContent, { + id: '1234', + }); + + const listener = jest.fn(); + const sub = eventBus.events$.subscribe(listener); + + const query = { title: 'Hell' }; + + const promise = await fooContentCrud!.search(ctx, query, { someOptions: 'baz' }); + + const searchItemStart: SearchItemStart = { + type: 'searchItemStart', + query, + contentTypeId: FOO_CONTENT_ID, + options: { someOptions: 'baz' }, + }; + + expect(listener).toHaveBeenCalledWith(searchItemStart); + + await promise; + + const searchItemSuccess: SearchItemSuccess = { + type: 'searchItemSuccess', + query, + data: [{ id: '1234', ...myContent }], + contentTypeId: FOO_CONTENT_ID, + options: { someOptions: 'baz' }, + }; + + expect(listener).toHaveBeenCalledWith(searchItemSuccess); + + listener.mockReset(); + + const errorMessage = 'Ohhh no!'; + const reject = jest.fn(); + await fooContentCrud! + .search(ctx, query, { + errorToThrow: errorMessage, + }) + .catch(reject); + + const searchItemError: SearchItemError = { + type: 'searchItemError', + contentTypeId: FOO_CONTENT_ID, + query, + error: errorMessage, + options: { errorToThrow: errorMessage }, + }; + + expect(listener).toHaveBeenLastCalledWith(searchItemError); + + expect(reject).toHaveBeenCalledWith(new Error(errorMessage)); + + sub.unsubscribe(); + cleanUp(); + }); }); }); }); diff --git a/src/plugins/content_management/server/core/crud.ts b/src/plugins/content_management/server/core/crud.ts index e56d79e8f47b23..cde3af9f2c2a27 100644 --- a/src/plugins/content_management/server/core/crud.ts +++ b/src/plugins/content_management/server/core/crud.ts @@ -72,6 +72,7 @@ export class ContentCrud implements ContentStorage { contentId, contentTypeId: this.contentTypeId, data: item, + options, }); return { contentTypeId: this.contentTypeId, item }; @@ -108,6 +109,7 @@ export class ContentCrud implements ContentStorage { ids, contentTypeId: this.contentTypeId, data: items, + options, }); return { @@ -120,7 +122,7 @@ export class ContentCrud implements ContentStorage { ids, contentTypeId: this.contentTypeId, options, - error: e, + error: e.message, }); throw e; @@ -238,4 +240,41 @@ export class ContentCrud implements ContentStorage { throw e; } } + + public async search( + ctx: StorageContext, + query: Query, + options?: Options + ): Promise> { + this.eventBus.emit({ + type: 'searchItemStart', + contentTypeId: this.contentTypeId, + query, + options, + }); + + try { + const result = await this.storage.search(ctx, query, options); + + this.eventBus.emit({ + type: 'searchItemSuccess', + contentTypeId: this.contentTypeId, + query, + data: result, + options, + }); + + return { contentTypeId: this.contentTypeId, result }; + } catch (e) { + this.eventBus.emit({ + type: 'searchItemError', + contentTypeId: this.contentTypeId, + query, + options, + error: e.message, + }); + + throw e; + } + } } diff --git a/src/plugins/content_management/server/core/event_types.ts b/src/plugins/content_management/server/core/event_types.ts index 815ea9a4f6710c..e1b6ebd67cf13e 100644 --- a/src/plugins/content_management/server/core/event_types.ts +++ b/src/plugins/content_management/server/core/event_types.ts @@ -5,116 +5,107 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ +interface BaseEvent { + type: T; + contentTypeId: string; + options?: object; +} -export interface GetItemStart { - type: 'getItemStart'; +export interface GetItemStart extends BaseEvent<'getItemStart'> { contentId: string; - contentTypeId: string; options?: object; } -export interface GetItemSuccess { - type: 'getItemSuccess'; +export interface GetItemSuccess extends BaseEvent<'getItemSuccess'> { contentId: string; - contentTypeId: string; data: unknown; } -export interface GetItemError { - type: 'getItemError'; +export interface GetItemError extends BaseEvent<'getItemError'> { contentId: string; - contentTypeId: string; error: unknown; - options?: object; } -export interface BulkGetItemStart { - type: 'bulkGetItemStart'; +export interface BulkGetItemStart extends BaseEvent<'bulkGetItemStart'> { ids: string[]; - contentTypeId: string; options?: object; } -export interface BulkGetItemSuccess { - type: 'bulkGetItemSuccess'; +export interface BulkGetItemSuccess extends BaseEvent<'bulkGetItemSuccess'> { ids: string[]; - contentTypeId: string; data: unknown; } -export interface BulkGetItemError { - type: 'bulkGetItemError'; +export interface BulkGetItemError extends BaseEvent<'bulkGetItemError'> { ids: string[]; - contentTypeId: string; error: unknown; options?: object; } -export interface CreateItemStart { - type: 'createItemStart'; - contentTypeId: string; +export interface CreateItemStart extends BaseEvent<'createItemStart'> { data: object; options?: object; } -export interface CreateItemSuccess { - type: 'createItemSuccess'; - contentTypeId: string; +export interface CreateItemSuccess extends BaseEvent<'createItemSuccess'> { data: object; options?: object; } -export interface CreateItemError { - type: 'createItemError'; - contentTypeId: string; +export interface CreateItemError extends BaseEvent<'createItemError'> { data: object; error: unknown; options?: object; } -export interface UpdateItemStart { - type: 'updateItemStart'; +export interface UpdateItemStart extends BaseEvent<'updateItemStart'> { contentId: string; - contentTypeId: string; data: object; options?: object; } -export interface UpdateItemSuccess { - type: 'updateItemSuccess'; +export interface UpdateItemSuccess extends BaseEvent<'updateItemSuccess'> { contentId: string; - contentTypeId: string; data: object; options?: object; } -export interface UpdateItemError { - type: 'updateItemError'; +export interface UpdateItemError extends BaseEvent<'updateItemError'> { contentId: string; - contentTypeId: string; data: object; error: unknown; options?: object; } -export interface DeleteItemStart { - type: 'deleteItemStart'; +export interface DeleteItemStart extends BaseEvent<'deleteItemStart'> { contentId: string; - contentTypeId: string; options?: object; } -export interface DeleteItemSuccess { - type: 'deleteItemSuccess'; +export interface DeleteItemSuccess extends BaseEvent<'deleteItemSuccess'> { contentId: string; - contentTypeId: string; options?: object; } -export interface DeleteItemError { - type: 'deleteItemError'; +export interface DeleteItemError extends BaseEvent<'deleteItemError'> { contentId: string; - contentTypeId: string; + error: unknown; + options?: object; +} + +export interface SearchItemStart extends BaseEvent<'searchItemStart'> { + query: object; + options?: object; +} + +export interface SearchItemSuccess extends BaseEvent<'searchItemSuccess'> { + query: object; + data: unknown; + options?: object; +} + +export interface SearchItemError extends BaseEvent<'searchItemError'> { + query: object; error: unknown; options?: object; } @@ -134,6 +125,9 @@ export type ContentEvent = | UpdateItemError | DeleteItemStart | DeleteItemSuccess - | DeleteItemError; + | DeleteItemError + | SearchItemStart + | SearchItemSuccess + | SearchItemError; export type ContentEventType = ContentEvent['type']; diff --git a/src/plugins/content_management/server/core/index.ts b/src/plugins/content_management/server/core/index.ts index f292f5fa2df9a3..8490272e90fb44 100644 --- a/src/plugins/content_management/server/core/index.ts +++ b/src/plugins/content_management/server/core/index.ts @@ -12,6 +12,8 @@ export type { CoreApi } from './core'; export type { ContentType } from './content_type'; -export type { ContentStorage, ContentTypeDefinition, StorageContext } from './types'; +export type { ContentStorage, ContentTypeDefinition, StorageContext, RpcSchemas } from './types'; export type { ContentRegistry } from './registry'; + +export type { ContentCrud } from './crud'; diff --git a/src/plugins/content_management/server/core/mocks/in_memory_storage.ts b/src/plugins/content_management/server/core/mocks/in_memory_storage.ts index a2297731198afa..e08261bbc1cb12 100644 --- a/src/plugins/content_management/server/core/mocks/in_memory_storage.ts +++ b/src/plugins/content_management/server/core/mocks/in_memory_storage.ts @@ -8,7 +8,7 @@ import type { ContentStorage, StorageContext } from '../types'; -export interface MockContent { +export interface FooContent { id: string; title: string; } @@ -16,7 +16,7 @@ export interface MockContent { let idx = 0; class InMemoryStorage implements ContentStorage { - private db: Map = new Map(); + private db: Map = new Map(); async get( ctx: StorageContext, @@ -41,16 +41,23 @@ class InMemoryStorage implements ContentStorage { async bulkGet( ctx: StorageContext, ids: string[], - { forwardInResponse }: { forwardInResponse?: object } = {} + { forwardInResponse, errorToThrow }: { forwardInResponse?: object; errorToThrow?: string } = {} ) { - return ids.map((id) => this.db.get(id)); + // This allows us to test that proper error events are thrown when the storage layer op fails + if (errorToThrow) { + throw new Error(errorToThrow); + } + + return ids.map((id) => + forwardInResponse ? { ...this.db.get(id), options: forwardInResponse } : this.db.get(id) + ); } async create( ctx: StorageContext, - data: Omit, + data: Omit, { id: _id, errorToThrow }: { id?: string; errorToThrow?: string } = {} - ): Promise { + ): Promise { // This allows us to test that proper error events are thrown when the storage layer op fails if (errorToThrow) { throw new Error(errorToThrow); @@ -59,7 +66,7 @@ class InMemoryStorage implements ContentStorage { const nextId = idx++; const id = _id ?? nextId.toString(); - const content: MockContent = { + const content: FooContent = { ...data, id, }; @@ -72,7 +79,7 @@ class InMemoryStorage implements ContentStorage { async update( ctx: StorageContext, id: string, - data: Partial>, + data: Partial>, { forwardInResponse, errorToThrow }: { forwardInResponse?: object; errorToThrow?: string } = {} ) { // This allows us to test that proper error events are thrown when the storage layer op fails @@ -134,8 +141,37 @@ class InMemoryStorage implements ContentStorage { status: 'success', }; } + + async search( + ctx: StorageContext, + query: { title: string }, + { errorToThrow }: { errorToThrow?: string } = {} + ): Promise { + // This allows us to test that proper error events are thrown when the storage layer op fails + if (errorToThrow) { + throw new Error(errorToThrow); + } + + if (query.title.length < 2) { + return []; + } + + const rgx = new RegExp(query.title); + return [...this.db.values()].filter(({ title }) => { + return title.match(rgx); + }); + } } export const createMemoryStorage = () => { return new InMemoryStorage(); }; + +export const createMockedStorage = (): jest.Mocked => ({ + get: jest.fn(), + bulkGet: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + search: jest.fn(), +}); diff --git a/src/plugins/content_management/server/core/mocks/index.ts b/src/plugins/content_management/server/core/mocks/index.ts index b7f9d8a2f25859..b7b8da240a4e7e 100644 --- a/src/plugins/content_management/server/core/mocks/index.ts +++ b/src/plugins/content_management/server/core/mocks/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export { createMemoryStorage } from './in_memory_storage'; -export type { MockContent } from './in_memory_storage'; +export { createMemoryStorage, createMockedStorage } from './in_memory_storage'; +export type { FooContent } from './in_memory_storage'; diff --git a/src/plugins/content_management/server/core/types.ts b/src/plugins/content_management/server/core/types.ts index 4ebd79d605717e..e3977e75338f4b 100644 --- a/src/plugins/content_management/server/core/types.ts +++ b/src/plugins/content_management/server/core/types.ts @@ -6,11 +6,12 @@ * Side Public License, v 1. */ +import type { Type } from '@kbn/config-schema'; import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; /** Context that is sent to all storage instance methods */ export interface StorageContext { - requestHandlerContext?: RequestHandlerContext; + requestHandlerContext: RequestHandlerContext; } export interface ContentStorage { @@ -21,18 +22,80 @@ export interface ContentStorage { bulkGet(ctx: StorageContext, ids: string[], options: unknown): Promise; /** Create an item */ - create(ctx: StorageContext, fields: object, options: unknown): Promise; + create(ctx: StorageContext, data: object, options: unknown): Promise; /** Update an item */ - update(ctx: StorageContext, id: string, fields: object, options: unknown): Promise; + update(ctx: StorageContext, id: string, data: object, options: unknown): Promise; /** Delete an item */ delete(ctx: StorageContext, id: string, options: unknown): Promise; + + /** Search items */ + search(ctx: StorageContext, query: object, options: unknown): Promise; +} + +export interface RpcSchemas { + get?: { + in?: { + options?: Type; + }; + out?: { + result: Type; + }; + }; + bulkGet?: { + in?: { + options?: Type; + }; + out?: { + result: Type; + }; + }; + create: { + in: { + data: Type; + options?: Type; + }; + out?: { + result: Type; + }; + }; + update: { + in: { + data: Type; + options?: Type; + }; + out?: { + result: Type; + }; + }; + delete?: { + in?: { + options?: Type; + }; + out?: { + result: Type; + }; + }; + search: { + in: { + query: Type; + options?: Type; + }; + out?: { + result: Type; + }; + }; } +export type ContentSchemas = RpcSchemas; + export interface ContentTypeDefinition { /** Unique id for the content type */ id: string; /** The storage layer for the content. It must implment the ContentStorage interface. */ storage: S; + schemas: { + content: ContentSchemas; + }; } diff --git a/src/plugins/content_management/server/plugin.test.ts b/src/plugins/content_management/server/plugin.test.ts new file mode 100644 index 00000000000000..4ec92f3bd22833 --- /dev/null +++ b/src/plugins/content_management/server/plugin.test.ts @@ -0,0 +1,164 @@ +/* + * 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 { loggingSystemMock, coreMock } from '@kbn/core/server/mocks'; +import { ContentManagementPlugin } from './plugin'; +import { IRouter } from '@kbn/core/server'; +import { ProcedureName, procedureNames } from '../common'; + +jest.mock('./core', () => ({ + ...jest.requireActual('./core'), + Core: class { + setup() { + return { + contentRegistry: 'mockedContentRegistry', + api: { + register: jest.fn().mockReturnValue('mockedRegister'), + crud: jest.fn().mockReturnValue('mockedCrud'), + eventBus: { + emit: jest.fn().mockReturnValue('mockedEventBusEmit'), + }, + }, + }; + } + }, +})); + +const mockGet = jest.fn().mockResolvedValue('getMocked'); +const mockBulkGet = jest.fn().mockResolvedValue('bulkGetMocked'); +const mockCreate = jest.fn().mockResolvedValue('createMocked'); +const mockUpdate = jest.fn().mockResolvedValue('updateMocked'); +const mockDelete = jest.fn().mockResolvedValue('deleteMocked'); +const mockSearch = jest.fn().mockResolvedValue('searchMocked'); + +jest.mock('./rpc/procedures/all_procedures', () => { + const mockedProcedure = (spyGetter: () => jest.Mock) => ({ + fn: (...args: unknown[]) => spyGetter()(...args), + schemas: { + in: { + validate: () => undefined, + } as any, + }, + }); + + const mockedProcedures: { [key in ProcedureName]: any } = { + get: mockedProcedure(() => mockGet), + bulkGet: mockedProcedure(() => mockBulkGet), + create: mockedProcedure(() => mockCreate), + update: mockedProcedure(() => mockUpdate), + delete: mockedProcedure(() => mockDelete), + search: mockedProcedure(() => mockSearch), + }; + + return { + procedures: mockedProcedures, + }; +}); + +const setup = () => { + const logger = loggingSystemMock.create(); + const { http } = coreMock.createSetup(); + + const router: IRouter = http.createRouter(); + router.post = jest.fn(); + + const plugin = new ContentManagementPlugin({ logger }); + + return { plugin, http: { createRouter: () => router }, router }; +}; + +describe('ContentManagementPlugin', () => { + describe('setup()', () => { + test('should expose the core API', () => { + const { plugin, http } = setup(); + const api = plugin.setup({ http }); + + expect(Object.keys(api).sort()).toEqual(['crud', 'eventBus', 'register']); + expect(api.crud('')).toBe('mockedCrud'); + expect(api.register({} as any)).toBe('mockedRegister'); + expect(api.eventBus.emit({} as any)).toBe('mockedEventBusEmit'); + }); + + describe('RPC', () => { + test('should create a single POST HTTP route on the router', () => { + const { plugin, http, router } = setup(); + plugin.setup({ http }); + + expect(router.post).toBeCalledTimes(1); + const [routeConfig]: Parameters = (router.post as jest.Mock).mock.calls[0]; + + expect(routeConfig.path).toBe('/api/content_management/rpc/{name}'); + }); + + test('should register all the procedures in the RPC service and the route handler must send to each procedure the core request context + the request body as input', async () => { + const { plugin, http, router } = setup(); + plugin.setup({ http }); + + const [_, handler]: Parameters = (router.post as jest.Mock).mock.calls[0]; + + const mockedRequestHandlerContext: any = { foo: 'bar' }; + const mockedResponse: any = { + ok: jest.fn((data: { body: unknown }) => data.body), + customError: jest.fn((e: any) => e), + }; + + const input = { testInput: 'baz' }; + + // Call the handler for each of our procedure names + const result = await Promise.all( + procedureNames.map((name) => { + const mockedRequest: any = { + params: { name }, + body: input, + }; + + return handler(mockedRequestHandlerContext, mockedRequest, mockedResponse); + }) + ); + + // Each procedure result is returned inside the response.ok() => body + expect(result).toEqual(procedureNames.map((name) => ({ result: `${name}Mocked` }))); + + // Each procedure has been called with the context and input + const context = { + requestHandlerContext: mockedRequestHandlerContext, + contentRegistry: 'mockedContentRegistry', + }; + expect(mockGet).toHaveBeenCalledWith(context, input); + expect(mockCreate).toHaveBeenCalledWith(context, input); + expect(mockUpdate).toHaveBeenCalledWith(context, input); + expect(mockDelete).toHaveBeenCalledWith(context, input); + expect(mockSearch).toHaveBeenCalledWith(context, input); + }); + + test('should return error in custom error format', async () => { + const { plugin, http, router } = setup(); + plugin.setup({ http }); + + const [_, handler]: Parameters = (router.post as jest.Mock).mock.calls[0]; + + // const mockedRequestHandlerContext: any = { foo: 'bar' }; + const mockedResponse: any = { + ok: jest.fn((response: { body: unknown }) => response.body), + customError: jest.fn((e: any) => e), + }; + + mockGet.mockRejectedValueOnce(new Error('Houston we got a problem.')); + const error = await handler({} as any, { params: { name: 'get' } } as any, mockedResponse); + + expect(error).toEqual({ + body: { + message: new Error('Houston we got a problem.'), + }, + headers: {}, + statusCode: 500, + }); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/plugin.ts b/src/plugins/content_management/server/plugin.ts index 5e3ba371a4e167..e13c5af7b7a6e5 100755 --- a/src/plugins/content_management/server/plugin.ts +++ b/src/plugins/content_management/server/plugin.ts @@ -14,11 +14,16 @@ import type { Logger, } from '@kbn/core/server'; import { Core } from './core'; +import { initRpcRoutes, registerProcedures, RpcService } from './rpc'; +import type { Context as RpcContext } from './rpc'; import { ContentManagementServerSetup, ContentManagementServerStart, SetupDependencies, } from './types'; +import { procedureNames } from '../common'; + +type CreateRouterFn = CoreSetup['http']['createRouter']; export class ContentManagementPlugin implements Plugin @@ -26,13 +31,22 @@ export class ContentManagementPlugin private readonly logger: Logger; private readonly core: Core; - constructor(initializerContext: PluginInitializerContext) { + constructor(initializerContext: { logger: PluginInitializerContext['logger'] }) { this.logger = initializerContext.logger.get(); this.core = new Core({ logger: this.logger }); } - public setup(core: CoreSetup) { - const { api: coreApi } = this.core.setup(); + public setup(core: { http: { createRouter: CreateRouterFn } }) { + const { api: coreApi, contentRegistry } = this.core.setup(); + + const rpc = new RpcService(); + registerProcedures(rpc); + + const router = core.http.createRouter(); + initRpcRoutes(procedureNames, router, { + rpc, + contentRegistry, + }); return { ...coreApi, diff --git a/src/plugins/content_management/server/rpc/index.ts b/src/plugins/content_management/server/rpc/index.ts new file mode 100644 index 00000000000000..3d68b6feb398d6 --- /dev/null +++ b/src/plugins/content_management/server/rpc/index.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. + */ + +export { RpcService } from './rpc_service'; + +export { initRpcRoutes } from './routes'; + +export { registerProcedures } from './procedures'; + +export type { Context } from './types'; + +export type { ProcedureDefinition } from './rpc_service'; diff --git a/src/plugins/content_management/server/rpc/procedures/all_procedures.ts b/src/plugins/content_management/server/rpc/procedures/all_procedures.ts new file mode 100644 index 00000000000000..6b177debf11dfe --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/all_procedures.ts @@ -0,0 +1,25 @@ +/* + * 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 { ProcedureName } from '../../../common'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { get } from './get'; +import { bulkGet } from './bulk_get'; +import { create } from './create'; +import { update } from './update'; +import { deleteProc } from './delete'; +import { search } from './search'; + +export const procedures: { [key in ProcedureName]: ProcedureDefinition } = { + get, + bulkGet, + create, + update, + delete: deleteProc, + search, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/bulk_get.test.ts b/src/plugins/content_management/server/rpc/procedures/bulk_get.test.ts new file mode 100644 index 00000000000000..c5d839b57c0d33 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/bulk_get.test.ts @@ -0,0 +1,246 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { bulkGet } from './bulk_get'; + +const { fn, schemas } = bulkGet; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [bulkGet] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [bulkGet] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; +const fooDataSchema = schema.object({ title: schema.string() }, { unknowns: 'forbid' }); + +describe('RPC -> bulkGet()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure in separate tests. + */ + test('should validate that a contentTypeId and "ids" array is passed', () => { + const ids = ['123', '456']; + + [ + { input: { contentTypeId: 'foo', ids } }, + { + input: { ids }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo' }, // ids missing + expectedError: '[ids]: expected value of type [array] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', ids: [] }, // ids array needs at least one value + expectedError: '[ids]: array size is [0], but cannot be smaller than [1]', + }, + { + input: { contentTypeId: 'foo', ids: [''] }, // ids must havr 1 char min + expectedError: '[ids.0]: value has length [0] but it must have a minimum length of [1].', + }, + { + input: { contentTypeId: 'foo', ids: 123 }, // ids is not an array of string + expectedError: '[ids]: expected value of type [array] but got [number]', + }, + { + input: { contentTypeId: 'foo', ids, unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (!expectedError) { + try { + expect(error).toBe(null); + } catch (e) { + throw new Error(`Expected no error but got [{${error?.message}}].`); + } + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + ids: ['123'], + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + ids: ['123'], + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object or an array of object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate( + [ + { + any: 'object', + }, + ], + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toContain( + 'expected a plain object value, but found [number] instead.' + ); + expect(error?.message).toContain('expected value of type [array] but got [number]'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return { + bulkGet: { + in: { + query: fooDataSchema, + }, + }, + } as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage bulkGet() result', async () => { + const { ctx, storage } = setup(); + + const expected = ['Item1', 'Item2']; + storage.bulkGet.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { contentTypeId: FOO_CONTENT_ID, ids: ['123', '456'] }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + items: expected, + }); + + expect(storage.bulkGet).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + ['123', '456'], + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => fn(ctx, { contentTypeId: 'unknown', ids: ['123', '456'] })).rejects.toEqual( + new Error('Content [unknown] is not registered.') + ); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + ids: ['123', '456'], + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [bulkGet.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + bulkGet: { + in: { + query: fooDataSchema, + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + ids: ['123', '456'], + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + bulkGet: { + in: { query: fooDataSchema }, + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.bulkGet.mockResolvedValueOnce(invalidResult); + + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, ids: ['123', '456'] }) + ).rejects.toEqual(new Error('[wrongField]: definition for this key is missing')); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/bulk_get.ts b/src/plugins/content_management/server/rpc/procedures/bulk_get.ts new file mode 100644 index 00000000000000..ee8c27271abfdc --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/bulk_get.ts @@ -0,0 +1,55 @@ +/* + * 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 { rpcSchemas } from '../../../common'; +import type { BulkGetIn } from '../../../common'; +import type { StorageContext, ContentCrud } from '../../core'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { validate } from '../../utils'; +import { BulkGetResponse } from '../../core/crud'; + +export const bulkGet: ProcedureDefinition, BulkGetResponse> = { + schemas: rpcSchemas.bulkGet, + fn: async (ctx, { contentTypeId, ids, options }) => { + const contentDefinition = ctx.contentRegistry.getDefinition(contentTypeId); + const { bulkGet: schemas } = contentDefinition.schemas.content; + + // Validate the possible options + if (options) { + if (!schemas?.in?.options) { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [bulkGet.in.options].'); + } + const error = validate(options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.bulkGet(storageContext, ids, options); + + // Validate result + const resultSchema = schemas?.out?.result; + if (resultSchema) { + const error = validate(result.items, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/create.test.ts b/src/plugins/content_management/server/rpc/procedures/create.test.ts new file mode 100644 index 00000000000000..cb05786f72d5dd --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/create.test.ts @@ -0,0 +1,245 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { create } from './create'; + +const { fn, schemas } = create; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [create] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [create] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; +const fooDataSchema = schema.object({ title: schema.string() }, { unknowns: 'forbid' }); + +describe('RPC -> create()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure in separate tests. + */ + test('should validate that a contentTypeId and "data" object is passed', () => { + [ + { input: { contentTypeId: 'foo', data: { title: 'hello' } } }, + { + input: { data: { title: 'hello' } }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo' }, // data missing + expectedError: '[data]: expected value of type [object] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', data: 123 }, // data is not an object + expectedError: '[data]: expected value of type [object] but got [number]', + }, + { + input: { contentTypeId: 'foo', data: { title: 'hello' }, unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (!expectedError) { + try { + expect(error).toBe(null); + } catch (e) { + throw new Error(`Expected no error but got [{${error?.message}}].`); + } + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + data: { title: 'hello' }, + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + data: { title: 'hello' }, + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toBe('expected a plain object value, but found [number] instead.'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return { + create: { + in: { + data: fooDataSchema, + }, + }, + } as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage create() result', async () => { + const { ctx, storage } = setup(); + + const expected = 'CreateResult'; + storage.create.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { contentTypeId: FOO_CONTENT_ID, data: { title: 'Hello' } }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + result: expected, + }); + + expect(storage.create).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + { title: 'Hello' }, + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: 'unknown', data: { title: 'Hello' } }) + ).rejects.toEqual(new Error('Content [unknown] is not registered.')); + }); + + test('should enforce a schema for the data', () => { + const { ctx } = setup({ contentSchemas: {} as any }); + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, data: {} })).rejects.toEqual( + new Error('Schema missing for rpc procedure [create.in.data].') + ); + }); + + test('should validate the data sent in input - missing field', () => { + const { ctx } = setup(); + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, data: {} })).rejects.toEqual( + new Error('[title]: expected value of type [string] but got [undefined]') + ); + }); + + test('should validate the data sent in input - unknown field', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + data: { title: 'Hello', unknownField: 'Hello' }, + }) + ).rejects.toEqual(new Error('[unknownField]: definition for this key is missing')); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + data: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [create.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + create: { + in: { + data: fooDataSchema, + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + data: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + create: { + in: { data: fooDataSchema }, + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.create.mockResolvedValueOnce(invalidResult); + + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, data: { title: 'Hello' } }) + ).rejects.toEqual(new Error('[wrongField]: definition for this key is missing')); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/create.ts b/src/plugins/content_management/server/rpc/procedures/create.ts new file mode 100644 index 00000000000000..fe2f4e0ab7d160 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/create.ts @@ -0,0 +1,66 @@ +/* + * 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 { rpcSchemas } from '../../../common'; +import type { CreateIn } from '../../../common'; +import type { StorageContext, ContentCrud } from '../../core'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { validate } from '../../utils'; + +export const create: ProcedureDefinition> = { + schemas: rpcSchemas.create, + fn: async (ctx, input) => { + const contentDefinition = ctx.contentRegistry.getDefinition(input.contentTypeId); + const { create: schemas } = contentDefinition.schemas.content; + + // Validate data to be stored + if (schemas?.in?.data) { + const error = validate(input.data, schemas.in.data); + if (error) { + // TODO: Improve error handling + throw error; + } + } else { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [create.in.data].'); + } + + // Validate the possible options + if (input.options) { + if (!schemas.in?.options) { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [create.in.options].'); + } + const error = validate(input.options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(input.contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.create(storageContext, input.data, input.options); + + // Validate result + const resultSchema = schemas.out?.result; + if (resultSchema) { + const error = validate(result.result, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/delete.test.ts b/src/plugins/content_management/server/rpc/procedures/delete.test.ts new file mode 100644 index 00000000000000..9b89adc7901977 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/delete.test.ts @@ -0,0 +1,200 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { deleteProc } from './delete'; + +const { fn, schemas } = deleteProc; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [update] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [update] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; + +describe('RPC -> delete()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure in separate tests. + */ + test('should validate that a contentTypeId and an id is passed', () => { + [ + { input: { contentTypeId: 'foo', id: '123' } }, + { + input: { id: '777' }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', id: '123', unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + { + input: { contentTypeId: 'foo', id: '' }, // id must have min 1 char + expectedError: '[id]: value has length [0] but it must have a minimum length of [1].', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (!expectedError) { + try { + expect(error).toBe(null); + } catch (e) { + throw new Error(`Expected no error but got [{${error?.message}}].`); + } + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + id: '123', + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + id: '123', + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toBe('expected a plain object value, but found [number] instead.'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return {} as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage delete() result', async () => { + const { ctx, storage } = setup(); + + const expected = 'DeleteResult'; + storage.delete.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234' }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + result: expected, + }); + + expect(storage.delete).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + '1234', + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => fn(ctx, { contentTypeId: 'unknown', id: '1234' })).rejects.toEqual( + new Error('Content [unknown] is not registered.') + ); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234', options: { foo: 'bar' } }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [delete.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + delete: { + in: { + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234', options: { foo: 'bar' } }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + delete: { + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.delete.mockResolvedValueOnce(invalidResult); + + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234' })).rejects.toEqual( + new Error('[wrongField]: definition for this key is missing') + ); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/delete.ts b/src/plugins/content_management/server/rpc/procedures/delete.ts new file mode 100644 index 00000000000000..c10cc02356beb0 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/delete.ts @@ -0,0 +1,52 @@ +/* + * 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 { rpcSchemas } from '../../../common'; +import type { DeleteIn } from '../../../common'; +import type { StorageContext, ContentCrud } from '../../core'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { validate } from '../../utils'; + +export const deleteProc: ProcedureDefinition> = { + schemas: rpcSchemas.delete, + fn: async (ctx, { contentTypeId, id, options }) => { + const contentDefinition = ctx.contentRegistry.getDefinition(contentTypeId); + const { delete: schemas } = contentDefinition.schemas.content; + + if (options) { + // Validate the options provided + if (!schemas?.in?.options) { + throw new Error(`Schema missing for rpc procedure [delete.in.options].`); + } + const error = validate(options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.delete(storageContext, id, options); + + // Validate result + const resultSchema = schemas?.out?.result; + if (resultSchema) { + const error = validate(result.result, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/get.test.ts b/src/plugins/content_management/server/rpc/procedures/get.test.ts new file mode 100644 index 00000000000000..d3214faaa1e9ca --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/get.test.ts @@ -0,0 +1,200 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { get } from './get'; + +const { fn, schemas } = get; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [get] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [get] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; + +describe('RPC -> get()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure in separate tests. + */ + test('should validate that a contentTypeId and an id is passed', () => { + [ + { input: { contentTypeId: 'foo', id: '123' } }, + { + input: { id: '777' }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', id: '123', unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + { + input: { contentTypeId: 'foo', id: '' }, // id must have min 1 char + expectedError: '[id]: value has length [0] but it must have a minimum length of [1].', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (!expectedError) { + try { + expect(error).toBe(null); + } catch (e) { + throw new Error(`Expected no error but got [{${error?.message}}].`); + } + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + id: '123', + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + id: '123', + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toBe('expected a plain object value, but found [number] instead.'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return {} as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage get() result', async () => { + const { ctx, storage } = setup(); + + const expected = 'GetResult'; + storage.get.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234' }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + item: expected, + }); + + expect(storage.get).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + '1234', + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => fn(ctx, { contentTypeId: 'unknown', id: '1234' })).rejects.toEqual( + new Error('Content [unknown] is not registered.') + ); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234', options: { foo: 'bar' } }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [get.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + get: { + in: { + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234', options: { foo: 'bar' } }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + get: { + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.get.mockResolvedValueOnce(invalidResult); + + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '1234' })).rejects.toEqual( + new Error('[wrongField]: definition for this key is missing') + ); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/get.ts b/src/plugins/content_management/server/rpc/procedures/get.ts new file mode 100644 index 00000000000000..73960ad8f3a2f8 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/get.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 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 { rpcSchemas } from '../../../common'; +import type { GetIn } from '../../../common'; +import type { ContentCrud, StorageContext } from '../../core'; +import { validate } from '../../utils'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; + +export const get: ProcedureDefinition> = { + schemas: rpcSchemas.get, + fn: async (ctx, input) => { + const contentDefinition = ctx.contentRegistry.getDefinition(input.contentTypeId); + const { get: schemas } = contentDefinition.schemas.content; + + if (input.options) { + // Validate the options provided + if (!schemas?.in?.options) { + throw new Error(`Schema missing for rpc procedure [get.in.options].`); + } + const error = validate(input.options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(input.contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.get(storageContext, input.id, input.options); + + // Validate result + const resultSchema = schemas?.out?.result; + if (resultSchema) { + const error = validate(result.item, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/index.ts b/src/plugins/content_management/server/rpc/procedures/index.ts new file mode 100644 index 00000000000000..6cfaba67c38c84 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/index.ts @@ -0,0 +1,25 @@ +/* + * 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 { ProcedureName } from '../../../common'; +import type { RpcService } from '../rpc_service'; +import type { Context } from '../types'; +import { procedures } from './all_procedures'; + +// Type utility to correclty set the type of JS Object.entries() +type Entries = Array< + { + [K in keyof T]: [K, T[K]]; + }[keyof T] +>; + +export function registerProcedures(rpc: RpcService) { + (Object.entries(procedures) as Entries).forEach(([name, definition]) => { + rpc.register(name, definition); + }); +} diff --git a/src/plugins/content_management/server/rpc/procedures/search.test.ts b/src/plugins/content_management/server/rpc/procedures/search.test.ts new file mode 100644 index 00000000000000..5f5f2e167ac3fb --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/search.test.ts @@ -0,0 +1,261 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { search } from './search'; + +const { fn, schemas } = search; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [search] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [search] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; +const fooDataSchema = schema.object({ title: schema.string() }, { unknowns: 'forbid' }); + +describe('RPC -> search()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure in separate tests. + */ + test('should validate that a contentTypeId and "query" object is passed', () => { + const query = { title: 'hello' }; + + [ + { input: { contentTypeId: 'foo', query } }, + { + input: { query }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo' }, // query missing + expectedError: '[query]: expected value of type [object] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', query: 123 }, // query is not an object + expectedError: '[query]: expected value of type [object] but got [number]', + }, + { + input: { contentTypeId: 'foo', query, unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (!expectedError) { + try { + expect(error).toBe(null); + } catch (e) { + throw new Error(`Expected no error but got [{${error?.message}}].`); + } + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + query: { title: 'hello' }, + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + query: { title: 'hello' }, + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object or an array of object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate( + [ + { + any: 'object', + }, + ], + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toContain( + 'expected a plain object value, but found [number] instead.' + ); + expect(error?.message).toContain('expected value of type [array] but got [number]'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return { + search: { + in: { + query: fooDataSchema, + }, + }, + } as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage search() result', async () => { + const { ctx, storage } = setup(); + + const expected = 'SearchResult'; + storage.search.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { contentTypeId: FOO_CONTENT_ID, query: { title: 'Hello' } }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + result: expected, + }); + + expect(storage.search).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + { title: 'Hello' }, + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: 'unknown', query: { title: 'Hello' } }) + ).rejects.toEqual(new Error('Content [unknown] is not registered.')); + }); + + test('should enforce a schema for the query', () => { + const { ctx } = setup({ contentSchemas: {} as any }); + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, query: {} })).rejects.toEqual( + new Error('Schema missing for rpc procedure [search.in.query].') + ); + }); + + test('should validate the query sent in input - missing field', () => { + const { ctx } = setup(); + expect(() => fn(ctx, { contentTypeId: FOO_CONTENT_ID, query: {} })).rejects.toEqual( + new Error('[title]: expected value of type [string] but got [undefined]') + ); + }); + + test('should validate the query sent in input - unknown field', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + query: { title: 'Hello', unknownField: 'Hello' }, + }) + ).rejects.toEqual(new Error('[unknownField]: definition for this key is missing')); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + query: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [search.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + search: { + in: { + query: fooDataSchema, + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + query: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + search: { + in: { query: fooDataSchema }, + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.search.mockResolvedValueOnce(invalidResult); + + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, query: { title: 'Hello' } }) + ).rejects.toEqual(new Error('[wrongField]: definition for this key is missing')); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/search.ts b/src/plugins/content_management/server/rpc/procedures/search.ts new file mode 100644 index 00000000000000..4c9d9a4a9b4c9d --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/search.ts @@ -0,0 +1,66 @@ +/* + * 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 { rpcSchemas } from '../../../common'; +import type { SearchIn } from '../../../common'; +import type { StorageContext, ContentCrud } from '../../core'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { validate } from '../../utils'; + +export const search: ProcedureDefinition> = { + schemas: rpcSchemas.search, + fn: async (ctx, { contentTypeId, query, options }) => { + const contentDefinition = ctx.contentRegistry.getDefinition(contentTypeId); + const { search: schemas } = contentDefinition.schemas.content; + + // Validate query to execute + if (schemas?.in?.query) { + const error = validate(query, schemas.in.query); + if (error) { + // TODO: Improve error handling + throw error; + } + } else { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [search.in.query].'); + } + + // Validate the possible options + if (options) { + if (!schemas.in?.options) { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [search.in.options].'); + } + const error = validate(options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.search(storageContext, query, options); + + // Validate result + const resultSchema = schemas.out?.result; + if (resultSchema) { + const error = validate(result.result, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/procedures/update.test.ts b/src/plugins/content_management/server/rpc/procedures/update.test.ts new file mode 100644 index 00000000000000..316456e2dd6290 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/update.test.ts @@ -0,0 +1,263 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { validate } from '../../utils'; +import { ContentRegistry } from '../../core/registry'; +import { createMockedStorage } from '../../core/mocks'; +import type { RpcSchemas } from '../../core'; +import { EventBus } from '../../core/event_bus'; +import { update } from './update'; + +const { fn, schemas } = update; + +const inputSchema = schemas?.in; +const outputSchema = schemas?.out; + +if (!inputSchema) { + throw new Error(`Input schema missing for [update] procedure.`); +} + +if (!outputSchema) { + throw new Error(`Output schema missing for [update] procedure.`); +} + +const FOO_CONTENT_ID = 'foo'; +const fooDataSchema = schema.object({ title: schema.string() }, { unknowns: 'forbid' }); + +describe('RPC -> update()', () => { + describe('Input/Output validation', () => { + /** + * These tests are for the procedure call itself. Every RPC needs to declare in/out schema + * We will test _specific_ validation schema inside the procedure suite below. + */ + test('should validate that a "contentTypeId", an "id" and "data" object is passed', () => { + const data = { title: 'hello' }; + + [ + { input: { contentTypeId: 'foo', id: '123', data } }, + { + input: { id: '123', data }, // contentTypeId missing + expectedError: '[contentTypeId]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', data }, // id missing + expectedError: '[id]: expected value of type [string] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', id: '' }, // id must have min 1 char + expectedError: '[id]: value has length [0] but it must have a minimum length of [1].', + }, + { + input: { contentTypeId: 'foo', id: '123' }, // data missing + expectedError: '[data]: expected value of type [object] but got [undefined]', + }, + { + input: { contentTypeId: 'foo', id: '123', data: 123 }, // data is not an object + expectedError: '[data]: expected value of type [object] but got [number]', + }, + { + input: { contentTypeId: 'foo', id: '123', data, unknown: 'foo' }, + expectedError: '[unknown]: definition for this key is missing', + }, + ].forEach(({ input, expectedError }) => { + const error = validate(input, inputSchema); + + if (error && !expectedError) { + throw new Error(`Expected no error but got [{${error.message}}].`); + } else { + expect(error?.message).toBe(expectedError); + } + }); + }); + + test('should allow an options "object" to be passed', () => { + let error = validate( + { + contentTypeId: 'foo', + id: '123', + data: { title: 'hello' }, + options: { any: 'object' }, + }, + inputSchema + ); + + expect(error).toBe(null); + + error = validate( + { + contentTypeId: 'foo', + data: { title: 'hello' }, + id: '123', + options: 123, // Not an object + }, + inputSchema + ); + + expect(error?.message).toBe( + '[options]: expected a plain object value, but found [number] instead.' + ); + }); + + test('should validate that the response is an object', () => { + let error = validate( + { + any: 'object', + }, + outputSchema + ); + + expect(error).toBe(null); + + error = validate(123, outputSchema); + + expect(error?.message).toBe('expected a plain object value, but found [number] instead.'); + }); + }); + + describe('procedure', () => { + const createSchemas = (): RpcSchemas => { + return { + update: { + in: { + data: fooDataSchema, + }, + }, + } as any; + }; + + const setup = ({ contentSchemas = createSchemas() } = {}) => { + const contentRegistry = new ContentRegistry(new EventBus()); + const storage = createMockedStorage(); + contentRegistry.register({ + id: FOO_CONTENT_ID, + storage, + schemas: { + content: contentSchemas, + }, + }); + + const requestHandlerContext = 'mockedRequestHandlerContext'; + const ctx: any = { contentRegistry, requestHandlerContext }; + + return { ctx, storage }; + }; + + test('should return the storage update() result', async () => { + const { ctx, storage } = setup(); + + const expected = 'UpdateResult'; + storage.update.mockResolvedValueOnce(expected); + + const result = await fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + id: '123', + data: { title: 'Hello' }, + }); + + expect(result).toEqual({ + contentTypeId: FOO_CONTENT_ID, + result: expected, + }); + + expect(storage.update).toHaveBeenCalledWith( + { requestHandlerContext: ctx.requestHandlerContext }, + '123', + { title: 'Hello' }, + undefined + ); + }); + + describe('validation', () => { + test('should validate that content type definition exist', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: 'unknown', id: '123', data: { title: 'Hello' } }) + ).rejects.toEqual(new Error('Content [unknown] is not registered.')); + }); + + test('should enforce a schema for the data', () => { + const { ctx } = setup({ contentSchemas: {} as any }); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '123', data: {} }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [update.in.data].')); + }); + + test('should validate the data sent in input - missing field', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '123', data: {} }) + ).rejects.toEqual( + new Error('[title]: expected value of type [string] but got [undefined]') + ); + }); + + test('should validate the data sent in input - unknown field', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + id: '123', + data: { title: 'Hello', unknownField: 'Hello' }, + }) + ).rejects.toEqual(new Error('[unknownField]: definition for this key is missing')); + }); + + test('should enforce a schema for options if options are passed', () => { + const { ctx } = setup(); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + id: '123', + data: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('Schema missing for rpc procedure [update.in.options].')); + }); + + test('should validate the options', () => { + const { ctx } = setup({ + contentSchemas: { + update: { + in: { + data: fooDataSchema, + options: schema.object({ validOption: schema.maybe(schema.boolean()) }), + }, + }, + } as any, + }); + expect(() => + fn(ctx, { + contentTypeId: FOO_CONTENT_ID, + id: '123', + data: { title: 'Hello' }, + options: { foo: 'bar' }, + }) + ).rejects.toEqual(new Error('[foo]: definition for this key is missing')); + }); + + test('should validate the result if schema is provided', () => { + const { ctx, storage } = setup({ + contentSchemas: { + update: { + in: { data: fooDataSchema }, + out: { result: schema.object({ validField: schema.maybe(schema.boolean()) }) }, + }, + } as any, + }); + + const invalidResult = { wrongField: 'bad' }; + storage.update.mockResolvedValueOnce(invalidResult); + + expect(() => + fn(ctx, { contentTypeId: FOO_CONTENT_ID, id: '123', data: { title: 'Hello' } }) + ).rejects.toEqual(new Error('[wrongField]: definition for this key is missing')); + }); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/procedures/update.ts b/src/plugins/content_management/server/rpc/procedures/update.ts new file mode 100644 index 00000000000000..4a9a7951079e52 --- /dev/null +++ b/src/plugins/content_management/server/rpc/procedures/update.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 { rpcSchemas } from '../../../common'; +import type { UpdateIn } from '../../../common'; +import type { StorageContext, ContentCrud } from '../../core'; +import type { ProcedureDefinition } from '../rpc_service'; +import type { Context } from '../types'; +import { validate } from '../../utils'; + +export const update: ProcedureDefinition> = { + schemas: rpcSchemas.update, + fn: async (ctx, { contentTypeId, id, data, options }) => { + const contentDefinition = ctx.contentRegistry.getDefinition(contentTypeId); + const { update: schemas } = contentDefinition.schemas.content; + + // Validate data to be stored + if (schemas?.in?.data) { + const error = validate(data, schemas.in.data); + if (error) { + // TODO: Improve error handling + throw error; + } + } else { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [update.in.data].'); + } + + // Validate the possible options + if (options) { + if (!schemas.in?.options) { + // TODO: Improve error handling + throw new Error('Schema missing for rpc procedure [update.in.options].'); + } + const error = validate(options, schemas.in.options); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + // Execute CRUD + const crudInstance: ContentCrud = ctx.contentRegistry.getCrud(contentTypeId); + const storageContext: StorageContext = { + requestHandlerContext: ctx.requestHandlerContext, + }; + const result = await crudInstance.update(storageContext, id, data, options); + + // Validate result + const resultSchema = schemas.out?.result; + if (resultSchema) { + const error = validate(result.result, resultSchema); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return result; + }, +}; diff --git a/src/plugins/content_management/server/rpc/routes/error_wrapper.ts b/src/plugins/content_management/server/rpc/routes/error_wrapper.ts new file mode 100644 index 00000000000000..9dc98810a08328 --- /dev/null +++ b/src/plugins/content_management/server/rpc/routes/error_wrapper.ts @@ -0,0 +1,25 @@ +/* + * 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 { boomify, isBoom } from '@hapi/boom'; +import { ResponseError, CustomHttpResponseOptions } from '@kbn/core/server'; + +export function wrapError(error: any): CustomHttpResponseOptions { + const boom = isBoom(error) + ? error + : boomify(error, { statusCode: error.status ?? error.statusCode }); + const statusCode = boom.output.statusCode; + return { + body: { + message: boom, + ...(statusCode !== 500 && error.body ? { attributes: { body: error.body } } : {}), + }, + headers: boom.output.headers as { [key: string]: string }, + statusCode, + }; +} diff --git a/src/plugins/content_management/server/rpc/routes/index.ts b/src/plugins/content_management/server/rpc/routes/index.ts new file mode 100644 index 00000000000000..60deb3ae64d666 --- /dev/null +++ b/src/plugins/content_management/server/rpc/routes/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 { initRpcRoutes } from './routes'; diff --git a/src/plugins/content_management/server/rpc/routes/routes.ts b/src/plugins/content_management/server/rpc/routes/routes.ts new file mode 100644 index 00000000000000..c5d57fe3e010ee --- /dev/null +++ b/src/plugins/content_management/server/rpc/routes/routes.ts @@ -0,0 +1,69 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import type { IRouter } from '@kbn/core/server'; + +import { ProcedureName } from '../../../common'; +import type { ContentRegistry } from '../../core'; + +import type { RpcService } from '../rpc_service'; +import type { Context as RpcContext } from '../types'; +import { wrapError } from './error_wrapper'; + +interface RouteContext { + rpc: RpcService; + contentRegistry: ContentRegistry; +} + +export function initRpcRoutes( + procedureNames: readonly ProcedureName[], + router: IRouter, + { rpc, contentRegistry }: RouteContext +) { + if (procedureNames.length === 0) { + throw new Error(`No procedure names provided.`); + } + + /** + * @apiGroup ContentManagement + * + * @api {post} /content_management/rpc/{call} Execute RPC call + * @apiName RPC + */ + router.post( + { + path: '/api/content_management/rpc/{name}', + validate: { + params: schema.object({ + // @ts-ignore We validate above that procedureNames has at least one item + // so we can ignore the "Target requires 1 element(s) but source may have fewer." TS error + name: schema.oneOf(procedureNames.map((fnName) => schema.literal(fnName))), + }), + // Any object payload can be passed, we will validate the input when calling the rpc handler + body: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }, + }, + async (requestHandlerContext, request, response) => { + try { + const context: RpcContext = { + contentRegistry, + requestHandlerContext, + }; + const { name } = request.params as { name: ProcedureName }; + + const result = await rpc.call(context, name, request.body); + + return response.ok({ + body: result, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + } + ); +} diff --git a/src/plugins/content_management/server/rpc/rpc_service.test.ts b/src/plugins/content_management/server/rpc/rpc_service.test.ts new file mode 100644 index 00000000000000..0ac81a3c3fa8fc --- /dev/null +++ b/src/plugins/content_management/server/rpc/rpc_service.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { ProcedureDefinition, RpcService } from './rpc_service'; + +describe('RpcService', () => { + describe('register()', () => { + test('should register a procedure', () => { + const rpc = new RpcService<{}, 'foo'>(); + const fn = jest.fn(); + const procedure: ProcedureDefinition<{}> = { fn }; + rpc.register('foo', procedure); + + const context = {}; + rpc.call(context, 'foo'); + + expect(fn).toHaveBeenCalledWith(context, undefined); + }); + }); + + describe('call()', () => { + test('should require a schema if an input is passed', () => { + const rpc = new RpcService<{}, 'foo'>(); + const fn = jest.fn(); + const procedure: ProcedureDefinition<{}> = { fn }; + rpc.register('foo', procedure); + + const context = {}; + const input = { foo: 'bar' }; + + expect(() => { + return rpc.call(context, 'foo', input); + }).rejects.toEqual(new Error('Input schema missing for [foo] procedure.')); + }); + + test('should call the provided handler with the input and context', async () => { + const rpc = new RpcService<{}, 'foo'>(); + + const output = { success: true }; + + const fn = jest.fn().mockResolvedValue(output); + const procedure: ProcedureDefinition<{}> = { + fn, + schemas: { in: schema.object({ foo: schema.string() }), out: schema.any() }, + }; + rpc.register('foo', procedure); + + const context = {}; + const input = { foo: 'bar' }; + + const { result } = await rpc.call(context, 'foo', input); + + expect(fn).toHaveBeenCalledWith(context, input); + expect(result).toEqual(output); + }); + + test('should throw an error if the procedure is not registered', () => { + const rpc = new RpcService(); + + expect(() => { + return rpc.call(undefined, 'unknown'); + }).rejects.toEqual(new Error('Procedure [unknown] is not registered.')); + }); + + test('should validate that the input is valid', () => { + const rpc = new RpcService<{}, 'foo'>(); + + const fn = jest.fn(); + const procedure: ProcedureDefinition<{}> = { + fn, + schemas: { in: schema.object({ foo: schema.string() }), out: schema.any() }, + }; + rpc.register('foo', procedure); + + const context = {}; + const input = { bad: 'unknown prop' }; + + expect(() => { + return rpc.call(context, 'foo', input); + }).rejects.toEqual(new Error('[foo]: expected value of type [string] but got [undefined]')); + }); + + test('should validate the output if schema is provided', () => { + const rpc = new RpcService<{}, 'foo'>(); + + const fn = jest.fn().mockResolvedValue({ bad: 'unknown prop' }); + const procedure: ProcedureDefinition<{}> = { + fn, + schemas: { in: schema.never(), out: schema.object({ foo: schema.string() }) }, + }; + rpc.register('foo', procedure); + + const context = {}; + expect(() => { + return rpc.call(context, 'foo'); + }).rejects.toEqual(new Error('[foo]: expected value of type [string] but got [undefined]')); + }); + }); +}); diff --git a/src/plugins/content_management/server/rpc/rpc_service.ts b/src/plugins/content_management/server/rpc/rpc_service.ts new file mode 100644 index 00000000000000..b7f6d8aedcd7a9 --- /dev/null +++ b/src/plugins/content_management/server/rpc/rpc_service.ts @@ -0,0 +1,60 @@ +/* + * 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 { ProcedureSchemas } from '../../common'; +import { validate } from '../utils'; + +export interface ProcedureDefinition< + Context extends object | void = void, + I extends object | void = void, + O = any +> { + fn: (context: Context, input: I extends void ? undefined : I) => Promise; + schemas?: ProcedureSchemas; +} + +export class RpcService { + private registry: Map> = new Map(); + + register(name: Names, definition: ProcedureDefinition) { + this.registry.set(name, definition); + } + + async call(context: Context, name: Names, input?: unknown): Promise<{ result: unknown }> { + const procedure: ProcedureDefinition | undefined = this.registry.get(name); + + if (!procedure) throw new Error(`Procedure [${name}] is not registered.`); + + const { fn, schemas } = procedure; + + // 1. Validate input + if (schemas?.in) { + const error = validate(input, schemas.in); + if (error) { + // TODO: Improve error handling + throw error; + } + } else if (input !== undefined) { + // TODO: Improve error handling + throw new Error(`Input schema missing for [${name}] procedure.`); + } + + // 2. Execute procedure + const result = await fn(context, input); + + // 3. Validate output + if (schemas?.out) { + const error = validate(result, schemas.out); + if (error) { + // TODO: Improve error handling + throw error; + } + } + + return { result }; + } +} diff --git a/src/plugins/content_management/server/rpc/types.ts b/src/plugins/content_management/server/rpc/types.ts new file mode 100644 index 00000000000000..71ce1bd4bf86d4 --- /dev/null +++ b/src/plugins/content_management/server/rpc/types.ts @@ -0,0 +1,14 @@ +/* + * 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 { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; +import type { ContentRegistry } from '../core'; + +export interface Context { + contentRegistry: ContentRegistry; + requestHandlerContext: RequestHandlerContext; +} diff --git a/src/plugins/content_management/server/utils.ts b/src/plugins/content_management/server/utils.ts new file mode 100644 index 00000000000000..cd001f77350a26 --- /dev/null +++ b/src/plugins/content_management/server/utils.ts @@ -0,0 +1,18 @@ +/* + * 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, ValidationError } from '@kbn/config-schema'; + +export const validate = (input: unknown, schema: Type): ValidationError | null => { + try { + schema.validate(input); + return null; + } catch (e: any) { + return e as ValidationError; + } +}; diff --git a/src/plugins/controls/public/time_slider/components/time_slider_popover_content.tsx b/src/plugins/controls/public/time_slider/components/time_slider_popover_content.tsx index f33a40393ee5ab..68201aa4debe6c 100644 --- a/src/plugins/controls/public/time_slider/components/time_slider_popover_content.tsx +++ b/src/plugins/controls/public/time_slider/components/time_slider_popover_content.tsx @@ -82,7 +82,7 @@ export function TimeSliderPopoverContent(props: Props) { { const nextIsAnchored = !isAnchored; if (nextIsAnchored) { diff --git a/src/plugins/controls/server/control_group/control_group_telemetry.ts b/src/plugins/controls/server/control_group/control_group_telemetry.ts index 83e363e081241e..141fb6808b5ee1 100644 --- a/src/plugins/controls/server/control_group/control_group_telemetry.ts +++ b/src/plugins/controls/server/control_group/control_group_telemetry.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { PersistableStateService } from '@kbn/kibana-utils-plugin/common'; import { ControlGroupTelemetry, diff --git a/src/plugins/controls/tsconfig.json b/src/plugins/controls/tsconfig.json index 9acd44b5c2f7ea..5029897be467ba 100644 --- a/src/plugins/controls/tsconfig.json +++ b/src/plugins/controls/tsconfig.json @@ -33,6 +33,7 @@ "@kbn/config-schema", "@kbn/storybook", "@kbn/ui-theme", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/src/plugins/dashboard/public/dashboard_actions/index.ts b/src/plugins/dashboard/public/dashboard_actions/index.ts index 6317c10dda1a63..652b66b2ad1951 100644 --- a/src/plugins/dashboard/public/dashboard_actions/index.ts +++ b/src/plugins/dashboard/public/dashboard_actions/index.ts @@ -39,7 +39,7 @@ export const buildAllDashboardActions = async ({ uiActions.registerAction(clonePanelAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction.id); - const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, uiSettings); + const SavedObjectFinder = getSavedObjectFinder(uiSettings, core.http); const changeViewAction = new ReplacePanelAction(SavedObjectFinder); uiActions.registerAction(changeViewAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction.id); diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index 94151273af0b7e..edea6b0e68dc11 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useState, useRef, useEffect, FC } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { EuiLoadingChart } from '@elastic/eui'; import classNames from 'classnames'; @@ -96,21 +96,20 @@ const Item = React.forwardRef( } ); -export const ObservedItem: FC = (props: Props) => { +export const ObservedItem = React.forwardRef((props, panelRef) => { const [intersection, updateIntersection] = useState(); const [isRenderable, setIsRenderable] = useState(false); - const panelRef = useRef(null); const observerRef = useRef( new window.IntersectionObserver(([value]) => updateIntersection(value), { - root: panelRef.current, + root: (panelRef as React.RefObject).current, }) ); useEffect(() => { const { current: currentObserver } = observerRef; currentObserver.disconnect(); - const { current } = panelRef; + const { current } = panelRef as React.RefObject; if (current) { currentObserver.observe(current); @@ -126,9 +125,11 @@ export const ObservedItem: FC = (props: Props) => { }, [intersection, isRenderable]); return ; -}; +}); -export const DashboardGridItem: FC = (props: Props) => { +// ReactGridLayout passes ref to children. Functional component children require forwardRef to avoid react warning +// https://github.com/react-grid-layout/react-grid-layout#custom-child-components-and-draggable-handles +export const DashboardGridItem = React.forwardRef((props, ref) => { const { settings: { isProjectEnabledInLabs }, } = pluginServices.getServices(); @@ -138,5 +139,5 @@ export const DashboardGridItem: FC = (props: Props) => { const isPrintMode = select((state) => state.explicitInput.viewMode) === ViewMode.PRINT; const isEnabled = !isPrintMode && isProjectEnabledInLabs('labs:dashboard:deferBelowFold'); - return isEnabled ? : ; -}; + return isEnabled ? : ; +}); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts index 1cd2d05d9282f3..79a3caeafba173 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/add_panel_from_library.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { HttpStart } from '@kbn/core/public'; import { isErrorEmbeddable, openAddPanelFlyout } from '@kbn/embeddable-plugin/public'; import { getSavedObjectFinder } from '@kbn/saved-objects-plugin/public'; @@ -18,14 +19,14 @@ export function addFromLibrary(this: DashboardContainer) { notifications, usageCollection, settings: { uiSettings, theme }, - dashboardSavedObject: { savedObjectsClient }, embeddable: { getEmbeddableFactories, getEmbeddableFactory }, + http, } = pluginServices.getServices(); if (isErrorEmbeddable(this)) return; this.openOverlay( openAddPanelFlyout({ - SavedObjectFinder: getSavedObjectFinder({ client: savedObjectsClient }, uiSettings), + SavedObjectFinder: getSavedObjectFinder(uiSettings, http as HttpStart), reportUiCounter: usageCollection.reportUiCounter, getAllFactories: getEmbeddableFactories, getFactory: getEmbeddableFactory, diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_functions.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_functions.ts index e4cc338f15dd6c..c4886c55d976c7 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_functions.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_functions.ts @@ -9,7 +9,12 @@ import fastIsEqual from 'fast-deep-equal'; import { persistableControlGroupInputIsEqual } from '@kbn/controls-plugin/common'; -import { compareFilters, COMPARE_ALL_OPTIONS, isFilterPinned } from '@kbn/es-query'; +import { + compareFilters, + COMPARE_ALL_OPTIONS, + isFilterPinned, + onlyDisabledFiltersChanged, +} from '@kbn/es-query'; import { DashboardContainer } from '../../dashboard_container'; import { DashboardContainerByValueInput } from '../../../../../common'; @@ -32,10 +37,11 @@ export type DashboardDiffFunctions = { export const isKeyEqual = async ( key: keyof DashboardContainerByValueInput, - diffFunctionProps: DiffFunctionProps + diffFunctionProps: DiffFunctionProps, + diffingFunctions: DashboardDiffFunctions ) => { const propsAsNever = diffFunctionProps as never; // todo figure out why props has conflicting types in some constituents. - const diffingFunction = dashboardDiffingFunctions[key]; + const diffingFunction = diffingFunctions[key]; if (diffingFunction) { return diffingFunction?.prototype?.name === 'AsyncFunction' ? await diffingFunction(propsAsNever) @@ -48,7 +54,7 @@ export const isKeyEqual = async ( * A collection of functions which diff individual keys of dashboard state. If a key is missing from this list it is * diffed by the default diffing function, fastIsEqual. */ -export const dashboardDiffingFunctions: DashboardDiffFunctions = { +export const unsavedChangesDiffingFunctions: DashboardDiffFunctions = { panels: async ({ currentValue, lastValue, container }) => { if (!getPanelLayoutsAreEqual(currentValue, lastValue)) return false; @@ -81,6 +87,7 @@ export const dashboardDiffingFunctions: DashboardDiffFunctions = { return await Promise.any(explicitInputComparePromises).catch(() => true); }, + // exclude pinned filters from comparision because pinned filters are not part of application state filters: ({ currentValue, lastValue }) => compareFilters( currentValue.filter((f) => !isFilterPinned(f)), @@ -109,3 +116,15 @@ export const dashboardDiffingFunctions: DashboardDiffFunctions = { viewMode: () => false, // When compared view mode is always considered unequal so that it gets backed up. }; + +const shouldRefreshFilterCompareOptions = { + ...COMPARE_ALL_OPTIONS, + // do not compare $state to avoid refreshing when filter is pinned/unpinned (which does not impact results) + state: false, +}; + +export const shouldRefreshDiffingFunctions: DashboardDiffFunctions = { + ...unsavedChangesDiffingFunctions, + filters: ({ currentValue, lastValue }) => + onlyDisabledFiltersChanged(lastValue, currentValue, shouldRefreshFilterCompareOptions), +}; diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.test.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.test.ts new file mode 100644 index 00000000000000..6c4e9c3989cd78 --- /dev/null +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.test.ts @@ -0,0 +1,63 @@ +/* + * 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 { buildExistsFilter, disableFilter, pinFilter, toggleFilterNegated } from '@kbn/es-query'; +import type { DataViewFieldBase, DataViewBase } from '@kbn/es-query'; +import { getShouldRefresh } from './dashboard_diffing_integration'; +import { DashboardContainer } from '../../dashboard_container'; +import { DashboardContainerByValueInput } from '../../../../../common'; + +describe('getShouldRefresh', () => { + const dashboardContainerMock = { + untilInitialized: () => {}, + } as unknown as DashboardContainer; + + const existsFilter = buildExistsFilter( + { + name: 'myFieldName', + } as DataViewFieldBase, + { + id: 'myDataViewId', + } as DataViewBase + ); + + test('should return true when pinned filters change', async () => { + const pinnedFilter = pinFilter(existsFilter); + const lastInput = { + filters: [pinnedFilter], + } as unknown as DashboardContainerByValueInput; + const input = { + filters: [toggleFilterNegated(pinnedFilter)], + } as unknown as DashboardContainerByValueInput; + expect(await getShouldRefresh.bind(dashboardContainerMock)(lastInput, { ...lastInput })).toBe( + false + ); + expect(await getShouldRefresh.bind(dashboardContainerMock)(lastInput, input)).toBe(true); + }); + + test('should return false when disabled filters change', async () => { + const disabledFilter = disableFilter(existsFilter); + const lastInput = { + filters: [disabledFilter], + } as unknown as DashboardContainerByValueInput; + const input = { + filters: [toggleFilterNegated(disabledFilter)], + } as unknown as DashboardContainerByValueInput; + expect(await getShouldRefresh.bind(dashboardContainerMock)(lastInput, input)).toBe(false); + }); + + test('should return false when pinned filter changes to unpinned', async () => { + const lastInput = { + filters: [existsFilter], + } as unknown as DashboardContainerByValueInput; + const input = { + filters: [pinFilter(existsFilter)], + } as unknown as DashboardContainerByValueInput; + expect(await getShouldRefresh.bind(dashboardContainerMock)(lastInput, input)).toBe(false); + }); +}); diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.ts index 32956cea18d141..2062ac3a4b6205 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/diff_state/dashboard_diffing_integration.ts @@ -13,7 +13,12 @@ import { DashboardContainer } from '../../dashboard_container'; import { pluginServices } from '../../../../services/plugin_services'; import { DashboardContainerByValueInput } from '../../../../../common'; import { CHANGE_CHECK_DEBOUNCE } from '../../../../dashboard_constants'; -import { isKeyEqual } from './dashboard_diffing_functions'; +import type { DashboardDiffFunctions } from './dashboard_diffing_functions'; +import { + isKeyEqual, + shouldRefreshDiffingFunctions, + unsavedChangesDiffingFunctions, +} from './dashboard_diffing_functions'; import { dashboardContainerReducers } from '../../../state/dashboard_container_reducers'; /** @@ -54,6 +59,23 @@ export const keysNotConsideredUnsavedChanges: Array = [ + 'query', + 'filters', + 'timeRange', + 'timeslice', + 'timeRestore', + 'lastReloadRequestTime', + + // also refetch when chart settings change + 'syncColors', + 'syncCursor', + 'syncTooltips', +]; + /** * Does an initial diff between @param initialInput and @param initialLastSavedInput, and created a middleware * which listens to the redux store and checks for & publishes the unsaved changes on dispatches. @@ -139,44 +161,67 @@ function backupUnsavedChanges( } /** - * Does a shallow diff between @param lastExplicitInput and @param currentExplicitInput and + * Does a shallow diff between @param lastInput and @param input and * @returns an object out of the keys which are different. */ export async function getUnsavedChanges( this: DashboardContainer, lastInput: DashboardContainerByValueInput, + input: DashboardContainerByValueInput +): Promise> { + const allKeys = [...new Set([...Object.keys(lastInput), ...Object.keys(input)])] as Array< + keyof DashboardContainerByValueInput + >; + return await getInputChanges(this, lastInput, input, allKeys, unsavedChangesDiffingFunctions); +} + +export async function getShouldRefresh( + this: DashboardContainer, + lastInput: DashboardContainerByValueInput, + input: DashboardContainerByValueInput +): Promise { + const inputChanges = await getInputChanges( + this, + lastInput, + input, + refetchKeys, + shouldRefreshDiffingFunctions + ); + return Object.keys(inputChanges).length > 0; +} + +async function getInputChanges( + container: DashboardContainer, + lastInput: DashboardContainerByValueInput, input: DashboardContainerByValueInput, - keys?: Array + keys: Array, + diffingFunctions: DashboardDiffFunctions ): Promise> { - await this.untilInitialized(); - const allKeys = - keys ?? - ([...new Set([...Object.keys(lastInput), ...Object.keys(input)])] as Array< - keyof DashboardContainerByValueInput - >); - const keyComparePromises = allKeys.map( + await container.untilInitialized(); + const keyComparePromises = keys.map( (key) => new Promise<{ key: keyof DashboardContainerByValueInput; isEqual: boolean }>((resolve) => - isKeyEqual(key, { - container: this, - - currentValue: input[key], - currentInput: input, - - lastValue: lastInput[key], - lastInput, - }).then((isEqual) => resolve({ key, isEqual })) + isKeyEqual( + key, + { + container, + + currentValue: input[key], + currentInput: input, + + lastValue: lastInput[key], + lastInput, + }, + diffingFunctions + ).then((isEqual) => resolve({ key, isEqual })) ) ); - const unsavedChanges = (await Promise.allSettled(keyComparePromises)).reduce( - (changes, current) => { - if (current.status === 'fulfilled') { - const { key, isEqual } = current.value; - if (!isEqual) (changes as { [key: string]: unknown })[key] = input[key]; - } - return changes; - }, - {} as Partial - ); - return unsavedChanges; + const inputChanges = (await Promise.allSettled(keyComparePromises)).reduce((changes, current) => { + if (current.status === 'fulfilled') { + const { key, isEqual } = current.value; + if (!isEqual) (changes as { [key: string]: unknown })[key] = input[key]; + } + return changes; + }, {} as Partial); + return inputChanges; } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/search_sessions/start_dashboard_search_session_integration.ts b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/search_sessions/start_dashboard_search_session_integration.ts index d8e1aadf0ed4a4..986a53a022c6ae 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/search_sessions/start_dashboard_search_session_integration.ts +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/integrations/search_sessions/start_dashboard_search_session_integration.ts @@ -15,24 +15,7 @@ import { pluginServices } from '../../../../services/plugin_services'; import { DashboardContainerByValueInput } from '../../../../../common'; import { CHANGE_CHECK_DEBOUNCE } from '../../../../dashboard_constants'; import { DashboardCreationOptions } from '../../dashboard_container_factory'; -import { getUnsavedChanges } from '../diff_state/dashboard_diffing_integration'; - -/** - * input keys that will cause a new session to be created. - */ -const refetchKeys: Array = [ - 'query', - 'filters', - 'timeRange', - 'timeslice', - 'timeRestore', - 'lastReloadRequestTime', - - // also refetch when chart settings change - 'syncColors', - 'syncCursor', - 'syncTooltips', -]; +import { getShouldRefresh } from '../diff_state/dashboard_diffing_integration'; /** * Enables dashboard search sessions. @@ -96,8 +79,7 @@ export function startDashboardSearchSessionIntegration( .pipe(pairwise(), debounceTime(CHANGE_CHECK_DEBOUNCE)) .subscribe(async (states) => { const [previous, current] = states as DashboardContainerByValueInput[]; - const changes = await getUnsavedChanges.bind(this)(previous, current, refetchKeys); - const shouldRefetch = Object.keys(changes).length > 0; + const shouldRefetch = await getShouldRefresh.bind(this)(previous, current); if (!shouldRefetch) return; const { diff --git a/src/plugins/dashboard/public/services/http/http.stub.ts b/src/plugins/dashboard/public/services/http/http.stub.ts index 37abd532f7d9da..8a2aac5dc44dba 100644 --- a/src/plugins/dashboard/public/services/http/http.stub.ts +++ b/src/plugins/dashboard/public/services/http/http.stub.ts @@ -17,5 +17,6 @@ export const httpServiceFactory: HttpServiceFactory = () => { return { basePath: serviceMock.http.basePath, + get: serviceMock.http.get, }; }; diff --git a/src/plugins/dashboard/public/services/http/http_service.ts b/src/plugins/dashboard/public/services/http/http_service.ts index 26ccc3a943f951..ee81ebacfd6869 100644 --- a/src/plugins/dashboard/public/services/http/http_service.ts +++ b/src/plugins/dashboard/public/services/http/http_service.ts @@ -16,10 +16,11 @@ export type HttpServiceFactory = KibanaPluginServiceFactory< >; export const httpServiceFactory: HttpServiceFactory = ({ coreStart }) => { const { - http: { basePath }, + http: { basePath, get }, } = coreStart; return { basePath, + get, }; }; diff --git a/src/plugins/dashboard/public/services/http/types.ts b/src/plugins/dashboard/public/services/http/types.ts index e92bac92f62868..3b0d16b6b372ef 100644 --- a/src/plugins/dashboard/public/services/http/types.ts +++ b/src/plugins/dashboard/public/services/http/types.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import type { CoreSetup } from '@kbn/core/public'; +import type { CoreStart } from '@kbn/core/public'; export interface DashboardHTTPService { - basePath: CoreSetup['http']['basePath']; + basePath: CoreStart['http']['basePath']; + get: CoreStart['http']['get']; } diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index be7bef0339f3fd..0ba2c77c8c0160 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -59,17 +59,7 @@ */ import { setWith } from '@kbn/safer-lodash-set'; -import { - difference, - isEqual, - isFunction, - isObject, - keyBy, - pick, - uniqueId, - uniqWith, - concat, -} from 'lodash'; +import { difference, isEqual, isFunction, isObject, keyBy, pick, uniqueId, concat } from 'lodash'; import { catchError, finalize, @@ -889,28 +879,28 @@ export class SearchSource { // inject the format from the computed fields if one isn't given const docvaluesIndex = keyBy(filteredDocvalueFields, 'field'); const bodyFields = this.getFieldsWithoutSourceFilters(index, body.fields); - body.fields = uniqWith( - bodyFields.concat(filteredDocvalueFields), - (fld1: SearchFieldValue, fld2: SearchFieldValue) => { - const field1Name = this.getFieldName(fld1); - const field2Name = this.getFieldName(fld2); - return field1Name === field2Name; + + const uniqueFieldNames = new Set(); + const uniqueFields = []; + for (const field of bodyFields.concat(filteredDocvalueFields)) { + const fieldName = this.getFieldName(field); + if (metaFields.includes(fieldName) || uniqueFieldNames.has(fieldName)) { + continue; } - ) - .filter((fld: SearchFieldValue) => { - return !metaFields.includes(this.getFieldName(fld)); - }) - .map((fld: SearchFieldValue) => { - const fieldName = this.getFieldName(fld); - if (Object.keys(docvaluesIndex).includes(fieldName)) { - // either provide the field object from computed docvalues, - // or merge the user-provided field with the one in docvalues - return typeof fld === 'string' - ? docvaluesIndex[fld] - : this.getFieldFromDocValueFieldsOrIndexPattern(docvaluesIndex, fld, index); - } - return fld; - }); + uniqueFieldNames.add(fieldName); + if (Object.keys(docvaluesIndex).includes(fieldName)) { + // either provide the field object from computed docvalues, + // or merge the user-provided field with the one in docvalues + uniqueFields.push( + typeof field === 'string' + ? docvaluesIndex[field] + : this.getFieldFromDocValueFieldsOrIndexPattern(docvaluesIndex, field, index) + ); + } else { + uniqueFields.push(field); + } + } + body.fields = uniqueFields; } } else { body.fields = filteredDocvalueFields; diff --git a/src/plugins/data_views/common/data_views/data_views.test.ts b/src/plugins/data_views/common/data_views/data_views.test.ts index b382827d5d37a4..01e2b9b1d95f3d 100644 --- a/src/plugins/data_views/common/data_views/data_views.test.ts +++ b/src/plugins/data_views/common/data_views/data_views.test.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { defaults, get, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { defaults, get } from 'lodash'; import { DataViewsService, DataView } from '.'; import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; diff --git a/src/plugins/data_views/tsconfig.json b/src/plugins/data_views/tsconfig.json index 614b1beda11152..ae13beea68d459 100644 --- a/src/plugins/data_views/tsconfig.json +++ b/src/plugins/data_views/tsconfig.json @@ -26,6 +26,7 @@ "@kbn/core-test-helpers-http-setup-browser", "@kbn/config-schema", "@kbn/utility-types-jest", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/src/plugins/discover/README.md b/src/plugins/discover/README.md index f7dcc54880ead3..6240cd63f3ea37 100644 --- a/src/plugins/discover/README.md +++ b/src/plugins/discover/README.md @@ -25,9 +25,15 @@ One folder for every "route", each folder contains files and folders related onl Contains all the server-only code. +* **[/sample_data](./server/sample_data)** (Registrations with the Sample Data Registry for Discover saved objects) +* **[/capabilities_provider](./server/capabilities_provider.ts)** (CapabilitiesProvider definition of capabilities for Core) +* **[/ui_settings](./server/ui_settings.ts)** (Settings and the default values for UiSettingsServiceSetup ) +* **[/locator](./server/locator)** (Extensions of DiscoverAppLocator for the DiscoverServerPlugin API) + ### [src/plugins/discover/common](./common)) Contains all code shared by client and server. - - +* **[/constants](./common/constants.ts)** (General contants) +* **[/field_types](./common/field_types.ts)** (Field types constants) +* **[/locator](./common/locator)** (Registration with the URL service for BWC deep-linking to Discover views.) diff --git a/src/plugins/discover/public/utils/sorting/get_default_sort.test.ts b/src/plugins/discover/common/utils/sorting/get_default_sort.test.ts similarity index 100% rename from src/plugins/discover/public/utils/sorting/get_default_sort.test.ts rename to src/plugins/discover/common/utils/sorting/get_default_sort.test.ts diff --git a/src/plugins/discover/public/utils/sorting/get_default_sort.ts b/src/plugins/discover/common/utils/sorting/get_default_sort.ts similarity index 100% rename from src/plugins/discover/public/utils/sorting/get_default_sort.ts rename to src/plugins/discover/common/utils/sorting/get_default_sort.ts diff --git a/src/plugins/discover/common/utils/sorting/get_sort.test.ts b/src/plugins/discover/common/utils/sorting/get_sort.test.ts new file mode 100644 index 00000000000000..bed10b3829de06 --- /dev/null +++ b/src/plugins/discover/common/utils/sorting/get_sort.test.ts @@ -0,0 +1,74 @@ +/* + * 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 { getSort, getSortArray } from './get_sort'; +import { + stubDataView, + stubDataViewWithoutTimeField, +} from '@kbn/data-views-plugin/common/data_view.stub'; + +describe('docTable', function () { + describe('getSort function', function () { + test('should be a function', function () { + expect(typeof getSort === 'function').toBeTruthy(); + }); + + test('should return an array of objects', function () { + expect(getSort([['bytes', 'desc']], stubDataView)).toEqual([{ bytes: 'desc' }]); + expect(getSort([['bytes', 'desc']], stubDataViewWithoutTimeField)).toEqual([ + { bytes: 'desc' }, + ]); + }); + + test('should passthrough arrays of objects', () => { + expect(getSort([{ bytes: 'desc' }], stubDataView)).toEqual([{ bytes: 'desc' }]); + }); + + test('should return an empty array when passed an unsortable field', function () { + expect(getSort([['non-sortable', 'asc']], stubDataView)).toEqual([]); + expect(getSort([['lol_nope', 'asc']], stubDataView)).toEqual([]); + + expect(getSort([['non-sortable', 'asc']], stubDataViewWithoutTimeField)).toEqual([]); + }); + + test('should return an empty array ', function () { + expect(getSort([], stubDataView)).toEqual([]); + expect(getSort([['foo', 'bar']], stubDataView)).toEqual([]); + expect(getSort([{ foo: 'bar' }], stubDataView)).toEqual([]); + }); + + test('should convert a legacy sort to an array of objects', function () { + expect(getSort(['foo', 'desc'], stubDataView)).toEqual([{ foo: 'desc' }]); + expect(getSort(['foo', 'asc'], stubDataView)).toEqual([{ foo: 'asc' }]); + }); + }); + describe('getSortArray function', function () { + test('should have an array method', function () { + expect(getSortArray).toBeInstanceOf(Function); + }); + + test('should return an array of arrays for sortable fields', function () { + expect(getSortArray([['bytes', 'desc']], stubDataView)).toEqual([['bytes', 'desc']]); + }); + + test('should return an array of arrays from an array of elasticsearch sort objects', function () { + expect(getSortArray([{ bytes: 'desc' }], stubDataView)).toEqual([['bytes', 'desc']]); + }); + + test('should sort by an empty array when an unsortable field is given', function () { + expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataView)).toEqual([]); + expect(getSortArray([{ lol_nope: 'asc' }], stubDataView)).toEqual([]); + expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataViewWithoutTimeField)).toEqual([]); + }); + + test('should return an empty array when passed an empty sort array', () => { + expect(getSortArray([], stubDataView)).toEqual([]); + expect(getSortArray([], stubDataViewWithoutTimeField)).toEqual([]); + }); + }); +}); diff --git a/src/plugins/discover/common/utils/sorting/get_sort.ts b/src/plugins/discover/common/utils/sorting/get_sort.ts new file mode 100644 index 00000000000000..aece689ae543f9 --- /dev/null +++ b/src/plugins/discover/common/utils/sorting/get_sort.ts @@ -0,0 +1,73 @@ +/* + * 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 { DataView } from '@kbn/data-views-plugin/common'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; +import { isPlainObject } from 'lodash'; + +export type SortPairObj = Record; +export type SortPair = SortOrder | SortPairObj; +export type SortInput = SortPair | SortPair[]; + +export function isSortable(fieldName: string, dataView: DataView): boolean { + const field = dataView.getFieldByName(fieldName); + return !!(field && field.sortable); +} + +function createSortObject(sortPair: SortInput, dataView: DataView): SortPairObj | undefined { + if ( + Array.isArray(sortPair) && + sortPair.length === 2 && + isSortable(String(sortPair[0]), dataView) + ) { + const [field, direction] = sortPair as SortOrder; + return { [field]: direction }; + } else if (isPlainObject(sortPair) && isSortable(Object.keys(sortPair)[0], dataView)) { + return sortPair as SortPairObj; + } +} + +export function isLegacySort(sort: SortPair[] | SortPair): sort is SortPair { + return ( + sort.length === 2 && typeof sort[0] === 'string' && (sort[1] === 'desc' || sort[1] === 'asc') + ); +} + +/** + * Take a sorting array and make it into an object + * @param {array} sort two dimensional array [[fieldToSort, directionToSort]] + * or an array of objects [{fieldToSort: directionToSort}] + * @param {object} dataView used for determining default sort + * @returns Array<{object}> an array of sort objects + */ +export function getSort(sort: SortPair[] | SortPair, dataView: DataView): SortPairObj[] { + if (Array.isArray(sort)) { + if (isLegacySort(sort)) { + // To stay compatible with legacy sort, which just supported a single sort field + return [{ [sort[0]]: sort[1] }]; + } + return sort + .map((sortPair: SortPair) => createSortObject(sortPair, dataView)) + .filter((sortPairObj) => typeof sortPairObj === 'object') as SortPairObj[]; + } + return []; +} + +/** + * compared to getSort it doesn't return an array of objects, it returns an array of arrays + * [[fieldToSort: directionToSort]] + */ +export function getSortArray(sort: SortInput, dataView: DataView): SortOrder[] { + return getSort(sort, dataView).reduce((acc: SortOrder[], sortPair) => { + const entries = Object.entries(sortPair); + if (entries && entries[0]) { + acc.push(entries[0]); + } + return acc; + }, []); +} diff --git a/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.test.ts b/src/plugins/discover/common/utils/sorting/get_sort_for_search_source.test.ts similarity index 100% rename from src/plugins/discover/public/utils/sorting/get_sort_for_search_source.test.ts rename to src/plugins/discover/common/utils/sorting/get_sort_for_search_source.test.ts diff --git a/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.ts b/src/plugins/discover/common/utils/sorting/get_sort_for_search_source.ts similarity index 100% rename from src/plugins/discover/public/utils/sorting/get_sort_for_search_source.ts rename to src/plugins/discover/common/utils/sorting/get_sort_for_search_source.ts diff --git a/src/plugins/discover/common/utils/sorting/index.ts b/src/plugins/discover/common/utils/sorting/index.ts new file mode 100644 index 00000000000000..b392da9167a62a --- /dev/null +++ b/src/plugins/discover/common/utils/sorting/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { getDefaultSort } from './get_default_sort'; +export { getSort, getSortArray } from './get_sort'; +export type { SortInput, SortPair } from './get_sort'; +export { getSortForSearchSource } from './get_sort_for_search_source'; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index cb7f9c64ff625b..da47f1c1e96262 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -156,12 +156,18 @@ export function DiscoverLayout({ [filterManager, dataView, dataViews, trackUiMetric, capabilities] ); - const onFieldEdited = useCallback(async () => { - if (!dataView.isPersisted()) { - await updateAdHocDataViewId(dataView); - } - stateContainer.dataState.refetch$.next('reset'); - }, [dataView, stateContainer, updateAdHocDataViewId]); + const onFieldEdited = useCallback( + async ({ removedFieldName }: { removedFieldName?: string } = {}) => { + if (removedFieldName && currentColumns.includes(removedFieldName)) { + onRemoveColumn(removedFieldName); + } + if (!dataView.isPersisted()) { + await updateAdHocDataViewId(dataView); + } + stateContainer.dataState.refetch$.next('reset'); + }, + [dataView, stateContainer, updateAdHocDataViewId, currentColumns, onRemoveColumn] + ); const onDisableFilters = useCallback(() => { const disabledFilters = filterManager diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx index 4c45500a84c600..9c6ae0a292d80e 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx @@ -232,7 +232,7 @@ export interface DiscoverFieldProps { */ onAddFilter?: (field: DataViewField | string, value: unknown, type: '+' | '-') => void; /** - * Callback to remove/deselect a the field + * Callback to remove a field column from the table * @param fieldName */ onRemoveField: (fieldName: string) => void; diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx index 72bfc8f24dcd4a..92cc33852ebc0f 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx @@ -173,7 +173,7 @@ export function DiscoverSidebarComponent({ }, fieldName, onDelete: async () => { - await onFieldEdited(); + await onFieldEdited({ removedFieldName: fieldName }); }, }); if (setFieldEditorRef) { diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx index b2b2715067d8ce..10876cf8aaabc3 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx @@ -79,7 +79,7 @@ export interface DiscoverSidebarResponsiveProps { */ onChangeDataView: (id: string) => void; /** - * Callback function when removing a field + * Callback to remove a field column from the table * @param fieldName */ onRemoveField: (fieldName: string) => void; @@ -100,7 +100,7 @@ export interface DiscoverSidebarResponsiveProps { /** * callback to execute on edit runtime field */ - onFieldEdited: () => Promise; + onFieldEdited: (options?: { removedFieldName?: string }) => Promise; /** * callback to execute on create dataview */ diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index bafa6b603d6e45..6b3dc0999410e3 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -26,7 +26,4 @@ export { getSavedSearchUrl, getSavedSearchUrlConflictMessage, throwErrorOnSavedSearchUrlConflict, - VIEW_MODE, - type DiscoverGridSettings, - type DiscoverGridSettingsColumn, } from '@kbn/saved-search-plugin/public'; diff --git a/src/plugins/discover/public/utils/sorting/get_sort.test.ts b/src/plugins/discover/public/utils/sorting/get_sort.test.ts index 0656a2e36c4ca3..23e56511f2ef05 100644 --- a/src/plugins/discover/public/utils/sorting/get_sort.test.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getSort, getSortArray, getSortForEmbeddable } from './get_sort'; +import { getSortForEmbeddable } from './get_sort'; import { stubDataView, stubDataViewWithoutTimeField, @@ -14,64 +14,6 @@ import { import { uiSettingsMock } from '../../__mocks__/ui_settings'; describe('docTable', function () { - describe('getSort function', function () { - test('should be a function', function () { - expect(typeof getSort === 'function').toBeTruthy(); - }); - - test('should return an array of objects', function () { - expect(getSort([['bytes', 'desc']], stubDataView)).toEqual([{ bytes: 'desc' }]); - expect(getSort([['bytes', 'desc']], stubDataViewWithoutTimeField)).toEqual([ - { bytes: 'desc' }, - ]); - }); - - test('should passthrough arrays of objects', () => { - expect(getSort([{ bytes: 'desc' }], stubDataView)).toEqual([{ bytes: 'desc' }]); - }); - - test('should return an empty array when passed an unsortable field', function () { - expect(getSort([['non-sortable', 'asc']], stubDataView)).toEqual([]); - expect(getSort([['lol_nope', 'asc']], stubDataView)).toEqual([]); - - expect(getSort([['non-sortable', 'asc']], stubDataViewWithoutTimeField)).toEqual([]); - }); - - test('should return an empty array ', function () { - expect(getSort([], stubDataView)).toEqual([]); - expect(getSort([['foo', 'bar']], stubDataView)).toEqual([]); - expect(getSort([{ foo: 'bar' }], stubDataView)).toEqual([]); - }); - - test('should convert a legacy sort to an array of objects', function () { - expect(getSort(['foo', 'desc'], stubDataView)).toEqual([{ foo: 'desc' }]); - expect(getSort(['foo', 'asc'], stubDataView)).toEqual([{ foo: 'asc' }]); - }); - }); - describe('getSortArray function', function () { - test('should have an array method', function () { - expect(getSortArray).toBeInstanceOf(Function); - }); - - test('should return an array of arrays for sortable fields', function () { - expect(getSortArray([['bytes', 'desc']], stubDataView)).toEqual([['bytes', 'desc']]); - }); - - test('should return an array of arrays from an array of elasticsearch sort objects', function () { - expect(getSortArray([{ bytes: 'desc' }], stubDataView)).toEqual([['bytes', 'desc']]); - }); - - test('should sort by an empty array when an unsortable field is given', function () { - expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataView)).toEqual([]); - expect(getSortArray([{ lol_nope: 'asc' }], stubDataView)).toEqual([]); - expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataViewWithoutTimeField)).toEqual([]); - }); - - test('should return an empty array when passed an empty sort array', () => { - expect(getSortArray([], stubDataView)).toEqual([]); - expect(getSortArray([], stubDataViewWithoutTimeField)).toEqual([]); - }); - }); describe('getSortForEmbeddable function', function () { test('should return an array of arrays for sortable fields', function () { expect(getSortForEmbeddable([['bytes', 'desc']], stubDataView)).toEqual([['bytes', 'desc']]); diff --git a/src/plugins/discover/public/utils/sorting/get_sort.ts b/src/plugins/discover/public/utils/sorting/get_sort.ts index 59d414d8e1eea4..39fcaeb64febed 100644 --- a/src/plugins/discover/public/utils/sorting/get_sort.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort.ts @@ -6,74 +6,11 @@ * Side Public License, v 1. */ -import { isPlainObject } from 'lodash'; -import { DataView } from '@kbn/data-views-plugin/public'; +import { DataView } from '@kbn/data-views-plugin/common'; import { IUiSettingsClient } from '@kbn/core/public'; import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../common'; -import { getDefaultSort } from './get_default_sort'; - -export type SortPairObj = Record; -export type SortPair = SortOrder | SortPairObj; -export type SortInput = SortPair | SortPair[]; - -export function isSortable(fieldName: string, dataView: DataView): boolean { - const field = dataView.getFieldByName(fieldName); - return !!(field && field.sortable); -} - -function createSortObject(sortPair: SortInput, dataView: DataView): SortPairObj | undefined { - if ( - Array.isArray(sortPair) && - sortPair.length === 2 && - isSortable(String(sortPair[0]), dataView) - ) { - const [field, direction] = sortPair as SortOrder; - return { [field]: direction }; - } else if (isPlainObject(sortPair) && isSortable(Object.keys(sortPair)[0], dataView)) { - return sortPair as SortPairObj; - } -} - -export function isLegacySort(sort: SortPair[] | SortPair): sort is SortPair { - return ( - sort.length === 2 && typeof sort[0] === 'string' && (sort[1] === 'desc' || sort[1] === 'asc') - ); -} - -/** - * Take a sorting array and make it into an object - * @param {array} sort two dimensional array [[fieldToSort, directionToSort]] - * or an array of objects [{fieldToSort: directionToSort}] - * @param {object} dataView used for determining default sort - * @returns Array<{object}> an array of sort objects - */ -export function getSort(sort: SortPair[] | SortPair, dataView: DataView): SortPairObj[] { - if (Array.isArray(sort)) { - if (isLegacySort(sort)) { - // To stay compatible with legacy sort, which just supported a single sort field - return [{ [sort[0]]: sort[1] }]; - } - return sort - .map((sortPair: SortPair) => createSortObject(sortPair, dataView)) - .filter((sortPairObj) => typeof sortPairObj === 'object') as SortPairObj[]; - } - return []; -} - -/** - * compared to getSort it doesn't return an array of objects, it returns an array of arrays - * [[fieldToSort: directionToSort]] - */ -export function getSortArray(sort: SortInput, dataView: DataView): SortOrder[] { - return getSort(sort, dataView).reduce((acc: SortOrder[], sortPair) => { - const entries = Object.entries(sortPair); - if (entries && entries[0]) { - acc.push(entries[0]); - } - return acc; - }, []); -} +import { getDefaultSort, getSortArray, SortInput } from '../../../common/utils/sorting'; /** * sorting for embeddable, like getSortArray,but returning a default in the case the given sort or dataView is not valid diff --git a/src/plugins/discover/public/utils/sorting/index.ts b/src/plugins/discover/public/utils/sorting/index.ts index 1d7f3ce6d671a7..6e9c5c0a08b926 100644 --- a/src/plugins/discover/public/utils/sorting/index.ts +++ b/src/plugins/discover/public/utils/sorting/index.ts @@ -5,7 +5,9 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -export { getSort, getSortArray, getSortForEmbeddable } from './get_sort'; -export { getSortForSearchSource } from './get_sort_for_search_source'; -export { getDefaultSort } from './get_default_sort'; -export type { SortPair } from './get_sort'; + +export { getDefaultSort } from '../../../common/utils/sorting/get_default_sort'; +export { getSort, getSortArray } from '../../../common/utils/sorting/get_sort'; +export type { SortPair } from '../../../common/utils/sorting/get_sort'; +export { getSortForSearchSource } from '../../../common/utils/sorting/get_sort_for_search_source'; +export { getSortForEmbeddable } from './get_sort'; diff --git a/src/plugins/discover/server/index.ts b/src/plugins/discover/server/index.ts index 85dd3ce422cffe..f899060f0304c0 100644 --- a/src/plugins/discover/server/index.ts +++ b/src/plugins/discover/server/index.ts @@ -6,6 +6,27 @@ * Side Public License, v 1. */ +import { KibanaRequest } from '@kbn/core/server'; +import { DataPluginStart } from '@kbn/data-plugin/server/plugin'; +import { ColumnsFromLocatorFn, SearchSourceFromLocatorFn, TitleFromLocatorFn } from './locator'; import { DiscoverServerPlugin } from './plugin'; +export interface DiscoverServerPluginStartDeps { + data: DataPluginStart; +} + +export interface LocatorServiceScopedClient { + columnsFromLocator: ColumnsFromLocatorFn; + searchSourceFromLocator: SearchSourceFromLocatorFn; + titleFromLocator: TitleFromLocatorFn; +} + +export interface DiscoverServerPluginLocatorService { + asScopedClient: (req: KibanaRequest) => Promise; +} + +export interface DiscoverServerPluginStart { + locator: DiscoverServerPluginLocatorService; +} + export const plugin = () => new DiscoverServerPlugin(); diff --git a/src/plugins/discover/server/locator/columns_from_locator.test.ts b/src/plugins/discover/server/locator/columns_from_locator.test.ts new file mode 100644 index 00000000000000..d866cb585f1694 --- /dev/null +++ b/src/plugins/discover/server/locator/columns_from_locator.test.ts @@ -0,0 +1,141 @@ +/* + * 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 { IUiSettingsClient, SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; +import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import { ISearchStartSearchSource, SearchSource } from '@kbn/data-plugin/common'; +import { createSearchSourceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; +import { SavedSearchAttributes } from '@kbn/saved-search-plugin/common'; +import { LocatorServicesDeps as Services } from '.'; +import { DiscoverAppLocatorParams, DOC_HIDE_TIME_COLUMN_SETTING } from '../../common'; +import { columnsFromLocatorFactory } from './columns_from_locator'; + +const mockSavedSearchId = 'abc-test-123'; +// object returned by savedObjectsClient.get in testing +const defaultSavedSearch: SavedObject = { + type: 'search', + id: mockSavedSearchId, + references: [ + { id: '90943e30-9a47-11e8-b64d-95841ca0b247', name: 'testIndexRefName', type: 'index-pattern' }, + ], + attributes: { + title: '[Logs] Visits', + description: '', + columns: ['response', 'url', 'clientip', 'machine.os', 'tags'], + sort: [['test', '134']] as unknown as [], + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"testIndexRefName"}', + }, + } as unknown as SavedSearchAttributes, +}; + +const coreStart = coreMock.createStart(); +let uiSettingsClient: IUiSettingsClient; +let soClient: SavedObjectsClientContract; +let searchSourceStart: ISearchStartSearchSource; +let mockServices: Services; +let mockSavedSearch: SavedObject; +let mockDataView: DataView; + +// mock search source belonging to the saved search +let mockSearchSource: SearchSource; + +// mock params containing the discover app locator +let mockPayload: Array<{ params: DiscoverAppLocatorParams }>; + +beforeAll(async () => { + const dataStartMock = dataPluginMock.createStartContract(); + const request = httpServerMock.createKibanaRequest(); + soClient = coreStart.savedObjects.getScopedClient(request); + uiSettingsClient = coreMock.createStart().uiSettings.asScopedToClient(soClient); + searchSourceStart = await dataStartMock.search.searchSource.asScoped(request); + + mockServices = { + searchSourceStart, + savedObjects: soClient, + uiSettings: uiSettingsClient, + }; + + const soClientGet = soClient.get; + soClient.get = jest.fn().mockImplementation((type, id) => { + if (id === mockSavedSearchId) return mockSavedSearch; + return soClientGet(type, id); + }); +}); + +beforeEach(() => { + mockPayload = [{ params: { savedSearchId: mockSavedSearchId } }]; + mockSavedSearch = { ...defaultSavedSearch, attributes: { ...defaultSavedSearch.attributes } }; + + mockDataView = createStubDataView({ + spec: { + id: '90943e30-9a47-11e8-b64d-95841ca0b247', + name: 'testIndexRefName', + timeFieldName: 'timestamp', + }, + }); + + mockSearchSource = createSearchSourceMock(); + mockSearchSource.setField('index', mockDataView); + searchSourceStart.create = jest.fn().mockResolvedValue(mockSearchSource); + + const uiSettingsGet = uiSettingsClient.get; + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return false; // this is the default for the real setting + } + return uiSettingsGet(key); + }); +}); + +test('with search source using columns with default time field', async () => { + const provider = columnsFromLocatorFactory(mockServices); + const columns = await provider(mockPayload[0].params); + expect(columns).toEqual(['timestamp', 'response', 'url', 'clientip', 'machine.os', 'tags']); +}); + +test('with search source using columns without time field in the DataView', async () => { + mockDataView = createStubDataView({ + spec: { + id: '90943e30-9a47-11e8-b64d-95841ca0b247', + name: 'testIndexRefName', + timeFieldName: undefined, + }, + }); + mockSearchSource.setField('index', mockDataView); + + const provider = columnsFromLocatorFactory(mockServices); + const columns = await provider(mockPayload[0].params); + expect(columns).toEqual(['response', 'url', 'clientip', 'machine.os', 'tags']); +}); + +test('with search source using columns when DOC_HIDE_TIME_COLUMN_SETTING is true', async () => { + const uiSettingsGet = uiSettingsClient.get; + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return true; + } + return uiSettingsGet(key); + }); + + const provider = columnsFromLocatorFactory(mockServices); + const columns = await provider(mockPayload[0].params); + expect(columns).toEqual(['response', 'url', 'clientip', 'machine.os', 'tags']); +}); + +test('with saved search containing ["_source"]', async () => { + mockSavedSearch.attributes.columns = ['_source']; + + const provider = columnsFromLocatorFactory(mockServices); + const columns = await provider(mockPayload[0].params); + expect(columns).not.toBeDefined(); // must erase the field since it can not be used for search query +}); diff --git a/src/plugins/discover/server/locator/columns_from_locator.ts b/src/plugins/discover/server/locator/columns_from_locator.ts new file mode 100644 index 00000000000000..65146168052353 --- /dev/null +++ b/src/plugins/discover/server/locator/columns_from_locator.ts @@ -0,0 +1,101 @@ +/* + * 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 { DataView } from '@kbn/data-views-plugin/common'; +import { SavedSearch } from '@kbn/saved-search-plugin/common'; +import { getSavedSearch } from '@kbn/saved-search-plugin/server'; +import { LocatorServicesDeps } from '.'; +import { + DiscoverAppLocatorParams, + DOC_HIDE_TIME_COLUMN_SETTING, + SEARCH_FIELDS_FROM_SOURCE, +} from '../../common'; + +function isStringArray(arr: unknown | string[]): arr is string[] { + return Array.isArray(arr) && arr.every((p) => typeof p === 'string'); +} + +/** + * @internal + */ +export const getColumns = async ( + services: LocatorServicesDeps, + index: DataView, + savedSearch: SavedSearch +) => { + const [hideTimeColumn, useFieldsFromSource] = await Promise.all([ + services.uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING), + services.uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), + ]); + + // Add/adjust columns from the saved search attributes and UI Settings + let columns: string[] | undefined; + let columnsNext: string[] | undefined; + let timeFieldName: string | undefined; + // ignore '_source' column: it may be the only column when the user wishes to export all fields + const columnsTemp = savedSearch.columns?.filter((col) => col !== '_source'); + + if (typeof columnsTemp !== 'undefined' && columnsTemp.length > 0 && isStringArray(columnsTemp)) { + columns = columnsTemp; + + // conditionally add the time field column: + if (index?.timeFieldName && !hideTimeColumn) { + timeFieldName = index.timeFieldName; + } + if (timeFieldName && !columnsTemp.includes(timeFieldName)) { + columns = [timeFieldName, ...columns]; + } + + /* + * For querying performance, the searchSource object must have fields set. + * Otherwise, the requests will ask for all fields, even if only a few are really needed. + * Discover does not set fields, since having all fields is needed for the UI. + */ + if (!useFieldsFromSource && columns.length) { + columnsNext = columns; + } + } + + return { + timeFieldName, + columns: columnsNext, + }; +}; + +/** + * @internal + */ +export function columnsFromLocatorFactory(services: LocatorServicesDeps) { + /** + * Allows consumers to retrieve a set of selected fields from a search in DiscoverAppLocatorParams + * + * @public + */ + const columnsFromLocator = async ( + params: DiscoverAppLocatorParams + ): Promise => { + if (!params.savedSearchId) { + throw new Error(`Saved Search ID is required in DiscoverAppLocatorParams`); + } + + const savedSearch = await getSavedSearch(params.savedSearchId, services); + + const index = savedSearch.searchSource.getField('index'); + + if (!index) { + throw new Error(`Search Source is missing the "index" field`); + } + + const { columns } = await getColumns(services, index, savedSearch); + + return columns; + }; + return columnsFromLocator; +} + +export type ColumnsFromLocatorFn = ReturnType; diff --git a/src/plugins/discover/server/locator/index.ts b/src/plugins/discover/server/locator/index.ts new file mode 100644 index 00000000000000..c1bbe2ded04af6 --- /dev/null +++ b/src/plugins/discover/server/locator/index.ts @@ -0,0 +1,33 @@ +/* + * 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 { CoreStart, IUiSettingsClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; +import { DiscoverServerPluginLocatorService, DiscoverServerPluginStartDeps } from '..'; +import { getScopedClient } from './service'; + +export type { ColumnsFromLocatorFn } from './columns_from_locator'; +export type { SearchSourceFromLocatorFn } from './searchsource_from_locator'; +export type { TitleFromLocatorFn } from './title_from_locator'; + +/** + * @internal + */ +export interface LocatorServicesDeps { + searchSourceStart: ISearchStartSearchSource; + savedObjects: SavedObjectsClientContract; + uiSettings: IUiSettingsClient; +} + +/** + * @internal + */ +export const initializeLocatorServices = ( + core: CoreStart, + deps: DiscoverServerPluginStartDeps +): DiscoverServerPluginLocatorService => getScopedClient(core, deps); diff --git a/src/plugins/discover/server/locator/mocks.ts b/src/plugins/discover/server/locator/mocks.ts new file mode 100644 index 00000000000000..686b161e5df664 --- /dev/null +++ b/src/plugins/discover/server/locator/mocks.ts @@ -0,0 +1,41 @@ +/* + * 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 { KibanaRequest } from '@kbn/core/server'; +import { SearchSource } from '@kbn/data-plugin/common'; +import { createSearchSourceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; +import { DiscoverServerPluginLocatorService, LocatorServiceScopedClient } from '..'; +import { DiscoverAppLocatorParams } from '../../common'; + +export const createLocatorServiceMock = (): DiscoverServerPluginLocatorService => { + const mockFields = ['@timestamp', 'mock-message']; + + const columnsFromLocatorMock = jest + .fn, [DiscoverAppLocatorParams]>() + .mockResolvedValue(mockFields); + + const searchSourceFromLocatorMock = jest + .fn, [DiscoverAppLocatorParams]>() + .mockResolvedValue(createSearchSourceMock({ fields: mockFields })); + + const titleFromLocatorMock = jest + .fn, [DiscoverAppLocatorParams]>() + .mockResolvedValue('mock search title'); + + return { + asScopedClient: jest + .fn, [req: KibanaRequest]>() + .mockImplementation(() => { + return Promise.resolve({ + columnsFromLocator: columnsFromLocatorMock, + searchSourceFromLocator: searchSourceFromLocatorMock, + titleFromLocator: titleFromLocatorMock, + } as LocatorServiceScopedClient); + }), + }; +}; diff --git a/src/plugins/discover/server/locator/searchsource_from_locator.test.ts b/src/plugins/discover/server/locator/searchsource_from_locator.test.ts new file mode 100644 index 00000000000000..e2315cf2e48729 --- /dev/null +++ b/src/plugins/discover/server/locator/searchsource_from_locator.test.ts @@ -0,0 +1,178 @@ +/* + * 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 { IUiSettingsClient, SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; +import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import { ISearchStartSearchSource, SearchSource } from '@kbn/data-plugin/common'; +import { createSearchSourceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; +import { SavedSearchAttributes } from '@kbn/saved-search-plugin/common'; +import { LocatorServicesDeps as Services } from '.'; +import { DiscoverAppLocatorParams, DOC_HIDE_TIME_COLUMN_SETTING } from '../../common'; +import { searchSourceFromLocatorFactory } from './searchsource_from_locator'; + +const mockSavedSearchId = 'abc-test-123'; +// object returned by savedObjectsClient.get in testing +const defaultSavedSearch: SavedObject = { + type: 'search', + id: mockSavedSearchId, + references: [ + { id: '90943e30-9a47-11e8-b64d-95841ca0b247', name: 'testIndexRefName', type: 'index-pattern' }, + ], + attributes: { + title: '[Logs] Visits', + description: '', + columns: ['response', 'url', 'clientip', 'machine.os', 'tags'], + sort: [['test', '134']] as unknown as [], + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"testIndexRefName"}', + }, + } as unknown as SavedSearchAttributes, +}; + +const coreStart = coreMock.createStart(); +let uiSettingsClient: IUiSettingsClient; +let soClient: SavedObjectsClientContract; +let searchSourceStart: ISearchStartSearchSource; +let mockServices: Services; +let mockSavedSearch: SavedObject; +let mockDataView: DataView; + +// mock search source belonging to the saved search +let mockSearchSource: SearchSource; + +// mock params containing the discover app locator +let mockPayload: Array<{ params: DiscoverAppLocatorParams }>; + +beforeAll(async () => { + const dataStartMock = dataPluginMock.createStartContract(); + const request = httpServerMock.createKibanaRequest(); + soClient = coreStart.savedObjects.getScopedClient(request); + uiSettingsClient = coreMock.createStart().uiSettings.asScopedToClient(soClient); + searchSourceStart = await dataStartMock.search.searchSource.asScoped(request); + + mockServices = { + searchSourceStart, + savedObjects: soClient, + uiSettings: uiSettingsClient, + }; + + const soClientGet = soClient.get; + soClient.get = jest.fn().mockImplementation((type, id) => { + if (id === mockSavedSearchId) return mockSavedSearch; + return soClientGet(type, id); + }); +}); + +beforeEach(() => { + mockPayload = [{ params: { savedSearchId: mockSavedSearchId } }]; + mockSavedSearch = { ...defaultSavedSearch, attributes: { ...defaultSavedSearch.attributes } }; + + mockDataView = createStubDataView({ + spec: { + id: '90943e30-9a47-11e8-b64d-95841ca0b247', + name: 'testIndexRefName', + timeFieldName: 'timestamp', + }, + }); + + mockSearchSource = createSearchSourceMock(); + mockSearchSource.setField('index', mockDataView); + searchSourceStart.create = jest.fn().mockResolvedValue(mockSearchSource); + + const uiSettingsGet = uiSettingsClient.get; + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return false; // this is the default for the real setting + } + return uiSettingsGet(key); + }); +}); + +test('with saved search containing a filter', async () => { + const testFilter = { + meta: { index: 'logstash-*' }, + query: { term: { host: 'elastic.co' } }, + }; + mockSearchSource.setField('filter', testFilter); + + const provider = searchSourceFromLocatorFactory(mockServices); + const searchSource = await provider(mockPayload[0].params); + expect(searchSource.getSerializedFields().filter).toEqual([testFilter]); +}); + +test('with locator params containing a filter', async () => { + const testFilter = { + meta: { index: 'logstash-*' }, + query: { term: { host: 'elastic.co' } }, + }; + mockPayload = [{ params: { savedSearchId: mockSavedSearchId, filters: [testFilter] } }]; + + const provider = searchSourceFromLocatorFactory(mockServices); + const searchSource = await provider(mockPayload[0].params); + expect(searchSource.getSerializedFields().filter).toEqual([testFilter]); +}); + +test('with saved search and locator params both containing a filter', async () => { + // search source belonging to the saved search + mockSearchSource.setField('filter', { + meta: { index: 'logstash-*' }, + query: { term: { host: 'elastic.co' } }, + }); + + // locator params + mockPayload = [ + { + params: { + savedSearchId: mockSavedSearchId, + filters: [ + { + meta: { index: 'logstash-*' }, + query: { term: { os: 'Palm Pilot' } }, + }, + ], + }, + }, + ]; + + const provider = searchSourceFromLocatorFactory(mockServices); + const searchSource = await provider(mockPayload[0].params); + expect(searchSource.getSerializedFields().filter).toEqual([ + { meta: { index: 'logstash-*' }, query: { term: { host: 'elastic.co' } } }, + { meta: { index: 'logstash-*' }, query: { term: { os: 'Palm Pilot' } } }, + ]); +}); + +test('with locator params containing a timeRange', async () => { + const testTimeRange = { from: 'now-15m', to: 'now', mode: 'absolute' as const }; + mockPayload = [{ params: { savedSearchId: mockSavedSearchId, timeRange: testTimeRange } }]; + + const provider = searchSourceFromLocatorFactory(mockServices); + const searchSource = await provider(mockPayload[0].params); + expect(searchSource.getSerializedFields().filter).toEqual([ + { + meta: { + index: '90943e30-9a47-11e8-b64d-95841ca0b247', + }, + query: { + range: { timestamp: { format: 'strict_date_optional_time', gte: 'now-15m', lte: 'now' } }, + }, + }, + ]); +}); + +test('with saved search containing ["_source"]', async () => { + mockSavedSearch.attributes.columns = ['_source']; + + const provider = searchSourceFromLocatorFactory(mockServices); + const searchSource = await provider(mockPayload[0].params); + expect(searchSource.getSerializedFields().fields).toEqual(['*']); +}); diff --git a/src/plugins/discover/server/locator/searchsource_from_locator.ts b/src/plugins/discover/server/locator/searchsource_from_locator.ts new file mode 100644 index 00000000000000..455efc968b5347 --- /dev/null +++ b/src/plugins/discover/server/locator/searchsource_from_locator.ts @@ -0,0 +1,159 @@ +/* + * 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 { SearchSource, TimeRange } from '@kbn/data-plugin/common'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { AggregateQuery, Filter, Query } from '@kbn/es-query'; +import { SavedSearch } from '@kbn/saved-search-plugin/common'; +import { getSavedSearch } from '@kbn/saved-search-plugin/server'; +import { LocatorServicesDeps } from '.'; +import { DiscoverAppLocatorParams } from '../../common'; +import { getSortForSearchSource } from '../../common/utils/sorting'; +import { getColumns } from './columns_from_locator'; + +// Shortcut for return type of searchSource.getField('filter'); +type FilterResponse = undefined | Filter | Filter[] | (() => Filter | Filter[] | undefined); + +// flattens filter objects coming from different sources +function normalizeFilter(savedSearchFilterTmp?: FilterResponse) { + let savedSearchFilter: Filter[] | undefined; + if (savedSearchFilterTmp && Array.isArray(savedSearchFilterTmp)) { + // can not include functions: could be recursive + savedSearchFilter = [...savedSearchFilterTmp.filter((f) => typeof f !== 'function')]; + } else if (savedSearchFilterTmp && typeof savedSearchFilterTmp !== 'function') { + savedSearchFilter = [savedSearchFilterTmp]; + } + return savedSearchFilter; +} + +/* + * Combine the time range filter from the job request body with any filters that have been saved into the saved search object + * NOTE: if the filters that were saved into the search are NOT an array, it may be a function, and can not be supported. + */ +const getFilters = ( + timeFieldName: string | undefined, + index: DataView, + savedSearch: SavedSearch, + searchSource: SearchSource, + params: DiscoverAppLocatorParams +) => { + const filters: Filter[] = []; + + // Set a time range filter from (1) DiscoverAppLocatorParams or (2) SavedSearch + if (timeFieldName) { + const timeRange = params.timeRange + ? params.timeRange + : savedSearch.timeRange + ? (savedSearch.timeRange as TimeRange) + : null; + + if (timeRange) { + filters.push({ + meta: { index: index.id }, + query: { + range: { + [timeFieldName]: { + format: 'strict_date_optional_time', + gte: timeRange.from, + lte: timeRange.to, + }, + }, + }, + }); + } + } + + const savedSearchFilter = normalizeFilter(searchSource.getField('filter')); + if (savedSearchFilter) { + filters.push(...savedSearchFilter); + } + const paramsFilter = normalizeFilter(params.filters); + if (paramsFilter) { + filters.push(...paramsFilter); + } + + return filters; +}; + +/* + * Pick the query from the job request body vs any query that has been saved into the saved search object. + */ +const getQuery = (searchSource: SearchSource, params: DiscoverAppLocatorParams) => { + let query: Query | AggregateQuery | undefined; + const paramsQuery = params.query; + const savedSearchQuery = searchSource.getField('query'); + if (paramsQuery) { + query = paramsQuery; + } else if (savedSearchQuery) { + // NOTE: cannot combine 2 queries (using AND): query can not be an array in SearchSourceFields + query = savedSearchQuery; + } + + return query; +}; + +/** + * @internal + */ +export function searchSourceFromLocatorFactory(services: LocatorServicesDeps) { + /** + * Allows consumers to transform DiscoverAppLocatorParams into a SearchSource object for querying. + * + * @public + */ + const searchSourceFromLocator = async ( + params: DiscoverAppLocatorParams + ): Promise => { + if (!params.savedSearchId) { + throw new Error(`Saved Search ID is required in DiscoverAppLocatorParams`); + } + + const savedSearch = await getSavedSearch(params.savedSearchId, services); + + const searchSource = savedSearch.searchSource.createCopy(); + const index = searchSource.getField('index'); + + if (!index) { + throw new Error(`Search Source is missing the "index" field`); + } + + const { columns, timeFieldName } = await getColumns(services, index, savedSearch); + + // Inject columns + if (columns) { + searchSource.setField('fields', columns); + } else { + searchSource.setField('fields', ['*']); + } + + // Inject updated filters + const filters = getFilters(timeFieldName, index, savedSearch, searchSource, params); + if (filters.length > 0) { + searchSource.removeField('filter'); + searchSource.setField('filter', filters); + } + + // Inject query + const query = getQuery(searchSource, params); + if (query) { + searchSource.removeField('query'); + searchSource.setField('query', query); + } + + // Inject sort + if (savedSearch.sort) { + const sort = getSortForSearchSource(savedSearch.sort as Array<[string, string]>, index); + searchSource.setField('sort', sort); + } + + return searchSource; + }; + return searchSourceFromLocator; +} + +export type SearchSourceFromLocatorFn = ReturnType; diff --git a/src/plugins/discover/server/locator/service.ts b/src/plugins/discover/server/locator/service.ts new file mode 100644 index 00000000000000..90e8b5a850a0b1 --- /dev/null +++ b/src/plugins/discover/server/locator/service.ts @@ -0,0 +1,33 @@ +/* + * 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 { CoreStart, KibanaRequest } from '@kbn/core/server'; +import { DiscoverServerPluginLocatorService, DiscoverServerPluginStartDeps } from '..'; +import { columnsFromLocatorFactory } from './columns_from_locator'; +import { searchSourceFromLocatorFactory } from './searchsource_from_locator'; +import { titleFromLocatorFactory } from './title_from_locator'; + +export const getScopedClient = ( + core: CoreStart, + deps: DiscoverServerPluginStartDeps +): DiscoverServerPluginLocatorService => { + return { + asScopedClient: async (req: KibanaRequest) => { + const searchSourceStart = await deps.data.search.searchSource.asScoped(req); + const savedObjects = core.savedObjects.getScopedClient(req); + const uiSettings = core.uiSettings.asScopedToClient(savedObjects); + const services = { searchSourceStart, savedObjects, uiSettings }; + + return { + columnsFromLocator: columnsFromLocatorFactory(services), + searchSourceFromLocator: searchSourceFromLocatorFactory(services), + titleFromLocator: titleFromLocatorFactory(services), + }; + }, + }; +}; diff --git a/src/plugins/discover/server/locator/title_from_locator.test.ts b/src/plugins/discover/server/locator/title_from_locator.test.ts new file mode 100644 index 00000000000000..7328a577238e7e --- /dev/null +++ b/src/plugins/discover/server/locator/title_from_locator.test.ts @@ -0,0 +1,110 @@ +/* + * 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 { IUiSettingsClient, SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; +import { coreMock, httpServerMock } from '@kbn/core/server/mocks'; +import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; +import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; +import { SavedSearchAttributes } from '@kbn/saved-search-plugin/common'; +import { LocatorServicesDeps as Services } from '.'; +import { DiscoverAppLocatorParams, DOC_HIDE_TIME_COLUMN_SETTING } from '../../common'; +import { titleFromLocatorFactory } from './title_from_locator'; + +const mockSavedSearchId = 'abc-test-123'; +const defaultSavedSearch: SavedObject = { + type: 'search', + id: mockSavedSearchId, + references: [ + { id: '90943e30-9a47-11e8-b64d-95841ca0b247', name: 'testIndexRefName', type: 'index-pattern' }, + ], + attributes: { + title: '[Logs] Visits', + description: '', + columns: ['response', 'url', 'clientip', 'machine.os', 'tags'], + sort: [['test', '134']] as unknown as [], + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"testIndexRefName"}', + }, + } as unknown as SavedSearchAttributes, +}; + +const coreStart = coreMock.createStart(); +let uiSettingsClient: IUiSettingsClient; +let soClient: SavedObjectsClientContract; +let searchSourceStart: ISearchStartSearchSource; +let mockServices: Services; +let mockSavedSearch: SavedObject; + +// mock params containing the discover app locator +let mockPayload: Array<{ params: DiscoverAppLocatorParams }>; + +beforeAll(async () => { + const dataStartMock = dataPluginMock.createStartContract(); + const request = httpServerMock.createKibanaRequest(); + soClient = coreStart.savedObjects.getScopedClient(request); + uiSettingsClient = coreMock.createStart().uiSettings.asScopedToClient(soClient); + searchSourceStart = await dataStartMock.search.searchSource.asScoped(request); + + mockServices = { + searchSourceStart, + savedObjects: soClient, + uiSettings: uiSettingsClient, + }; + + const soClientGet = soClient.get; + soClient.get = jest.fn().mockImplementation((type, id) => { + if (id === mockSavedSearchId) return mockSavedSearch; + return soClientGet(type, id); + }); +}); + +beforeEach(() => { + mockPayload = [{ params: { savedSearchId: mockSavedSearchId } }]; + mockSavedSearch = { ...defaultSavedSearch, attributes: { ...defaultSavedSearch.attributes } }; + const uiSettingsGet = uiSettingsClient.get; + uiSettingsClient.get = jest.fn().mockImplementation((key: string) => { + if (key === DOC_HIDE_TIME_COLUMN_SETTING) { + return false; // this is the default for the real setting + } + return uiSettingsGet(key); + }); +}); + +test(`retrieves title from DiscoverAppLocatorParams`, async () => { + const testTitle = 'Test Title from DiscoverAppLocatorParams'; + mockPayload = [{ params: { title: testTitle } }]; + + const provider = titleFromLocatorFactory(mockServices); + const title = await provider(mockPayload[0].params); + expect(title).toBe(testTitle); +}); + +test(`retrieves title from saved search contents`, async () => { + const testTitle = 'Test Title from Saved Search Contents'; + mockSavedSearch = { + ...defaultSavedSearch, + attributes: { ...defaultSavedSearch.attributes, title: testTitle }, + }; + + const provider = titleFromLocatorFactory(mockServices); + const title = await provider(mockPayload[0].params); + expect(title).toBe(testTitle); +}); + +test(`throws error if DiscoverAppLocatorParams do not contain a saved search ID`, async () => { + const testFn = async () => { + mockPayload = [{ params: { dataViewId: 'not-yet-supported' } }]; + const provider = titleFromLocatorFactory(mockServices); + return await provider(mockPayload[0].params); + }; + + expect(testFn).rejects.toEqual( + new Error('DiscoverAppLocatorParams must contain a saved search reference') + ); +}); diff --git a/src/plugins/discover/server/locator/title_from_locator.ts b/src/plugins/discover/server/locator/title_from_locator.ts new file mode 100644 index 00000000000000..4b2d91269146cd --- /dev/null +++ b/src/plugins/discover/server/locator/title_from_locator.ts @@ -0,0 +1,56 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { SavedObject } from '@kbn/core/server'; +import { LocatorServicesDeps } from '.'; +import { DiscoverAppLocatorParams } from '../../common'; + +/** + * @internal + */ +export const titleFromLocatorFactory = (services: LocatorServicesDeps) => { + /** + * Allows consumers to derive a title of a search in Disocver from DiscoverAppLocatorParams. + * For now, this assumes the DiscoverAppLocatorParams contain a reference to a saved search. In the future, + * the params may only contain a reference to a DataView + * + * @public + */ + const titleFromLocator = async (params: DiscoverAppLocatorParams): Promise => { + const { savedSearchId, title: paramsTitle } = params as { + savedSearchId?: string; + title?: string; + }; + + if (paramsTitle) { + return paramsTitle; + } + + if (!savedSearchId) { + throw new Error(`DiscoverAppLocatorParams must contain a saved search reference`); + } + + const { savedObjects } = services; + const searchObject: SavedObject<{ title?: string }> = await savedObjects.get( + 'search', + savedSearchId // assumes params contains saved search reference + ); + + return ( + searchObject.attributes.title ?? + i18n.translate('discover.serverLocatorExtension.titleFromLocatorUnknown', { + defaultMessage: 'Unknown search', + }) + ); + }; + + return titleFromLocator; +}; + +export type TitleFromLocatorFn = ReturnType; diff --git a/src/plugins/discover/server/mocks.ts b/src/plugins/discover/server/mocks.ts new file mode 100644 index 00000000000000..34c8dc02ff3cd1 --- /dev/null +++ b/src/plugins/discover/server/mocks.ts @@ -0,0 +1,16 @@ +/* + * 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 { DiscoverServerPluginStart } from '.'; +import { createLocatorServiceMock } from './locator/mocks'; + +export const discoverPluginMock = { + createStartContract: (): DiscoverServerPluginStart => ({ + locator: createLocatorServiceMock(), + }), +}; diff --git a/src/plugins/discover/server/plugin.ts b/src/plugins/discover/server/plugin.ts index a2ee1d79b6a17a..666ab85ad21057 100644 --- a/src/plugins/discover/server/plugin.ts +++ b/src/plugins/discover/server/plugin.ts @@ -6,17 +6,21 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/server'; +import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/server'; import type { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; -import { SharePluginSetup } from '@kbn/share-plugin/server'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common'; -import { getUiSettings } from './ui_settings'; +import type { SharePluginSetup } from '@kbn/share-plugin/server'; +import type { DiscoverServerPluginStart, DiscoverServerPluginStartDeps } from '.'; +import { DiscoverAppLocatorDefinition } from '../common/locator'; import { capabilitiesProvider } from './capabilities_provider'; +import { initializeLocatorServices } from './locator'; import { registerSampleData } from './sample_data'; -import { DiscoverAppLocatorDefinition } from '../common/locator'; +import { getUiSettings } from './ui_settings'; -export class DiscoverServerPlugin implements Plugin { +export class DiscoverServerPlugin + implements Plugin +{ public setup( core: CoreSetup, plugins: { @@ -41,8 +45,8 @@ export class DiscoverServerPlugin implements Plugin { return {}; } - public start(core: CoreStart) { - return {}; + public start(core: CoreStart, deps: DiscoverServerPluginStartDeps) { + return { locator: initializeLocatorServices(core, deps) }; } public stop() {} diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 937ea9a28639d1..1ea92fe129ccf8 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -207,7 +207,7 @@ export class EmbeddablePublicPlugin implements Plugin diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts index 48410081da3ff6..5c4ba047d107c4 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts @@ -7,7 +7,7 @@ */ import type { Logger } from '@kbn/core/server'; -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { Readable } from 'stream'; import { encode } from 'cbor-x'; import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; diff --git a/src/plugins/files/tsconfig.json b/src/plugins/files/tsconfig.json index 02b5acc39ff80d..8a14fd5ef06bc4 100644 --- a/src/plugins/files/tsconfig.json +++ b/src/plugins/files/tsconfig.json @@ -27,6 +27,7 @@ "@kbn/core-saved-objects-api-server", "@kbn/core-logging-server-mocks", "@kbn/ecs", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/src/plugins/saved_objects/common/index.ts b/src/plugins/saved_objects/common/index.ts index f2a1aa7c06e547..056d0b4638efcb 100644 --- a/src/plugins/saved_objects/common/index.ts +++ b/src/plugins/saved_objects/common/index.ts @@ -8,3 +8,4 @@ export const PER_PAGE_SETTING = 'savedObjects:perPage'; export const LISTING_LIMIT_SETTING = 'savedObjects:listingLimit'; +export type { SavedObjectCommon, FindQueryHTTP, FindResponseHTTP, FinderAttributes } from './types'; diff --git a/src/plugins/saved_objects/common/types.ts b/src/plugins/saved_objects/common/types.ts new file mode 100644 index 00000000000000..7feca5eecb40e2 --- /dev/null +++ b/src/plugins/saved_objects/common/types.ts @@ -0,0 +1,35 @@ +/* + * 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 { SavedObject } from '@kbn/core-saved-objects-server'; + +export type SavedObjectCommon = SavedObject; + +export interface FindQueryHTTP { + perPage?: number; + page?: number; + type: string | string[]; + search?: string; + searchFields?: string[]; + defaultSearchOperator?: 'AND' | 'OR'; + sortField?: string; + sortOrder?: 'asc' | 'desc'; + fields?: string | string[]; +} + +export interface FinderAttributes { + title?: string; + name?: string; + type: string; +} + +export interface FindResponseHTTP { + saved_objects: Array>; + total: number; + page: number; + per_page: number; +} diff --git a/src/plugins/saved_objects/public/finder/index.ts b/src/plugins/saved_objects/public/finder/index.ts index dc4213978aa521..aaf6259daca1d6 100644 --- a/src/plugins/saved_objects/public/finder/index.ts +++ b/src/plugins/saved_objects/public/finder/index.ts @@ -6,9 +6,5 @@ * Side Public License, v 1. */ -export type { - SavedObjectMetaData, - SavedObjectFinderUiProps, - FinderAttributes, -} from './saved_object_finder'; +export type { SavedObjectMetaData, SavedObjectFinderUiProps } from './saved_object_finder'; export { SavedObjectFinderUi, getSavedObjectFinder } from './saved_object_finder'; diff --git a/src/plugins/saved_objects/public/finder/saved_object_finder.test.tsx b/src/plugins/saved_objects/public/finder/saved_object_finder.test.tsx index bb33de184f6ce6..17f81733f831b8 100644 --- a/src/plugins/saved_objects/public/finder/saved_object_finder.test.tsx +++ b/src/plugins/saved_objects/public/finder/saved_object_finder.test.tsx @@ -52,43 +52,45 @@ describe('SavedObjectsFinder', () => { }, ]; - it('should call saved object client on startup', async () => { + it('should call api find on startup', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( ); wrapper.instance().componentDidMount!(); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['search'], - fields: ['title', 'name'], - search: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description', 'name'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['search'], + fields: ['title', 'name'], + search: undefined, + page: 1, + perPage: 10, + searchFields: ['title^3', 'description', 'name'], + defaultSearchOperator: 'AND', + }, }); }); it('should list initial items', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -104,14 +106,14 @@ describe('SavedObjectsFinder', () => { it('should call onChoose on item click', async () => { const chooseStub = sinon.stub(); const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { describe('sorting', () => { it('should list items ascending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -150,14 +152,14 @@ describe('SavedObjectsFinder', () => { it('should list items descending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -174,14 +176,14 @@ describe('SavedObjectsFinder', () => { it('should not show the saved objects which get filtered by showSavedObject', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { describe('search', () => { it('should request filtered list on search input', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -223,25 +225,27 @@ describe('SavedObjectsFinder', () => { .first() .simulate('change', { target: { value: 'abc' } }); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['search'], - fields: ['title', 'name'], - search: 'abc*', - page: 1, - perPage: 10, - searchFields: ['title^3', 'description', 'name'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['search'], + fields: ['title', 'name'], + search: 'abc*', + page: 1, + perPage: 10, + searchFields: ['title^3', 'description', 'name'], + defaultSearchOperator: 'AND', + }, }); }); it('should include additional fields in search if listed in meta data', async () => { const core = coreMock.createStart(); core.uiSettings.get.mockImplementation(() => 10); - (core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] }); + (core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] }); const wrapper = shallow( { .first() .simulate('change', { target: { value: 'abc' } }); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['type1', 'type2'], - fields: ['title', 'name', 'field1', 'field2', 'field3'], - search: 'abc*', - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['type1', 'type2'], + fields: ['title', 'name', 'field1', 'field2', 'field3'], + search: 'abc*', + page: 1, + perPage: 10, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + }, }); }); it('should respect response order on search input', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -307,14 +313,14 @@ describe('SavedObjectsFinder', () => { it('should request multiple saved object types at once', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { ); wrapper.instance().componentDidMount!(); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['search', 'vis'], + fields: ['title', 'name'], + search: undefined, + page: 1, + perPage: 10, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + }, }); }); @@ -359,16 +367,16 @@ describe('SavedObjectsFinder', () => { it('should not render filter buttons if disabled', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => + (core.http.get as any as jest.SpyInstance).mockImplementation(() => Promise.resolve({ - savedObjects: [doc, doc2, doc3], + saved_objects: [doc, doc2, doc3], }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should not render filter buttons if there is only one type in the list', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => + (core.http.get as any as jest.SpyInstance).mockImplementation(() => Promise.resolve({ - savedObjects: [doc, doc2], + saved_objects: [doc, doc2], }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should apply filter if selected', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => + (core.http.get as any as jest.SpyInstance).mockImplementation(() => Promise.resolve({ - savedObjects: [doc, doc2, doc3], + saved_objects: [doc, doc2, doc3], }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should display no items message if there are no items', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [] }) ); core.uiSettings.get.mockImplementation(() => 10); const noItemsMessage = ; const wrapper = shallow( { it('should show a table pagination with initial per page', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: longItemList }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: longItemList }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should allow switching the page size', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: longItemList }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: longItemList }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should switch page correctly', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: longItemList }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: longItemList }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should show an ordinary pagination for fixed page sizes', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: longItemList }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: longItemList }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { it('should switch page correctly for fixed page sizes', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: longItemList }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: longItemList }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { describe('loading state', () => { it('should display a spinner during initial loading', () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] }); + (core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] }); const wrapper = shallow( @@ -597,13 +605,13 @@ describe('SavedObjectsFinder', () => { it('should hide the spinner if data is shown', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc] }) ); const wrapper = shallow( { it('should not show the spinner if there are already items', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc] }) ); const wrapper = shallow( @@ -649,14 +657,14 @@ describe('SavedObjectsFinder', () => { it('should render with children', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { type: string; name: string; - getIconForSavedObject(savedObject: SimpleSavedObject): IconType; - getTooltipForSavedObject?(savedObject: SimpleSavedObject): string; - showSavedObject?(savedObject: SimpleSavedObject): boolean; - getSavedObjectSubType?(savedObject: SimpleSavedObject): string; + getIconForSavedObject(savedObject: SavedObjectCommon): IconType; + getTooltipForSavedObject?(savedObject: SavedObjectCommon): string; + showSavedObject?(savedObject: SavedObjectCommon): boolean; + getSavedObjectSubType?(savedObject: SavedObjectCommon): string; includeFields?: string[]; defaultSearchField?: string; } -export interface FinderAttributes { - title?: string; - name?: string; - type: string; -} - interface SavedObjectFinderState { items: Array<{ title: string | null; name: string | null; - id: SimpleSavedObject['id']; - type: SimpleSavedObject['type']; - savedObject: SimpleSavedObject; + id: SavedObjectCommon['id']; + type: SavedObjectCommon['type']; + savedObject: SavedObjectCommon; }>; query: string; isFetchingItems: boolean; @@ -77,10 +72,10 @@ interface SavedObjectFinderState { interface BaseSavedObjectFinder { onChoose?: ( - id: SimpleSavedObject['id'], - type: SimpleSavedObject['type'], + id: SavedObjectCommon['id'], + type: SavedObjectCommon['type'], name: string, - savedObject: SimpleSavedObject + savedObject: SavedObjectCommon ) => void; noItemsMessage?: React.ReactNode; savedObjectMetaData: Array>; @@ -100,8 +95,8 @@ interface SavedObjectFinderInitialPageSize extends BaseSavedObjectFinder { export type SavedObjectFinderProps = SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize; export type SavedObjectFinderUiProps = { - savedObjects: CoreStart['savedObjects']; uiSettings: CoreStart['uiSettings']; + http: CoreStart['http']; } & SavedObjectFinderProps; class SavedObjectFinderUi extends React.Component< @@ -134,7 +129,7 @@ class SavedObjectFinderUi extends React.Component< }, []); const perPage = this.props.uiSettings.get(LISTING_LIMIT_SETTING); - const resp = await this.props.savedObjects.client.find({ + const params: FindQueryHTTP = { type: Object.keys(metaDataMap), fields: [...new Set(fields)], search: query ? `${query}*` : undefined, @@ -142,15 +137,17 @@ class SavedObjectFinderUi extends React.Component< perPage, searchFields: ['title^3', 'description', ...additionalSearchFields], defaultSearchOperator: 'AND', - }); + }; + const resp = (await this.props.http.get('/internal/saved-objects-finder/find', { + query: params as Record, + })) as FindResponseHTTP; - resp.savedObjects = resp.savedObjects.filter((savedObject) => { + resp.saved_objects = resp.saved_objects.filter((savedObject) => { const metaData = metaDataMap[savedObject.type]; if (metaData.showSavedObject) { return metaData.showSavedObject(savedObject); - } else { - return true; } + return true; }); if (!this.isComponentMounted) { @@ -163,14 +160,11 @@ class SavedObjectFinderUi extends React.Component< this.setState({ isFetchingItems: false, page: 0, - items: resp.savedObjects.map((savedObject) => { - const { - attributes: { name, title }, - id, - type, - } = savedObject; + items: resp.saved_objects.map((savedObject) => { + const { attributes, id, type } = savedObject; + const { name, title } = attributes as FinderAttributes; const titleToUse = typeof title === 'string' ? title : ''; - const nameToUse = name && typeof name === 'string' ? name : titleToUse; + const nameToUse = name ? name : titleToUse; return { title: titleToUse, name: nameToUse, @@ -533,9 +527,9 @@ class SavedObjectFinderUi extends React.Component< } } -const getSavedObjectFinder = (savedObject: SavedObjectsStart, uiSettings: IUiSettingsClient) => { +const getSavedObjectFinder = (uiSettings: IUiSettingsClient, http: HttpStart) => { return (props: SavedObjectFinderProps) => ( - + ); }; diff --git a/src/plugins/saved_objects/public/index.ts b/src/plugins/saved_objects/public/index.ts index 2cfb84d608c671..5d10887c8c7227 100644 --- a/src/plugins/saved_objects/public/index.ts +++ b/src/plugins/saved_objects/public/index.ts @@ -10,7 +10,8 @@ import { SavedObjectsPublicPlugin } from './plugin'; export type { OnSaveProps, OriginSaveModalProps, SaveModalState, SaveResult } from './save_modal'; export { SavedObjectSaveModal, SavedObjectSaveModalOrigin, showSaveModal } from './save_modal'; -export type { SavedObjectFinderUiProps, SavedObjectMetaData, FinderAttributes } from './finder'; +export type { SavedObjectFinderUiProps, SavedObjectMetaData } from './finder'; +export type { FinderAttributes } from '../common/types'; export { getSavedObjectFinder, SavedObjectFinderUi } from './finder'; export type { SavedObjectDecorator, diff --git a/src/plugins/saved_objects/server/plugin.test.mocks.ts b/src/plugins/saved_objects/server/plugin.test.mocks.ts new file mode 100644 index 00000000000000..af29314a63c795 --- /dev/null +++ b/src/plugins/saved_objects/server/plugin.test.mocks.ts @@ -0,0 +1,12 @@ +/* + * 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 const registerRoutesMock = jest.fn(); +jest.doMock('./routes', () => ({ + registerRoutes: registerRoutesMock, +})); diff --git a/src/plugins/saved_objects/server/plugin.test.ts b/src/plugins/saved_objects/server/plugin.test.ts new file mode 100644 index 00000000000000..68569a6a24c173 --- /dev/null +++ b/src/plugins/saved_objects/server/plugin.test.ts @@ -0,0 +1,37 @@ +/* + * 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 { registerRoutesMock } from './plugin.test.mocks'; + +import { coreMock } from '@kbn/core/server/mocks'; +import { SavedObjectsServerPlugin } from './plugin'; +import { uiSettings } from './ui_settings'; + +describe('SavedObjectsPlugin', () => { + let plugin: SavedObjectsServerPlugin; + let coreSetup: ReturnType; + + beforeEach(() => { + coreSetup = coreMock.createSetup(); + plugin = new SavedObjectsServerPlugin(); + }); + + afterEach(() => { + registerRoutesMock.mockReset(); + }); + + describe('#setup', () => { + it('calls `registerRoutes` and `registerSettings` with the correct parameters', () => { + plugin.setup(coreSetup); + + expect(coreSetup.uiSettings.register).toHaveBeenCalledWith(uiSettings); + expect(coreSetup.http.createRouter).toHaveBeenCalledTimes(1); + expect(registerRoutesMock).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/plugins/saved_objects/server/plugin.ts b/src/plugins/saved_objects/server/plugin.ts index c540846a191f8f..6d01010e37612d 100644 --- a/src/plugins/saved_objects/server/plugin.ts +++ b/src/plugins/saved_objects/server/plugin.ts @@ -6,12 +6,15 @@ * Side Public License, v 1. */ -import { CoreSetup, Plugin } from '@kbn/core/server'; +import type { CoreSetup, Plugin, RequestHandlerContext } from '@kbn/core/server'; +import { registerRoutes } from './routes'; import { uiSettings } from './ui_settings'; export class SavedObjectsServerPlugin implements Plugin { public setup(core: CoreSetup) { core.uiSettings.register(uiSettings); + const router = core.http.createRouter(); + registerRoutes(router); return {}; } diff --git a/src/plugins/saved_objects/server/routes/find.ts b/src/plugins/saved_objects/server/routes/find.ts new file mode 100644 index 00000000000000..37439429451ed5 --- /dev/null +++ b/src/plugins/saved_objects/server/routes/find.ts @@ -0,0 +1,61 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { SavedObjectsRouter } from '../types'; +import type { SavedObjectCommon, FindResponseHTTP } from '../../common'; + +export const registerFindRoute = (router: SavedObjectsRouter) => { + router.get( + { + path: '/internal/saved-objects-finder/find', + validate: { + query: schema.object({ + perPage: schema.number({ min: 0, defaultValue: 20 }), + page: schema.number({ min: 0, defaultValue: 1 }), + type: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), + search: schema.maybe(schema.string()), + defaultSearchOperator: schema.oneOf([schema.literal('AND'), schema.literal('OR')]), + sortField: schema.maybe(schema.string()), + sortOrder: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + defaultValue: [], + }), + searchFields: schema.maybe(schema.arrayOf(schema.string())), + }), + }, + options: { + authRequired: 'optional', + }, + }, + async (ctx, req, res) => { + const savedObjectsClient = (await ctx.core).savedObjects.client; + const { query } = req; + + const searchTypes = Array.isArray(query.type) ? query.type : [query.type]; + const includedFields = Array.isArray(query.fields) ? query.fields : [query.fields]; + + const findResponse = await savedObjectsClient.find>({ + ...query, + type: searchTypes, + fields: includedFields, + }); + + const savedObjects = findResponse.saved_objects; + + const response: FindResponseHTTP = { + saved_objects: savedObjects, + total: findResponse.total, + per_page: findResponse.per_page, + page: findResponse.page, + }; + + return res.ok({ body: response }); + } + ); +}; diff --git a/src/plugins/saved_objects/server/routes/index.ts b/src/plugins/saved_objects/server/routes/index.ts new file mode 100644 index 00000000000000..df9a797e8184db --- /dev/null +++ b/src/plugins/saved_objects/server/routes/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { SavedObjectsRouter } from '../types'; +import { registerFindRoute } from './find'; + +export const registerRoutes = (router: SavedObjectsRouter) => { + registerFindRoute(router); +}; diff --git a/src/plugins/saved_objects/server/types.ts b/src/plugins/saved_objects/server/types.ts new file mode 100644 index 00000000000000..e6ec45a63d04f0 --- /dev/null +++ b/src/plugins/saved_objects/server/types.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. + */ +import { IRouter, RequestHandlerContext } from '@kbn/core/server'; + +export type SavedObjectsRouter = IRouter; diff --git a/src/plugins/saved_objects/tsconfig.json b/src/plugins/saved_objects/tsconfig.json index d35fe2e1cc1839..4307e0768cb17a 100644 --- a/src/plugins/saved_objects/tsconfig.json +++ b/src/plugins/saved_objects/tsconfig.json @@ -15,6 +15,7 @@ "@kbn/test-jest-helpers", "@kbn/utility-types", "@kbn/config-schema", + "@kbn/core-saved-objects-server", ], "exclude": [ "target/**/*", diff --git a/src/plugins/saved_search/common/index.ts b/src/plugins/saved_search/common/index.ts index 014fdb31ed438a..8eac1650434d82 100644 --- a/src/plugins/saved_search/common/index.ts +++ b/src/plugins/saved_search/common/index.ts @@ -7,3 +7,16 @@ */ export { getSavedSearchUrl, getSavedSearchFullPathUrl } from './saved_searches_url'; +export { fromSavedSearchAttributes } from './saved_searches_utils'; + +export type { + DiscoverGridSettings, + DiscoverGridSettingsColumn, + SavedSearch, + SavedSearchAttributes, +} from './types'; + +export enum VIEW_MODE { + DOCUMENT_LEVEL = 'documents', + AGGREGATED_LEVEL = 'aggregated', +} diff --git a/src/plugins/saved_search/common/saved_searches_utils.ts b/src/plugins/saved_search/common/saved_searches_utils.ts new file mode 100644 index 00000000000000..41934b86a36d5e --- /dev/null +++ b/src/plugins/saved_search/common/saved_searches_utils.ts @@ -0,0 +1,36 @@ +/* + * 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 { SavedSearch, SavedSearchAttributes } from '.'; + +export const fromSavedSearchAttributes = ( + id: string, + attributes: SavedSearchAttributes, + tags: string[] | undefined, + searchSource: SavedSearch['searchSource'] +): SavedSearch => ({ + id, + searchSource, + title: attributes.title, + sort: attributes.sort, + columns: attributes.columns, + description: attributes.description, + tags, + grid: attributes.grid, + hideChart: attributes.hideChart, + viewMode: attributes.viewMode, + hideAggregatedPreview: attributes.hideAggregatedPreview, + rowHeight: attributes.rowHeight, + isTextBasedQuery: attributes.isTextBasedQuery, + usesAdHocDataView: attributes.usesAdHocDataView, + timeRestore: attributes.timeRestore, + timeRange: attributes.timeRange, + refreshInterval: attributes.refreshInterval, + rowsPerPage: attributes.rowsPerPage, + breakdownField: attributes.breakdownField, +}); diff --git a/src/plugins/saved_search/common/types.ts b/src/plugins/saved_search/common/types.ts new file mode 100644 index 00000000000000..630323413fcb34 --- /dev/null +++ b/src/plugins/saved_search/common/types.ts @@ -0,0 +1,76 @@ +/* + * 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 { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common'; +import { VIEW_MODE } from '.'; + +export interface DiscoverGridSettings { + columns?: Record; +} + +export interface DiscoverGridSettingsColumn { + width?: number; +} + +/** @internal **/ +export interface SavedSearchAttributes { + title: string; + sort: Array<[string, string]>; + columns: string[]; + description: string; + grid: { + columns?: Record; + }; + hideChart: boolean; + isTextBasedQuery: boolean; + usesAdHocDataView?: boolean; + kibanaSavedObjectMeta: { + searchSourceJSON: string; + }; + viewMode?: VIEW_MODE; + hideAggregatedPreview?: boolean; + rowHeight?: number; + + timeRestore?: boolean; + timeRange?: TimeRange; + refreshInterval?: RefreshInterval; + + rowsPerPage?: number; + breakdownField?: string; +} + +/** @internal **/ +export type SortOrder = [string, string]; + +/** @public **/ +export interface SavedSearch { + searchSource: ISearchSource; + id?: string; + title?: string; + sort?: SortOrder[]; + columns?: string[]; + description?: string; + tags?: string[] | undefined; + grid?: { + columns?: Record; + }; + hideChart?: boolean; + viewMode?: VIEW_MODE; + hideAggregatedPreview?: boolean; + rowHeight?: number; + isTextBasedQuery?: boolean; + usesAdHocDataView?: boolean; + + // for restoring time range with a saved search + timeRestore?: boolean; + timeRange?: TimeRange; + refreshInterval?: RefreshInterval; + + rowsPerPage?: number; + breakdownField?: string; +} diff --git a/src/plugins/saved_search/public/index.ts b/src/plugins/saved_search/public/index.ts index 047d663b16caa9..506e90825209a1 100644 --- a/src/plugins/saved_search/public/index.ts +++ b/src/plugins/saved_search/public/index.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -export type { SavedSearch, SaveSavedSearchOptions, SortOrder } from './services/saved_searches'; +export type { SortOrder } from '../common/types'; +export type { SavedSearch, SaveSavedSearchOptions } from './services/saved_searches'; export { getSavedSearch, getSavedSearchFullPathUrl, @@ -15,11 +16,7 @@ export { throwErrorOnSavedSearchUrlConflict, saveSavedSearch, } from './services/saved_searches'; -export type { - DiscoverGridSettings, - DiscoverGridSettingsColumn, -} from './services/saved_searches/types'; -export { VIEW_MODE } from './services/saved_searches/types'; +export { VIEW_MODE } from '../common'; export function plugin() { return { diff --git a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts index 59f2104adbcad2..0cae15e7292094 100644 --- a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts +++ b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts @@ -12,8 +12,8 @@ import { injectSearchSourceReferences, parseSearchSourceJSON } from '@kbn/data-p import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { SavedSearchAttributes, SavedSearch } from './types'; - +import type { SavedSearchAttributes } from '../../../common'; +import type { SavedSearch } from './types'; import { SAVED_SEARCH_TYPE } from './constants'; import { fromSavedSearchAttributes } from './saved_searches_utils'; diff --git a/src/plugins/saved_search/public/services/saved_searches/index.ts b/src/plugins/saved_search/public/services/saved_searches/index.ts index fbdcfbf5793c6b..3aa4120e19e782 100644 --- a/src/plugins/saved_search/public/services/saved_searches/index.ts +++ b/src/plugins/saved_search/public/services/saved_searches/index.ts @@ -16,4 +16,4 @@ export { export type { SaveSavedSearchOptions } from './save_saved_searches'; export { saveSavedSearch } from './save_saved_searches'; export { SAVED_SEARCH_TYPE } from './constants'; -export type { SavedSearch, SortOrder } from './types'; +export type { SavedSearch } from './types'; diff --git a/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts index 029d7380968592..a7d11ab69166ea 100644 --- a/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts +++ b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts @@ -7,8 +7,8 @@ */ import type { SavedObjectsClientContract, SavedObjectsStart } from '@kbn/core/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { SavedSearch, SavedSearchAttributes } from './types'; - +import type { SavedSearchAttributes } from '../../../common'; +import type { SavedSearch } from './types'; import { SAVED_SEARCH_TYPE } from './constants'; import { toSavedSearchAttributes } from './saved_searches_utils'; diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts index feabac408c116e..511385276ab11c 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts @@ -14,7 +14,8 @@ import { import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks'; -import type { SavedSearchAttributes, SavedSearch } from './types'; +import type { SavedSearchAttributes } from '../../../common'; +import type { SavedSearch } from './types'; describe('saved_searches_utils', () => { describe('fromSavedSearchAttributes', () => { diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts index 83286f455d8c44..3a05572935281f 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts @@ -6,7 +6,9 @@ * Side Public License, v 1. */ import { i18n } from '@kbn/i18n'; -import type { SavedSearchAttributes, SavedSearch } from './types'; +import type { SavedSearchAttributes } from '../../../common'; +import { fromSavedSearchAttributes as fromSavedSearchAttributesCommon } from '../../../common'; +import type { SavedSearch } from './types'; export { getSavedSearchUrl, getSavedSearchFullPathUrl } from '../../../common'; @@ -31,26 +33,8 @@ export const fromSavedSearchAttributes = ( searchSource: SavedSearch['searchSource'], sharingSavedObjectProps: SavedSearch['sharingSavedObjectProps'] ): SavedSearch => ({ - id, - searchSource, + ...fromSavedSearchAttributesCommon(id, attributes, tags, searchSource), sharingSavedObjectProps, - title: attributes.title, - sort: attributes.sort, - columns: attributes.columns, - description: attributes.description, - tags, - grid: attributes.grid, - hideChart: attributes.hideChart, - viewMode: attributes.viewMode, - hideAggregatedPreview: attributes.hideAggregatedPreview, - rowHeight: attributes.rowHeight, - isTextBasedQuery: attributes.isTextBasedQuery, - usesAdHocDataView: attributes.usesAdHocDataView, - timeRestore: attributes.timeRestore, - timeRange: attributes.timeRange, - refreshInterval: attributes.refreshInterval, - rowsPerPage: attributes.rowsPerPage, - breakdownField: attributes.breakdownField, }); export const toSavedSearchAttributes = ( diff --git a/src/plugins/saved_search/public/services/saved_searches/types.ts b/src/plugins/saved_search/public/services/saved_searches/types.ts index f4e5ebecd559fa..2850b479cb1146 100644 --- a/src/plugins/saved_search/public/services/saved_searches/types.ts +++ b/src/plugins/saved_search/public/services/saved_searches/types.ts @@ -7,81 +7,14 @@ */ import type { ResolvedSimpleSavedObject } from '@kbn/core/public'; -import type { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common'; - -export enum VIEW_MODE { - DOCUMENT_LEVEL = 'documents', - AGGREGATED_LEVEL = 'aggregated', -} - -export interface DiscoverGridSettings { - columns?: Record; -} - -export interface DiscoverGridSettingsColumn { - width?: number; -} - -/** @internal **/ -export interface SavedSearchAttributes { - title: string; - sort: Array<[string, string]>; - columns: string[]; - description: string; - grid: { - columns?: Record; - }; - hideChart: boolean; - isTextBasedQuery: boolean; - usesAdHocDataView?: boolean; - kibanaSavedObjectMeta: { - searchSourceJSON: string; - }; - viewMode?: VIEW_MODE; - hideAggregatedPreview?: boolean; - rowHeight?: number; - - timeRestore?: boolean; - timeRange?: TimeRange; - refreshInterval?: RefreshInterval; - - rowsPerPage?: number; - breakdownField?: string; -} - -/** @internal **/ -export type SortOrder = [string, string]; +import { SavedSearch as SavedSearchCommon } from '../../../common'; /** @public **/ -export interface SavedSearch { - searchSource: ISearchSource; - id?: string; - title?: string; - sort?: SortOrder[]; - columns?: string[]; - description?: string; - tags?: string[] | undefined; - grid?: { - columns?: Record; - }; - hideChart?: boolean; +export interface SavedSearch extends SavedSearchCommon { sharingSavedObjectProps?: { outcome?: ResolvedSimpleSavedObject['outcome']; aliasTargetId?: ResolvedSimpleSavedObject['alias_target_id']; aliasPurpose?: ResolvedSimpleSavedObject['alias_purpose']; errorJSON?: string; }; - viewMode?: VIEW_MODE; - hideAggregatedPreview?: boolean; - rowHeight?: number; - isTextBasedQuery?: boolean; - usesAdHocDataView?: boolean; - - // for restoring time range with a saved search - timeRestore?: boolean; - timeRange?: TimeRange; - refreshInterval?: RefreshInterval; - - rowsPerPage?: number; - breakdownField?: string; } diff --git a/src/plugins/saved_search/server/index.ts b/src/plugins/saved_search/server/index.ts index 4ec3dc6fea4918..b125cf3d1fe522 100644 --- a/src/plugins/saved_search/server/index.ts +++ b/src/plugins/saved_search/server/index.ts @@ -8,4 +8,6 @@ import { SavedSearchServerPlugin } from './plugin'; +export { getSavedSearch } from './services/saved_searches'; + export const plugin = () => new SavedSearchServerPlugin(); diff --git a/src/plugins/saved_search/server/services/saved_searches/get_saved_searches.ts b/src/plugins/saved_search/server/services/saved_searches/get_saved_searches.ts new file mode 100644 index 00000000000000..6a097481b67b32 --- /dev/null +++ b/src/plugins/saved_search/server/services/saved_searches/get_saved_searches.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 { SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; +import { + injectReferences, + ISearchStartSearchSource, + parseSearchSourceJSON, +} from '@kbn/data-plugin/common'; +import { fromSavedSearchAttributes, SavedSearchAttributes } from '../../../common'; + +interface GetSavedSearchDependencies { + savedObjects: SavedObjectsClientContract; + searchSourceStart: ISearchStartSearchSource; +} + +export const getSavedSearch = async (savedSearchId: string, deps: GetSavedSearchDependencies) => { + const savedSearch: SavedObject = await deps.savedObjects.get( + 'search', + savedSearchId + ); + + const parsedSearchSourceJSON = parseSearchSourceJSON( + savedSearch.attributes.kibanaSavedObjectMeta?.searchSourceJSON ?? '{}' + ); + + const searchSourceValues = injectReferences( + parsedSearchSourceJSON as Parameters[0], + savedSearch.references + ); + + return fromSavedSearchAttributes( + savedSearchId, + savedSearch.attributes, + undefined, + await deps.searchSourceStart.create(searchSourceValues) + ); +}; diff --git a/src/plugins/saved_search/server/services/saved_searches/index.ts b/src/plugins/saved_search/server/services/saved_searches/index.ts new file mode 100644 index 00000000000000..16aa47551fbe68 --- /dev/null +++ b/src/plugins/saved_search/server/services/saved_searches/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 { getSavedSearch } from './get_saved_searches'; diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx index f145a6ebece4e7..89bf46254b6bf0 100644 --- a/src/plugins/share/public/components/url_panel_content.tsx +++ b/src/plugins/share/public/components/url_panel_content.tsx @@ -20,7 +20,6 @@ import { EuiRadioGroup, EuiSwitch, EuiSwitchEvent, - EuiToolTip, } from '@elastic/eui'; import { format as formatUrl, parse as parseUrl } from 'url'; @@ -71,6 +70,7 @@ interface State { urlParams?: UrlParams; anonymousAccessParameters: AnonymousAccessState['accessURLParameters']; showPublicUrlSwitch: boolean; + showWarningButton: boolean; } export class UrlPanelContent extends Component { @@ -89,6 +89,7 @@ export class UrlPanelContent extends Component { url: '', anonymousAccessParameters: null, showPublicUrlSwitch: false, + showWarningButton: Boolean(this.props.snapshotShareWarning), }; } @@ -144,6 +145,7 @@ export class UrlPanelContent extends Component { public render() { const shortUrlSwitch = this.renderShortUrlSwitch(); const publicUrlSwitch = this.renderPublicUrlSwitch(); + const copyButton = this.renderCopyButton(); const urlRow = (!!shortUrlSwitch || !!publicUrlSwitch) && ( { ); - const showWarningButton = - this.props.snapshotShareWarning && - this.state.exportUrlAs === ExportUrlAsType.EXPORT_URL_AS_SNAPSHOT; - - const copyButton = (copy: () => void) => ( - - {this.props.isEmbedded ? ( - - ) : ( - - )} - - ); - return ( @@ -193,23 +168,7 @@ export class UrlPanelContent extends Component { - - {(copy: () => void) => ( - <> - {showWarningButton ? ( - - {copyButton(copy)} - - ) : ( - copyButton(copy) - )} - - )} - + {copyButton} ); @@ -356,6 +315,9 @@ export class UrlPanelContent extends Component { private handleExportUrlAs = (optionId: string) => { this.setState( { + showWarningButton: + Boolean(this.props.snapshotShareWarning) && + (optionId as ExportUrlAsType) === ExportUrlAsType.EXPORT_URL_AS_SNAPSHOT, exportUrlAs: optionId as ExportUrlAsType, }, this.setUrl @@ -428,6 +390,37 @@ export class UrlPanelContent extends Component { } }; + private renderCopyButton = () => ( + + {(copy) => ( + + {this.props.isEmbedded ? ( + + ) : ( + + )} + + )} + + ); + private renderExportUrlAsOptions = () => { const snapshotLabel = ( diff --git a/src/plugins/usage_collection/server/collector/collector_set.test.ts b/src/plugins/usage_collection/server/collector/collector_set.test.ts index bf3381c4510d3a..56b4e55eccfc47 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.test.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.test.ts @@ -601,5 +601,57 @@ describe('CollectorSet', () => { expect.any(Function) ); }); + + it('reuses ongoing collectors for subsequent calls', async () => { + const fetchMock = jest.fn( + () => new Promise((resolve) => setTimeout(() => resolve({ test: 1000 }), 100)) + ); + + collectorSet.registerCollector( + collectorSet.makeUsageCollector({ + type: 'slow_collector', + isReady: () => true, + schema: { test: { type: 'long' } }, + fetch: fetchMock, + }) + ); + + const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const mockSoClient = savedObjectsClientMock.create(); + + // Call bulkFetch twice concurrently + await Promise.all([ + collectorSet.bulkFetch(mockEsClient, mockSoClient), + collectorSet.bulkFetch(mockEsClient, mockSoClient), + ]); + + // It should be called once + expect(fetchMock).toHaveBeenCalledTimes(1); + }); + + it('calls completed collectors on subsequent calls', async () => { + const fetchMock = jest.fn( + () => new Promise((resolve) => setTimeout(() => resolve({ test: 1000 }), 100)) + ); + + collectorSet.registerCollector( + collectorSet.makeUsageCollector({ + type: 'slow_collector', + isReady: () => true, + schema: { test: { type: 'long' } }, + fetch: fetchMock, + }) + ); + + const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + const mockSoClient = savedObjectsClientMock.create(); + + // Call bulkFetch twice sequentially + await collectorSet.bulkFetch(mockEsClient, mockSoClient); + await collectorSet.bulkFetch(mockEsClient, mockSoClient); + + // It should be called once + expect(fetchMock).toHaveBeenCalledTimes(2); + }); }); }); diff --git a/src/plugins/usage_collection/server/collector/collector_set.ts b/src/plugins/usage_collection/server/collector/collector_set.ts index 8251b95a1beb8b..d1b06e63b3b956 100644 --- a/src/plugins/usage_collection/server/collector/collector_set.ts +++ b/src/plugins/usage_collection/server/collector/collector_set.ts @@ -31,6 +31,12 @@ interface CollectorWithStatus { collector: AnyCollector; } +interface FetchCollectorOutput { + result?: unknown; + status: 'failed' | 'success'; + type: string; +} + export interface CollectorSetConfig { logger: Logger; executionContext: ExecutionContextSetup; @@ -43,6 +49,7 @@ export class CollectorSet { private readonly executionContext: ExecutionContextSetup; private readonly maximumWaitTimeForAllCollectorsInS: number; private readonly collectors: Map; + private readonly fetchingCollectors = new WeakMap>(); constructor({ logger, executionContext, @@ -190,11 +197,7 @@ export class CollectorSet { private fetchCollector = async ( collector: AnyCollector, context: CollectorFetchContext - ): Promise<{ - result?: unknown; - status: 'failed' | 'success'; - type: string; - }> => { + ): Promise => { const { type } = collector; this.logger.debug(`Fetching data from ${type} collector`); const executionContext: KibanaExecutionContext = { @@ -231,12 +234,22 @@ export class CollectorSet { const fetchExecutions = await Promise.all( readyCollectors.map(async (collector) => { - const wrappedPromise = perfTimerify( - `fetch_${collector.type}`, - async () => await this.fetchCollector(collector, context) - ); + // If the collector is processing from a concurrent request, reuse it. + let wrappedPromise = this.fetchingCollectors.get(collector); + + if (!wrappedPromise) { + // Otherwise, call it + wrappedPromise = perfTimerify( + `fetch_${collector.type}`, + async () => await this.fetchCollector(collector, context) + )(); + } + + this.fetchingCollectors.set(collector, wrappedPromise); + + wrappedPromise.finally(() => this.fetchingCollectors.delete(collector)); - return await wrappedPromise(); + return await wrappedPromise; }) ); const durationMarks = getMarks(); diff --git a/src/plugins/visualizations/public/actions/edit_in_lens_action.tsx b/src/plugins/visualizations/public/actions/edit_in_lens_action.tsx index 16977cdcfac177..dad2efbdedfc26 100644 --- a/src/plugins/visualizations/public/actions/edit_in_lens_action.tsx +++ b/src/plugins/visualizations/public/actions/edit_in_lens_action.tsx @@ -71,9 +71,12 @@ export class EditInLensAction implements Action { if (isVisualizeEmbeddable(embeddable)) { const vis = embeddable.getVis(); const navigateToLensConfig = await vis.type.navigateToLens?.(vis, this.timefilter); + // Filters and query set on the visualization level + const visFilters = vis.data.searchSource?.getField('filter'); + const visQuery = vis.data.searchSource?.getField('query'); const parentSearchSource = vis.data.searchSource?.getParent(); - const searchFilters = parentSearchSource?.getField('filter'); - const searchQuery = parentSearchSource?.getField('query'); + const searchFilters = parentSearchSource?.getField('filter') ?? visFilters; + const searchQuery = parentSearchSource?.getField('query') ?? visQuery; const title = vis.title || embeddable.getOutput().title; const updatedWithMeta = { ...navigateToLensConfig, diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx index 36d756d63f6606..edce87cebe4957 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx @@ -10,8 +10,9 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { TypesStart, VisGroups, BaseVisType } from '../vis_types'; import NewVisModal from './new_vis_modal'; -import { ApplicationStart, SavedObjectsStart, DocLinksStart } from '@kbn/core/public'; +import { ApplicationStart, DocLinksStart } from '@kbn/core/public'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; describe('NewVisModal', () => { const defaultVisTypeParams = { @@ -75,6 +76,7 @@ describe('NewVisModal', () => { }, }, }; + const http = httpServiceMock.createStartContract({ basePath: '' }); beforeAll(() => { Object.defineProperty(window, 'location', { @@ -98,7 +100,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(true); @@ -115,7 +117,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(true); @@ -131,7 +133,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); expect(wrapper.find('[data-test-subj="visType-vis2"]').exists()).toBe(true); @@ -148,7 +150,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); const visCard = wrapper.find('[data-test-subj="visType-vis"]').last(); @@ -167,7 +169,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); const visCard = wrapper.find('[data-test-subj="visType-vis"]').last(); @@ -193,7 +195,7 @@ describe('NewVisModal', () => { application={{ navigateToApp } as unknown as ApplicationStart} docLinks={docLinks as DocLinksStart} stateTransfer={stateTransfer} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last(); @@ -218,7 +220,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{ navigateToApp } as unknown as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last(); @@ -239,7 +241,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - savedObjects={{} as SavedObjectsStart} + http={http} /> ); const aggBasedGroupCard = wrapper diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx index 4ceb93b7ec0614..ed682ca54e680c 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx @@ -12,12 +12,7 @@ import { EuiModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; -import { - ApplicationStart, - IUiSettingsClient, - SavedObjectsStart, - DocLinksStart, -} from '@kbn/core/public'; +import { ApplicationStart, IUiSettingsClient, DocLinksStart, HttpStart } from '@kbn/core/public'; import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; import { SearchSelection } from './search_selection'; import { GroupSelection } from './group_selection'; @@ -34,7 +29,7 @@ interface TypeSelectionProps { addBasePath: (path: string) => string; uiSettings: IUiSettingsClient; docLinks: DocLinksStart; - savedObjects: SavedObjectsStart; + http: HttpStart; application: ApplicationStart; outsideVisualizeApp?: boolean; stateTransfer?: EmbeddableStateTransfer; @@ -97,7 +92,7 @@ class NewVisModal extends React.Component this.setState({ showSearchVisModal: false })} /> diff --git a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx index 5771747794273a..02e5864da9ce02 100644 --- a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx +++ b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { IUiSettingsClient, SavedObjectsStart } from '@kbn/core/public'; +import { IUiSettingsClient, HttpStart } from '@kbn/core/public'; import { SavedObjectFinderUi } from '@kbn/saved-objects-plugin/public'; import type { BaseVisType } from '../../vis_types'; @@ -21,7 +21,7 @@ interface SearchSelectionProps { onSearchSelected: (searchId: string, searchType: string) => void; visType: BaseVisType; uiSettings: IUiSettingsClient; - savedObjects: SavedObjectsStart; + http: HttpStart; goBack: () => void; } @@ -85,7 +85,7 @@ export class SearchSelection extends React.Component { ]} fixedPageSize={this.fixedPageSize} uiSettings={this.props.uiSettings} - savedObjects={this.props.savedObjects} + http={this.props.http} /> diff --git a/src/plugins/visualizations/public/wizard/show_new_vis.tsx b/src/plugins/visualizations/public/wizard/show_new_vis.tsx index b702cb5aa4209f..6e298bb0361220 100644 --- a/src/plugins/visualizations/public/wizard/show_new_vis.tsx +++ b/src/plugins/visualizations/public/wizard/show_new_vis.tsx @@ -13,7 +13,6 @@ import { I18nProvider } from '@kbn/i18n-react'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { getHttp, - getSavedObjects, getTypes, getUISettings, getApplication, @@ -81,7 +80,7 @@ export function showNewVisModal({ visTypesRegistry={getTypes()} addBasePath={getHttp().basePath.prepend} uiSettings={getUISettings()} - savedObjects={getSavedObjects()} + http={getHttp()} application={getApplication()} docLinks={getDocLinks()} showAggsSelection={showAggsSelection} diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 658d391f0a0de2..01fdf03133b739 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -50,6 +50,7 @@ "@kbn/core-overlays-browser", "@kbn/config-schema", "@kbn/usage-collection-plugin", + "@kbn/core-http-browser-mocks", "@kbn/shared-ux-router", ], "exclude": [ diff --git a/test/functional/apps/discover/group1/_sidebar.ts b/test/functional/apps/discover/group1/_sidebar.ts index d57b3edfe83e0f..9842cc3df554ae 100644 --- a/test/functional/apps/discover/group1/_sidebar.ts +++ b/test/functional/apps/discover/group1/_sidebar.ts @@ -26,6 +26,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const fieldEditor = getService('fieldEditor'); const retry = getService('retry'); + const dataGrid = getService('dataGrid'); const INITIAL_FIELD_LIST_SUMMARY = '53 available fields. 0 empty fields. 3 meta fields.'; describe('discover sidebar', function describeIndexTests() { @@ -715,6 +716,40 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'test/functional/fixtures/es_archiver/index_pattern_without_timefield' ); }); + + it('should remove the table column after a field was deleted', async () => { + const newField = '_test_field_and_column_removal'; + await PageObjects.discover.addRuntimeField(newField, `emit("hi there")`); + + await retry.waitFor('form to close', async () => { + return !(await testSubjects.exists('fieldEditor')); + }); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSidebarHasLoaded(); + + let selectedFields = await PageObjects.discover.getSidebarSectionFieldNames('selected'); + expect(selectedFields.includes(newField)).to.be(false); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + + await PageObjects.discover.clickFieldListItemAdd(newField); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSidebarHasLoaded(); + + selectedFields = await PageObjects.discover.getSidebarSectionFieldNames('selected'); + expect(selectedFields.includes(newField)).to.be(true); + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', newField]); + + await PageObjects.discover.removeField(newField); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSidebarHasLoaded(); + + await retry.waitFor('sidebar to update', async () => { + return !(await PageObjects.discover.getAllFieldNames()).includes(newField); + }); + + expect(await dataGrid.getHeaderFields()).to.eql(['@timestamp', 'Document']); + }); }); }); } diff --git a/versions.json b/versions.json index 91bf9e9b16fc4d..7e832470e4a96b 100644 --- a/versions.json +++ b/versions.json @@ -14,7 +14,7 @@ "previousMinor": true }, { - "version": "8.6.2", + "version": "8.6.3", "branch": "8.6", "currentMajor": true, "previousMinor": true diff --git a/x-pack/examples/alerting_example/public/alert_types/astros.tsx b/x-pack/examples/alerting_example/public/alert_types/astros.tsx index eee4e92b623f75..61559590240536 100644 --- a/x-pack/examples/alerting_example/public/alert_types/astros.tsx +++ b/x-pack/examples/alerting_example/public/alert_types/astros.tsx @@ -28,7 +28,7 @@ export function registerNavigation(alerting: AlertingSetup) { alerting.registerNavigation( ALERTING_EXAMPLE_APP_ID, 'example.people-in-space', - (rule: SanitizedRule) => `/astros/${rule.id}` + (rule: SanitizedRule) => `/app/${ALERTING_EXAMPLE_APP_ID}/astros/${rule.id}` ); } diff --git a/x-pack/examples/alerting_example/public/alert_types/index.ts b/x-pack/examples/alerting_example/public/alert_types/index.ts index 4cb30b9f4df027..44712b69fb34be 100644 --- a/x-pack/examples/alerting_example/public/alert_types/index.ts +++ b/x-pack/examples/alerting_example/public/alert_types/index.ts @@ -14,7 +14,7 @@ export function registerNavigation(alerting: AlertingSetup) { // register default navigation alerting.registerDefaultNavigation( ALERTING_EXAMPLE_APP_ID, - (rule: SanitizedRule) => `/rule/${rule.id}` + (rule: SanitizedRule) => `/app/${ALERTING_EXAMPLE_APP_ID}/rule/${rule.id}` ); registerPeopleInSpaceNavigation(alerting); diff --git a/x-pack/examples/alerting_example/server/alert_types/astros.ts b/x-pack/examples/alerting_example/server/alert_types/astros.ts index 64accdc550298d..c73ec8ecbc8bf4 100644 --- a/x-pack/examples/alerting_example/server/alert_types/astros.ts +++ b/x-pack/examples/alerting_example/server/alert_types/astros.ts @@ -81,4 +81,7 @@ export const alertType: RuleType< }; }, producer: ALERTING_EXAMPLE_APP_ID, + getViewInAppRelativeUrl({ rule }) { + return `/app/${ALERTING_EXAMPLE_APP_ID}/astros/${rule.id}`; + }, }; diff --git a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx index e12cc70e9b5873..bfdd1cb43138d3 100644 --- a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx +++ b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx @@ -90,43 +90,39 @@ export const FullTimeRangeSelector: FC = (props) => } = useDatePickerContext(); // wrapper around setFullTimeRange to allow for the calling of the optional callBack prop - const setRange = useCallback( - async (i: DataView, q?: QueryDslQueryContainer, excludeFrozenData?: boolean) => { - try { - const fullTimeRange = await setFullTimeRange( - timefilter, - i, - toasts, - http, - q, - excludeFrozenData - ); - if (typeof callback === 'function') { - callback(fullTimeRange); - } - } catch (e) { - toasts.addDanger( - i18n.translate( - 'xpack.ml.datePicker.fullTimeRangeSelector.errorSettingTimeRangeNotification', - { - defaultMessage: 'An error occurred setting the time range.', - } - ) - ); + const setRange = useCallback(async () => { + try { + const fullTimeRange = await setFullTimeRange( + timefilter, + dataView, + toasts, + http, + query, + frozenDataPreference === FROZEN_TIER_PREFERENCE.EXCLUDE + ); + if (typeof callback === 'function') { + callback(fullTimeRange); } - }, - [callback, http, timefilter, toasts] - ); + } catch (e) { + toasts.addDanger( + i18n.translate( + 'xpack.ml.datePicker.fullTimeRangeSelector.errorSettingTimeRangeNotification', + { + defaultMessage: 'An error occurred setting the time range.', + } + ) + ); + } + }, [callback, dataView, frozenDataPreference, http, query, timefilter, toasts]); const [isPopoverOpen, setPopover] = useState(false); const setPreference = useCallback( (id: string) => { setFrozenDataPreference(id as FrozenTierPreference); - setRange(dataView, query, id === FROZEN_TIER_PREFERENCE.EXCLUDE); closePopover(); }, - [dataView, query, setFrozenDataPreference, setRange] + [setFrozenDataPreference] ); const onButtonClick = () => { @@ -195,7 +191,7 @@ export const FullTimeRangeSelector: FC = (props) => setRange(dataView, query, true)} + onClick={() => setRange()} data-test-subj="mlDatePickerButtonUseFullData" > { lastRun?: RuleLastRun | null; nextRun?: Date | null; running?: boolean | null; + viewInAppRelativeUrl?: string; } export type SanitizedRule = Omit, 'apiKey'>; diff --git a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts index bedb17270a4777..c7bb9a4feb8baf 100644 --- a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts +++ b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts @@ -31,7 +31,7 @@ const mockRuleType = (id: string): RuleType => ({ describe('AlertNavigationRegistry', () => { function handler(rule: SanitizedRule) { - return {}; + return ''; } describe('has()', () => { @@ -151,7 +151,7 @@ describe('AlertNavigationRegistry', () => { const registry = new AlertNavigationRegistry(); function indexThresholdHandler(rule: SanitizedRule) { - return {}; + return ''; } const indexThresholdRuleType = mockRuleType('indexThreshold'); @@ -163,7 +163,7 @@ describe('AlertNavigationRegistry', () => { const registry = new AlertNavigationRegistry(); function defaultHandler(rule: SanitizedRule) { - return {}; + return ''; } registry.registerDefault('siem', defaultHandler); @@ -173,10 +173,10 @@ describe('AlertNavigationRegistry', () => { test('returns default handlers by consumer when there are other rule type handler', () => { const registry = new AlertNavigationRegistry(); - registry.register('siem', mockRuleType('indexThreshold').id, () => ({})); + registry.register('siem', mockRuleType('indexThreshold').id, () => ''); function defaultHandler(rule: SanitizedRule) { - return {}; + return ''; } registry.registerDefault('siem', defaultHandler); diff --git a/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts b/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts index 3c7b7aa3c8c060..405f040d5b3ae2 100644 --- a/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts +++ b/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { JsonObject } from '@kbn/utility-types'; import { SanitizedRule } from '../../common'; /** @@ -17,4 +16,4 @@ import { SanitizedRule } from '../../common'; * originally registered to {@link PluginSetupContract.registerNavigation}. * */ -export type AlertNavigationHandler = (rule: SanitizedRule) => JsonObject | string; +export type AlertNavigationHandler = (rule: SanitizedRule) => string; diff --git a/x-pack/plugins/alerting/public/lib/common_transformations.ts b/x-pack/plugins/alerting/public/lib/common_transformations.ts index 6a89b1ce9958ba..b123962bb4ea73 100644 --- a/x-pack/plugins/alerting/public/lib/common_transformations.ts +++ b/x-pack/plugins/alerting/public/lib/common_transformations.ts @@ -118,6 +118,7 @@ export function transformRule(input: ApiRule): Rule { next_run: nextRun, last_run: lastRun, monitoring: monitoring, + view_in_app_relative_url: viewInAppRelativeUrl, ...rest } = input; @@ -135,6 +136,7 @@ export function transformRule(input: ApiRule): Rule { executionStatus: transformExecutionStatus(executionStatusAPI), actions: actionsAPI ? actionsAPI.map((action) => transformAction(action)) : [], scheduledTaskId, + ...(viewInAppRelativeUrl ? { viewInAppRelativeUrl } : {}), ...(nextRun ? { nextRun: new Date(nextRun) } : {}), ...(monitoring ? { monitoring: transformMonitoring(monitoring) } : {}), ...(lastRun ? { lastRun: transformLastRun(lastRun) } : {}), diff --git a/x-pack/plugins/alerting/public/plugin.test.ts b/x-pack/plugins/alerting/public/plugin.test.ts new file mode 100644 index 00000000000000..fce03fa48ce0e4 --- /dev/null +++ b/x-pack/plugins/alerting/public/plugin.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { AlertingPublicPlugin } from './plugin'; +import { coreMock } from '@kbn/core/public/mocks'; + +jest.mock('./alert_api', () => ({ + loadRule: jest.fn(), + loadRuleType: jest.fn(), +})); + +describe('Alerting Public Plugin', () => { + describe('start()', () => { + it(`should fallback to the viewInAppRelativeUrl part of the rule object if navigation isn't registered`, async () => { + const { loadRule, loadRuleType } = jest.requireMock('./alert_api'); + loadRule.mockResolvedValue({ + alertTypeId: 'foo', + consumer: 'abc', + viewInAppRelativeUrl: '/my/custom/path', + }); + loadRuleType.mockResolvedValue({}); + + const plugin = new AlertingPublicPlugin(); + plugin.setup(); + const pluginStart = plugin.start(coreMock.createStart()); + + const navigationPath = await pluginStart.getNavigation('123'); + expect(navigationPath).toEqual('/my/custom/path'); + }); + }); +}); diff --git a/x-pack/plugins/alerting/public/plugin.ts b/x-pack/plugins/alerting/public/plugin.ts index 57ab4172b4689e..2e29a40b7dba01 100644 --- a/x-pack/plugins/alerting/public/plugin.ts +++ b/x-pack/plugins/alerting/public/plugin.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { CoreSetup, Plugin, CoreStart } from '@kbn/core/public'; +import { Plugin, CoreStart } from '@kbn/core/public'; import { AlertNavigationRegistry, AlertNavigationHandler } from './alert_navigation_registry'; import { loadRule, loadRuleType } from './alert_api'; -import { Rule, RuleNavigation } from '../common'; +import { Rule } from '../common'; export interface PluginSetupContract { /** @@ -26,6 +26,8 @@ export interface PluginSetupContract { * @param handler The navigation handler should return either a relative URL, or a state object. This information can be used, * in conjunction with the consumer id, to navigate the user to a custom URL to view a rule's details. * @throws an error if the given applicationId and ruleType combination has already been registered. + * + * @deprecated use "getViewInAppRelativeUrl" on the server side rule type instead. */ registerNavigation: ( applicationId: string, @@ -42,16 +44,18 @@ export interface PluginSetupContract { * @param applicationId The application id that the user should be navigated to, to view a particular rule in a custom way. * @param handler The navigation handler should return either a relative URL, or a state object. This information can be used, * in conjunction with the consumer id, to navigate the user to a custom URL to view a rule's details. + * + * @deprecated use "getViewInAppRelativeUrl" on the server side rule type instead. */ registerDefaultNavigation: (applicationId: string, handler: AlertNavigationHandler) => void; } export interface PluginStartContract { - getNavigation: (ruleId: Rule['id']) => Promise; + getNavigation: (ruleId: Rule['id']) => Promise; } export class AlertingPublicPlugin implements Plugin { private alertNavigationRegistry?: AlertNavigationRegistry; - public setup(core: CoreSetup) { + public setup() { this.alertNavigationRegistry = new AlertNavigationRegistry(); const registerNavigation = async ( @@ -89,8 +93,11 @@ export class AlertingPublicPlugin implements Plugin> = ({ isSnoozedUntil, lastRun, nextRun, + viewInAppRelativeUrl, ...rest }) => ({ ...rest, @@ -74,6 +75,7 @@ const rewriteBodyRes: RewriteResponseCase> = ({ })), ...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}), ...(nextRun ? { next_run: nextRun } : {}), + ...(viewInAppRelativeUrl ? { view_in_app_relative_url: viewInAppRelativeUrl } : {}), }); interface BuildGetRulesRouteParams { diff --git a/x-pack/plugins/alerting/server/rules_client/common/apply_bulk_edit_operation.ts b/x-pack/plugins/alerting/server/rules_client/common/apply_bulk_edit_operation.ts index b5ca53642496eb..e20624c77b2c5a 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/apply_bulk_edit_operation.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/apply_bulk_edit_operation.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { set, get, isEqual } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { get, isEqual } from 'lodash'; import type { BulkEditOperation, BulkEditFields } from '../types'; // defining an union type that will passed directly to generic function as a workaround for the issue similar to diff --git a/x-pack/plugins/alerting/server/rules_client/common/calculate_is_snoozed_until.ts b/x-pack/plugins/alerting/server/rules_client/common/calculate_is_snoozed_until.ts deleted file mode 100644 index d77a013ae3f6ba..00000000000000 --- a/x-pack/plugins/alerting/server/rules_client/common/calculate_is_snoozed_until.ts +++ /dev/null @@ -1,17 +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 { RuleSnooze } from '../../types'; -import { getRuleSnoozeEndTime } from '../../lib'; - -export function calculateIsSnoozedUntil(rule: { - muteAll: boolean; - snoozeSchedule?: RuleSnooze; -}): string | null { - const isSnoozedUntil = getRuleSnoozeEndTime(rule); - return isSnoozedUntil ? isSnoozedUntil.toISOString() : null; -} diff --git a/x-pack/plugins/alerting/server/rules_client/common/index.ts b/x-pack/plugins/alerting/server/rules_client/common/index.ts index 6019eb0f4307e4..ab380a6ca178b8 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/index.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/index.ts @@ -14,7 +14,6 @@ export { buildKueryNodeFilter } from './build_kuery_node_filter'; export { generateAPIKeyName } from './generate_api_key_name'; export * from './mapped_params_utils'; export { apiKeyAsAlertAttributes } from './api_key_as_alert_attributes'; -export { calculateIsSnoozedUntil } from './calculate_is_snoozed_until'; export * from './inject_references'; export { parseDate } from './parse_date'; export { includeFieldsRequiredForAuthentication } from './include_fields_required_for_authentication'; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts b/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts index 41330fe9b7eb60..59ed14ecf27356 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/get_alert_from_raw.ts @@ -16,14 +16,14 @@ import { RuleWithLegacyId, PartialRuleWithLegacyId, } from '../../types'; -import { ruleExecutionStatusFromRaw, convertMonitoringFromRawAndVerify } from '../../lib'; +import { + ruleExecutionStatusFromRaw, + convertMonitoringFromRawAndVerify, + getRuleSnoozeEndTime, +} from '../../lib'; import { UntypedNormalizedRuleType } from '../../rule_type_registry'; import { getActiveScheduledSnoozes } from '../../lib/is_rule_snoozed'; -import { - calculateIsSnoozedUntil, - injectReferencesIntoActions, - injectReferencesIntoParams, -} from '../common'; +import { injectReferencesIntoActions, injectReferencesIntoParams } from '../common'; import { RulesClientContext } from '../types'; export interface GetAlertFromRawParams { @@ -98,20 +98,20 @@ export function getPartialRuleFromRaw( ...s, rRule: { ...s.rRule, - dtstart: new Date(s.rRule.dtstart), - ...(s.rRule.until ? { until: new Date(s.rRule.until) } : {}), + dtstart: new Date(s.rRule.dtstart).toISOString(), + ...(s.rRule.until ? { until: new Date(s.rRule.until).toISOString() } : {}), }, })); const includeSnoozeSchedule = snoozeSchedule !== undefined && !isEmpty(snoozeSchedule) && !excludeFromPublicApi; const isSnoozedUntil = includeSnoozeSchedule - ? calculateIsSnoozedUntil({ + ? getRuleSnoozeEndTime({ muteAll: partialRawRule.muteAll ?? false, snoozeSchedule, }) : null; const includeMonitoring = monitoring && !excludeFromPublicApi; - const rule = { + const rule: PartialRule = { id, notifyWhen, ...omit(partialRawRule, excludeFromPublicApi ? [...context.fieldsToExcludeFromPublicApi] : ''), @@ -152,7 +152,23 @@ export function getPartialRuleFromRaw( : {}), }; - return includeLegacyId - ? ({ ...rule, legacyId } as PartialRuleWithLegacyId) - : (rule as PartialRule); + // Need the `rule` object to build a URL + if (!excludeFromPublicApi) { + const viewInAppRelativeUrl = + ruleType.getViewInAppRelativeUrl && + ruleType.getViewInAppRelativeUrl({ rule: rule as Rule }); + if (viewInAppRelativeUrl) { + rule.viewInAppRelativeUrl = viewInAppRelativeUrl; + } + } + + if (includeLegacyId) { + const result: PartialRuleWithLegacyId = { + ...rule, + legacyId, + }; + return result; + } + + return rule; } diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts index b41db1147f3b76..cc1741fe722fd1 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts @@ -1472,5 +1472,38 @@ describe('Execution Handler', () => { ] `); }); + + it('sets the rule.url to the value from getViewInAppRelativeUrl when the rule type has it defined', async () => { + const execParams = { + ...defaultExecutionParams, + rule: ruleWithUrl, + taskRunnerContext: { + ...defaultExecutionParams.taskRunnerContext, + kibanaBaseUrl: 'http://localhost:12345', + }, + ruleType: { + ...ruleType, + getViewInAppRelativeUrl() { + return '/app/management/some/other/place'; + }, + }, + }; + + const executionHandler = new ExecutionHandler(generateExecutionParams(execParams)); + await executionHandler.run(generateAlert({ id: 1 })); + + expect(injectActionParamsMock.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "actionParams": Object { + "val": "rule url: http://localhost:12345/s/test1/app/management/some/other/place", + }, + "actionTypeId": "test", + "ruleId": "1", + "spaceId": "test1", + }, + ] + `); + }); }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts index d0784805c5942d..9975c8f9e69235 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts @@ -270,8 +270,8 @@ export class ExecutionHandler< kibanaBaseUrl: this.taskRunnerContext.kibanaBaseUrl, alertParams: this.rule.params, actionParams: action.params, - ruleUrl: this.buildRuleUrl(spaceId), flapping: executableAlert.getFlapping(), + ruleUrl: this.buildRuleUrl(spaceId), }), }), }; @@ -409,11 +409,13 @@ export class ExecutionHandler< return; } + const relativePath = this.ruleType.getViewInAppRelativeUrl + ? this.ruleType.getViewInAppRelativeUrl({ rule: this.rule }) + : `${triggersActionsRoute}${getRuleDetailsRoute(this.rule.id)}`; + try { const ruleUrl = new URL( - `${ - spaceId !== 'default' ? `/s/${spaceId}` : '' - }${triggersActionsRoute}${getRuleDetailsRoute(this.rule.id)}`, + `${spaceId !== 'default' ? `/s/${spaceId}` : ''}${relativePath}`, this.taskRunnerContext.kibanaBaseUrl ); diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 09493e4357a15a..1ecff391be4af0 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -48,6 +48,7 @@ import { RuleSnooze, IntervalSchedule, RuleLastRun, + SanitizedRule, } from '../common'; import { PublicAlertFactory } from './alert/create_alert_factory'; import { FieldMap } from '../common/alert_schema/field_maps/types'; @@ -161,6 +162,12 @@ export interface SummarizedAlerts { }; } export type GetSummarizedAlertsFn = (opts: GetSummarizedAlertsFnOpts) => Promise; +export interface GetViewInAppRelativeUrlFnOpts { + rule: Omit, 'viewInAppRelativeUrl'>; +} +export type GetViewInAppRelativeUrlFn = ( + opts: GetViewInAppRelativeUrlFnOpts +) => string; export interface IRuleTypeAlerts { context: string; namespace?: string; @@ -218,6 +225,7 @@ export interface RuleType< * automatically make recovery determination. Defaults to true. */ autoRecoverAlerts?: boolean; + getViewInAppRelativeUrl?: GetViewInAppRelativeUrlFn; } export type UntypedRuleType = RuleType< RuleTypeParams, diff --git a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap index 29ae8156230d72..8a9559fc4f7b9d 100644 --- a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap @@ -92,6 +92,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -146,6 +149,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -200,6 +206,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -254,6 +263,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -308,6 +320,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -362,6 +377,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -416,6 +434,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -470,6 +491,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -524,6 +548,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -578,6 +605,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -632,6 +662,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, @@ -1175,6 +1208,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the }, "version": { "type": "keyword" + }, + "activation_method": { + "type": "keyword" } } }, diff --git a/x-pack/plugins/apm/common/es_fields/__snapshots__/es_fields.test.ts.snap b/x-pack/plugins/apm/common/es_fields/__snapshots__/es_fields.test.ts.snap index 0cb355aaab5729..f39d2e3b2e8081 100644 --- a/x-pack/plugins/apm/common/es_fields/__snapshots__/es_fields.test.ts.snap +++ b/x-pack/plugins/apm/common/es_fields/__snapshots__/es_fields.test.ts.snap @@ -7,6 +7,8 @@ Object { } `; +exports[`Error AGENT_ACTIVATION_METHOD 1`] = `undefined`; + exports[`Error AGENT_NAME 1`] = `"java"`; exports[`Error AGENT_VERSION 1`] = `"agent version"`; @@ -313,6 +315,8 @@ Object { } `; +exports[`Span AGENT_ACTIVATION_METHOD 1`] = `undefined`; + exports[`Span AGENT_NAME 1`] = `"java"`; exports[`Span AGENT_VERSION 1`] = `"agent version"`; @@ -602,6 +606,8 @@ Object { } `; +exports[`Transaction AGENT_ACTIVATION_METHOD 1`] = `undefined`; + exports[`Transaction AGENT_NAME 1`] = `"java"`; exports[`Transaction AGENT_VERSION 1`] = `"agent version"`; diff --git a/x-pack/plugins/apm/common/es_fields/apm.ts b/x-pack/plugins/apm/common/es_fields/apm.ts index e38d805565c48b..4dbcfd1608adc7 100644 --- a/x-pack/plugins/apm/common/es_fields/apm.ts +++ b/x-pack/plugins/apm/common/es_fields/apm.ts @@ -8,6 +8,7 @@ export const TIMESTAMP = 'timestamp.us'; export const AGENT = 'agent'; export const AGENT_NAME = 'agent.name'; export const AGENT_VERSION = 'agent.version'; +export const AGENT_ACTIVATION_METHOD = 'agent.activation_method'; export const DESTINATION_ADDRESS = 'destination.address'; diff --git a/x-pack/plugins/apm/public/components/app/dependencies_inventory/dependencies_inventory_table/index.tsx b/x-pack/plugins/apm/public/components/app/dependencies_inventory/dependencies_inventory_table/index.tsx index 20d92bc5025d6a..c04fb9211d91b2 100644 --- a/x-pack/plugins/apm/public/components/app/dependencies_inventory/dependencies_inventory_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/dependencies_inventory/dependencies_inventory_table/index.tsx @@ -14,7 +14,7 @@ import { getNodeName, NodeType } from '../../../../../common/connections'; import { useApmParams } from '../../../../hooks/use_apm_params'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; -import { DependencyLink } from '../../../shared/dependency_link'; +import { DependencyLink } from '../../../shared/links/dependency_link'; import { DependenciesTable } from '../../../shared/dependencies_table'; export function DependenciesInventoryTable() { diff --git a/x-pack/plugins/apm/public/components/app/dependencies_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/dependencies_inventory/index.tsx index 0e999f7e9aa467..b4ae13619abb00 100644 --- a/x-pack/plugins/apm/public/components/app/dependencies_inventory/index.tsx +++ b/x-pack/plugins/apm/public/components/app/dependencies_inventory/index.tsx @@ -12,7 +12,7 @@ import { kueryBarPlaceholder, } from '../../../../common/dependencies'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { DependenciesInventoryTable } from './dependencies_inventory_table'; export function DependenciesInventory() { diff --git a/x-pack/plugins/apm/public/components/shared/detail_view_header/index.tsx b/x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/detail_view_header/index.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/shared/detail_view_header/index.tsx rename to x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/detail_view_header/index.tsx diff --git a/x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/index.tsx b/x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/index.tsx index 1a43cbda917733..9aeff02dff4f3d 100644 --- a/x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/index.tsx +++ b/x-pack/plugins/apm/public/components/app/dependency_operation_detail_view/index.tsx @@ -17,7 +17,7 @@ import { useDependencyDetailOperationsBreadcrumb } from '../../../hooks/use_depe import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { DependencyMetricCharts } from '../../shared/dependency_metric_charts'; -import { DetailViewHeader } from '../../shared/detail_view_header'; +import { DetailViewHeader } from './detail_view_header'; import { ResettingHeightRetainer } from '../../shared/height_retainer/resetting_height_container'; import { push, replace } from '../../shared/links/url_helpers'; import { SortFunction } from '../../shared/managed_table'; diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx index 9c4db624edb73d..197a24051b2b28 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx @@ -26,7 +26,7 @@ import { usePreferredDataSourceAndBucketSize } from '../../../hooks/use_preferre import { useProgressiveFetcher } from '../../../hooks/use_progressive_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { MLCallout, shouldDisplayMlCallout } from '../../shared/ml_callout'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { isTimeComparison } from '../../shared/time_comparison/get_comparison_options'; import { ServiceList } from './service_list'; import { orderServiceItems } from './service_list/order_service_items'; diff --git a/x-pack/plugins/apm/public/components/app/service_map/index.tsx b/x-pack/plugins/apm/public/components/app/service_map/index.tsx index d1be9af798dd72..bc75102fa7d677 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/index.tsx @@ -29,7 +29,7 @@ import { EmptyPrompt } from './empty_prompt'; import { Popover } from './popover'; import { TimeoutPrompt } from './timeout_prompt'; import { useRefDimensions } from './use_ref_dimensions'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { useServiceName } from '../../../hooks/use_service_name'; import { useApmParams, useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { Environment } from '../../../../common/environment_rt'; diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx index 439adb4c5e413b..ca39fb50fb7b89 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx @@ -16,7 +16,7 @@ import { useApmServiceContext } from '../../../../context/apm_service/use_apm_se import { useApmParams } from '../../../../hooks/use_apm_params'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; -import { DependencyLink } from '../../../shared/dependency_link'; +import { DependencyLink } from '../../../shared/links/dependency_link'; import { DependenciesTable } from '../../../shared/dependencies_table'; import { ServiceLink } from '../../../shared/links/apm/service_link'; diff --git a/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/form_row_suggestions_select.tsx b/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/form_row_suggestions_select.tsx index 41e22ac840bc1e..4c3ed111dd8ff0 100644 --- a/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/form_row_suggestions_select.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/form_row_suggestions_select.tsx @@ -6,7 +6,7 @@ */ import moment from 'moment'; import { EuiDescribedFormGroup, EuiFormRow } from '@elastic/eui'; -import React from 'react'; +import React, { ReactNode } from 'react'; import { i18n } from '@kbn/i18n'; import { SuggestionsSelect } from '../../../../../shared/suggestions_select'; import { @@ -23,6 +23,8 @@ interface Props { allowAll?: boolean; onChange: (value?: string) => void; dataTestSubj?: string; + isInvalid?: boolean; + error?: ReactNode | ReactNode[]; } export function FormRowSuggestionsSelect({ @@ -34,6 +36,8 @@ export function FormRowSuggestionsSelect({ allowAll = true, onChange, dataTestSubj, + isInvalid, + error, }: Props) { return ( {title}} description={description} > - + diff --git a/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/service_page.tsx b/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/service_page.tsx index 31b8ae54a4fc22..617c255c4f96b6 100644 --- a/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/service_page.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/agent_configurations/agent_configuration_create_edit/service_page/service_page.tsx @@ -5,7 +5,13 @@ * 2.0. */ -import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; +import { + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiCallOut, +} from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { isString } from 'lodash'; @@ -14,12 +20,16 @@ import { AgentConfigurationIntake } from '../../../../../../../common/agent_conf import { omitAllOption, getOptionLabel, + ALL_OPTION_VALUE, } from '../../../../../../../common/agent_configuration/all_option'; import { useFetcher, FETCH_STATUS } from '../../../../../../hooks/use_fetcher'; import { FormRowSelect } from './form_row_select'; import { LegacyAPMLink } from '../../../../../shared/links/apm/apm_link'; import { FormRowSuggestionsSelect } from './form_row_suggestions_select'; import { SERVICE_NAME } from '../../../../../../../common/es_fields/apm'; +import { isOpenTelemetryAgentName } from '../../../../../../../common/agent_name'; +import { AgentName } from '../../../../../../../typings/es_schemas/ui/fields/agent'; + interface Props { newConfig: AgentConfigurationIntake; setNewConfig: React.Dispatch>; @@ -81,6 +91,26 @@ export function ServicePage({ newConfig, setNewConfig, onClickNext }: Props) { }) ); + const isAgentConfigurationSupported = + !newConfig.agent_name || + (newConfig.agent_name && + !isOpenTelemetryAgentName(newConfig.agent_name as AgentName)); + + const INCORRECT_SERVICE_NAME_TRANSLATED = i18n.translate( + 'xpack.apm.settings.agentConfiguration.service.otel.error', + { + defaultMessage: + 'Selected service uses an OpenTelemetry agent, which is not supported', + } + ); + + const isAllOptionSelected = newConfig.service.name === ALL_OPTION_VALUE; + const isSaveButtonDisabled = + !newConfig.service.name || + !newConfig.service.environment || + agentNameStatus === FETCH_STATUS.LOADING || + !isAgentConfigurationSupported; + return ( <> {/* Service name options */} @@ -106,7 +136,22 @@ export function ServicePage({ newConfig, setNewConfig, onClickNext }: Props) { })); }} dataTestSubj="serviceNameComboBox" + isInvalid={!isAgentConfigurationSupported} + error={INCORRECT_SERVICE_NAME_TRANSLATED} /> + {isAllOptionSelected && ( + + )} {/* Environment options */} {i18n.translate( 'xpack.apm.agentConfig.saveConfigurationButtonLabel', diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx index 060c8c00da6e7c..98992e97988f58 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/index.tsx @@ -22,7 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; import { IndexLifecyclePhaseSelect } from './index_lifecycle_phase_select'; import { ServicesTable } from './services_table'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { StorageChart } from './storage_chart'; import { PermissionDenied } from './prompts/permission_denied'; import { useFetcher, FETCH_STATUS } from '../../../hooks/use_fetcher'; diff --git a/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx b/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx index 685074155c3801..486a54b4000982 100644 --- a/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/top_traces_overview/index.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { useApmParams } from '../../../hooks/use_apm_params'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { TraceList } from './trace_list'; import { useFallbackToTransactionsFetcher } from '../../../hooks/use_fallback_to_transactions_fetcher'; import { AggregatedTransactionsBadge } from '../../shared/aggregated_transactions_badge'; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/sticky_span_properties.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/sticky_span_properties.tsx index 8866f62ae04544..bb942a735792cb 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/sticky_span_properties.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/sticky_span_properties.tsx @@ -19,7 +19,7 @@ import { NOT_AVAILABLE_LABEL } from '../../../../../../../../common/i18n'; import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { useAnyOfApmParams } from '../../../../../../../hooks/use_apm_params'; -import { DependencyLink } from '../../../../../../shared/dependency_link'; +import { DependencyLink } from '../../../../../../shared/links/dependency_link'; import { TransactionDetailLink } from '../../../../../../shared/links/apm/transaction_detail_link'; import { ServiceLink } from '../../../../../../shared/links/apm/service_link'; import { StickyProperties } from '../../../../../../shared/sticky_properties'; diff --git a/x-pack/plugins/apm/public/components/routing/apm_error_boundary.tsx b/x-pack/plugins/apm/public/components/routing/apm_error_boundary.tsx index 2292b9aa256923..26b641a25896d9 100644 --- a/x-pack/plugins/apm/public/components/routing/apm_error_boundary.tsx +++ b/x-pack/plugins/apm/public/components/routing/apm_error_boundary.tsx @@ -9,9 +9,15 @@ import { EuiErrorBoundary } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import React from 'react'; import { NotFoundPrompt } from '@kbn/shared-ux-prompt-not-found'; +import { useLocation } from 'react-router-dom'; import { ApmPluginStartDeps } from '../../plugin'; -export class ApmErrorBoundary extends React.Component< +export function ApmErrorBoundary({ children }: { children?: React.ReactNode }) { + const location = useLocation(); + return {children}; +} + +class ErrorBoundary extends React.Component< { children?: React.ReactNode }, { error?: Error }, {} diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/alerting_popover_flyout.tsx similarity index 95% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/alerting_popover_flyout.tsx index 115c7019be611b..7b4b56bace9285 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/alerting_popover_flyout.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/alerting_popover_flyout.tsx @@ -14,9 +14,9 @@ import { import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; import { IBasePath } from '@kbn/core/public'; -import { ApmRuleType } from '../../../../common/rules/apm_rule_types'; -import { AlertingFlyout } from '../../alerting/ui_components/alerting_flyout'; -import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; +import { ApmRuleType } from '../../../../../common/rules/apm_rule_types'; +import { AlertingFlyout } from '../../../alerting/ui_components/alerting_flyout'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; const alertLabel = i18n.translate('xpack.apm.home.alertsMenu.alerts', { defaultMessage: 'Alerts and rules', diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.test.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.test.tsx similarity index 91% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.test.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.test.tsx index 4de3536d61593e..5e8a59fc3739c5 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.test.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.test.tsx @@ -9,12 +9,12 @@ import { fireEvent, render, waitFor } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import React from 'react'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -import { ApmMlJob } from '../../../../common/anomaly_detection/apm_ml_job'; -import { getAnomalyDetectionSetupState } from '../../../../common/anomaly_detection/get_anomaly_detection_setup_state'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; -import * as hooks from '../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context'; -import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context'; -import { FETCH_STATUS } from '../../../hooks/use_fetcher'; +import { ApmMlJob } from '../../../../../common/anomaly_detection/apm_ml_job'; +import { getAnomalyDetectionSetupState } from '../../../../../common/anomaly_detection/get_anomaly_detection_setup_state'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; +import * as hooks from '../../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context'; +import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; +import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; import { AnomalyDetectionSetupLink } from './anomaly_detection_setup_link'; async function renderTooltipAnchor({ diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.tsx similarity index 86% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.tsx index 74757fb5fd2c25..e6201c312d0987 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/anomaly_detection_setup_link.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/anomaly_detection_setup_link.tsx @@ -10,16 +10,16 @@ import { IconType } from '@elastic/eui'; import { EuiHeaderLink, EuiIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { AnomalyDetectionSetupState } from '../../../../common/anomaly_detection/get_anomaly_detection_setup_state'; +import { AnomalyDetectionSetupState } from '../../../../../common/anomaly_detection/get_anomaly_detection_setup_state'; import { ENVIRONMENT_ALL, getEnvironmentLabel, -} from '../../../../common/environment_filter_values'; -import { useAnomalyDetectionJobsContext } from '../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context'; -import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; -import { useApmParams } from '../../../hooks/use_apm_params'; -import { useTheme } from '../../../hooks/use_theme'; -import { getLegacyApmHref } from '../links/apm/apm_link'; +} from '../../../../../common/environment_filter_values'; +import { useAnomalyDetectionJobsContext } from '../../../../context/anomaly_detection_jobs/use_anomaly_detection_jobs_context'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { useApmParams } from '../../../../hooks/use_apm_params'; +import { useTheme } from '../../../../hooks/use_theme'; +import { getLegacyApmHref } from '../../../shared/links/apm/apm_link'; export function AnomalyDetectionSetupLink() { const { query } = useApmParams('/*'); diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/index.tsx similarity index 90% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/index.tsx index db5ab8786c23bc..1db19ff3833d9a 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/index.tsx @@ -14,12 +14,12 @@ import { import { apmLabsButton } from '@kbn/observability-plugin/common'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { getAlertingCapabilities } from '../../alerting/utils/get_alerting_capabilities'; -import { getLegacyApmHref } from '../links/apm/apm_link'; -import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; +import { getAlertingCapabilities } from '../../../alerting/utils/get_alerting_capabilities'; +import { getLegacyApmHref } from '../../../shared/links/apm/apm_link'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { AlertingPopoverAndFlyout } from './alerting_popover_flyout'; import { AnomalyDetectionSetupLink } from './anomaly_detection_setup_link'; -import { useServiceName } from '../../../hooks/use_service_name'; +import { useServiceName } from '../../../../hooks/use_service_name'; import { InspectorHeaderLink } from './inspector_header_link'; import { Labs } from './labs'; diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/inspector_header_link.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/inspector_header_link.tsx similarity index 92% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/inspector_header_link.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/inspector_header_link.tsx index c4effa76c854cd..7d4abd62de3348 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/inspector_header_link.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/inspector_header_link.tsx @@ -13,7 +13,7 @@ import { enableInspectEsQueries, useInspectorContext, } from '@kbn/observability-plugin/public'; -import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; export function InspectorHeaderLink() { const { inspector } = useApmPluginContext(); diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/labs/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/labs/index.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/labs/index.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/labs/index.tsx diff --git a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/labs/labs_flyout.tsx b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/labs/labs_flyout.tsx similarity index 94% rename from x-pack/plugins/apm/public/components/shared/apm_header_action_menu/labs/labs_flyout.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/labs/labs_flyout.tsx index 6c5d38d0f1f7de..cda57400b59996 100644 --- a/x-pack/plugins/apm/public/components/shared/apm_header_action_menu/labs/labs_flyout.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/apm_header_action_menu/labs/labs_flyout.tsx @@ -24,9 +24,9 @@ import { import { LazyField } from '@kbn/advanced-settings-plugin/public'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; -import { useApmEditableSettings } from '../../../../hooks/use_apm_editable_settings'; -import { useFetcher, isPending } from '../../../../hooks/use_fetcher'; +import { useApmPluginContext } from '../../../../../context/apm_plugin/use_apm_plugin_context'; +import { useApmEditableSettings } from '../../../../../hooks/use_apm_editable_settings'; +import { useFetcher, isPending } from '../../../../../hooks/use_fetcher'; interface Props { onClose: () => void; diff --git a/x-pack/plugins/apm/public/components/routing/app_root.tsx b/x-pack/plugins/apm/public/components/routing/app_root/index.tsx similarity index 55% rename from x-pack/plugins/apm/public/components/routing/app_root.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/index.tsx index 57fbc70143a97e..d6e2b8065a1977 100644 --- a/x-pack/plugins/apm/public/components/routing/app_root.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/index.tsx @@ -21,26 +21,27 @@ import { euiDarkVars, euiLightVars } from '@kbn/ui-theme'; import React from 'react'; import { Route } from '@kbn/shared-ux-router'; import { DefaultTheme, ThemeProvider } from 'styled-components'; -import { AnomalyDetectionJobsContextProvider } from '../../context/anomaly_detection_jobs/anomaly_detection_jobs_context'; +import { AnomalyDetectionJobsContextProvider } from '../../../context/anomaly_detection_jobs/anomaly_detection_jobs_context'; import { ApmPluginContext, ApmPluginContextValue, -} from '../../context/apm_plugin/apm_plugin_context'; -import { useApmPluginContext } from '../../context/apm_plugin/use_apm_plugin_context'; -import { BreadcrumbsContextProvider } from '../../context/breadcrumbs/context'; -import { LicenseProvider } from '../../context/license/license_context'; -import { TimeRangeIdContextProvider } from '../../context/time_range_id/time_range_id_context'; -import { UrlParamsProvider } from '../../context/url_params_context/url_params_context'; -import { ApmPluginStartDeps } from '../../plugin'; -import { ScrollToTopOnPathChange } from '../app/main/scroll_to_top_on_path_change'; -import { ApmHeaderActionMenu } from '../shared/apm_header_action_menu'; -import { RedirectWithDefaultDateRange } from '../shared/redirect_with_default_date_range'; -import { RedirectWithDefaultEnvironment } from '../shared/redirect_with_default_environment'; -import { RedirectWithOffset } from '../shared/redirect_with_offset'; -import { ApmErrorBoundary } from './apm_error_boundary'; -import { apmRouter } from './apm_route_config'; -import { RedirectDependenciesToDependenciesInventory } from './home/redirect_dependencies_to_dependencies_inventory'; -import { TrackPageview } from './track_pageview'; +} from '../../../context/apm_plugin/apm_plugin_context'; +import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; +import { BreadcrumbsContextProvider } from '../../../context/breadcrumbs/context'; +import { LicenseProvider } from '../../../context/license/license_context'; +import { TimeRangeIdContextProvider } from '../../../context/time_range_id/time_range_id_context'; +import { UrlParamsProvider } from '../../../context/url_params_context/url_params_context'; +import { ApmPluginStartDeps } from '../../../plugin'; +import { ScrollToTopOnPathChange } from './scroll_to_top_on_path_change'; +import { ApmHeaderActionMenu } from './apm_header_action_menu'; +import { RedirectWithDefaultDateRange } from './redirect_with_default_date_range'; +import { RedirectWithDefaultEnvironment } from './redirect_with_default_environment'; +import { RedirectWithOffset } from './redirect_with_offset'; +import { ApmErrorBoundary } from '../apm_error_boundary'; +import { apmRouter } from '../apm_route_config'; +import { RedirectDependenciesToDependenciesInventory } from './redirect_dependencies_to_dependencies_inventory'; +import { TrackPageview } from '../track_pageview'; +import { UpdateExecutionContextOnRouteChange } from './update_execution_context_on_route_change'; const storage = new Storage(localStorage); @@ -73,24 +74,26 @@ export function ApmAppRoot({ - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + + diff --git a/x-pack/plugins/apm/public/components/routing/home/redirect_dependencies_to_dependencies_inventory.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_dependencies_to_dependencies_inventory.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/routing/home/redirect_dependencies_to_dependencies_inventory.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_dependencies_to_dependencies_inventory.tsx diff --git a/x-pack/plugins/apm/public/components/shared/redirect_with_default_date_range/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_date_range/index.tsx similarity index 83% rename from x-pack/plugins/apm/public/components/shared/redirect_with_default_date_range/index.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_date_range/index.tsx index dd8393934d561c..66da40d6490956 100644 --- a/x-pack/plugins/apm/public/components/shared/redirect_with_default_date_range/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_date_range/index.tsx @@ -6,9 +6,9 @@ */ import { ReactElement } from 'react'; import { useLocation } from 'react-router-dom'; -import { useApmRouter } from '../../../hooks/use_apm_router'; -import { useDateRangeRedirect } from '../../../hooks/use_date_range_redirect'; -import { isRouteWithTimeRange } from '../is_route_with_time_range'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { useDateRangeRedirect } from '../../../../hooks/use_date_range_redirect'; +import { isRouteWithTimeRange } from '../../../shared/is_route_with_time_range'; // This is a top-level component that blocks rendering of the routes // if there is no valid date range, and redirects to one if needed. diff --git a/x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.test.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.test.tsx similarity index 92% rename from x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.test.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.test.tsx index fb6dd69128200a..86e641418b7df2 100644 --- a/x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.test.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.test.tsx @@ -10,9 +10,9 @@ import { render } from '@testing-library/react'; import { createMemoryHistory, Location, MemoryHistory } from 'history'; import qs from 'query-string'; import { RedirectWithDefaultEnvironment } from '.'; -import { apmRouter } from '../../routing/apm_route_config'; -import * as useApmPluginContextExports from '../../../context/apm_plugin/use_apm_plugin_context'; -import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; +import { apmRouter } from '../../apm_route_config'; +import * as useApmPluginContextExports from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; describe('RedirectWithDefaultEnvironment', () => { let history: MemoryHistory; diff --git a/x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.tsx similarity index 92% rename from x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.tsx index 860b8f5df230b6..54997abf35dcc4 100644 --- a/x-pack/plugins/apm/public/components/shared/redirect_with_default_environment/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_default_environment/index.tsx @@ -8,7 +8,7 @@ import { useLocation, Redirect } from 'react-router-dom'; import qs from 'query-string'; import React from 'react'; -import { useDefaultEnvironment } from '../../../hooks/use_default_environment'; +import { useDefaultEnvironment } from '../../../../hooks/use_default_environment'; export function RedirectWithDefaultEnvironment({ children, diff --git a/x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.test.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.test.tsx similarity index 94% rename from x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.test.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.test.tsx index 2a04856a7a1c40..1d099584e8cbc5 100644 --- a/x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.test.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.test.tsx @@ -10,9 +10,9 @@ import { render } from '@testing-library/react'; import { createMemoryHistory, Location, MemoryHistory } from 'history'; import qs from 'query-string'; import { RedirectWithOffset } from '.'; -import { apmRouter } from '../../routing/apm_route_config'; -import * as useApmPluginContextExports from '../../../context/apm_plugin/use_apm_plugin_context'; -import { TimeRangeComparisonEnum } from '../time_comparison/get_comparison_options'; +import { apmRouter } from '../../apm_route_config'; +import * as useApmPluginContextExports from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { TimeRangeComparisonEnum } from '../../../shared/time_comparison/get_comparison_options'; describe('RedirectWithOffset', () => { let history: MemoryHistory; diff --git a/x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.tsx similarity index 77% rename from x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.tsx index 268735128659da..3c9a92b3c84020 100644 --- a/x-pack/plugins/apm/public/components/shared/redirect_with_offset/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/redirect_with_offset/index.tsx @@ -8,16 +8,16 @@ import { useLocation } from 'react-router-dom'; import qs from 'query-string'; import React from 'react'; -import { useApmRouter } from '../../../hooks/use_apm_router'; -import { isRouteWithComparison } from '../is_route_with_time_range'; +import { useApmRouter } from '../../../../hooks/use_apm_router'; +import { isRouteWithComparison } from '../../../shared/is_route_with_time_range'; import { TimeRangeComparisonEnum, dayAndWeekBeforeToOffset, -} from '../time_comparison/get_comparison_options'; -import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; -import { getComparisonEnabled } from '../time_comparison/get_comparison_enabled'; -import { toBoolean } from '../../../context/url_params_context/helpers'; -import { RenderRedirectTo } from '../../routing/redirect_to'; +} from '../../../shared/time_comparison/get_comparison_options'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; +import { getComparisonEnabled } from '../../../shared/time_comparison/get_comparison_enabled'; +import { toBoolean } from '../../../../context/url_params_context/helpers'; +import { RenderRedirectTo } from '../../redirect_to'; export function RedirectWithOffset({ children, diff --git a/x-pack/plugins/apm/public/components/app/main/scroll_to_top_on_path_change.tsx b/x-pack/plugins/apm/public/components/routing/app_root/scroll_to_top_on_path_change.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/app/main/scroll_to_top_on_path_change.tsx rename to x-pack/plugins/apm/public/components/routing/app_root/scroll_to_top_on_path_change.tsx diff --git a/x-pack/plugins/apm/public/components/routing/app_root/update_execution_context_on_route_change.ts b/x-pack/plugins/apm/public/components/routing/app_root/update_execution_context_on_route_change.ts new file mode 100644 index 00000000000000..d264e72685dc12 --- /dev/null +++ b/x-pack/plugins/apm/public/components/routing/app_root/update_execution_context_on_route_change.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; +import { useMatchRoutes } from '@kbn/typed-react-router-config'; +import { last } from 'lodash'; +import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context'; + +export function UpdateExecutionContextOnRouteChange({ + children, +}: { + children: React.ReactElement; +}) { + const { core } = useApmPluginContext(); + const lastMatch = last(useMatchRoutes()); + + useExecutionContext(core.executionContext, { + type: 'application', + name: 'apm', + page: lastMatch?.match?.path, + }); + + return children; +} diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index 02929c63e2e597..156ebac930dbd2 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -40,7 +40,7 @@ import { useTimeRange } from '../../../../hooks/use_time_range'; import { getAlertingCapabilities } from '../../../alerting/utils/get_alerting_capabilities'; import { BetaBadge } from '../../../shared/beta_badge'; import { replace } from '../../../shared/links/url_helpers'; -import { SearchBar } from '../../../shared/search_bar'; +import { SearchBar } from '../../../shared/search_bar/search_bar'; import { ServiceIcons } from '../../../shared/service_icons'; import { TechnicalPreviewBadge } from '../../../shared/technical_preview_badge'; import { ApmMainTemplate } from '../apm_main_template'; diff --git a/x-pack/plugins/apm/public/components/routing/templates/dependency_detail_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/dependency_detail_template.tsx index 605936dd57944f..7b57dbade22168 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/dependency_detail_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/dependency_detail_template.tsx @@ -18,7 +18,7 @@ import { useApmRoutePath } from '../../../hooks/use_apm_route_path'; import { useFetcher } from '../../../hooks/use_fetcher'; import { useTimeRange } from '../../../hooks/use_time_range'; import { BetaBadge } from '../../shared/beta_badge'; -import { SearchBar } from '../../shared/search_bar'; +import { SearchBar } from '../../shared/search_bar/search_bar'; import { SpanIcon } from '../../shared/span_icon'; import { ApmMainTemplate } from './apm_main_template'; diff --git a/x-pack/plugins/apm/public/components/shared/dependency_link.stories.tsx b/x-pack/plugins/apm/public/components/shared/links/dependency_link.stories.tsx similarity index 91% rename from x-pack/plugins/apm/public/components/shared/dependency_link.stories.tsx rename to x-pack/plugins/apm/public/components/shared/links/dependency_link.stories.tsx index e4652caed9dddf..b240cafb20ed26 100644 --- a/x-pack/plugins/apm/public/components/shared/dependency_link.stories.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/dependency_link.stories.tsx @@ -7,7 +7,7 @@ import { Story } from '@storybook/react'; import React, { ComponentProps, ComponentType } from 'react'; -import { MockApmPluginStorybook } from '../../context/apm_plugin/mock_apm_plugin_storybook'; +import { MockApmPluginStorybook } from '../../../context/apm_plugin/mock_apm_plugin_storybook'; import { DependencyLink } from './dependency_link'; type Args = ComponentProps; diff --git a/x-pack/plugins/apm/public/components/shared/dependency_link.test.tsx b/x-pack/plugins/apm/public/components/shared/links/dependency_link.test.tsx similarity index 100% rename from x-pack/plugins/apm/public/components/shared/dependency_link.test.tsx rename to x-pack/plugins/apm/public/components/shared/links/dependency_link.test.tsx diff --git a/x-pack/plugins/apm/public/components/shared/dependency_link.tsx b/x-pack/plugins/apm/public/components/shared/links/dependency_link.tsx similarity index 86% rename from x-pack/plugins/apm/public/components/shared/dependency_link.tsx rename to x-pack/plugins/apm/public/components/shared/links/dependency_link.tsx index 77901974e81d29..824e08752e0952 100644 --- a/x-pack/plugins/apm/public/components/shared/dependency_link.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/dependency_link.tsx @@ -9,10 +9,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import { TypeOf } from '@kbn/typed-react-router-config'; import React from 'react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { useApmRouter } from '../../hooks/use_apm_router'; -import { truncate } from '../../utils/style'; -import { ApmRoutes } from '../routing/apm_route_config'; -import { SpanIcon } from './span_icon'; +import { useApmRouter } from '../../../hooks/use_apm_router'; +import { truncate } from '../../../utils/style'; +import { ApmRoutes } from '../../routing/apm_route_config'; +import { SpanIcon } from '../span_icon'; const StyledLink = euiStyled(EuiLink)`${truncate('100%')};`; diff --git a/x-pack/plugins/apm/public/components/shared/metadata_table/helper.ts b/x-pack/plugins/apm/public/components/shared/metadata_table/helper.ts index c9e0f2aa66745f..67e2d2b85500b2 100644 --- a/x-pack/plugins/apm/public/components/shared/metadata_table/helper.ts +++ b/x-pack/plugins/apm/public/components/shared/metadata_table/helper.ts @@ -43,7 +43,7 @@ export const getSectionsFromFields = (fields: Record) => { const [labelSections, otherSections] = partition( sections, - (section) => section.key === 'labels' + (section) => section.key === 'labels' || section.key === 'numeric_labels' ); return [...labelSections, ...otherSections]; diff --git a/x-pack/plugins/apm/public/components/shared/metadata_table/metadata_table.test.tsx b/x-pack/plugins/apm/public/components/shared/metadata_table/metadata_table.test.tsx index 084729a08146dc..f973879c7029fd 100644 --- a/x-pack/plugins/apm/public/components/shared/metadata_table/metadata_table.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/metadata_table/metadata_table.test.tsx @@ -28,11 +28,10 @@ const renderOptions = { describe('MetadataTable', () => { it('shows sections', () => { const sections: SectionDescriptor[] = [ - { key: 'foo', label: 'Foo', required: true, properties: [] }, + { key: 'foo', label: 'Foo', properties: [] }, { key: 'bar', label: 'Bar', - required: false, properties: [ { field: 'props.A', value: ['A'] }, { field: 'props.B', value: ['B'] }, @@ -59,7 +58,6 @@ describe('MetadataTable', () => { { key: 'foo', label: 'Foo', - required: true, properties: [], }, ]; diff --git a/x-pack/plugins/apm/public/components/shared/metadata_table/types.ts b/x-pack/plugins/apm/public/components/shared/metadata_table/types.ts index 3ce7698460f301..fc08f3de24614c 100644 --- a/x-pack/plugins/apm/public/components/shared/metadata_table/types.ts +++ b/x-pack/plugins/apm/public/components/shared/metadata_table/types.ts @@ -8,6 +8,5 @@ export interface SectionDescriptor { key: string; label: string; - required?: boolean; properties: Array<{ field: string; value: string[] | number[] }>; } diff --git a/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx similarity index 84% rename from x-pack/plugins/apm/public/components/shared/search_bar.test.tsx rename to x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx index 1fb1e15a26ee6c..f07fc415eaf7da 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.test.tsx @@ -10,15 +10,15 @@ import { createMemoryHistory, MemoryHistory } from 'history'; import React from 'react'; import { Router } from 'react-router-dom'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { MockApmPluginContextWrapper } from '../../context/apm_plugin/mock_apm_plugin_context'; -import { ApmServiceContextProvider } from '../../context/apm_service/apm_service_context'; -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'; +import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context'; +import { ApmServiceContextProvider } from '../../../context/apm_service/apm_service_context'; +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'; import { CoreStart } from '@kbn/core/public'; import { SearchBar } from './search_bar'; diff --git a/x-pack/plugins/apm/public/components/shared/search_bar.tsx b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx similarity index 85% rename from x-pack/plugins/apm/public/components/shared/search_bar.tsx rename to x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx index 1a46ca2e875685..edff90281b9ec7 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx @@ -13,13 +13,13 @@ import { EuiSpacer, } from '@elastic/eui'; import React from 'react'; -import { isMobileAgentName } from '../../../common/agent_name'; -import { useApmServiceContext } from '../../context/apm_service/use_apm_service_context'; -import { useBreakpoints } from '../../hooks/use_breakpoints'; -import { ApmDatePicker } from './date_picker/apm_date_picker'; -import { KueryBar } from './kuery_bar'; -import { TimeComparison } from './time_comparison'; -import { TransactionTypeSelect } from './transaction_type_select'; +import { isMobileAgentName } from '../../../../common/agent_name'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; +import { useBreakpoints } from '../../../hooks/use_breakpoints'; +import { ApmDatePicker } from '../date_picker/apm_date_picker'; +import { KueryBar } from '../kuery_bar'; +import { TimeComparison } from '../time_comparison'; +import { TransactionTypeSelect } from '../transaction_type_select'; interface Props { hidden?: boolean; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index 88cbcdc842d110..0c4f7b46e84545 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -12,6 +12,7 @@ import { flatten, merge, pickBy, sortBy, sum, uniq } from 'lodash'; import { SavedObjectsClient } from '@kbn/core/server'; import { AGENT_NAMES, RUM_AGENT_NAMES } from '../../../../common/agent_name'; import { + AGENT_ACTIVATION_METHOD, AGENT_NAME, AGENT_VERSION, CLIENT_GEO_COUNTRY_ISO_CODE, @@ -858,6 +859,12 @@ export const tasks: TelemetryTask[] = [ '@timestamp': 'desc', }, aggs: { + [AGENT_ACTIVATION_METHOD]: { + terms: { + field: AGENT_ACTIVATION_METHOD, + size, + }, + }, [AGENT_VERSION]: { terms: { field: AGENT_VERSION, @@ -943,6 +950,9 @@ export const tasks: TelemetryTask[] = [ ...data, [agentName]: { agent: { + activation_method: aggregations[AGENT_ACTIVATION_METHOD].buckets + .map((bucket) => bucket.key as string) + .slice(0, size), version: aggregations[AGENT_VERSION].buckets.map( (bucket) => bucket.key as string ), @@ -1278,6 +1288,9 @@ export const tasks: TelemetryTask[] = [ top_metrics: { sort: '_score', metrics: [ + { + field: AGENT_ACTIVATION_METHOD, + }, { field: AGENT_NAME, }, @@ -1382,6 +1395,9 @@ export const tasks: TelemetryTask[] = [ }, agent: { name: envBucket.top_metrics?.top[0].metrics[AGENT_NAME] as string, + activation_method: envBucket.top_metrics?.top[0].metrics[ + AGENT_ACTIVATION_METHOD + ] as string, version: envBucket.top_metrics?.top[0].metrics[ AGENT_VERSION ] as string, diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts index 11b8d34da19ad4..5156345dbafeb8 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts @@ -42,6 +42,7 @@ const timeframeMapSchema: MakeSchemaFrom = { const agentSchema: MakeSchemaFrom['agents'][ElasticAgentName] = { agent: { version: { type: 'array', items: { type: 'keyword' } }, + activation_method: { type: 'array', items: { type: 'keyword' } }, }, service: { framework: { @@ -134,6 +135,7 @@ export const apmPerServiceSchema: MakeSchemaFrom = { agent: { name: keyword, version: keyword, + activation_method: keyword, }, service: { language: { diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts index 54f0963dfbb627..f7f3f07fca4570 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts @@ -42,6 +42,7 @@ export interface APMPerService { agent: { name: string; version: string; + activation_method: string; }; service: { language: { @@ -137,6 +138,7 @@ export interface APMUsage { { agent: { version: string[]; + activation_method: string[]; }; service: { framework: { diff --git a/x-pack/plugins/apm/server/routes/fleet/get_package_policy_decorators.ts b/x-pack/plugins/apm/server/routes/fleet/get_package_policy_decorators.ts index 577d83dc765ca0..39d02e95b6109f 100644 --- a/x-pack/plugins/apm/server/routes/fleet/get_package_policy_decorators.ts +++ b/x-pack/plugins/apm/server/routes/fleet/get_package_policy_decorators.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { cloneDeep, get, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep, get } from 'lodash'; import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { AgentConfiguration } from '../../../common/agent_configuration/configuration_types'; import { AGENT_NAME } from '../../../common/es_fields/apm'; diff --git a/x-pack/plugins/apm/tsconfig.json b/x-pack/plugins/apm/tsconfig.json index b1bb6362af1a95..4fc45adafd44d5 100644 --- a/x-pack/plugins/apm/tsconfig.json +++ b/x-pack/plugins/apm/tsconfig.json @@ -78,6 +78,7 @@ "@kbn/core-elasticsearch-server", "@kbn/shared-ux-prompt-not-found", "@kbn/core-saved-objects-api-server", + "@kbn/safer-lodash-set", "@kbn/shared-ux-router", ], "exclude": [ diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/extended_template.tsx b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/extended_template.tsx index af74acc622789f..2e7007e8d2551a 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/extended_template.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/extended_template.tsx @@ -25,7 +25,7 @@ import { EuiText, } from '@elastic/eui'; import { ExpressionAstExpression } from '@kbn/expressions-plugin/common'; -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { defaultExpression } from './default_expression'; import { Fields } from './types'; import { getFieldPath, getFieldValue } from './utils'; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/simple_template.tsx b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/simple_template.tsx index 53d9b3e2d41462..08e27fbcd0988c 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/simple_template.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/partition_labels/simple_template.tsx @@ -9,7 +9,7 @@ import React, { FunctionComponent, useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import { EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; import { ExpressionAstExpression } from '@kbn/expressions-plugin/common'; -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { defaultExpression } from './default_expression'; import { getFieldPath, getFieldValue } from './utils'; diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index 0ac0dd279560bb..e92c8277488caf 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -38,7 +38,7 @@ export const AddEmbeddableFlyout: FC = ({ const embeddablesService = useEmbeddablesService(); const platformService = usePlatformService(); const { getEmbeddableFactories } = embeddablesService; - const { getSavedObjects, getUISettings } = platformService; + const { getHttp, getUISettings } = platformService; const onAddPanel = useCallback( (id: string, savedObjectType: string) => { @@ -82,8 +82,8 @@ export const AddEmbeddableFlyout: FC = ({ savedObjectMetaData={availableSavedObjects} showFilter={true} noItemsMessage={strings.getNoItemsText()} - savedObjects={getSavedObjects()} uiSettings={getUISettings()} + http={getHttp()} /> diff --git a/x-pack/plugins/canvas/public/services/kibana/platform.ts b/x-pack/plugins/canvas/public/services/kibana/platform.ts index 8a6ea957ab97c7..0b51963eeee31f 100644 --- a/x-pack/plugins/canvas/public/services/kibana/platform.ts +++ b/x-pack/plugins/canvas/public/services/kibana/platform.ts @@ -45,5 +45,6 @@ export const platformServiceFactory: CanvaPlatformServiceFactory = ({ getSavedObjects: () => coreStart.savedObjects, getSavedObjectsClient: () => coreStart.savedObjects.client, getUISettings: () => coreStart.uiSettings, + getHttp: () => coreStart.http, }; }; diff --git a/x-pack/plugins/canvas/public/services/platform.ts b/x-pack/plugins/canvas/public/services/platform.ts index 613c89770e6e86..b436f51bb33f94 100644 --- a/x-pack/plugins/canvas/public/services/platform.ts +++ b/x-pack/plugins/canvas/public/services/platform.ts @@ -13,6 +13,7 @@ import { ChromeBreadcrumb, IBasePath, ChromeStart, + HttpStart, } from '@kbn/core/public'; import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; @@ -37,4 +38,5 @@ export interface CanvasPlatformService { getSavedObjects: () => SavedObjectsStart; getSavedObjectsClient: () => SavedObjectsClientContract; getUISettings: () => IUiSettingsClient; + getHttp: () => HttpStart; } diff --git a/x-pack/plugins/canvas/public/services/stubs/platform.ts b/x-pack/plugins/canvas/public/services/stubs/platform.ts index 6a0b1220699350..d96599257f9b65 100644 --- a/x-pack/plugins/canvas/public/services/stubs/platform.ts +++ b/x-pack/plugins/canvas/public/services/stubs/platform.ts @@ -36,4 +36,5 @@ export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({ setFullscreen: noop, redirectLegacyUrl: noop, getLegacyUrlConflict: undefined, + getHttp: noop, }); diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts index 489ee28a26cd66..8ca2c23c1eb8df 100644 --- a/x-pack/plugins/cases/common/index.ts +++ b/x-pack/plugins/cases/common/index.ts @@ -16,6 +16,7 @@ // See: https://docs.elastic.dev/kibana-dev-docs/key-concepts/platform-intro#public-plugin-api export { + APP_ID, CASES_URL, SECURITY_SOLUTION_OWNER, OBSERVABILITY_OWNER, @@ -25,6 +26,7 @@ export { PUSH_CASES_CAPABILITY, READ_CASES_CAPABILITY, UPDATE_CASES_CAPABILITY, + INTERNAL_BULK_GET_CASES_URL, } from './constants'; export { @@ -35,6 +37,12 @@ export { ExternalReferenceStorageType, } from './api'; +export type { + CaseResponse, + CasesBulkGetRequestCertainFields, + CasesBulkGetResponseCertainFields, +} from './api'; + export type { Case, Ecs, diff --git a/x-pack/plugins/cases/common/utils/markdown_plugins/utils.ts b/x-pack/plugins/cases/common/utils/markdown_plugins/utils.ts index 0d25bbd3a2765a..0790c7fef79473 100644 --- a/x-pack/plugins/cases/common/utils/markdown_plugins/utils.ts +++ b/x-pack/plugins/cases/common/utils/markdown_plugins/utils.ts @@ -7,7 +7,7 @@ import { filter } from 'lodash'; import type { Node } from 'unist'; -import markdown from 'remark-parse'; +import markdown from 'remark-parse-no-trim'; import remarkStringify from 'remark-stringify'; import unified from 'unified'; diff --git a/x-pack/plugins/cases/public/api/utils.ts b/x-pack/plugins/cases/public/api/utils.ts index 87b48a0df9c58f..f7ce3bf0817d2e 100644 --- a/x-pack/plugins/cases/public/api/utils.ts +++ b/x-pack/plugins/cases/public/api/utils.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { isArray, set, camelCase, isObject, omit, get } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { isArray, camelCase, isObject, omit, get } from 'lodash'; import { isCommentRequestTypeExternalReference, isCommentRequestTypePersistableState, diff --git a/x-pack/plugins/cases/public/common/mock/connectors.ts b/x-pack/plugins/cases/public/common/mock/connectors.ts index a036b5a6b89816..4d733c4e660a84 100644 --- a/x-pack/plugins/cases/public/common/mock/connectors.ts +++ b/x-pack/plugins/cases/public/common/mock/connectors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import type { ActionConnector, ActionTypeConnector } from '../../../common/api'; import { basicPush } from '../../containers/mock'; import type { CaseConnectors } from '../../containers/types'; diff --git a/x-pack/plugins/cases/public/containers/api.test.tsx b/x-pack/plugins/cases/public/containers/api.test.tsx index 2f0c8645b3317b..546fcb921b2709 100644 --- a/x-pack/plugins/cases/public/containers/api.test.tsx +++ b/x-pack/plugins/cases/public/containers/api.test.tsx @@ -62,7 +62,8 @@ import { import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases'; import { getCasesStatus } from '../api'; import { getCaseConnectorsMockResponse } from '../common/mock/connectors'; -import { cloneDeep, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep } from 'lodash'; const abortCtrl = new AbortController(); const mockKibanaServices = KibanaServices.get as jest.Mock; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts index 70cf3296751267..a9c329d4e85b98 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts @@ -10,7 +10,8 @@ import type { SavedObjectMigrationContext, SavedObjectsMigrationLogger, } from '@kbn/core/server'; -import { cloneDeep, omit, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep, omit } from 'lodash'; import { migrationMocks } from '@kbn/core/server/mocks'; import { removeRuleInformation } from './alerts'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx b/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx index cb3d0c3527c575..2db04c6f6ebff8 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/csp_counter_card.tsx @@ -18,6 +18,17 @@ export interface CspCounterCardProps { description: EuiStatProps['description']; } +// Todo: remove when EuiIcon type="pivot" is available +const PivotIcon = ({ ...props }) => ( + + + +); + export const CspCounterCard = (counter: CspCounterCardProps) => { const { euiTheme } = useEuiTheme(); @@ -46,6 +57,7 @@ export const CspCounterCard = (counter: CspCounterCardProps) => { justifyContent: 'space-around', '.euiText h6': { textTransform: 'capitalize', + fontSize: euiTheme.size.m, }, }} titleSize="s" @@ -56,8 +68,10 @@ export const CspCounterCard = (counter: CspCounterCardProps) => { /> {counter.onClick && ( - - + > + + + + + + ); diff --git a/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts b/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts index 5702cc79eba8ac..93ea23a4e5b1e4 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { errors } from '@elastic/elasticsearch'; +import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; import { BENCHMARK_SCORE_INDEX_DEFAULT_NS, BENCHMARK_SCORE_INDEX_PATTERN, @@ -107,7 +108,21 @@ const createLatestFindingsIndex = async (esClient: ElasticsearchClient, logger: composed_of, }); - await createIndexSafe(esClient, logger, LATEST_FINDINGS_INDEX_DEFAULT_NS); + const result = await createIndexSafe(esClient, logger, LATEST_FINDINGS_INDEX_DEFAULT_NS); + + if (result === 'already-exists') { + // Make sure mappings are up-to-date + const simulateResponse = await esClient.indices.simulateTemplate({ + name: LATEST_FINDINGS_INDEX_TEMPLATE_NAME, + }); + + await updateIndexSafe( + esClient, + logger, + LATEST_FINDINGS_INDEX_DEFAULT_NS, + simulateResponse.template.mappings + ); + } } catch (e) { logger.error( `Failed to upsert index template [Template: ${LATEST_FINDINGS_INDEX_TEMPLATE_NAME}]` @@ -155,11 +170,32 @@ const createIndexSafe = async (esClient: ElasticsearchClient, logger: Logger, in }); logger.info(`Created index successfully [Name: ${index}]`); + return 'success'; } else { logger.trace(`Index already exists [Name: ${index}]`); + return 'already-exists'; } } catch (e) { logger.error(`Failed to create index [Name: ${index}]`); logger.error(e); + return 'fail'; + } +}; + +const updateIndexSafe = async ( + esClient: ElasticsearchClient, + logger: Logger, + index: string, + mappings: MappingTypeMapping +) => { + try { + await esClient.indices.putMapping({ + index, + properties: mappings.properties, + }); + logger.info(`Updated index successfully [Name: ${index}]`); + } catch (e) { + logger.error(`Failed to update index [Name: ${index}]`); + logger.error(e); } }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/api/add_analytics_collection/add_analytics_collection_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/api/add_analytics_collection/add_analytics_collection_api_logic.ts index 6b5e17b188d0fe..2aee9c0feb26bc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/api/add_analytics_collection/add_analytics_collection_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/api/add_analytics_collection/add_analytics_collection_api_logic.ts @@ -30,5 +30,6 @@ export const createAnalyticsCollection = async ({ export const AddAnalyticsCollectionsAPILogic = createApiLogic( ['analytics', 'add_analytics_collections_api_logic'], - createAnalyticsCollection + createAnalyticsCollection, + { showErrorFlash: false } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.test.tsx index f635b0699e0bbb..fed4e0d539d8f3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.test.tsx @@ -11,8 +11,10 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { EuiButton } from '@elastic/eui'; + import { AddAnalyticsCollection } from './add_analytics_collection'; -import { AddAnalyticsCollectionForm } from './add_analytics_collection_form'; +import { AddAnalyticsCollectionModal } from './add_analytics_collection_modal'; describe('AddAnalyticsCollection', () => { beforeEach(() => { @@ -21,6 +23,15 @@ describe('AddAnalyticsCollection', () => { it('renders', () => { const wrapper = shallow(); - expect(wrapper.find(AddAnalyticsCollectionForm)).toHaveLength(1); + + expect(wrapper.find(EuiButton)).toHaveLength(1); + expect(wrapper.find(AddAnalyticsCollectionModal)).toHaveLength(0); + }); + + it('show render modal after click on button', () => { + const wrapper = shallow(); + + (wrapper.find(EuiButton).prop('onClick') as Function)?.(); + expect(wrapper.find(AddAnalyticsCollectionModal)).toHaveLength(1); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.tsx index 0a6a7891a782a4..52fe8ed486dbb8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection.tsx @@ -5,28 +5,27 @@ * 2.0. */ -import React from 'react'; +import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; - -import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; +import { EuiButton } from '@elastic/eui'; -import { AddAnalyticsCollectionForm } from './add_analytics_collection_form'; +import { i18n } from '@kbn/i18n'; -export const collectionsCreateBreadcrumbs = [ - i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.breadcrumb', { - defaultMessage: 'Create collection', - }), -]; +import { AddAnalyticsCollectionModal } from './add_analytics_collection_modal'; export const AddAnalyticsCollection: React.FC = () => { + const [isModalVisible, setIsModalVisible] = useState(false); + const closeModal = () => setIsModalVisible(false); + const showModal = () => setIsModalVisible(true); + return ( - - - + <> + + {i18n.translate('xpack.enterpriseSearch.analytics.collections.create.buttonTitle', { + defaultMessage: 'Create collection', + })} + + {isModalVisible && } + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.test.tsx index 3bf3cf0d4f7214..0f8d3a66c66cf7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.test.tsx @@ -7,19 +7,18 @@ import '../../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, setMockActions, mockKibanaValues } from '../../../__mocks__/kea_logic'; +import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic'; import React from 'react'; import { shallow } from 'enzyme'; -import { EuiButtonEmpty, EuiFieldText, EuiForm } from '@elastic/eui'; +import { EuiFieldText, EuiForm, EuiFormRow } from '@elastic/eui'; import { AddAnalyticsCollectionForm } from './add_analytics_collection_form'; const mockValues = { canSubmit: true, - hasInputError: false, inputError: false, isLoading: false, name: 'test', @@ -31,7 +30,8 @@ const mockActions = { }; describe('AddAnalyticsCollectionForm', () => { - const { navigateToUrl } = mockKibanaValues; + const formId = 'addAnalyticsCollectionFormId'; + const collectionNameField = 'collectionNameField'; beforeEach(() => { jest.clearAllMocks(); @@ -41,25 +41,19 @@ describe('AddAnalyticsCollectionForm', () => { setMockValues(mockValues); setMockActions(mockActions); - const wrapper = shallow(); + const wrapper = shallow( + + ); expect(wrapper.find(EuiForm)).toHaveLength(1); }); - it('navigates back to root when cancel is clicked', () => { - setMockValues(mockValues); - setMockActions(mockActions); - - const wrapper = shallow(); - - wrapper.find(EuiButtonEmpty).simulate('click'); - expect(navigateToUrl).toHaveBeenCalledWith('/'); - }); - it('submit form will call create analytics collection action', () => { setMockValues(mockValues); setMockActions(mockActions); - const wrapper = shallow(); + const wrapper = shallow( + + ); wrapper.find(EuiForm).simulate('submit', { preventDefault: jest.fn() }); expect(mockActions.createAnalyticsCollection).toHaveBeenCalled(); @@ -69,11 +63,12 @@ describe('AddAnalyticsCollectionForm', () => { setMockValues({ ...mockValues, canSubmit: false, - hasInputError: true, }); setMockActions(mockActions); - const wrapper = shallow(); + const wrapper = shallow( + + ); wrapper.find(EuiForm).simulate('submit', { preventDefault: jest.fn() }); expect(mockActions.createAnalyticsCollection).not.toHaveBeenCalled(); @@ -83,9 +78,27 @@ describe('AddAnalyticsCollectionForm', () => { setMockValues(mockValues); setMockActions(mockActions); - const wrapper = shallow(); + const wrapper = shallow( + + ); wrapper.find(EuiFieldText).simulate('change', { target: { value: 'test' } }); expect(mockActions.setNameValue).toHaveBeenCalledWith('test'); }); + + it('should show error when input error exists', () => { + const inputErrorMock = 'Already exists'; + setMockValues({ + ...mockValues, + inputError: inputErrorMock, + }); + setMockActions(mockActions); + + const wrapper = shallow( + + ); + expect(wrapper.find(EuiFormRow).prop('error')).toEqual(inputErrorMock); + expect(wrapper.find(EuiFormRow).prop('isInvalid')).toBeTruthy(); + expect(wrapper.find(EuiFieldText).prop('isInvalid')).toBeTruthy(); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.tsx index 86356275f5a3ba..baa0430150c091 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_form.tsx @@ -9,103 +9,54 @@ import React from 'react'; import { useActions, useValues } from 'kea'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiTitle, - EuiSpacer, - EuiText, - EuiButtonEmpty, - EuiFormRow, - EuiFieldText, - EuiForm, - EuiButton, -} from '@elastic/eui'; +import { EuiFormRow, EuiFieldText, EuiForm } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { KibanaLogic } from '../../../shared/kibana'; -import { ROOT_PATH } from '../../routes'; - import { AddAnalyticsCollectionLogic } from './add_analytics_collection_logic'; -export const AddAnalyticsCollectionForm = () => { +interface AddAnalyticsCollectionForm { + collectionNameField: string; + formId: string; +} + +export const AddAnalyticsCollectionForm: React.FC = ({ + formId, + collectionNameField, +}) => { const { createAnalyticsCollection, setNameValue } = useActions(AddAnalyticsCollectionLogic); - const { name, isLoading, canSubmit } = useValues(AddAnalyticsCollectionLogic); - const { navigateToUrl } = useValues(KibanaLogic); + const { name, isLoading, canSubmit, inputError } = useValues(AddAnalyticsCollectionLogic); return ( - - - - -

- {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.title', { - defaultMessage: 'Create an analytics collection', - })} -

-
- - -

- {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.subtitle', { - defaultMessage: - 'An analytics collection provides a place to store the analytics events for any given search application you are building. Give it a memorable name below.', - })} -

-
- - { - e.preventDefault(); - if (canSubmit) { - createAnalyticsCollection(); - } - }} - > - - { - setNameValue(e.target.value); - }} - /> - - - - - { - navigateToUrl(ROOT_PATH); - }} - > - {i18n.translate( - 'xpack.enterpriseSearch.analytics.collectionsCreate.form.cancelButton', - { - defaultMessage: 'Cancel', - } - )} - - - - - {i18n.translate( - 'xpack.enterpriseSearch.analytics.collectionsCreate.form.continueButton', - { - defaultMessage: 'Continue', - } - )} - - - - -
-
-
+ { + e.preventDefault(); + if (canSubmit) { + createAnalyticsCollection(); + } + }} + > + + { + setNameValue(e.target.value); + }} + /> + + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts index 3c313c895adbb8..16e77b0ae84e14 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.test.ts @@ -8,6 +8,7 @@ import { LogicMounter, mockFlashMessageHelpers, + mockFlashMessagesActions, mockHttpValues, mockKibanaValues, } from '../../../__mocks__/kea_logic'; @@ -22,6 +23,7 @@ import { AddAnalyticsCollectionLogic } from './add_analytics_collection_logic'; describe('addAnalyticsCollectionLogic', () => { const { mount } = new LogicMounter(AddAnalyticsCollectionLogic); const { flashSuccessToast, flashAPIErrors } = mockFlashMessageHelpers; + const { setFlashMessages } = mockFlashMessagesActions; const { http } = mockHttpValues; beforeEach(() => { @@ -32,7 +34,11 @@ describe('addAnalyticsCollectionLogic', () => { it('has expected default values', () => { expect(AddAnalyticsCollectionLogic.values).toEqual({ canSubmit: false, + error: undefined, + inputError: null, isLoading: false, + isSuccess: false, + isSystemError: false, name: '', status: Status.IDLE, }); @@ -42,12 +48,14 @@ describe('addAnalyticsCollectionLogic', () => { describe('setNameValue', () => { it('should set name', () => { AddAnalyticsCollectionLogic.actions.setNameValue('valid'); - expect(AddAnalyticsCollectionLogic.values).toEqual({ - canSubmit: true, - isLoading: false, - name: 'valid', - status: Status.IDLE, - }); + expect(AddAnalyticsCollectionLogic.values.name).toEqual('valid'); + }); + }); + + describe('setInputError', () => { + it('should set error', () => { + AddAnalyticsCollectionLogic.actions.setInputError('invalid name'); + expect(AddAnalyticsCollectionLogic.values.inputError).toEqual('invalid name'); }); }); }); @@ -75,11 +83,33 @@ describe('addAnalyticsCollectionLogic', () => { }); describe('onApiError', () => { - it('should flash an error toast', () => { + it('should call setFlashMessages with an error when system error with message', () => { const httpError: HttpError = { body: { - error: 'Bad Request', - statusCode: 400, + error: 'Bad Gateway', + message: 'Something went wrong', + statusCode: 502, + }, + fetchOptions: {}, + request: {}, + } as HttpError; + AddAnalyticsCollectionLogic.actions.apiError(httpError); + + expect(flashAPIErrors).not.toHaveBeenCalled(); + expect(setFlashMessages).toHaveBeenCalledWith([ + { + description: 'Something went wrong', + message: 'Sorry, there was an error creating your collection.', + type: 'error', + }, + ]); + }); + + it('should flash a default error toast when system error without message', () => { + const httpError: HttpError = { + body: { + error: 'Bad Gateway', + statusCode: 502, }, fetchOptions: {}, request: {}, @@ -88,6 +118,25 @@ describe('addAnalyticsCollectionLogic', () => { expect(flashAPIErrors).toHaveBeenCalledWith(httpError); }); + + it('should set input error when is client error', () => { + const errorMessage = 'Collection already exists'; + const httpError: HttpError = { + body: { + error: 'Conflict', + message: errorMessage, + statusCode: 409, + }, + fetchOptions: {}, + request: {}, + } as HttpError; + AddAnalyticsCollectionLogic.actions.setInputError = jest.fn(); + AddAnalyticsCollectionLogic.actions.apiError(httpError); + + expect(AddAnalyticsCollectionLogic.actions.setInputError).toHaveBeenCalledWith( + errorMessage + ); + }); }); describe('createAnalyticsCollection', () => { @@ -105,7 +154,7 @@ describe('addAnalyticsCollectionLogic', () => { }); describe('selectors', () => { - describe('loading & status', () => { + describe('status', () => { it('updates when makeRequest triggered', () => { const promise = Promise.resolve({ name: 'result' }); http.post.mockReturnValue(promise); @@ -123,9 +172,38 @@ describe('addAnalyticsCollectionLogic', () => { name: 'test', }); - expect(AddAnalyticsCollectionLogic.values.isLoading).toBe(true); + expect(AddAnalyticsCollectionLogic.values.isSuccess).toBe(true); expect(AddAnalyticsCollectionLogic.values.status).toBe(Status.SUCCESS); }); }); + + describe('isSystemError', () => { + it('set true when error is 50x', () => { + expect(AddAnalyticsCollectionLogic.values.isSystemError).toBe(false); + AddAnalyticsCollectionLogic.actions.apiError({ + body: { + error: 'Bad Gateway', + message: 'Something went wrong', + statusCode: 502, + }, + } as HttpError); + + expect(AddAnalyticsCollectionLogic.values.isSystemError).toBe(true); + expect(AddAnalyticsCollectionLogic.values.status).toBe(Status.ERROR); + }); + + it('keep false if error code is 40x', () => { + AddAnalyticsCollectionLogic.actions.apiError({ + body: { + error: 'Conflict', + message: 'Something went wrong', + statusCode: 409, + }, + } as HttpError); + + expect(AddAnalyticsCollectionLogic.values.isSystemError).toBe(false); + expect(AddAnalyticsCollectionLogic.values.status).toBe(Status.ERROR); + }); + }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.ts index 1e97b48975d68a..95614426e29419 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_logic.ts @@ -9,11 +9,15 @@ import { kea, MakeLogicType } from 'kea'; import { i18n } from '@kbn/i18n'; -import { Status } from '../../../../../common/types/api'; +import { HttpError, Status } from '../../../../../common/types/api'; import { Actions } from '../../../shared/api_logic/create_api_logic'; import { generateEncodedPath } from '../../../shared/encode_path_params'; -import { flashSuccessToast } from '../../../shared/flash_messages'; +import { + flashAPIErrors, + FlashMessagesLogic, + flashSuccessToast, +} from '../../../shared/flash_messages'; import { KibanaLogic } from '../../../shared/kibana'; import { AddAnalyticsCollectionsAPILogic, @@ -22,6 +26,8 @@ import { } from '../../api/add_analytics_collection/add_analytics_collection_api_logic'; import { COLLECTION_VIEW_PATH } from '../../routes'; +const SERVER_ERROR_CODE = 500; + export interface AddAnalyticsCollectionsActions { apiError: Actions< AddAnalyticsCollectionApiLogicArgs, @@ -36,12 +42,17 @@ export interface AddAnalyticsCollectionsActions { AddAnalyticsCollectionApiLogicArgs, AddAnalyticsCollectionApiLogicResponse >['makeRequest']; + setInputError: (inputError: string | null) => { inputError: string | null }; setNameValue(name: string): { name: string }; } interface AddAnalyticsCollectionValues { canSubmit: boolean; + error: HttpError | undefined; + inputError: string | null; isLoading: boolean; + isSuccess: boolean; + isSystemError: boolean; name: string; status: Status; } @@ -51,16 +62,37 @@ export const AddAnalyticsCollectionLogic = kea< >({ actions: { createAnalyticsCollection: () => {}, - setInputError: (inputError: string | boolean) => ({ inputError }), + setInputError: (inputError) => ({ inputError }), setNameValue: (name: string) => ({ name }), }, connect: { actions: [AddAnalyticsCollectionsAPILogic, ['apiError', 'apiSuccess', 'makeRequest']], - values: [AddAnalyticsCollectionsAPILogic, ['status']], + values: [AddAnalyticsCollectionsAPILogic, ['status', 'error']], }, listeners: ({ values, actions }) => ({ - apiSuccess: async ({ name, id }, breakpoint) => { - // Wait for propagation of the new collection + apiError: async (error) => { + if (values.isSystemError) { + if (error?.body?.message) { + FlashMessagesLogic.actions.setFlashMessages([ + { + description: error.body.message, + message: i18n.translate( + 'xpack.enterpriseSearch.analytics.collectionsCreate.action.systemErrorMessage', + { + defaultMessage: 'Sorry, there was an error creating your collection.', + } + ), + type: 'error', + }, + ]); + } else { + flashAPIErrors(error); + } + } else { + actions.setInputError(error?.body?.message || null); + } + }, + apiSuccess: async ({ name, id }) => { flashSuccessToast( i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.action.successMessage', { defaultMessage: "Successfully added collection '{name}'", @@ -69,7 +101,6 @@ export const AddAnalyticsCollectionLogic = kea< }, }) ); - await breakpoint(1000); KibanaLogic.values.navigateToUrl( generateEncodedPath(COLLECTION_VIEW_PATH, { id, @@ -84,6 +115,13 @@ export const AddAnalyticsCollectionLogic = kea< }), path: ['enterprise_search', 'analytics', 'add_analytics_collection'], reducers: { + inputError: [ + null, + { + setInputError: (_, { inputError }) => inputError, + setNameValue: () => null, + }, + ], name: [ '', { @@ -96,10 +134,12 @@ export const AddAnalyticsCollectionLogic = kea< () => [selectors.isLoading, selectors.name], (isLoading, name) => !isLoading && name.length > 0, ], - isLoading: [ - () => [selectors.status], - // includes success to include the redirect wait time - (status: Status) => [Status.LOADING, Status.SUCCESS].includes(status), + isLoading: [() => [selectors.status], (status: Status) => status === Status.LOADING], + isSuccess: [() => [selectors.status], (status: Status) => status === Status.SUCCESS], + isSystemError: [ + () => [selectors.status, selectors.error], + (status: Status, error?: HttpError) => + Boolean(status === Status.ERROR && (error?.body?.statusCode || 0) >= SERVER_ERROR_CODE), ], }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.test.tsx new file mode 100644 index 00000000000000..7744df74320601 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.test.tsx @@ -0,0 +1,79 @@ +/* + * 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 '../../../__mocks__/shallow_useeffect.mock'; + +import { setMockValues, setMockActions } from '../../../__mocks__/kea_logic'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiButton, EuiModal } from '@elastic/eui'; + +import { AddAnalyticsCollectionForm } from './add_analytics_collection_form'; + +import { AddAnalyticsCollectionModal } from './add_analytics_collection_modal'; + +const mockValues = { + canSubmit: true, + isLoading: false, + isSuccess: false, + isSystemError: false, +}; + +const mockActions = { + createAnalyticsCollection: jest.fn(), + setNameValue: jest.fn(), +}; + +describe('AddAnalyticsCollectionModal', () => { + const mockOnClose = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders', () => { + setMockValues(mockValues); + setMockActions(mockActions); + + const wrapper = shallow(); + expect(wrapper.find(EuiModal)).toHaveLength(1); + expect(wrapper.find(AddAnalyticsCollectionForm)).toHaveLength(1); + }); + + it('successful creation will call onClose action', () => { + setMockValues({ ...mockValues, isSuccess: true }); + setMockActions(mockActions); + + shallow(); + + expect(mockOnClose).toHaveBeenCalled(); + }); + + it('system error will call onClose action', () => { + setMockValues({ ...mockValues, isSystemError: true }); + setMockActions(mockActions); + + shallow(); + + expect(mockOnClose).toHaveBeenCalled(); + }); + + it('disabled confirmed button when canSubmit is false', () => { + setMockValues({ + ...mockValues, + canSubmit: false, + }); + setMockActions(mockActions); + + const wrapper = shallow(); + + expect(wrapper.find(EuiButton).prop('isDisabled')).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.tsx new file mode 100644 index 00000000000000..a13fd20760c11d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/add_analytics_collections/add_analytics_collection_modal.tsx @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useValues } from 'kea'; + +import { + EuiButton, + EuiButtonEmpty, + EuiFlexItem, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSpacer, + EuiText, + useGeneratedHtmlId, +} from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { AddAnalyticsCollectionForm } from './add_analytics_collection_form'; + +import { AddAnalyticsCollectionLogic } from './add_analytics_collection_logic'; + +const collectionNameField = 'collection-name'; +const minModalWidth = 400; + +interface AddAnalyticsCollectionModalProps { + onClose: () => void; +} + +export const AddAnalyticsCollectionModal: React.FC = ({ + onClose, +}) => { + const { isLoading, isSuccess, isSystemError, canSubmit } = useValues(AddAnalyticsCollectionLogic); + const modalFormId = useGeneratedHtmlId({ prefix: 'createAnalyticsCollection' }); + + useEffect(() => { + if (isSuccess || isSystemError) { + onClose(); + } + }, [isSuccess, isSystemError]); + + return ( + + + + + {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.title', { + defaultMessage: 'Name your Collection', + })} + + + +

+ {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.subtitle', { + defaultMessage: + "Consider carefully what you want to name your Collection. You can't rename it later.", + })} +

+
+
+
+ + + + + + + + {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.cancelButton', { + defaultMessage: 'Cancel', + })} + + + + {i18n.translate('xpack.enterpriseSearch.analytics.collectionsCreate.form.createButton', { + defaultMessage: 'Create', + })} + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx index 17e89d97195a2b..a91bc4a9db079b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_collection_view/analytics_collection_view.tsx @@ -26,8 +26,8 @@ import { RedirectAppLinks } from '@kbn/kibana-react-plugin/public'; import { generateEncodedPath } from '../../../shared/encode_path_params'; import { KibanaLogic } from '../../../shared/kibana'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; -import { COLLECTION_CREATION_PATH, COLLECTION_VIEW_PATH } from '../../routes'; +import { COLLECTION_VIEW_PATH } from '../../routes'; +import { AddAnalyticsCollection } from '../add_analytics_collections/add_analytics_collection'; import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; @@ -157,14 +157,7 @@ export const AnalyticsCollectionView: React.FC = () => {
- - {i18n.translate( - 'xpack.enterpriseSearch.analytics.collections.collectionsView.create.buttonTitle', - { - defaultMessage: 'Create new collection', - } - )} - + )} @@ -204,16 +197,7 @@ export const AnalyticsCollectionView: React.FC = () => { )}

} - actions={[ - - {i18n.translate( - 'xpack.enterpriseSearch.analytics.collections.collectionsView.create.buttonTitle', - { - defaultMessage: 'Create new collection', - } - )} - , - ]} + actions={[]} /> )} diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx index 39ab22a675c426..465205f4aac8e5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview.tsx @@ -9,16 +9,17 @@ import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; -import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; -import { EuiButtonTo } from '../../../shared/react_router_helpers'; -import { COLLECTION_CREATION_PATH } from '../../routes'; +import { AddAnalyticsCollection } from '../add_analytics_collections/add_analytics_collection'; import { EnterpriseSearchAnalyticsPageTemplate } from '../layout/page_template'; import { AnalyticsCollectionTable } from './analytics_collection_table'; import { AnalyticsCollectionsLogic } from './analytics_collections_logic'; +import { AnalyticsOverviewEmptyPage } from './analytics_overview_empty_page'; export const AnalyticsOverview: React.FC = () => { const { fetchAnalyticsCollections } = useActions(AnalyticsCollectionsLogic); @@ -46,6 +47,7 @@ export const AnalyticsOverview: React.FC = () => { pageTitle: i18n.translate('xpack.enterpriseSearch.analytics.collections.pageTitle', { defaultMessage: 'Behavioral Analytics', }), + rightSideItems: [], }} > {!hasNoAnalyticsCollections && ( @@ -60,48 +62,14 @@ export const AnalyticsOverview: React.FC = () => { - - {i18n.translate('xpack.enterpriseSearch.analytics.collections.create.buttonTitle', { - defaultMessage: 'Create new collection', - })} - + )} {hasNoAnalyticsCollections ? ( - - {i18n.translate( - 'xpack.enterpriseSearch.analytics.collections.emptyState.headingTitle', - { - defaultMessage: 'You dont have any collections yet', - } - )} - - } - body={ -

- {i18n.translate( - 'xpack.enterpriseSearch.analytics.collections.emptyState.subHeading', - { - defaultMessage: - 'An analytics collection provides a place to store the analytics events for any given search application you are building. Create a new collection to get started.', - } - )} -

- } - actions={[ - - {i18n.translate('xpack.enterpriseSearch.analytics.collections.create.buttonTitle', { - defaultMessage: 'Create new collection', - })} - , - ]} - /> + ) : ( )} diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview_empty_page.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview_empty_page.tsx new file mode 100644 index 00000000000000..f57d9b851cd460 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/components/analytics_overview/analytics_overview_empty_page.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiEmptyPrompt, EuiImage, EuiLink, EuiTitle } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import noMlModelsGraphicDark from '../../../../assets/images/no_ml_models_dark.svg'; + +import { docLinks } from '../../../shared/doc_links'; +import { AddAnalyticsCollection } from '../add_analytics_collections/add_analytics_collection'; + +const ICON_WIDTH = 294; + +export const AnalyticsOverviewEmptyPage: React.FC = () => ( + } + layout="horizontal" + color="plain" + title={ +

+ {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.headingTitle', { + defaultMessage: 'Create your first Collection', + })} +

+ } + body={ +

+ {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.subHeading', { + defaultMessage: + 'Collections are required to store analytics events for your search application.', + })} +

+ } + actions={[]} + footer={ + <> + + + {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.footerText', { + defaultMessage: 'Want to learn more?', + })} + + {' '} + + {i18n.translate('xpack.enterpriseSearch.analytics.collections.emptyState.footerLink', { + defaultMessage: 'Read documentation', + })} + + + } + /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx index 092129e17dd248..5e4ffd15d2aa74 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx @@ -14,12 +14,10 @@ import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { VersionMismatchPage } from '../shared/version_mismatch'; -import { AddAnalyticsCollection } from './components/add_analytics_collections/add_analytics_collection'; - import { AnalyticsCollectionView } from './components/analytics_collection_view/analytics_collection_view'; import { AnalyticsOverview } from './components/analytics_overview/analytics_overview'; -import { ROOT_PATH, COLLECTION_CREATION_PATH, COLLECTION_VIEW_PATH } from './routes'; +import { ROOT_PATH, COLLECTION_VIEW_PATH } from './routes'; export const Analytics: React.FC = (props) => { const { enterpriseSearchVersion, kibanaVersion } = props; @@ -37,9 +35,6 @@ export const Analytics: React.FC = (props) => { )} - - - diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/routes.ts b/x-pack/plugins/enterprise_search/public/applications/analytics/routes.ts index f21f3de52f0861..b213203c574e1c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/routes.ts @@ -7,5 +7,4 @@ export const ROOT_PATH = '/'; export const COLLECTIONS_PATH = '/collections'; -export const COLLECTION_CREATION_PATH = `${COLLECTIONS_PATH}/new`; export const COLLECTION_VIEW_PATH = `${COLLECTIONS_PATH}/:id/:section`; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_details_flyout/crawl_details_preview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_details_flyout/crawl_details_preview.test.tsx index b941b8d4978507..07871fe7dd7ecc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_details_flyout/crawl_details_preview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/crawler/components/crawl_details_flyout/crawl_details_preview.test.tsx @@ -9,7 +9,8 @@ import { setMockValues } from '../../../../../__mocks__/kea_logic'; import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { set } from 'lodash/fp'; + +import { set } from '@kbn/safer-lodash-set/fp'; import { AccordionList } from '../../../../../shared/accordion_list/accordion_list'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx index 4fdce0bcd02997..ef1077e4dc9a34 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/suggested_documents_callout.test.tsx @@ -11,7 +11,8 @@ import { setMockValues } from '../../../../__mocks__/kea_logic'; import React from 'react'; import { shallow } from 'enzyme'; -import { set } from 'lodash/fp'; + +import { set } from '@kbn/safer-lodash-set/fp'; import { SuggestionsCallout } from '../components/suggestions_callout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx index 3de39f21e1de09..8bc5e33263da02 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations.test.tsx @@ -14,9 +14,8 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { set } from 'lodash/fp'; - import { EuiTab } from '@elastic/eui'; +import { set } from '@kbn/safer-lodash-set/fp'; import { getPageHeaderTabs, getPageTitle } from '../../../../test_helpers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx index b7da6d64b6a8a0..ba8ec782a4afde 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curations_overview.test.tsx @@ -12,7 +12,8 @@ import '../../../__mocks__/engine_logic.mock'; import React from 'react'; import { shallow } from 'enzyme'; -import { set } from 'lodash/fp'; + +import { set } from '@kbn/safer-lodash-set/fp'; import { CurationsTable, EmptyState } from '../components'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx index 2fb9bb255110dc..f539adda4ccf37 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/suggested_curations_callout.test.tsx @@ -11,7 +11,8 @@ import { setMockValues } from '../../../../__mocks__/kea_logic'; import React from 'react'; import { shallow } from 'enzyme'; -import { set } from 'lodash/fp'; + +import { set } from '@kbn/safer-lodash-set/fp'; import { SuggestionsCallout } from '../../curations/components/suggestions_callout'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_config.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_config.tsx index 35914ddb510b77..bf28aaa0322112 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_config.tsx @@ -45,7 +45,7 @@ export const ConnectorConfigurationConfig: React.FC = ({ children }) => { displayList.length > 0 && ( - + diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/select_connector/select_connector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/select_connector/select_connector.tsx index 572f345422bab8..219ad302821219 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/select_connector/select_connector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/select_connector/select_connector.tsx @@ -125,9 +125,10 @@ export const SelectConnector: React.FC = () => { {NATIVE_CONNECTORS.map((nativeConnector) => ( - + setSelectedConnector(nativeConnector)} documentationUrl={nativeConnector.docsUrl} checked={nativeConnector === selectedNativeConnector} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawl_details_flyout/crawl_details_preview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawl_details_flyout/crawl_details_preview.test.tsx index 590989db59d024..58a593ebdd037b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawl_details_flyout/crawl_details_preview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawl_details_flyout/crawl_details_preview.test.tsx @@ -9,7 +9,8 @@ import { setMockValues } from '../../../../../__mocks__/kea_logic'; import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { set } from 'lodash/fp'; + +import { set } from '@kbn/safer-lodash-set/fp'; import { AccordionList } from '../../../../../shared/accordion_list/accordion_list'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/extraction_rules_logic.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/extraction_rules_logic.tsx index f44d83cb7c99df..8c56f4c4d5f199 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/extraction_rules_logic.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/extraction_rules_logic.tsx @@ -250,6 +250,7 @@ export const ExtractionRulesLogic = kea< cancelEditExtractionRule: () => null, editExtractionRule: (_, { extractionRule }) => extractionRule, updateSuccess: () => null, + updateExtractionRuleSuccess: () => null, }, ], extractionRuleToEditIsNew: [ @@ -257,6 +258,8 @@ export const ExtractionRulesLogic = kea< { addSuccess: () => false, editNewExtractionRule: () => true, + editExtractionRule: () => false, + updateExtractionRuleSuccess: () => false, }, ], fieldRuleFlyoutVisible: [ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/field_rules_table.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/field_rules_table.tsx index c8f6b3a882a969..19f313d66e5bae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/field_rules_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/crawler_domain_detail/extraction_rules/field_rules_table.tsx @@ -7,7 +7,14 @@ import React from 'react'; -import { EuiBasicTable, EuiBasicTableColumn, EuiCode, EuiFlexGroup, EuiText } from '@elastic/eui'; +import { + EuiBasicTable, + EuiBasicTableColumn, + EuiCode, + EuiFlexGroup, + EuiFlexItem, + EuiText, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -48,16 +55,20 @@ export const FieldRulesTable: React.FC = ({ }), render: (rule: FieldRuleWithId) => ( - - {rule.source_type === FieldType.HTML - ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.HTMLLabel', { - defaultMessage: 'HTML: ', - }) - : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.UrlLabel', { - defaultMessage: 'URL: ', - })} - - {rule.selector} + + + {rule.source_type === FieldType.HTML + ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.HTMLLabel', { + defaultMessage: 'HTML: ', + }) + : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.UrlLabel', { + defaultMessage: 'URL: ', + })} + + + + {rule.selector} + ), }, @@ -70,26 +81,30 @@ export const FieldRulesTable: React.FC = ({ multiple_objects_handling: multipleObjectsHandling, }: FieldRuleWithId) => ( - - {content.value_type === ContentFrom.EXTRACTED - ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.extractedLabel', { - defaultMessage: 'Extracted as: ', - }) - : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.fixedLabel', { - defaultMessage: 'Fixed value: ', - })} - - - {content.value_type === ContentFrom.FIXED - ? content.value - : multipleObjectsHandling === MultipleObjectsHandling.ARRAY - ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.arrayLabel', { - defaultMessage: 'array', - }) - : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.stringLabel', { - defaultMessage: 'string', - })} - + + + {content.value_type === ContentFrom.EXTRACTED + ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.extractedLabel', { + defaultMessage: 'Extracted as: ', + }) + : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.fixedLabel', { + defaultMessage: 'Fixed value: ', + })} + + + + + {content.value_type === ContentFrom.FIXED + ? content.value + : multipleObjectsHandling === MultipleObjectsHandling.ARRAY + ? i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.arrayLabel', { + defaultMessage: 'array', + }) + : i18n.translate('xpack.enterpriseSearch.crawler.fieldRulesTable.stringLabel', { + defaultMessage: 'string', + })} + + ), }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/events_panel.test.tsx.snap b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/events_panel.test.tsx.snap index 64c8de8f77b974..d4bdda45ccc3b0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/events_panel.test.tsx.snap +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/events_panel.test.tsx.snap @@ -15,6 +15,7 @@ exports[`EventsPanel renders 1`] = ` Object { "field": "date", "name": "Time", + "render": [Function], "width": "50%", }, ] @@ -22,27 +23,27 @@ exports[`EventsPanel renders 1`] = ` items={ Array [ Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Canceled", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Cancelation requested", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Completed", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Last updated", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Sync started", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Sync requested manually", }, ] @@ -74,6 +75,7 @@ exports[`EventsPanel renders with some values missing 1`] = ` Object { "field": "date", "name": "Time", + "render": [Function], "width": "50%", }, ] @@ -81,23 +83,23 @@ exports[`EventsPanel renders with some values missing 1`] = ` items={ Array [ Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Canceled", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Completed", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Last updated", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Sync started", }, Object { - "date": "Mon Oct 24 2022 02:44:19 GMT+0000", + "date": "2022-10-24T02:44:19.660365+00:00", "title": "Sync requested manually", }, ] diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/sync_callouts.test.tsx.snap b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/sync_callouts.test.tsx.snap index a528bf1326d67b..ec2e279a49cf84 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/sync_callouts.test.tsx.snap +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/__snapshots__/sync_callouts.test.tsx.snap @@ -8,7 +8,17 @@ exports[`SyncCalloutsPanel renders 1`] = ` iconType="check" title="Sync complete" > - Completed at Mon Sep 05 2022 15:59:39 GMT+0000 + , + } + } + /> @@ -17,7 +27,17 @@ exports[`SyncCalloutsPanel renders 1`] = ` iconType="iInCircle" title="Sync started manually" > - Started at Mon Sep 05 2022 14:59:39 GMT+0000. + , + } + } + /> @@ -31,7 +51,17 @@ exports[`SyncCalloutsPanel renders canceled job 1`] = ` iconType="check" title="Sync complete" > - Completed at Mon Sep 05 2022 15:59:39 GMT+0000 + , + } + } + /> @@ -39,9 +69,7 @@ exports[`SyncCalloutsPanel renders canceled job 1`] = ` color="danger" iconType="cross" title="Sync canceled" - > - Sync canceled at . - + /> - Started at Mon Sep 05 2022 14:59:39 GMT+0000. + , + } + } + /> @@ -63,7 +101,17 @@ exports[`SyncCalloutsPanel renders different trigger method 1`] = ` iconType="check" title="Sync complete" > - Completed at Mon Sep 05 2022 15:59:39 GMT+0000 + , + } + } + /> @@ -81,7 +129,17 @@ exports[`SyncCalloutsPanel renders different trigger method 1`] = ` iconType="iInCircle" title="Sync started by schedule" > - Started at Mon Sep 05 2022 14:59:39 GMT+0000. + , + } + } + /> @@ -95,7 +153,17 @@ exports[`SyncCalloutsPanel renders error job 1`] = ` iconType="check" title="Sync complete" > - Completed at Mon Sep 05 2022 15:59:39 GMT+0000 + , + } + } + /> @@ -113,7 +181,17 @@ exports[`SyncCalloutsPanel renders error job 1`] = ` iconType="iInCircle" title="Sync started manually" > - Started at Mon Sep 05 2022 14:59:39 GMT+0000. + , + } + } + /> @@ -127,7 +205,17 @@ exports[`SyncCalloutsPanel renders in progress job 1`] = ` iconType="check" title="Sync complete" > - Completed at Mon Sep 05 2022 15:59:39 GMT+0000 + , + } + } + /> @@ -145,7 +233,17 @@ exports[`SyncCalloutsPanel renders in progress job 1`] = ` iconType="iInCircle" title="Sync started manually" > - Started at Mon Sep 05 2022 14:59:39 GMT+0000. + , + } + } + /> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/events_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/events_panel.tsx index 0366ce2a0fe1c4..00c67249523c30 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/events_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/events_panel.tsx @@ -14,7 +14,7 @@ import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TriggerMethod } from '../../../../../../common/types/connectors'; -import { dateToString } from '../../../utils/date_to_string'; +import { FormattedDateTime } from '../../../../shared/formatted_date_time'; import { FlyoutPanel } from './flyout_panel'; @@ -44,7 +44,7 @@ export const SyncJobEventsPanel: React.FC = ({ }) => { const events: SyncJobEvent[] = [ { - date: dateToString(syncRequestedAt), + date: syncRequestedAt, title: triggerMethod === TriggerMethod.ON_DEMAND ? i18n.translate( @@ -57,25 +57,25 @@ export const SyncJobEventsPanel: React.FC = ({ ), }, { - date: dateToString(syncStarted), + date: syncStarted, title: i18n.translate('xpack.enterpriseSearch.content.index.syncJobs.events.syncStarted', { defaultMessage: 'Sync started', }), }, { - date: dateToString(lastUpdated), + date: lastUpdated, title: i18n.translate('xpack.enterpriseSearch.content.index.syncJobs.events.lastUpdated', { defaultMessage: 'Last updated', }), }, { - date: dateToString(completed), + date: completed, title: i18n.translate('xpack.enterpriseSearch.content.index.syncJobs.events.completed', { defaultMessage: 'Completed', }), }, { - date: dateToString(cancelationRequestedAt), + date: cancelationRequestedAt, title: i18n.translate( 'xpack.enterpriseSearch.content.index.syncJobs.events.cancelationRequested', { @@ -84,7 +84,7 @@ export const SyncJobEventsPanel: React.FC = ({ ), }, { - date: dateToString(canceledAt), + date: canceledAt, title: i18n.translate('xpack.enterpriseSearch.content.index.syncJobs.events.canceled', { defaultMessage: 'Canceled', }), @@ -106,6 +106,7 @@ export const SyncJobEventsPanel: React.FC = ({ name: i18n.translate('xpack.enterpriseSearch.content.index.syncJobs.events.time', { defaultMessage: 'Time', }), + render: (date: string) => , width: '50%', }, ]; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/sync_callouts.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/sync_callouts.tsx index 09e2f91b6c1d87..461132980c66b7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/sync_callouts.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/sync_jobs/sync_callouts.tsx @@ -11,9 +11,11 @@ import { EuiFlexItem, EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + import { SyncStatus, TriggerMethod } from '../../../../../../common/types/connectors'; +import { FormattedDateTime } from '../../../../shared/formatted_date_time'; -import { dateToString } from '../../../utils/date_to_string'; import { durationToText } from '../../../utils/duration_to_text'; import { SyncJobView } from './sync_jobs_view_logic'; @@ -34,12 +36,13 @@ export const SyncJobCallouts: React.FC = ({ syncJob }) => defaultMessage: 'Sync complete', })} > - {i18n.translate('xpack.enterpriseSearch.content.syncJobs.flyout.completedDescription', { - defaultMessage: 'Completed at {date}', - values: { - date: dateToString(syncJob.completed_at), - }, - })} + , + }} + /> )} @@ -70,12 +73,15 @@ export const SyncJobCallouts: React.FC = ({ syncJob }) => defaultMessage: 'Sync canceled', })} > - {i18n.translate('xpack.enterpriseSearch.content.syncJobs.flyout.canceledDescription', { - defaultMessage: 'Sync canceled at {date}.', - values: { - date: dateToString(syncJob.canceled_at ?? ''), - }, - })} + {!!syncJob.canceled_at && ( + , + }} + /> + )} )} @@ -124,12 +130,13 @@ export const SyncJobCallouts: React.FC = ({ syncJob }) => ) } > - {i18n.translate('xpack.enterpriseSearch.content.syncJobs.flyout.startedAtDescription', { - defaultMessage: 'Started at {date}.', - values: { - date: dateToString(syncJob.started_at), - }, - })} + , + }} + /> )} diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts index 9306a1958956a5..724e159618df6d 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/analytics.ts @@ -124,7 +124,7 @@ export function registerAnalyticsRoutes({ message: i18n.translate( 'xpack.enterpriseSearch.server.routes.addAnalyticsCollection.analyticsCollectionExistsError', { - defaultMessage: 'Analytics collection already exists', + defaultMessage: 'Collection name already exists. Choose another name.', } ), response, diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json index 8b9eef8ce18644..3d027fd53e0f7c 100644 --- a/x-pack/plugins/enterprise_search/tsconfig.json +++ b/x-pack/plugins/enterprise_search/tsconfig.json @@ -47,6 +47,7 @@ "@kbn/cypress-config", "@kbn/discover-plugin", "@kbn/guided-onboarding", + "@kbn/safer-lodash-set", "@kbn/shared-ux-router", "@kbn/core-http-browser", ] diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index 37acc7b0569170..349fb089259fff 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -20,6 +20,7 @@ export const allowedExperimentalValues = Object.freeze({ displayAgentMetrics: true, showIntegrationsSubcategories: false, agentFqdnMode: true, + showExperimentalShipperOptions: false, }); type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index f535bad37c6c27..11ddf379df0428 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -435,6 +435,12 @@ "type": "string", "format": "binary" } + }, + "application/gzip": { + "schema": { + "type": "string", + "format": "binary" + } } } } @@ -2075,7 +2081,7 @@ } } }, - "/agents/{agentId}/upload": { + "/agents/{agentId}/uploads": { "parameters": [ { "schema": { @@ -5728,12 +5734,10 @@ "nullable": true }, "unenroll_timeout": { - "type": "number", - "nullable": true + "type": "number" }, "inactivity_timeout": { - "type": "number", - "nullable": true + "type": "number" } }, "required": [ diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 7dcc4ba9610d23..5b4b6a61a9fffb 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -281,6 +281,10 @@ paths: schema: type: string format: binary + application/gzip: + schema: + type: string + format: binary /epm/packages/_bulk: post: summary: Packages - Bulk install @@ -1285,7 +1289,7 @@ paths: application/json: schema: $ref: '#/components/schemas/upgrade_agent' - /agents/{agentId}/upload: + /agents/{agentId}/uploads: parameters: - schema: type: string @@ -3647,10 +3651,8 @@ components: nullable: true unenroll_timeout: type: number - nullable: true inactivity_timeout: type: number - nullable: true required: - name - namespace diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/new_agent_policy.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/new_agent_policy.yaml index 4dcd8681ac0eae..2edab88c704906 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/new_agent_policy.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/new_agent_policy.yaml @@ -30,10 +30,8 @@ properties: nullable: true unenroll_timeout: type: number - nullable: true inactivity_timeout: type: number - nullable: true required: - name - namespace diff --git a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml index 14162c841a0c00..4ff56806eb0ef2 100644 --- a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml +++ b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml @@ -71,7 +71,7 @@ paths: $ref: 'paths/agents@{agent_id}@unenroll.yaml' '/agents/{agentId}/upgrade': $ref: 'paths/agents@{agent_id}@upgrade.yaml' - '/agents/{agentId}/upload': + '/agents/{agentId}/uploads': $ref: 'paths/agents@{agent_id}@uploads.yaml' '/agents/bulk_reassign': $ref: 'paths/agents@bulk_reassign.yaml' diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml index d3ef2a279494e0..b44ab7e9b81688 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml @@ -80,6 +80,10 @@ post: requestBody: content: application/zip: + schema: + type: string + format: binary + application/gzip: schema: type: string format: binary \ No newline at end of file diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts index c3844b8a06bf10..d318f964ccd11c 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.test.ts @@ -400,7 +400,7 @@ describe('Fleet - validatePackagePolicy()', () => { }, bar: { vars: { - 'bar-input-var-name': ['Invalid format'], + 'bar-input-var-name': ['Invalid format for bar-input-var-name: expected array'], 'bar-input2-var-name': ['bar-input2-var-name is required'], }, streams: { @@ -470,7 +470,7 @@ describe('Fleet - validatePackagePolicy()', () => { }, bar: { vars: { - 'bar-input-var-name': ['Invalid format'], + 'bar-input-var-name': ['Invalid format for bar-input-var-name: expected array'], 'bar-input2-var-name': ['bar-input2-var-name is required'], }, streams: { diff --git a/x-pack/plugins/fleet/common/services/validate_package_policy.ts b/x-pack/plugins/fleet/common/services/validate_package_policy.ts index 0859ef63c3edd0..82fb8c82da39ca 100644 --- a/x-pack/plugins/fleet/common/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/validate_package_policy.ts @@ -258,7 +258,10 @@ export const validatePackagePolicyConfig = ( if (parsedValue && !Array.isArray(parsedValue)) { errors.push( i18n.translate('xpack.fleet.packagePolicyValidation.invalidArrayErrorMessage', { - defaultMessage: 'Invalid format', + defaultMessage: 'Invalid format for {fieldName}: expected array', + values: { + fieldName: varDef.title || varDef.name, + }, }) ); return errors; diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index cc0f0be82eae05..465d6adcb1acd3 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -114,6 +114,15 @@ export interface FullAgentPolicy { }; download: { sourceURI: string }; features: Record; + protection?: { + enabled: boolean; + uninstall_token_hash: string; + signing_key: string; + }; + }; + signed?: { + data: string; + signature: string; }; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx index 34f30e169cd97d..240c09c7777eb8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy.tsx @@ -36,6 +36,7 @@ import { } from '../../create_package_policy_page/services'; import type { PackagePolicyFormState } from '../../create_package_policy_page/types'; import { fixApmDurationVars, hasUpgradeAvailable } from '../utils'; +import { prepareInputPackagePolicyDataset } from '../../create_package_policy_page/services/prepare_input_pkg_policy_dataset'; function mergeVars( packageVars?: PackagePolicyConfigRecord, @@ -94,7 +95,9 @@ export function usePackagePolicyWithRelatedData( const savePackagePolicy = async () => { setFormState('LOADING'); - const { elasticsearch, ...restPackagePolicy } = packagePolicy; // ignore 'elasticsearch' property since it fails route validation + const { + policy: { elasticsearch, ...restPackagePolicy }, + } = await prepareInputPackagePolicyDataset(packagePolicy); const result = await sendUpdatePackagePolicy(packagePolicyId, restPackagePolicy); setFormState('SUBMITTED'); return result; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx index 0225cec66a3cd0..9f5cf41ecbcdef 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx @@ -54,6 +54,4 @@ export const AGENT_LOG_LEVELS = { DEBUG: 'debug', }; -export const ORDERED_FILTER_LOG_LEVELS = ['error', 'warning', 'warn', 'notice', 'info', 'debug']; - export const DEFAULT_LOG_LEVEL = AGENT_LOG_LEVELS.INFO; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.test.tsx deleted file mode 100644 index 721be29a5e2bdc..00000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import { render, act, fireEvent } from '@testing-library/react'; - -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; - -import { LogLevelFilter } from './filter_log_level'; - -const renderComponent = (props: React.ComponentProps) => { - return render( - - - - ); -}; - -jest.mock('../../../../../hooks', () => ({ - ...jest.requireActual('../../../../../hooks'), - useStartServices: jest.fn().mockReturnValue({ - data: { - dataViews: { - getFieldsForWildcard: jest.fn().mockResolvedValue([]), - create: jest.fn().mockResolvedValue([]), - }, - }, - unifiedSearch: { - autocomplete: { - getValueSuggestions: jest.fn().mockResolvedValue(['error', 'warn', 'info', 'debug']), - }, - }, - }), -})); - -describe('LogLevelFilter', () => { - const { getByRole, getByText } = renderComponent({ - selectedLevels: [], - onToggleLevel: () => {}, - }); - - it('Renders all statuses', () => { - act(() => { - fireEvent.click(getByRole('button')); - }); - - expect(getByText('error')).toBeInTheDocument(); - expect(getByText('warn')).toBeInTheDocument(); - expect(getByText('info')).toBeInTheDocument(); - expect(getByText('debug')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx index 1fca50180b6828..6b1f1060beb094 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx @@ -5,82 +5,24 @@ * 2.0. */ -import React, { memo, useState, useEffect, useCallback } from 'react'; -import { EuiPopover, EuiFilterButton, EuiFilterSelectItem, EuiIcon, EuiSpacer } from '@elastic/eui'; +import React, { memo, useState, useCallback } from 'react'; +import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { DataViewField, FieldSpec } from '@kbn/data-views-plugin/public'; -import { useStartServices } from '../../../../../hooks'; +import { AGENT_LOG_LEVELS } from './constants'; -import { ORDERED_FILTER_LOG_LEVELS, AGENT_LOG_INDEX_PATTERN, LOG_LEVEL_FIELD } from './constants'; - -function sortLogLevels(levels: string[]): string[] { - return [ - ...new Set([ - // order by severity for known level - ...ORDERED_FILTER_LOG_LEVELS.filter((level) => levels.includes(level)), - // Add unknown log level - ...levels.sort(), - ]), - ]; -} +const LEVEL_VALUES = Object.values(AGENT_LOG_LEVELS); export const LogLevelFilter: React.FunctionComponent<{ selectedLevels: string[]; onToggleLevel: (level: string) => void; }> = memo(({ selectedLevels, onToggleLevel }) => { - const { unifiedSearch, data } = useStartServices(); const [isOpen, setIsOpen] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [levelValues, setLevelValues] = useState([]); const togglePopover = useCallback(() => setIsOpen((prevIsOpen) => !prevIsOpen), []); const closePopover = useCallback(() => setIsOpen(false), []); - useEffect(() => { - const fetchValues = async () => { - setIsLoading(true); - try { - const fields: FieldSpec[] = await data.dataViews.getFieldsForWildcard({ - pattern: AGENT_LOG_INDEX_PATTERN, - }); - const fieldsMap = fields.reduce((acc: Record, curr: FieldSpec) => { - acc[curr.name] = curr; - return acc; - }, {}); - const newDataView = await data.dataViews.create({ - title: AGENT_LOG_INDEX_PATTERN, - fields: fieldsMap, - }); - - const values: string[] = await unifiedSearch.autocomplete.getValueSuggestions({ - indexPattern: newDataView, - field: LOG_LEVEL_FIELD as DataViewField, - query: '', - }); - setLevelValues(sortLogLevels(values)); - } catch (e) { - setLevelValues([]); - } - setIsLoading(false); - }; - fetchValues(); - }, [data.dataViews, unifiedSearch.autocomplete]); - - const noLogsFound = ( -
-
- - -

- {i18n.translate('xpack.fleet.agentLogs.logLevelEmpty', { - defaultMessage: 'No Logs Found', - })} -

-
-
- ); - const filterSelect = levelValues.map((level) => ( + const filterSelect = LEVEL_VALUES.map((level) => ( 0} numActiveFilters={selectedLevels.length} > @@ -112,7 +53,7 @@ export const LogLevelFilter: React.FunctionComponent<{ closePopover={closePopover} panelPaddingSize="none" > - {levelValues.length === 0 ? noLogsFound : filterSelect} + {filterSelect} ); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx index 409a259f934dd2..9ad6cc482fb1a7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx @@ -66,7 +66,7 @@ export const EnrollmentRecommendation: React.FunctionComponent<{ ), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/advanced_options_section.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/advanced_options_section.tsx index fa0d5762823724..2c33383a63acca 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/advanced_options_section.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/advanced_options_section.tsx @@ -23,6 +23,8 @@ import { import { i18n } from '@kbn/i18n'; +import { ExperimentalFeaturesService } from '../../../../services'; + import type { OutputFormInputsType } from './use_output_form'; export interface AdvancedOptionsSectionProps { @@ -46,6 +48,7 @@ export const AdvancedOptionsSection: React.FunctionComponent - + {showExperimentalShipperOptions && ( + <> + - - - - + + + + } /> - } - /> - - - - - - - - - + + + + + + +
+ + - - - - + + + + } /> - } - /> - - - + + + + + + + + + + - - - - - - - } - {...diskQueuePathInput.formRowProps} - > - - + {...diskQueuePathInput.formRowProps} + > + + - - } - > - - - - - - + - - - - + } + > + + + + + + + + + + + - + - - - - + + + + } /> - } - /> - - - - - - - - + + + + + + + + - + - - - - + + + + } /> - } - /> - - - - - - - - - - - + + + + + + + + + + + + + )} ) : null; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx index 5c012c12924d89..28175ebeafeba8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx @@ -23,6 +23,7 @@ import { } from '../../../../hooks'; import type { Output, PostOutputRequest } from '../../../../types'; import { useConfirmModal } from '../../hooks/use_confirm_modal'; +import { ExperimentalFeaturesService } from '../../../../services'; import { validateName, @@ -65,6 +66,8 @@ export interface OutputFormInputsType { export function useOutputForm(onSucess: () => void, output?: Output) { const fleetStatus = useFleetStatus(); + const { showExperimentalShipperOptions } = ExperimentalFeaturesService.get(); + const hasEncryptedSavedObjectConfigured = !fleetStatus.missingOptionalFeatures?.includes( 'encrypted_saved_object_encryption_key_required' ); @@ -159,7 +162,6 @@ export function useOutputForm(onSucess: () => void, output?: Output) { !diskQueueCompressionEnabled.value ?? false ); - // These parameters are yet tbd - https://github.com/elastic/kibana/issues/147613 const memQueueEvents = useNumberInput(output?.shipper?.mem_queue_events || undefined); const queueFlushTimeout = useNumberInput(output?.shipper?.queue_flush_timeout || undefined); const maxBatchBytes = useNumberInput(output?.shipper?.max_batch_bytes || undefined); @@ -265,8 +267,20 @@ export function useOutputForm(onSucess: () => void, output?: Output) { setIsloading(true); let shipperParams = {}; + if (!isShipperDisabled) { shipperParams = { + shipper: { + mem_queue_events: memQueueEvents.value ? Number(memQueueEvents.value) : null, + queue_flush_timeout: queueFlushTimeout.value ? Number(queueFlushTimeout.value) : null, + max_batch_bytes: maxBatchBytes.value ? Number(maxBatchBytes.value) : null, + }, + }; + } + + if (!isShipperDisabled && showExperimentalShipperOptions) { + shipperParams = { + ...shipperParams, shipper: { disk_queue_enabled: diskQueueEnabledInput.value, disk_queue_path: @@ -284,9 +298,6 @@ export function useOutputForm(onSucess: () => void, output?: Output) { ? Number(compressionLevelInput.value) : null, loadbalance: loadBalanceEnabledInput.value, - mem_queue_events: memQueueEvents.value ? Number(memQueueEvents.value) : null, - queue_flush_timeout: queueFlushTimeout.value ? Number(queueFlushTimeout.value) : null, - max_batch_bytes: maxBatchBytes.value ? Number(maxBatchBytes.value) : null, }, }; } @@ -353,8 +364,10 @@ export function useOutputForm(onSucess: () => void, output?: Output) { } }, [ validate, - isLogstash, isShipperDisabled, + showExperimentalShipperOptions, + proxyIdInput.value, + isLogstash, nameInput.value, typeInput.value, logstashHostsInput.value, @@ -366,10 +379,11 @@ export function useOutputForm(onSucess: () => void, output?: Output) { sslCertificateAuthoritiesInput.value, elasticsearchUrlInput.value, caTrustedFingerprintInput.value, - proxyIdInput.value, - notifications.toasts, - onSucess, output, + onSucess, + memQueueEvents.value, + queueFlushTimeout.value, + maxBatchBytes.value, diskQueueEnabledInput.value, diskQueuePathInput.value, diskQueueMaxSizeInput.value, @@ -377,10 +391,8 @@ export function useOutputForm(onSucess: () => void, output?: Output) { diskQueueCompressionEnabled.value, compressionLevelInput.value, loadBalanceEnabledInput.value, - memQueueEvents.value, - queueFlushTimeout.value, - maxBatchBytes.value, confirm, + notifications.toasts, ]); return { diff --git a/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts b/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts index 223a9d293d0702..6c3204aadada74 100644 --- a/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts +++ b/x-pack/plugins/fleet/server/constants/fleet_es_assets.ts @@ -13,7 +13,7 @@ const meta = getESAssetMetadata(); export const FLEET_INSTALL_FORMAT_VERSION = '1.0.0'; -export const FLEET_AGENT_POLICIES_SCHEMA_VERSION = '1.0.0'; +export const FLEET_AGENT_POLICIES_SCHEMA_VERSION = '1.1.0'; export const FLEET_FINAL_PIPELINE_ID = '.fleet_final_pipeline-1'; diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index 75f55a1b353d47..4c1d37e3d0f522 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -76,6 +76,7 @@ export const createAppContextStartContractMock = ( telemetryEventsSender: createMockTelemetryEventsSender(), bulkActionsResolver: {} as any, messageSigningService: { + isEncryptionAvailable: true, generateKeyPair: jest.fn(), sign: jest.fn(), getPublicKey: jest.fn(), diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index 505f5e1b89b0ab..83e2600d1beb25 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -358,7 +358,7 @@ export const downloadFullAgentPolicy: FleetRequestHandler< const body = fullAgentConfigMap; const headers: ResponseHeaders = { 'content-type': 'text/x-yaml', - 'content-disposition': `attachment; filename="elastic-agent-standalone-kubernetes.yaml"`, + 'content-disposition': `attachment; filename="elastic-agent-standalone-kubernetes.yml"`, }; return response.ok({ body, @@ -438,7 +438,7 @@ export const downloadK8sManifest: FleetRequestHandler< const body = fullAgentManifest; const headers: ResponseHeaders = { 'content-type': 'text/x-yaml', - 'content-disposition': `attachment; filename="elastic-agent-managed-kubernetes.yaml"`, + 'content-disposition': `attachment; filename="elastic-agent-managed-kubernetes.yml"`, }; return response.ok({ body, diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 16480b00316282..2b1732142686bc 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -410,6 +410,6 @@ export function registerEncryptedSavedObjects( // Encrypted saved objects encryptedSavedObjects.registerType({ type: MESSAGE_SIGNING_KEYS_SAVED_OBJECT_TYPE, - attributesToEncrypt: new Set(['private_key', 'passphrase']), + attributesToEncrypt: new Set(['passphrase']), }); } diff --git a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap index 030dd4d9ec36ff..e96997db071a81 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap +++ b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap @@ -14,6 +14,11 @@ Object { "namespace": "default", "use_output": "default", }, + "protection": Object { + "enabled": false, + "signing_key": "", + "uninstall_token_hash": "", + }, }, "fleet": Object { "hosts": Array [ @@ -63,6 +68,10 @@ Object { }, }, "revision": 1, + "signed": Object { + "data": "", + "signature": "", + }, } `; @@ -80,6 +89,11 @@ Object { "namespace": "default", "use_output": "monitoring-output-id", }, + "protection": Object { + "enabled": false, + "signing_key": "", + "uninstall_token_hash": "", + }, }, "fleet": Object { "hosts": Array [ @@ -129,6 +143,10 @@ Object { }, }, "revision": 1, + "signed": Object { + "data": "", + "signature": "", + }, } `; @@ -146,6 +164,11 @@ Object { "namespace": "default", "use_output": "monitoring-output-id", }, + "protection": Object { + "enabled": false, + "signing_key": "", + "uninstall_token_hash": "", + }, }, "fleet": Object { "hosts": Array [ @@ -195,5 +218,9 @@ Object { }, }, "revision": 1, + "signed": Object { + "data": "", + "signature": "", + }, } `; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts index 93c6b6dc891ea3..72ad9b3e5a99c5 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts @@ -8,9 +8,11 @@ import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import type { AgentPolicy, Output, DownloadSource } from '../../types'; +import { createAppContextStartContractMock } from '../../mocks'; import { agentPolicyService } from '../agent_policy'; import { agentPolicyUpdateEventHandler } from '../agent_policy_update'; +import { appContextService } from '../app_context'; import { generateFleetConfig, @@ -433,6 +435,35 @@ describe('getFullAgentPolicy', () => { }, }); }); + + it('should populate agent.protection and signed properties if encryption is available', async () => { + const mockContext = createAppContextStartContractMock(); + mockContext.messageSigningService.sign = jest + .fn() + .mockImplementation((message: Record) => + Promise.resolve({ + data: Buffer.from(JSON.stringify(message), 'utf8'), + signature: 'thisisasignature', + }) + ); + mockContext.messageSigningService.getPublicKey = jest + .fn() + .mockResolvedValue('thisisapublickey'); + appContextService.start(mockContext); + + mockAgentPolicy({}); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy!.agent!.protection).toMatchObject({ + enabled: true, + uninstall_token_hash: '', + signing_key: 'thisisapublickey', + }); + expect(agentPolicy!.signed).toMatchObject({ + data: 'eyJpZCI6ImFnZW50LXBvbGljeSIsImFnZW50Ijp7InByb3RlY3Rpb24iOnsiZW5hYmxlZCI6dHJ1ZSwidW5pbnN0YWxsX3Rva2VuX2hhc2giOiIiLCJzaWduaW5nX2tleSI6InRoaXNpc2FwdWJsaWNrZXkifX19', + signature: 'thisisasignature', + }); + }); }); describe('transformOutputToFullPolicyOutput', () => { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index fe434c015e438b..6fd6e9fdf512b0 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -24,6 +24,7 @@ import { DEFAULT_OUTPUT } from '../../constants'; import { getPackageInfo } from '../epm/packages'; import { pkgToPkgKey, splitPkgKey } from '../epm/registry'; +import { appContextService } from '../app_context'; import { getMonitoringPermissions } from './monitoring_permissions'; import { storedPackagePoliciesToAgentInputs } from '.'; @@ -124,6 +125,15 @@ export async function getFullAgentPolicy( acc[name] = featureConfig; return acc; }, {} as NonNullable['features']), + protection: { + enabled: false, + uninstall_token_hash: '', + signing_key: '', + }, + }, + signed: { + data: '', + signature: '', }, }; @@ -173,6 +183,32 @@ export async function getFullAgentPolicy( if (!standalone && fleetServerHosts) { fullAgentPolicy.fleet = generateFleetConfig(fleetServerHosts, proxies); } + + // populate protection and signed properties + const messageSigningService = appContextService.getMessageSigningService(); + if (messageSigningService?.isEncryptionAvailable && fullAgentPolicy.agent) { + const publicKey = await messageSigningService.getPublicKey(); + + fullAgentPolicy.agent.protection = { + enabled: true, + uninstall_token_hash: '', + signing_key: publicKey, + }; + + const dataToSign = { + id: fullAgentPolicy.id, + agent: { + protection: fullAgentPolicy.agent.protection, + }, + }; + + const { data: signedData, signature } = await messageSigningService.sign(dataToSign); + fullAgentPolicy.signed = { + data: signedData.toString('base64'), + signature, + }; + } + return fullAgentPolicy; } @@ -221,10 +257,6 @@ export function transformOutputToFullPolicyOutput( if (!isShipperDisabled) { shipperDiskQueueData = buildShipperQueueData(shipper); } - /* - TODO: Once the Elastic-Shipper is ready, - Verify that these parameters have the correct names and structure - */ /* eslint-disable @typescript-eslint/naming-convention */ const { loadbalance, diff --git a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts index 3ef1a269d8e6f1..ab407705007db6 100644 --- a/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/update_agent_tags.test.ts @@ -110,7 +110,7 @@ describe('update_agent_tags', () => { expect(agentAction?.body).toEqual( expect.objectContaining({ action_id: expect.anything(), - agents: ['agent1'], + agents: [expect.any(String)], type: 'UPDATE_TAGS', total: 1, }) @@ -120,7 +120,7 @@ describe('update_agent_tags', () => { const agentIds = actionResults?.body ?.filter((i: any) => i.agent_id) .map((i: any) => i.agent_id); - expect(agentIds).toEqual(['agent1']); + expect(agentIds.length).toEqual(1); expect(actionResults.body[1].error).not.toBeDefined(); }); @@ -142,7 +142,7 @@ describe('update_agent_tags', () => { expect(agentAction?.body).toEqual( expect.objectContaining({ action_id: expect.anything(), - agents: [agentInRegularDoc._id], + agents: [expect.any(String)], type: 'UPDATE_TAGS', total: 1, }) @@ -152,12 +152,23 @@ describe('update_agent_tags', () => { it('should write error action results when failures are returned', async () => { esClient.updateByQuery.mockReset(); esClient.updateByQuery.mockResolvedValue({ - failures: [{ cause: { reason: 'error reason' } }], + failures: [{ id: 'failure1', cause: { reason: 'error reason' } }], updated: 0, + total: 1, } as any); await updateAgentTags(soClient, esClient, { agentIds: ['agent1'] }, ['one'], []); + const agentAction = esClient.create.mock.calls[0][0] as any; + expect(agentAction?.body).toEqual( + expect.objectContaining({ + action_id: expect.anything(), + agents: ['failure1'], + type: 'UPDATE_TAGS', + total: 1, + }) + ); + const errorResults = esClient.bulk.mock.calls[0][0] as any; expect(errorResults.body[1].error).toEqual('error reason'); }); @@ -181,6 +192,7 @@ describe('update_agent_tags', () => { failures: [], updated: 0, version_conflicts: 100, + total: 100, } as any); await expect( @@ -198,10 +210,43 @@ describe('update_agent_tags', () => { } ) ).rejects.toThrowError('version conflict of 100 agents'); + + const agentAction = esClient.create.mock.calls[0][0] as any; + expect(agentAction?.body.agents.length).toEqual(100); + const errorResults = esClient.bulk.mock.calls[0][0] as any; expect(errorResults.body[1].error).toEqual('version conflict on last retry'); }); + it('should combine action agents from updated, failures and version conflicts on last retry', async () => { + esClient.updateByQuery.mockReset(); + esClient.updateByQuery.mockResolvedValue({ + failures: [{ id: 'failure1', cause: { reason: 'error reason' } }], + updated: 1, + version_conflicts: 1, + total: 3, + } as any); + + await expect( + updateTagsBatch( + soClient, + esClient, + [{ id: 'agent1' } as Agent], + {}, + { + tagsToAdd: ['new'], + tagsToRemove: [], + kuery: '', + total: 3, + retryCount: MAX_RETRY_COUNT, + } + ) + ).rejects.toThrowError('version conflict of 1 agents'); + + const agentAction = esClient.create.mock.calls[0][0] as any; + expect(agentAction?.body.agents.length).toEqual(3); + }); + it('should run add tags async when actioning more agents than batch size', async () => { esClient.search.mockResolvedValue({ hits: { @@ -301,7 +346,7 @@ describe('update_agent_tags', () => { it('should write total from total param if updateByQuery returns less results', async () => { esClient.updateByQuery.mockReset(); - esClient.updateByQuery.mockResolvedValue({ failures: [], updated: 0, total: 50 } as any); + esClient.updateByQuery.mockResolvedValue({ failures: [], updated: 1, total: 50 } as any); await updateTagsBatch( soClient, @@ -320,7 +365,7 @@ describe('update_agent_tags', () => { expect(agentAction?.body).toEqual( expect.objectContaining({ action_id: expect.anything(), - agents: ['agent1'], + agents: [expect.any(String)], type: 'UPDATE_TAGS', total: 100, }) diff --git a/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts b/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts index 1f12968b67c367..d8208fd5f8d08a 100644 --- a/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts +++ b/x-pack/plugins/fleet/server/services/agents/update_agent_tags_action_runner.ts @@ -129,56 +129,81 @@ export async function updateTagsBatch( appContextService.getLogger().debug(JSON.stringify(res).slice(0, 1000)); - if (options.retryCount === undefined) { - // creating an action doc so that update tags shows up in activity - await createAgentAction(esClient, { - id: actionId, - agents: agentIds, - created_at: new Date().toISOString(), - type: 'UPDATE_TAGS', - total: options.total ?? res.total, - }); - } - // creating unique ids to use as agentId, as we don't have all agent ids in case of action by kuery const getUuidArray = (count: number) => Array.from({ length: count }, () => uuidv4()); + const updatedCount = res.updated ?? 0; + const updatedIds = getUuidArray(updatedCount); + + const failures = res.failures ?? []; + const failureCount = failures.length; + + const isLastRetry = options.retryCount === MAX_RETRY_COUNT; + + const versionConflictCount = res.version_conflicts ?? 0; + const versionConflictIds = isLastRetry ? getUuidArray(versionConflictCount) : []; + + // creating an action doc so that update tags shows up in activity + // the logic only saves agent count in the action that updated, failed or in case of last retry, conflicted + // this ensures that the action status count will be accurate + await createAgentAction(esClient, { + id: actionId, + agents: updatedIds + .concat(failures.map((failure) => failure.id)) + .concat(isLastRetry ? versionConflictIds : []), + created_at: new Date().toISOString(), + type: 'UPDATE_TAGS', + total: options.total ?? res.total, + }); + appContextService + .getLogger() + .debug( + `action doc wrote on ${ + updatedCount + failureCount + (isLastRetry ? versionConflictCount : 0) + } agentIds, updated: ${updatedCount}, failed: ${failureCount}, version_conflicts: ${versionConflictCount}` + ); + // writing successful action results - if (res.updated ?? 0 > 0) { + if (updatedCount > 0) { await bulkCreateAgentActionResults( esClient, - agentIds.map((id) => ({ + updatedIds.map((id) => ({ agentId: id, actionId, })) ); + appContextService.getLogger().debug(`action updated result wrote on ${updatedCount} agents`); } // writing failures from es update - if (res.failures && res.failures.length > 0) { + if (failures.length > 0) { await bulkCreateAgentActionResults( esClient, - res.failures.map((failure) => ({ + failures.map((failure) => ({ agentId: failure.id, actionId, error: failure.cause.reason, })) ); + appContextService.getLogger().debug(`action failed result wrote on ${failureCount} agents`); } - if (res.version_conflicts ?? 0 > 0) { + if (versionConflictCount > 0) { // write out error results on last retry, so action is not stuck in progress if (options.retryCount === MAX_RETRY_COUNT) { await bulkCreateAgentActionResults( esClient, - getUuidArray(res.version_conflicts!).map((id) => ({ + versionConflictIds.map((id) => ({ agentId: id, actionId, error: 'version conflict on last retry', })) ); + appContextService + .getLogger() + .debug(`action conflict result wrote on ${versionConflictCount} agents`); } - throw new Error(`version conflict of ${res.version_conflicts} agents`); + throw new Error(`version conflict of ${versionConflictCount} agents`); } return { actionId, updated: res.updated, took: res.took }; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/parse.ts b/x-pack/plugins/fleet/server/services/epm/archive/parse.ts index 04ed584481205e..8ec5312aa1484e 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/parse.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/parse.ts @@ -38,7 +38,7 @@ import { pkgToPkgKey } from '../registry'; import { unpackBufferEntries } from '.'; const readFileAsync = promisify(readFile); -const MANIFEST_NAME = 'manifest.yml'; +export const MANIFEST_NAME = 'manifest.yml'; const DEFAULT_RELEASE_VALUE = 'ga'; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts index 3ecdcdaad8aa76..cbea18b8b8338b 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts @@ -7,8 +7,6 @@ import { extname } from 'path'; -import { uniq } from 'lodash'; -import { safeLoad } from 'js-yaml'; import { isBinaryFile } from 'isbinaryfile'; import mime from 'mime-types'; import { v5 as uuidv5 } from 'uuid'; @@ -20,19 +18,13 @@ import type { InstallablePackage, InstallSource, PackageAssetReference, - RegistryDataStream, } from '../../../../common/types'; -import { pkgToPkgKey } from '../registry'; import { appContextService } from '../../app_context'; import { getArchiveEntry, setArchiveEntry, setArchiveFilelist, setPackageInfo } from '.'; import type { ArchiveEntry } from '.'; -import { - parseAndVerifyPolicyTemplates, - parseAndVerifyStreams, - parseTopLevelElasticsearchEntry, -} from './parse'; +import { MANIFEST_NAME, parseAndVerifyArchive } from './parse'; const ONE_BYTE = 1024 * 1024; // could be anything, picked this from https://github.com/elastic/elastic-agent-client/issues/17 @@ -188,7 +180,6 @@ export const getEsPackage = async ( savedObjectsClient: SavedObjectsClientContract ) => { const logger = appContextService.getLogger(); - const pkgKey = pkgToPkgKey({ name: pkgName, version: pkgVersion }); const bulkRes = await savedObjectsClient.bulkGet( references.map((reference) => ({ ...reference, @@ -216,87 +207,25 @@ export const getEsPackage = async ( return undefined; } - const paths: string[] = []; + const manifests: Record = {}; const entries: ArchiveEntry[] = assets.map(packageAssetToArchiveEntry); + const paths: string[] = []; entries.forEach(({ path, buffer }) => { if (path && buffer) { setArchiveEntry(path, buffer); paths.push(path); } + paths.push(path); + if (path.endsWith(MANIFEST_NAME) && buffer) manifests[path] = buffer; }); - - // create the packageInfo - // TODO: this is mostly copied from validtion.ts, needed in case package does not exist in storage yet or is missing from cache - // we don't want to reach out to the registry again so recreate it here. should check whether it exists in packageInfoCache first - const manifestPath = `${pkgName}-${pkgVersion}/manifest.yml`; - const soResManifest = await savedObjectsClient.get( - ASSETS_SAVED_OBJECT_TYPE, - assetPathToObjectId(manifestPath) - ); - const packageInfo = safeLoad(soResManifest.attributes.data_utf8); - if (packageInfo.elasticsearch) { - packageInfo.elasticsearch = parseTopLevelElasticsearchEntry(packageInfo.elasticsearch); - } - try { - const readmePath = `docs/README.md`; - await savedObjectsClient.get( - ASSETS_SAVED_OBJECT_TYPE, - assetPathToObjectId(`${pkgName}-${pkgVersion}/${readmePath}`) - ); - packageInfo.readme = `/package/${pkgName}/${pkgVersion}/${readmePath}`; - } catch (err) { - // read me doesn't exist - } - - let dataStreamPaths: string[] = []; - const dataStreams: RegistryDataStream[] = []; - paths - .filter((path) => path.startsWith(`${pkgKey}/data_stream/`)) - .forEach((path) => { - const parts = path.split('/'); - if (parts.length > 2 && parts[2]) dataStreamPaths.push(parts[2]); - }); - - dataStreamPaths = uniq(dataStreamPaths); - - await Promise.all( - dataStreamPaths.map(async (dataStreamPath) => { - const dataStreamManifestPath = `${pkgKey}/data_stream/${dataStreamPath}/manifest.yml`; - const soResDataStreamManifest = await savedObjectsClient.get( - ASSETS_SAVED_OBJECT_TYPE, - assetPathToObjectId(dataStreamManifestPath) - ); - const dataStreamManifest = safeLoad(soResDataStreamManifest.attributes.data_utf8); - const { - ingest_pipeline: ingestPipeline, - dataset, - streams: manifestStreams, - ...dataStreamManifestProps - } = dataStreamManifest; - const streams = parseAndVerifyStreams(manifestStreams, dataStreamPath); - - dataStreams.push({ - dataset: dataset || `${pkgName}.${dataStreamPath}`, - package: pkgName, - ingest_pipeline: ingestPipeline, - path: dataStreamPath, - streams, - ...dataStreamManifestProps, - }); - }) - ); - packageInfo.policy_templates = parseAndVerifyPolicyTemplates(packageInfo); - packageInfo.data_streams = dataStreams; - packageInfo.assets = paths.map((path) => { - return path.replace(`${pkgName}-${pkgVersion}`, `/package/${pkgName}/${pkgVersion}`); - }); - - // Add asset references to cache + // // Add asset references to cache setArchiveFilelist({ name: pkgName, version: pkgVersion }, paths); + + const packageInfo = parseAndVerifyArchive(paths, manifests); setPackageInfo({ name: pkgName, version: pkgVersion, packageInfo }); return { - paths, packageInfo, + paths, }; }; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts index a893fefe1b390f..9a03fd720bc103 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts @@ -26,7 +26,7 @@ import { getSettings } from '../../settings'; import { getPackageInfo, getPackages, getPackageUsageStats } from './get'; -const MockRegistry = Registry as jest.Mocked; +const MockRegistry = jest.mocked(Registry); jest.mock('../../settings'); @@ -200,6 +200,7 @@ describe('When using EPM `get` services', () => { ]); MockRegistry.fetchFindLatestPackageOrUndefined.mockResolvedValue(undefined); MockRegistry.fetchInfo.mockResolvedValue({} as any); + MockRegistry.pkgToPkgKey.mockImplementation(({ name, version }) => `${name}-${version}`); }); it('should return installed package that is not in registry with package info', async () => { @@ -246,9 +247,27 @@ description: Elasticsearch description`, } }); soClient.bulkGet.mockResolvedValue({ - saved_objects: [], + saved_objects: [ + { + id: 'test', + references: [], + type: 'epm-package-assets', + attributes: { + asset_path: 'elasticsearch-0.0.1/manifest.yml', + data_utf8: ` +name: elasticsearch +version: 0.0.1 +title: Elastic +description: Elasticsearch description +format_version: 0.0.1 +owner: elastic`, + }, + }, + ], + }); + await getPackages({ + savedObjectsClient: soClient, }); - await expect( getPackages({ savedObjectsClient: soClient, diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 5eacf8dd0c3a83..282cb85b2b895b 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -2151,6 +2151,14 @@ export function _validateRestrictedFieldsNotModifiedOrThrow(opts: { oldStream?.vars['data_stream.dataset']?.value !== stream?.vars?.['data_stream.dataset']?.value ) { + // seeing this error in dev? Package policy must be called with prepareInputPackagePolicyDataset function first in UI code + appContextService + .getLogger() + .debug( + `Rejecting package policy update due to dataset change, old val '${ + oldStream?.vars['data_stream.dataset']?.value + }, new val '${JSON.stringify(stream?.vars?.['data_stream.dataset']?.value)}'` + ); throw new PackagePolicyValidationError( i18n.translate('xpack.fleet.updatePackagePolicy.datasetCannotBeModified', { defaultMessage: diff --git a/x-pack/plugins/fleet/server/services/security/message_signing_service.ts b/x-pack/plugins/fleet/server/services/security/message_signing_service.ts index 6e323a55fc6f8d..590421113f3397 100644 --- a/x-pack/plugins/fleet/server/services/security/message_signing_service.ts +++ b/x-pack/plugins/fleet/server/services/security/message_signing_service.ts @@ -22,8 +22,11 @@ interface MessageSigningKeys { } export interface MessageSigningServiceInterface { - generateKeyPair(providedPassphrase?: string): Promise; - sign(serializedMessage: Buffer | object): Promise<{ data: Buffer; signature: string }>; + get isEncryptionAvailable(): boolean; + generateKeyPair( + providedPassphrase?: string + ): Promise<{ privateKey: string; publicKey: string; passphrase: string }>; + sign(message: Buffer | Record): Promise<{ data: Buffer; signature: string }>; getPublicKey(): Promise; } @@ -32,12 +35,18 @@ export class MessageSigningService implements MessageSigningServiceInterface { constructor(private esoClient: EncryptedSavedObjectsClient) {} - public async generateKeyPair(providedPassphrase?: string) { + public get isEncryptionAvailable(): boolean { + return appContextService.getEncryptedSavedObjectsSetup()?.canEncrypt ?? false; + } + + public async generateKeyPair( + providedPassphrase?: string + ): Promise<{ privateKey: string; publicKey: string; passphrase: string }> { this.checkForEncryptionKey(); const currentKeyPair = await this.getCurrentKeyPair(); if (currentKeyPair.privateKey && currentKeyPair.publicKey && currentKeyPair.passphrase) { - return; + return currentKeyPair; } const passphrase = providedPassphrase || this.generatePassphrase(); @@ -56,19 +65,25 @@ export class MessageSigningService implements MessageSigningServiceInterface { }, }); + const privateKey = keyPair.privateKey.toString('base64'); + const publicKey = keyPair.publicKey.toString('base64'); await this.soClient.create(MESSAGE_SIGNING_KEYS_SAVED_OBJECT_TYPE, { - private_key: keyPair.privateKey.toString('base64'), - public_key: keyPair.publicKey.toString('base64'), + private_key: privateKey, + public_key: publicKey, passphrase, }); - return; + return { + privateKey, + publicKey, + passphrase, + }; } public async sign( message: Buffer | Record ): Promise<{ data: Buffer; signature: string }> { - this.checkForEncryptionKey(); + const { privateKey: serializedPrivateKey, passphrase } = await this.generateKeyPair(); const msgBuffer = Buffer.isBuffer(message) ? message @@ -78,8 +93,6 @@ export class MessageSigningService implements MessageSigningServiceInterface { signer.update(msgBuffer); signer.end(); - const { privateKey: serializedPrivateKey, passphrase } = await this.getCurrentKeyPair(); - if (!serializedPrivateKey) { throw new Error('unable to find private key'); } @@ -99,9 +112,7 @@ export class MessageSigningService implements MessageSigningServiceInterface { } public async getPublicKey(): Promise { - this.checkForEncryptionKey(); - - const { publicKey } = await this.getCurrentKeyPair(); + const { publicKey } = await this.generateKeyPair(); if (!publicKey) { throw new Error('unable to find public key'); @@ -170,7 +181,7 @@ export class MessageSigningService implements MessageSigningServiceInterface { } private checkForEncryptionKey(): void { - if (!appContextService.getEncryptedSavedObjectsSetup()?.canEncrypt) { + if (!this.isEncryptionAvailable) { throw new Error('encryption key not set, message signing service is disabled'); } } diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 7acf46408367bd..db4a9155ba89ef 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -165,19 +165,19 @@ async function createSetupSideEffects( logger.debug('Upgrade Fleet package install versions'); await upgradePackageInstallVersion({ soClient, esClient, logger }); - logger.debug('Upgrade Agent policy schema version'); - await upgradeAgentPolicySchemaVersion(soClient); - - logger.debug('Setting up Fleet enrollment keys'); - await ensureDefaultEnrollmentAPIKeysExists(soClient, esClient); - - if (appContextService.getEncryptedSavedObjectsSetup()?.canEncrypt) { + if (appContextService.getMessageSigningService()?.isEncryptionAvailable) { logger.debug('Generating key pair for message signing'); await appContextService.getMessageSigningService()?.generateKeyPair(); } else { logger.info('No encryption key set, skipping key pair generation for message signing'); } + logger.debug('Upgrade Agent policy schema version'); + await upgradeAgentPolicySchemaVersion(soClient); + + logger.debug('Setting up Fleet enrollment keys'); + await ensureDefaultEnrollmentAPIKeysExists(soClient, esClient); + if (nonFatalErrors.length > 0) { logger.info('Encountered non fatal errors during Fleet setup'); formatNonFatalErrors(nonFatalErrors).forEach((error) => logger.info(JSON.stringify(error))); diff --git a/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx b/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx index 3f95b6adf6b451..81be2e191516a4 100644 --- a/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx +++ b/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx @@ -77,7 +77,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) { const kibana = useKibana(); const { services, overlays } = kibana; - const { savedObjects, uiSettings, application, data } = services; + const { http, uiSettings, application, data } = services; const [hasDataViews, setHasDataViews] = useState(true); useEffect(() => { @@ -90,7 +90,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) { if (!overlays || !application) return null; const onOpenDatasourcePicker = () => { - openSourceModal({ overlays, savedObjects, uiSettings }, onIndexPatternSelected); + openSourceModal({ overlays, http, uiSettings }, onIndexPatternSelected); }; let content = ( diff --git a/x-pack/plugins/graph/public/components/search_bar.tsx b/x-pack/plugins/graph/public/components/search_bar.tsx index c3e846adffbd33..fcd5d576116d9f 100644 --- a/x-pack/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/plugins/graph/public/components/search_bar.tsx @@ -98,7 +98,6 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) const kibana = useKibana(); const { services, overlays } = kibana; const { - savedObjects, uiSettings, appName, unifiedSearch, @@ -132,8 +131,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) data-test-subj="graphDatasourceButton" onClick={() => { confirmWipeWorkspace( - () => - openSourceModal({ overlays, savedObjects, uiSettings }, onIndexPatternSelected), + () => openSourceModal({ overlays, http, uiSettings }, onIndexPatternSelected), i18n.translate('xpack.graph.clearWorkspace.confirmText', { defaultMessage: 'If you change data sources, your current fields and vertices will be reset.', diff --git a/x-pack/plugins/graph/public/components/source_picker.tsx b/x-pack/plugins/graph/public/components/source_picker.tsx index 31ec5b0663ea2f..ceb165fd508400 100644 --- a/x-pack/plugins/graph/public/components/source_picker.tsx +++ b/x-pack/plugins/graph/public/components/source_picker.tsx @@ -14,20 +14,16 @@ import { IndexPatternSavedObject } from '../types'; export interface SourcePickerProps { onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void; - savedObjects: CoreStart['savedObjects']; + http: CoreStart['http']; uiSettings: CoreStart['uiSettings']; } const fixedPageSize = 8; -export function SourcePicker({ - savedObjects, - uiSettings, - onIndexPatternSelected, -}: SourcePickerProps) { +export function SourcePicker({ http, uiSettings, onIndexPatternSelected }: SourcePickerProps) { return ( { onIndexPatternSelected(indexPattern as IndexPatternSavedObject); diff --git a/x-pack/plugins/graph/public/services/source_modal.tsx b/x-pack/plugins/graph/public/services/source_modal.tsx index cf20e017331390..258bb58d1e0771 100644 --- a/x-pack/plugins/graph/public/services/source_modal.tsx +++ b/x-pack/plugins/graph/public/services/source_modal.tsx @@ -14,11 +14,11 @@ import { IndexPatternSavedObject } from '../types'; export function openSourceModal( { overlays, - savedObjects, + http, uiSettings, }: { overlays: KibanaReactOverlays; - savedObjects: CoreStart['savedObjects']; + http: CoreStart['http']; uiSettings: CoreStart['uiSettings']; }, onSelected: (indexPattern: IndexPatternSavedObject) => void @@ -26,7 +26,7 @@ export function openSourceModal( const modalRef = overlays.openModal( { onSelected(indexPattern); modalRef.close(); diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts index dce09b154bda92..278849eaa71525 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/index.ts @@ -6,7 +6,6 @@ */ import { cpu } from './snapshot/cpu'; -import { cpuCores } from './snapshot/cpu_cores'; import { diskLatency } from './snapshot/disk_latency'; import { count } from '../../shared/metrics/snapshot/count'; import { load } from './snapshot/load'; @@ -38,7 +37,6 @@ import { InventoryMetrics } from '../../types'; const exposedHostSnapshotMetrics = { cpu, - cpuCores, diskLatency, load, logRate, diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index cf8cbc089ebfa8..13e4e294247245 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -344,7 +344,6 @@ export type MetricsUIAggregation = rt.TypeOf; export const SnapshotMetricTypeKeys = { count: null, cpu: null, - cpuCores: null, diskLatency: null, load: null, memory: null, diff --git a/x-pack/plugins/infra/docs/state_machines/README.md b/x-pack/plugins/infra/docs/state_machines/README.md index b7eac58a546686..b282211313c295 100644 --- a/x-pack/plugins/infra/docs/state_machines/README.md +++ b/x-pack/plugins/infra/docs/state_machines/README.md @@ -6,3 +6,4 @@ implementation patterns: - [Patterns for designing XState state machines](./xstate_machine_patterns.md) - [Patterns for using XState with React](./xstate_react_patterns.md) +- [Patterns for working with URLs and URL precedence](./xstate_url_patterns_and_precedence.md) diff --git a/x-pack/plugins/infra/docs/state_machines/xstate_url_patterns_and_precedence.md b/x-pack/plugins/infra/docs/state_machines/xstate_url_patterns_and_precedence.md new file mode 100644 index 00000000000000..cac619a75fa916 --- /dev/null +++ b/x-pack/plugins/infra/docs/state_machines/xstate_url_patterns_and_precedence.md @@ -0,0 +1,114 @@ +# URL patterns and URL precedence + +## Summary + +When working with state it's common to synchronise a portion to the URL. + +### Patterns + +Within our state machines we begin in an `uninitialized` state, from here we move in to states that represent initialisation of intitial values. This may differ between machines depending on which Kibana services (if any) are relied on. It could also be possible to have a machine that merely has defaults and does not rely on services and URL state. + +For example here is an example of our `uninitialized` state immediately transitioning to `initializingFromTimeFilterService`. + +```ts +uninitialized: { + always: { + target: 'initializingFromTimeFilterService', + }, +}, +``` + +Our `initializingFromTimeFilterService` target might look something like this: + +```ts + initializingFromTimeFilterService: { + on: { + INITIALIZED_FROM_TIME_FILTER_SERVICE: { + target: 'initializingFromUrl', + actions: ['updateTimeContextFromTimeFilterService'], + }, + }, + invoke: { + src: 'initializeFromTimeFilterService', + }, +}, +``` + +This invokes an (xstate) service to interact with the (Kibana) service and read values. We then receive an `INITIALIZED_FROM_TIME_FILTER_SERVICE` event, store what we need in context, and move to the next level of initialisation (URL). + +As the target becomes `initializingFromUrl` we see much the same thing: + +```ts +initializingFromUrl: { + on: { + INITIALIZED_FROM_URL: { + target: 'initialized', + actions: ['storeQuery', 'storeFilters', 'updateTimeContextFromUrl'], + }, + }, + invoke: { + src: 'initializeFromUrl', + }, +}, +``` + +Eventually we receive an `INITIALIZED_FROM_URL` event, values are stored in context, and we then move to the `initialized` state. + +The code that interacts with the URL is in a file called `url_state_storage_service.ts` under the directory of the machine. + +This is powerful because we could have as many layers as we need here, and we will only move to the `initialized` state at the end of the chain. Since the UI won't attempt to render content until we're in an `initialized` state we are safe from subtle race conditions where we might attempt to read a value too early. + +## Precedence + +In the Logs solution the order of precedence is as follows: + +- Defaults +- Kibana services (time filter, query, filter manager etc) +- URL + +That is to say the URL has most precedence and will overwrite defaults and service values. + +### Log Stream + +Within the Log Stream we have the following state held in the URL (and managed by xstate): + +- Log filter + - Time range + - From + - To + - Refresh interval + - Pause + - Value + - Query + - Language + - Query + - Filters + +- Log position + - Position + - Time + - Tiebreaker + +#### Warning! + +Due to legacy reasons the `logFilter` key should be initialised before the `logPosition` key. Otherwise the `logPosition` key might be overwritten before the `logFilter` code has had a chance to read from the key. + +#### Backwards compatibility + +The Log Stream does have some legacy URL state that needs to be translated for backwards compatibility. Here is an example of the previous legacy formats: + +- Log filter + - Language + - Query + +- Log filter (this version is older than language / query) + - Kind + - Expression + +- Log position + - Start (now log filter > time range > from) + - End (now log filter > time range > to) + - StreamLive (now log filter > refresh interval > pause) + - Position + - Time (used to determine log filter > time range > from / to if start and end aren't set within legacy log position) + - Tiebreaker \ No newline at end of file diff --git a/x-pack/plugins/infra/public/components/try_it_button.tsx b/x-pack/plugins/infra/public/components/try_it_button.tsx index eeb9d68a93a692..8097461986287f 100644 --- a/x-pack/plugins/infra/public/components/try_it_button.tsx +++ b/x-pack/plugins/infra/public/components/try_it_button.tsx @@ -13,6 +13,7 @@ import { css } from '@emotion/react'; import { EuiLinkColor } from '@elastic/eui'; import { ExperimentalBadge } from './experimental_badge'; +type OnClickEvent = React.MouseEvent | React.MouseEvent; interface Props { color?: EuiLinkColor; 'data-test-subj'?: string; @@ -20,7 +21,7 @@ interface Props { label: string; link: LinkDescriptor; hideBadge?: boolean; - onClick?: () => void; + onClick?: (e?: OnClickEvent) => void; } export const TryItButton = ({ label, @@ -33,6 +34,11 @@ export const TryItButton = ({ }: Props) => { const linkProps = useLinkProps({ ...link }); + const handleClick = (event: OnClickEvent) => { + if (linkProps.onClick) linkProps.onClick(event); + if (onClick) onClick(event); + }; + return ( {!hideBadge && ( @@ -40,7 +46,7 @@ export const TryItButton = ({ {experimental && ( diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/index.ts b/x-pack/plugins/infra/public/containers/logs/log_position/index.ts index e4e6ad6c54deb8..677428ac7a3f7a 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_position/index.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_position/index.ts @@ -5,7 +5,4 @@ * 2.0. */ -export * from './log_position_state'; -export * from './replace_log_position_in_query_string'; export * from './use_log_position'; -export type { LogPositionUrlState } from './use_log_position_url_state_sync'; diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.test.ts b/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.test.ts deleted file mode 100644 index b87dca28fc048b..00000000000000 --- a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.test.ts +++ /dev/null @@ -1,287 +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 moment from 'moment'; -import { createInitialLogPositionState, updateStateFromUrlState } from './log_position_state'; - -describe('function createInitialLogPositionState', () => { - it('initializes state without url and timefilter', () => { - const initialState = createInitialLogPositionState({ - initialStateFromUrl: null, - initialStateFromTimefilter: null, - now: getTestMoment().toDate(), - }); - - expect(initialState).toMatchInlineSnapshot(` - Object { - "latestPosition": null, - "refreshInterval": Object { - "pause": true, - "value": 5000, - }, - "targetPosition": null, - "timeRange": Object { - "expression": Object { - "from": "now-1d", - "to": "now", - }, - "lastChangedCompletely": 1640995200000, - }, - "timestamps": Object { - "endTimestamp": 1640995200000, - "lastChangedTimestamp": 1640995200000, - "startTimestamp": 1640908800000, - }, - "visiblePositions": Object { - "endKey": null, - "middleKey": null, - "pagesAfterEnd": Infinity, - "pagesBeforeStart": Infinity, - "startKey": null, - }, - } - `); - }); - - it('initializes state from complete url state', () => { - const initialState = createInitialLogPositionState({ - initialStateFromUrl: { - start: 'now-2d', - end: 'now-1d', - position: { - time: getTestMoment().subtract(36, 'hours').valueOf(), - tiebreaker: 0, - }, - streamLive: false, - }, - initialStateFromTimefilter: null, - now: getTestMoment().toDate(), - }); - - expect(initialState).toMatchInlineSnapshot(` - Object { - "latestPosition": Object { - "tiebreaker": 0, - "time": 1640865600000, - }, - "refreshInterval": Object { - "pause": true, - "value": 5000, - }, - "targetPosition": Object { - "tiebreaker": 0, - "time": 1640865600000, - }, - "timeRange": Object { - "expression": Object { - "from": "now-2d", - "to": "now-1d", - }, - "lastChangedCompletely": 1640995200000, - }, - "timestamps": Object { - "endTimestamp": 1640908800000, - "lastChangedTimestamp": 1640995200000, - "startTimestamp": 1640822400000, - }, - "visiblePositions": Object { - "endKey": null, - "middleKey": null, - "pagesAfterEnd": Infinity, - "pagesBeforeStart": Infinity, - "startKey": null, - }, - } - `); - }); - - it('initializes state from from url state with just a time range', () => { - const initialState = createInitialLogPositionState({ - initialStateFromUrl: { - start: 'now-2d', - end: 'now-1d', - }, - initialStateFromTimefilter: null, - now: getTestMoment().toDate(), - }); - - expect(initialState).toMatchInlineSnapshot(` - Object { - "latestPosition": null, - "refreshInterval": Object { - "pause": true, - "value": 5000, - }, - "targetPosition": null, - "timeRange": Object { - "expression": Object { - "from": "now-2d", - "to": "now-1d", - }, - "lastChangedCompletely": 1640995200000, - }, - "timestamps": Object { - "endTimestamp": 1640908800000, - "lastChangedTimestamp": 1640995200000, - "startTimestamp": 1640822400000, - }, - "visiblePositions": Object { - "endKey": null, - "middleKey": null, - "pagesAfterEnd": Infinity, - "pagesBeforeStart": Infinity, - "startKey": null, - }, - } - `); - }); - - it('initializes state from from url state with just a position', () => { - const initialState = createInitialLogPositionState({ - initialStateFromUrl: { - position: { - time: getTestMoment().subtract(36, 'hours').valueOf(), - }, - }, - initialStateFromTimefilter: null, - now: getTestMoment().toDate(), - }); - - expect(initialState).toMatchInlineSnapshot(` - Object { - "latestPosition": Object { - "tiebreaker": 0, - "time": 1640865600000, - }, - "refreshInterval": Object { - "pause": true, - "value": 5000, - }, - "targetPosition": Object { - "tiebreaker": 0, - "time": 1640865600000, - }, - "timeRange": Object { - "expression": Object { - "from": "2021-12-30T11:00:00.000Z", - "to": "2021-12-30T13:00:00.000Z", - }, - "lastChangedCompletely": 1640995200000, - }, - "timestamps": Object { - "endTimestamp": 1640869200000, - "lastChangedTimestamp": 1640995200000, - "startTimestamp": 1640862000000, - }, - "visiblePositions": Object { - "endKey": null, - "middleKey": null, - "pagesAfterEnd": Infinity, - "pagesBeforeStart": Infinity, - "startKey": null, - }, - } - `); - }); -}); - -describe('function updateStateFromUrlState', () => { - it('applies a new target position that is within the date range', () => { - const initialState = createInitialTestState(); - const newState = updateStateFromUrlState({ - position: { - time: initialState.timestamps.startTimestamp + 1, - tiebreaker: 2, - }, - })(initialState); - - expect(newState).toEqual({ - ...initialState, - targetPosition: { - time: initialState.timestamps.startTimestamp + 1, - tiebreaker: 2, - }, - latestPosition: { - time: initialState.timestamps.startTimestamp + 1, - tiebreaker: 2, - }, - }); - }); - - it('applies a new partial target position that is within the date range', () => { - const initialState = createInitialTestState(); - const newState = updateStateFromUrlState({ - position: { - time: initialState.timestamps.startTimestamp + 1, - }, - })(initialState); - - expect(newState).toEqual({ - ...initialState, - targetPosition: { - time: initialState.timestamps.startTimestamp + 1, - tiebreaker: 0, - }, - latestPosition: { - time: initialState.timestamps.startTimestamp + 1, - tiebreaker: 0, - }, - }); - }); - - it('rejects a target position that is outside the date range', () => { - const initialState = createInitialTestState(); - const newState = updateStateFromUrlState({ - position: { - time: initialState.timestamps.startTimestamp - 1, - }, - })(initialState); - - expect(newState).toEqual({ - ...initialState, - targetPosition: null, - latestPosition: null, - }); - }); - - it('applies a new time range and updates timestamps', () => { - const initialState = createInitialTestState(); - const updateDate = getTestMoment().add(1, 'hour').toDate(); - const newState = updateStateFromUrlState( - { - start: 'now-2d', - end: 'now-1d', - }, - updateDate - )(initialState); - - expect(newState).toEqual({ - ...initialState, - timeRange: { - expression: { - from: 'now-2d', - to: 'now-1d', - }, - lastChangedCompletely: updateDate.valueOf(), - }, - timestamps: { - startTimestamp: moment(updateDate).subtract(2, 'day').valueOf(), - endTimestamp: moment(updateDate).subtract(1, 'day').valueOf(), - lastChangedTimestamp: updateDate.valueOf(), - }, - }); - }); -}); - -const getTestMoment = () => moment.utc('2022-01-01T00:00:00.000Z'); - -const createInitialTestState = () => - createInitialLogPositionState({ - initialStateFromUrl: null, - initialStateFromTimefilter: null, - now: getTestMoment().toDate(), - }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.ts b/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.ts deleted file mode 100644 index cd5f11346c56aa..00000000000000 --- a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_state.ts +++ /dev/null @@ -1,308 +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 { RefreshInterval } from '@kbn/data-plugin/public'; -import { TimeRange } from '@kbn/es-query'; -import { createStateContainer } from '@kbn/kibana-utils-plugin/public'; -import { identity, pipe } from 'fp-ts/lib/function'; -import produce, { Draft, original } from 'immer'; -import moment, { DurationInputObject } from 'moment'; -import { isSameTimeKey, MinimalTimeKey, pickTimeKey, TimeKey } from '../../../../common/time'; -import { datemathToEpochMillis } from '../../../utils/datemath'; -import { TimefilterState } from '../../../utils/timefilter_state_storage'; -import { LogPositionUrlState } from './use_log_position_url_state_sync'; - -interface VisiblePositions { - startKey: TimeKey | null; - middleKey: TimeKey | null; - endKey: TimeKey | null; - pagesAfterEnd: number; - pagesBeforeStart: number; -} - -export interface LogPositionState { - timeRange: { - expression: TimeRange; - lastChangedCompletely: number; - }; - timestamps: { - startTimestamp: number; - endTimestamp: number; - lastChangedTimestamp: number; - }; - refreshInterval: RefreshInterval; - latestPosition: TimeKey | null; - targetPosition: TimeKey | null; - visiblePositions: VisiblePositions; -} - -export interface InitialLogPositionArguments { - initialStateFromUrl: LogPositionUrlState | null; - initialStateFromTimefilter: TimefilterState | null; - now?: Date; -} - -/** - * Initial state - */ - -const initialTimeRangeExpression: TimeRange = { - from: 'now-1d', - to: 'now', -}; - -const initialRefreshInterval: RefreshInterval = { - pause: true, - value: 5000, -}; - -const initialVisiblePositions: VisiblePositions = { - endKey: null, - middleKey: null, - startKey: null, - pagesBeforeStart: Infinity, - pagesAfterEnd: Infinity, -}; - -export const createInitialLogPositionState = ({ - initialStateFromUrl, - initialStateFromTimefilter, - now, -}: InitialLogPositionArguments): LogPositionState => { - const nowTimestamp = now?.valueOf() ?? Date.now(); - - return pipe( - { - timeRange: { - expression: initialTimeRangeExpression, - lastChangedCompletely: nowTimestamp, - }, - timestamps: { - startTimestamp: datemathToEpochMillis(initialTimeRangeExpression.from, 'down', now) ?? 0, - endTimestamp: datemathToEpochMillis(initialTimeRangeExpression.to, 'up', now) ?? 0, - lastChangedTimestamp: nowTimestamp, - }, - refreshInterval: initialRefreshInterval, - targetPosition: null, - latestPosition: null, - visiblePositions: initialVisiblePositions, - }, - initialStateFromUrl != null - ? initializeStateFromUrlState(initialStateFromUrl, now) - : initialStateFromTimefilter != null - ? updateStateFromTimefilterState(initialStateFromTimefilter, now) - : identity - ); -}; - -export const createLogPositionStateContainer = (initialArguments: InitialLogPositionArguments) => - createStateContainer(createInitialLogPositionState(initialArguments), { - updateTimeRange: (state: LogPositionState) => (timeRange: Partial) => - updateTimeRange(timeRange)(state), - updateRefreshInterval: - (state: LogPositionState) => (refreshInterval: Partial) => - updateRefreshInterval(refreshInterval)(state), - startLiveStreaming: (state: LogPositionState) => () => - updateRefreshInterval({ pause: false })(state), - stopLiveStreaming: (state: LogPositionState) => () => - updateRefreshInterval({ pause: true })(state), - jumpToTargetPosition: (state: LogPositionState) => (targetPosition: TimeKey | null) => - updateTargetPosition(targetPosition)(state), - jumpToTargetPositionTime: (state: LogPositionState) => (time: number) => - updateTargetPosition({ time })(state), - reportVisiblePositions: (state: LogPositionState) => (visiblePositions: VisiblePositions) => - updateVisiblePositions(visiblePositions)(state), - }); - -/** - * Common updaters - */ - -const updateVisiblePositions = (visiblePositions: VisiblePositions) => - produce((draftState) => { - draftState.visiblePositions = visiblePositions; - - updateLatestPositionDraft(draftState); - }); - -const updateTargetPosition = (targetPosition: Partial | null) => - produce((draftState) => { - if (targetPosition?.time != null) { - draftState.targetPosition = { - time: targetPosition.time, - tiebreaker: targetPosition.tiebreaker ?? 0, - }; - } else { - draftState.targetPosition = null; - } - - updateLatestPositionDraft(draftState); - }); - -const updateLatestPositionDraft = (draftState: Draft) => { - const previousState = original(draftState); - const previousVisibleMiddleKey = previousState?.visiblePositions?.middleKey ?? null; - const previousTargetPosition = previousState?.targetPosition ?? null; - - if (!isSameTimeKey(previousVisibleMiddleKey, draftState.visiblePositions.middleKey)) { - draftState.latestPosition = draftState.visiblePositions.middleKey; - } else if (!isSameTimeKey(previousTargetPosition, draftState.targetPosition)) { - draftState.latestPosition = draftState.targetPosition; - } -}; - -const updateTimeRange = (timeRange: Partial, now?: Date) => - produce((draftState) => { - const newFrom = timeRange?.from; - const newTo = timeRange?.to; - const nowTimestamp = now?.valueOf() ?? Date.now(); - - // Update expression and timestamps - if (newFrom != null) { - draftState.timeRange.expression.from = newFrom; - const newStartTimestamp = datemathToEpochMillis(newFrom, 'down', now); - if (newStartTimestamp != null) { - draftState.timestamps.startTimestamp = newStartTimestamp; - draftState.timestamps.lastChangedTimestamp = nowTimestamp; - } - } - if (newTo != null) { - draftState.timeRange.expression.to = newTo; - const newEndTimestamp = datemathToEpochMillis(newTo, 'up', now); - if (newEndTimestamp != null) { - draftState.timestamps.endTimestamp = newEndTimestamp; - draftState.timestamps.lastChangedTimestamp = nowTimestamp; - } - } - if (newFrom != null && newTo != null) { - draftState.timeRange.lastChangedCompletely = nowTimestamp; - } - - // Reset the target position if it doesn't fall within the new range. - if ( - draftState.targetPosition != null && - (draftState.timestamps.startTimestamp > draftState.targetPosition.time || - draftState.timestamps.endTimestamp < draftState.targetPosition.time) - ) { - draftState.targetPosition = null; - - updateLatestPositionDraft(draftState); - } - }); - -const updateRefreshInterval = - (refreshInterval: Partial) => (state: LogPositionState) => - pipe( - state, - produce((draftState) => { - if (refreshInterval.pause != null) { - draftState.refreshInterval.pause = refreshInterval.pause; - } - if (refreshInterval.value != null) { - draftState.refreshInterval.value = refreshInterval.value; - } - - if (!draftState.refreshInterval.pause) { - draftState.targetPosition = null; - - updateLatestPositionDraft(draftState); - } - }), - (currentState) => { - if (!currentState.refreshInterval.pause) { - return updateTimeRange(initialTimeRangeExpression)(currentState); - } else { - return currentState; - } - } - ); - -/** - * URL state helpers - */ - -export const getUrlState = (state: LogPositionState): LogPositionUrlState => ({ - streamLive: !state.refreshInterval.pause, - start: state.timeRange.expression.from, - end: state.timeRange.expression.to, - position: state.latestPosition ? pickTimeKey(state.latestPosition) : null, -}); - -export const initializeStateFromUrlState = - (urlState: LogPositionUrlState | null, now?: Date) => - (state: LogPositionState): LogPositionState => - pipe( - state, - updateTargetPosition(urlState?.position ?? null), - updateTimeRange( - { - from: urlState?.start ?? getTimeRangeStartFromPosition(urlState?.position), - to: urlState?.end ?? getTimeRangeEndFromPosition(urlState?.position), - }, - now - ), - updateRefreshInterval({ pause: !urlState?.streamLive }) - ); - -export const updateStateFromUrlState = - (urlState: LogPositionUrlState | null, now?: Date) => - (state: LogPositionState): LogPositionState => - pipe( - state, - updateTargetPosition(urlState?.position ?? null), - updateTimeRange( - { - from: urlState?.start, - to: urlState?.end, - }, - now - ), - updateRefreshInterval({ pause: !urlState?.streamLive }) - ); - -/** - * Timefilter helpers - */ - -export const getTimefilterState = (state: LogPositionState): TimefilterState => ({ - timeRange: state.timeRange.expression, - refreshInterval: state.refreshInterval, -}); - -export const updateStateFromTimefilterState = - (timefilterState: TimefilterState | null, now?: Date) => - (state: LogPositionState): LogPositionState => - pipe( - state, - updateTimeRange( - { - from: timefilterState?.timeRange?.from, - to: timefilterState?.timeRange?.to, - }, - now - ), - updateRefreshInterval({ - pause: timefilterState?.refreshInterval?.pause, - value: Math.max(timefilterState?.refreshInterval?.value ?? 0, initialRefreshInterval.value), - }) - ); - -const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 }; - -const getTimeRangeStartFromPosition = ( - position: Partial | null | undefined -): string | undefined => - position?.time != null - ? moment(position.time).subtract(defaultTimeRangeFromPositionOffset).toISOString() - : undefined; - -const getTimeRangeEndFromPosition = ( - position: Partial | null | undefined -): string | undefined => - position?.time != null - ? moment(position.time).add(defaultTimeRangeFromPositionOffset).toISOString() - : undefined; diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_timefilter_state.ts b/x-pack/plugins/infra/public/containers/logs/log_position/log_position_timefilter_state.ts deleted file mode 100644 index 35c2a2f367c4e6..00000000000000 --- a/x-pack/plugins/infra/public/containers/logs/log_position/log_position_timefilter_state.ts +++ /dev/null @@ -1,55 +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 { INullableBaseStateContainer, syncState } from '@kbn/kibana-utils-plugin/public'; -import { useCallback, useState } from 'react'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { - createTimefilterStateStorage, - TimefilterState, - timefilterStateStorageKey, -} from '../../../utils/timefilter_state_storage'; - -export const useLogPositionTimefilterStateSync = () => { - const { - services: { - data: { - query: { - timefilter: { timefilter }, - }, - }, - }, - } = useKibanaContextForPlugin(); - - const [timefilterStateStorage] = useState(() => createTimefilterStateStorage({ timefilter })); - - const [initialStateFromTimefilter] = useState(() => - timefilterStateStorage.get(timefilterStateStorageKey) - ); - - const startSyncingWithTimefilter = useCallback( - (stateContainer: INullableBaseStateContainer) => { - timefilterStateStorage.set(timefilterStateStorageKey, stateContainer.get()); - - const { start, stop } = syncState({ - storageKey: timefilterStateStorageKey, - stateContainer, - stateStorage: timefilterStateStorage, - }); - - start(); - - return stop; - }, - [timefilterStateStorage] - ); - - return { - initialStateFromTimefilter, - startSyncingWithTimefilter, - }; -}; diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/replace_log_position_in_query_string.ts b/x-pack/plugins/infra/public/containers/logs/log_position/replace_log_position_in_query_string.ts deleted file mode 100644 index e447c2c1436d29..00000000000000 --- a/x-pack/plugins/infra/public/containers/logs/log_position/replace_log_position_in_query_string.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { replaceStateKeyInQueryString } from '../../../utils/url_state'; -import { LogPositionUrlState, LOG_POSITION_URL_STATE_KEY } from './use_log_position_url_state_sync'; - -const ONE_HOUR = 3600000; - -export const replaceLogPositionInQueryString = (time: number) => - Number.isNaN(time) - ? (value: string) => value - : replaceStateKeyInQueryString(LOG_POSITION_URL_STATE_KEY, { - position: { - time, - tiebreaker: 0, - }, - end: new Date(time + ONE_HOUR).toISOString(), - start: new Date(time - ONE_HOUR).toISOString(), - streamLive: false, - }); diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position.ts b/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position.ts index 61e543b6b96eac..2471acf6e92834 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position.ts @@ -6,24 +6,14 @@ */ import createContainer from 'constate'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import useInterval from 'react-use/lib/useInterval'; -import useThrottle from 'react-use/lib/useThrottle'; -import { TimeKey } from '../../../../common/time'; -import { withReduxDevTools } from '../../../utils/state_container_devtools'; -import { TimefilterState } from '../../../utils/timefilter_state_storage'; -import { useObservableState } from '../../../utils/use_observable'; -import { wrapStateContainer } from '../../../utils/wrap_state_container'; +import { useMemo } from 'react'; +import { VisiblePositions } from '../../../observability_logs/log_stream_position_state/src/types'; import { - createLogPositionStateContainer, - getTimefilterState, - getUrlState, - LogPositionState, - updateStateFromTimefilterState, - updateStateFromUrlState, -} from './log_position_state'; -import { useLogPositionTimefilterStateSync } from './log_position_timefilter_state'; -import { LogPositionUrlState, useLogPositionUrlStateSync } from './use_log_position_url_state_sync'; + LogStreamPageActorRef, + LogStreamPageCallbacks, +} from '../../../observability_logs/log_stream_page/state'; +import { MatchedStateFromActor } from '../../../observability_logs/xstate_helpers'; +import { TimeKey } from '../../../../common/time'; type TimeKeyOrNull = TimeKey | null; @@ -36,14 +26,6 @@ interface DateRange { lastCompleteDateRangeExpressionUpdate: number; } -interface VisiblePositions { - startKey: TimeKeyOrNull; - middleKey: TimeKeyOrNull; - endKey: TimeKeyOrNull; - pagesAfterEnd: number; - pagesBeforeStart: number; -} - export type LogPositionStateParams = DateRange & { targetPosition: TimeKeyOrNull; isStreaming: boolean; @@ -68,69 +50,44 @@ type UpdateDateRangeFn = ( newDateRange: Partial> ) => void; -const DESIRED_BUFFER_PAGES = 2; -const RELATIVE_END_UPDATE_DELAY = 1000; - -export const useLogPositionState: () => LogPositionStateParams & LogPositionCallbacks = () => { - const { initialStateFromUrl, startSyncingWithUrl } = useLogPositionUrlStateSync(); - const { initialStateFromTimefilter, startSyncingWithTimefilter } = - useLogPositionTimefilterStateSync(); - - const [logPositionStateContainer] = useState(() => - withReduxDevTools( - createLogPositionStateContainer({ - initialStateFromUrl, - initialStateFromTimefilter, - }), - { - name: 'logPosition', - } - ) - ); - - useEffect(() => { - return startSyncingWithUrl( - wrapStateContainer({ - wrapGet: getUrlState, - wrapSet: updateStateFromUrlState, - })(logPositionStateContainer) - ); - }, [logPositionStateContainer, startSyncingWithUrl]); - - useEffect(() => { - return startSyncingWithTimefilter( - wrapStateContainer({ - wrapGet: getTimefilterState, - wrapSet: updateStateFromTimefilterState, - })(logPositionStateContainer) - ); - }, [logPositionStateContainer, startSyncingWithTimefilter, startSyncingWithUrl]); - - const { latestValue: latestLogPositionState } = useObservableState( - logPositionStateContainer.state$, - () => logPositionStateContainer.get() - ); - - const dateRange = useMemo( - () => getLegacyDateRange(latestLogPositionState), - [latestLogPositionState] - ); - - const { targetPosition, visiblePositions } = latestLogPositionState; - - const isStreaming = useMemo( - () => !latestLogPositionState.refreshInterval.pause, - [latestLogPositionState] - ); - - const updateDateRange = useCallback( - (newDateRange: Partial>) => - logPositionStateContainer.transitions.updateTimeRange({ - from: newDateRange.startDateExpression, - to: newDateRange.endDateExpression, - }), - [logPositionStateContainer] - ); +export const useLogPositionState = ({ + logStreamPageState, + logStreamPageCallbacks, +}: { + logStreamPageState: InitializedLogStreamPageState; + logStreamPageCallbacks: LogStreamPageCallbacks; +}): LogPositionStateParams & LogPositionCallbacks => { + const dateRange = useMemo(() => getLegacyDateRange(logStreamPageState), [logStreamPageState]); + + const { refreshInterval, targetPosition, visiblePositions, latestPosition } = + logStreamPageState.context; + + const actions = useMemo(() => { + const { + updateTimeRange, + jumpToTargetPosition, + jumpToTargetPositionTime, + reportVisiblePositions, + startLiveStreaming, + stopLiveStreaming, + } = logStreamPageCallbacks; + + return { + jumpToTargetPosition, + jumpToTargetPositionTime, + reportVisiblePositions, + startLiveStreaming, + stopLiveStreaming, + updateDateRange: ( + newDateRange: Partial> + ) => { + updateTimeRange({ + from: newDateRange.startDateExpression, + to: newDateRange.endDateExpression, + }); + }, + }; + }, [logStreamPageCallbacks]); const visibleTimeInterval = useMemo( () => @@ -140,62 +97,41 @@ export const useLogPositionState: () => LogPositionStateParams & LogPositionCall [visiblePositions.startKey, visiblePositions.endKey] ); - // `endTimestamp` update conditions - const throttledPagesAfterEnd = useThrottle( - visiblePositions.pagesAfterEnd, - RELATIVE_END_UPDATE_DELAY - ); - useEffect(() => { - if (dateRange.endDateExpression !== 'now') { - return; - } - - // User is close to the bottom edge of the scroll. - if (throttledPagesAfterEnd <= DESIRED_BUFFER_PAGES) { - logPositionStateContainer.transitions.updateTimeRange({ to: 'now' }); - } - }, [dateRange.endDateExpression, throttledPagesAfterEnd, logPositionStateContainer]); - - useInterval( - () => logPositionStateContainer.transitions.updateTimeRange({ from: 'now-1d', to: 'now' }), - latestLogPositionState.refreshInterval.pause || - latestLogPositionState.refreshInterval.value <= 0 - ? null - : latestLogPositionState.refreshInterval.value - ); - return { // position state targetPosition, - isStreaming, + isStreaming: !refreshInterval.pause, ...dateRange, // visible positions state firstVisiblePosition: visiblePositions.startKey, pagesBeforeStart: visiblePositions.pagesBeforeStart, pagesAfterEnd: visiblePositions.pagesAfterEnd, - visibleMidpoint: latestLogPositionState.latestPosition, - visibleMidpointTime: latestLogPositionState.latestPosition?.time ?? null, + visibleMidpoint: latestPosition, + visibleMidpointTime: latestPosition?.time ?? null, visibleTimeInterval, // actions - jumpToTargetPosition: logPositionStateContainer.transitions.jumpToTargetPosition, - jumpToTargetPositionTime: logPositionStateContainer.transitions.jumpToTargetPositionTime, - reportVisiblePositions: logPositionStateContainer.transitions.reportVisiblePositions, - startLiveStreaming: logPositionStateContainer.transitions.startLiveStreaming, - stopLiveStreaming: logPositionStateContainer.transitions.stopLiveStreaming, - updateDateRange, + ...actions, }; }; export const [LogPositionStateProvider, useLogPositionStateContext] = createContainer(useLogPositionState); -const getLegacyDateRange = (logPositionState: LogPositionState): DateRange => ({ - endDateExpression: logPositionState.timeRange.expression.to, - endTimestamp: logPositionState.timestamps.endTimestamp, - lastCompleteDateRangeExpressionUpdate: logPositionState.timeRange.lastChangedCompletely, - startDateExpression: logPositionState.timeRange.expression.from, - startTimestamp: logPositionState.timestamps.startTimestamp, - timestampsLastUpdate: logPositionState.timestamps.lastChangedTimestamp, -}); +const getLegacyDateRange = (logStreamPageState: InitializedLogStreamPageState): DateRange => { + return { + startDateExpression: logStreamPageState.context.timeRange.from, + endDateExpression: logStreamPageState.context.timeRange.to, + startTimestamp: logStreamPageState.context.timestamps.startTimestamp, + endTimestamp: logStreamPageState.context.timestamps.endTimestamp, + lastCompleteDateRangeExpressionUpdate: + logStreamPageState.context.timeRange.lastChangedCompletely, + timestampsLastUpdate: logStreamPageState.context.timestamps.lastChangedTimestamp, + }; +}; + +type InitializedLogStreamPageState = MatchedStateFromActor< + LogStreamPageActorRef, + { hasLogViewIndices: 'initialized' } +>; diff --git a/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position_url_state_sync.ts b/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position_url_state_sync.ts deleted file mode 100644 index b9e6a8a5b3eb6a..00000000000000 --- a/x-pack/plugins/infra/public/containers/logs/log_position/use_log_position_url_state_sync.ts +++ /dev/null @@ -1,78 +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 { INullableBaseStateContainer, syncState } from '@kbn/kibana-utils-plugin/public'; -import { getOrElseW } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import * as rt from 'io-ts'; -import { useCallback, useState } from 'react'; -import { map } from 'rxjs/operators'; -import { minimalTimeKeyRT } from '../../../../common/time'; -import { datemathStringRT } from '../../../utils/datemath'; -import { useKbnUrlStateStorageFromRouterContext } from '../../../utils/kbn_url_state_context'; - -export const logPositionUrlStateRT = rt.partial({ - streamLive: rt.boolean, - position: rt.union([rt.partial(minimalTimeKeyRT.props), rt.null]), - start: datemathStringRT, - end: datemathStringRT, -}); - -export type LogPositionUrlState = rt.TypeOf; - -export const LOG_POSITION_URL_STATE_KEY = 'logPosition'; - -export const useLogPositionUrlStateSync = () => { - const urlStateStorage = useKbnUrlStateStorageFromRouterContext(); - - const [initialStateFromUrl] = useState(() => - pipe( - logPositionUrlStateRT.decode(urlStateStorage.get(LOG_POSITION_URL_STATE_KEY)), - getOrElseW(() => null) - ) - ); - - const startSyncingWithUrl = useCallback( - (stateContainer: INullableBaseStateContainer) => { - if (initialStateFromUrl == null) { - urlStateStorage.set(LOG_POSITION_URL_STATE_KEY, stateContainer.get(), { - replace: true, - }); - } - - const { start, stop } = syncState({ - storageKey: LOG_POSITION_URL_STATE_KEY, - stateContainer: { - state$: stateContainer.state$.pipe(map(logPositionUrlStateRT.encode)), - set: (value) => - stateContainer.set( - pipe( - logPositionUrlStateRT.decode(value), - getOrElseW(() => null) - ) - ), - get: () => logPositionUrlStateRT.encode(stateContainer.get()), - }, - stateStorage: { - ...urlStateStorage, - set: (key: string, state: State) => - urlStateStorage.set(key, state, { replace: true }), - }, - }); - - start(); - - return stop; - }, - [initialStateFromUrl, urlStateStorage] - ); - - return { - initialStateFromUrl, - startSyncingWithUrl, - }; -}; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts index ec1460e41b86f0..431d2df5d99a15 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/initial_parameters_service.ts @@ -5,16 +5,22 @@ * 2.0. */ +import { RefreshInterval } from '@kbn/data-plugin/public'; import { InvokeCreator, Receiver } from 'xstate'; -import { ParsedQuery } from '../../../log_stream_query_state'; +import { TimeKey } from '../../../../../common/time'; +import { VisiblePositions } from '../../../log_stream_position_state'; +import { ExtendedTimeRange, ParsedQuery, Timestamps } from '../../../log_stream_query_state'; import { LogStreamPageContext, LogStreamPageEvent } from './types'; -export const waitForInitialParameters = +export const waitForInitialQueryParameters = (): InvokeCreator => (_context, _event) => (send, onEvent: Receiver) => { // constituents of the set of initial parameters let latestValidQuery: ParsedQuery | undefined; + let latestTimeRange: ExtendedTimeRange | undefined; + let latestRefreshInterval: RefreshInterval | undefined; + let latestTimestamps: Timestamps | undefined; onEvent((event) => { switch (event.type) { @@ -23,13 +29,60 @@ export const waitForInitialParameters = case 'INVALID_QUERY_CHANGED': latestValidQuery = event.parsedQuery; break; + case 'TIME_CHANGED': + latestTimeRange = event.timeRange; + latestRefreshInterval = event.refreshInterval; + latestTimestamps = event.timestamps; + break; } // if all constituents of the parameters have been delivered - if (latestValidQuery != null) { + if ( + latestValidQuery !== undefined && + latestTimeRange !== undefined && + latestRefreshInterval !== undefined && + latestTimestamps !== undefined + ) { send({ - type: 'RECEIVED_INITIAL_PARAMETERS', + type: 'RECEIVED_INITIAL_QUERY_PARAMETERS', validatedQuery: latestValidQuery, + timeRange: latestTimeRange, + refreshInterval: latestRefreshInterval, + timestamps: latestTimestamps, + }); + } + }); + }; + +export const waitForInitialPositionParameters = + (): InvokeCreator => + (_context, _event) => + (send, onEvent: Receiver) => { + // constituents of the set of initial parameters + let latestTargetPosition: TimeKey | null; + let latestLatestPosition: TimeKey | null; + let latestVisiblePositions: VisiblePositions; + + onEvent((event) => { + switch (event.type) { + case 'POSITIONS_CHANGED': + latestTargetPosition = event.targetPosition; + latestLatestPosition = event.latestPosition; + latestVisiblePositions = event.visiblePositions; + break; + } + + // if all constituents of the parameters have been delivered + if ( + latestTargetPosition !== undefined && + latestLatestPosition !== undefined && + latestVisiblePositions !== undefined + ) { + send({ + type: 'RECEIVED_INITIAL_POSITION_PARAMETERS', + targetPosition: latestTargetPosition, + latestPosition: latestLatestPosition, + visiblePositions: latestVisiblePositions, }); } }); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx index b5d31e0ea81873..0da26759b6a043 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/provider.tsx @@ -7,6 +7,7 @@ import { useInterpret } from '@xstate/react'; import createContainer from 'constate'; +import useMount from 'react-use/lib/useMount'; import { isDevMode } from '../../../../utils/dev_mode'; import { createLogStreamPageStateMachine, @@ -21,9 +22,17 @@ export const useLogStreamPageState = ({ filterManagerService, urlStateStorage, useDevTools = isDevMode(), + timeFilterService, }: { useDevTools?: boolean; } & LogStreamPageStateMachineDependencies) => { + useMount(() => { + // eslint-disable-next-line no-console + console.log( + "A warning in console stating: 'The result of getSnapshot should be cached to avoid an infinite loop' is expected. This will be fixed once we can upgrade versions." + ); + }); + const logStreamPageStateService = useInterpret( () => createLogStreamPageStateMachine({ @@ -33,6 +42,7 @@ export const useLogStreamPageState = ({ toastsService, filterManagerService, urlStateStorage, + timeFilterService, }), { devTools: useDevTools } ); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts index 3e343e15bf01ff..dba97dc5f8efb9 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/state_machine.ts @@ -5,25 +5,36 @@ * 2.0. */ +import { RefreshInterval } from '@kbn/data-plugin/public'; +import { TimeRange } from '@kbn/es-query'; import { actions, ActorRefFrom, createMachine, EmittedFrom } from 'xstate'; +import { datemathToEpochMillis } from '../../../../utils/datemath'; +import { createLogStreamPositionStateMachine } from '../../../log_stream_position_state/src/state_machine'; import { createLogStreamQueryStateMachine, + DEFAULT_REFRESH_INTERVAL, + DEFAULT_TIMERANGE, LogStreamQueryStateMachineDependencies, } from '../../../log_stream_query_state'; import type { LogViewNotificationChannel } from '../../../log_view_state'; import { OmitDeprecatedState } from '../../../xstate_helpers'; -import { waitForInitialParameters } from './initial_parameters_service'; +import { + waitForInitialQueryParameters, + waitForInitialPositionParameters, +} from './initial_parameters_service'; import type { LogStreamPageContext, LogStreamPageContextWithLogView, LogStreamPageContextWithLogViewError, + LogStreamPageContextWithPositions, LogStreamPageContextWithQuery, + LogStreamPageContextWithTime, LogStreamPageEvent, LogStreamPageTypestate, } from './types'; export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPageContext = {}) => - /** @xstate-layout N4IgpgJg5mDOIC5QBsD2UDKAXATmAhgLYAK+M2+WYAdAK4B2Alk1o-sowF6QDEAMgHkAggBEAkgDkA4gH1BsgGpiAogHUZGACpCASpuUiA2gAYAuolAAHVLEatU9CyAAeiALQAmAJzUPHgGwArIEALAAcHmHhXsEhADQgAJ6IAQDM1IHGYQDs2ZnZxl5e-l6pAL5lCWiYuAQkZGAUVHRMLGwc3BD8wuLScgKKKuoAYkJifAYm5kgg1rb2jjOuCJ4hAIzUqZklHgX+xqlrkQnJCKlB1P4loYH+qV7hHoEVVejYeESk5FiUNAzMdnaXF4glEklk8hkSjUGgAqgBheHKAyTMxOOaAhxOZbZNbZajGXLBVIkrJrYInRBHYzUEIeVIhVJhNZZLws7IhF4garvOpfRo-Zr-NrsYFdUG9CEDKFDOGI5EiSZraZWGyYxagHEhEIEwkeI7Zc7GO6UhCZHzZML7MKBDwhQp0zmVblvWqfBpNGhofAQZhQPjoBSMMAAd26YL6kOhIzGEyMaJmGIW2JS4VpJTCWXp5K82Q8pvN1Et1tt9oedq5PLd9W+v2o3t99H9geDYYl4P6gxhGARSJR8ZVszVyaWiEZPnt-m8Ry8xjta38pqN1FK+uy+w8xhCgS8lddHxrArrDb9AagQdD4clnZl3d7CqVg6TjCxo4QISumy2MWNMWiAVNO58WMFkImMOc50CMI9xqA9+U9etUB9U8W1DYZ8EYZAQR6Dso1lLRdH0Ad0WHF8NRcdxvF8AJYgiKIwhiUIC1SDwMgNcC8g5O1nmdKs4I9QUaAAC3wWAzwvEMxHoX0AGM4BaAFWFFToeB0ZQkTEBQDBkSQxE0MQhD4GRiF0IQAFllH0HQMCmEj5jIlMEBnfxqAiYojjWVJCjnJcwnSIIrSuNZZ2CGJyl4-c+QEusRLE1DJOkxg5NgBSRQ6XgFEMsQRBkABFWFlB0ABNGR4QACSEaRUSfUjX01Kl-DyWk1giW0p3tElTTxfFwhCPYQIXXE1idV5YKi2tmli8TWyk2T5OFQFlN4SRMr4bK8oK4rSoqqriMTWryOWBdGtckCQMCEknn8MIl21FcWLxVJDUzfwWv8GDeXdCbhNE6bQ1mpL5MUoEVNW9b8sKkrysqqRqrs9VHMGwJmtagI7QOVICznFd1yebdMgutY1gqZ16FQCA4CcPjxqPKh4ZHeqVkiHwtl-XZjQOTzTTcNk2NtQ4-A5q0PureDBNSxb0ogemHLfOkurpahyXArIbTZIItxF-jvsQ5Cmz+kMZbqiiEF2DJQiuK0bVyH94iSRAmTCTZ3ICPMtj8HjRs+w8EJPfX4vQzDICNw7EGR5k7S8NJGrZNXAJ3IsnvtImt28aCIrGr7aZ+uLzxmxLkpDxHNxpC7dn2K404pe331YrwokNQ1GIF7ItZphCpvigHkolpSpaLt8jjTMv12NKd6+r04nlYgbDjxO0-KnNus4736u4LoG0rFAfGc8qIi0Cck1cCQ1K4LJ4iznS1zjzG0WOXn3xcIRhYFsf28-+jf4H2+zjaOw4XKbijt4YIWRbjZHjhaJ6T1cSwIxiTMoQA */ + /** @xstate-layout N4IgpgJg5mDOIC5QBsD2UDKAXATmAhgLYAK+M2+WYAdAK4B2Alk1o-sowF6QDEAMgHkAggBEAkgDkA4gH1BsgGpiAogHUZGACpCASpuUiA2gAYAuolAAHVLEatU9CyAAeiALQAmAJzUPHgGwArIEALAAcHmHhXsEhADQgAJ6IAQDM1IHGYQDs2ZnZxl5e-l6pAL5lCWiYuAQkZGAUVHRMLGwc3BD8wuLScgKKKuoAYkJifAYm5kgg1rb2jjOuCJ4hAIzUqZklHgX+xqlrkQnJCKlB1P4loYH+qV7hHoEVVejYeESk5FiUNAzMdnaXF4glEklk8hkSjUGgAqgBheHKAyTMxOOaAhxOZbZNbZajGXLBVIkrJrYInRBHYzUEIeVIhVJhNZZLws7IhF4garvOpfRo-Zr-NrsYFdUG9CEDKFDOGI5EiSZraZWGyYxagHEhEIEwkeI7Zc7GO6UhCZHzZML7MKBDwhQp0zmVblvWqfBpNGhofAQZhQPjoBSMMAAd26YL6kOhIzGEyMaJmGIW2JS4VpJTCWXp5K82Q8pvN1Et1tt9oedq5PLd9W+v2o3t99H9geDYYl4P6gxhGARSJR8ZVszVyaWiEZPnt-m8Ry8xjta38pqN1FK+uy+w8xhCgS8lddHxrArrDb9AagQdD4clnZl3d7CqVg6TjCxo4QISumy2MWNMWiAVNO58WMFkImMOc50CMI9xqA9+U9etUB9U8W1DYZ8EYZAQR6Dso1lLRdH0Ad0WHF8NRcdxvF8AJYgiKIwhiUIC1SDwMgNcC8g5O1nmdKs4I9QUaAAC3wWAzwvEMxHoX0AGM4GoAFWFFTg-QARVoMAcESHgdGUJExAUAwZEkMRNDEIQ+BkVTYWUHQAE0ZGIXQhAAWWUfQdAwKYSPmMinFOKcNgKXYwnOPMbRYhJlhCYoYN5d1a2aESxNQyTpMYOTYAUkUOjUjStJ4BQLLEEQrJs+yZHhAAJIRpFRJ9SNfTUx2KAtDSLOdLTCyJAhYuLq3gwTqGS8TWyk2T5MUoEVKbdTNO0yQir4EqytshzqtqqR6p89UU3fVqkkQS1WNKXEoP8cLeo8fr+MS4TRNG0Nxoyyacq4PL5p4My3Mqmq6uIxNGvI6KDtOW1Ag6kLuoi67eP3PkBLrEbUuezLssBZS-WIIHYB0vTlAMoyTLMizHIEDBTLEAQJEc5y3I8ryE1VXymoo-bF0OhAGI2EDbVCi6er6uHYIRu7hoelH0rRqbMabbGWfoXHiHJynqYwX7Nu2wGFb2mKOdOIofEKBksgFmGbtFo8kol88xql16MY6XglpW6y1o1-7vO13a3wXPJaTWCJbSne0SQLOcV3XJ5t0yXq1jWC2Eqt+6Uttp77aymWna6b7lA9raAeZn3moQBdCV8b99hiQ0rnzTntx1XMpxuWPDgT4X4sPBDkbTtKJszt7Oh4ZWKbMtX861ouRxLsv8XpHcq8CGup0A+OCVCVJskY4w49h14RaT7ubYk1GHaU7OeAAKVhFziBkTQBHv3Qts0MnR6piQvanvzff2OfK8KEvc4K967Gkjs3GOO826Jy7kNHuJ8M7o3PmKPGys9AygpgAIQmG-VWEhGYNR1r-cu89iiAOXnXU4WwwjgOjsEKB8cYGDSRsfO2-ckHTV4LCYgIghD6HvmIH6OhNZfyHEQmef8K4L3IcAyhR01g+DWCxTIkDd5MMRtbVOCD2FZxQdw3h-DdLDF0hgKqxkJAeSWqI58rNlizykWQ6usilwsloS3Bh7d96d2YZox6fcXoD0digpyW0ZDKAkKVTBsJhjDFsjIXSQhqqTzEcXNm9jSGLwoaaAIJ0o7uLju3Z09BUAQDgE4PiltPQ7WnmzTwDFNjbC8LsY0BwlGmjcCxAk9IOSZgXDuUotx1Fi2FEEzo1Sf4lzpKaNYdJqDknAlkG0bIghbiGcnRCyEmx+PGbYlI+JYhXCtDaXIP54icyZDQ+4-gjgCy2H4HiXiBoaK9EhRszZe7oUwpAHZwNEAQ2ZHaJpdwLpsiWYBHcRZN72njlubw0EO5PLFvAthASfl7TcOEaZEcQhR3WDaGKXVPEugPrAlhWiUXS0Hh9LSaK3zGEAvqSGXUzZXTWUfcl6cdFUrljjWlJd6WcwiKxTcUMWVC0ebddZyLOUBI4cpb53sal2KZDqPI5IllANrgWJ4TL+aXXFcS7xzzqCEEYLAWwWzJb9z5Wkw4-hfCFD8NvG0F1wUWk3pvXEXqDjlAqGUIAA */ createMachine( { context: initialContext, @@ -83,31 +94,65 @@ export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPag }, }, hasLogViewIndices: { - initial: 'uninitialized', + initial: 'initializingQuery', states: { - uninitialized: { + initializingQuery: { + meta: { + _DX_warning_: + "The Query machine must be invoked and complete initialisation before the Position machine is invoked. This is due to legacy URL dependencies on the 'logPosition' key, we need to read the key before it is reset by the Position machine.", + }, + invoke: { - src: 'waitForInitialParameters', - id: 'waitForInitialParameters', + src: 'waitForInitialQueryParameters', + id: 'waitForInitialQueryParameters', }, on: { - RECEIVED_INITIAL_PARAMETERS: { - target: 'initialized', - actions: 'storeQuery', + RECEIVED_INITIAL_QUERY_PARAMETERS: { + target: 'initializingPositions', + actions: ['storeQuery', 'storeTime', 'forwardToLogPosition'], }, VALID_QUERY_CHANGED: { - target: 'uninitialized', + target: 'initializingQuery', internal: true, - actions: 'forwardToInitialParameters', + actions: 'forwardToInitialQueryParameters', }, INVALID_QUERY_CHANGED: { - target: 'uninitialized', + target: 'initializingQuery', + internal: true, + actions: 'forwardToInitialQueryParameters', + }, + TIME_CHANGED: { + target: 'initializingQuery', + internal: true, + actions: 'forwardToInitialQueryParameters', + }, + }, + }, + initializingPositions: { + meta: { + _DX_warning_: + "The Position machine must be invoked after the Query machine has been invoked and completed initialisation. This is due to the Query machine having some legacy URL dependencies on the 'logPosition' key, we don't want the Position machine to reset the URL parameters before the Query machine has had a chance to read them.", + }, + invoke: [ + { + src: 'waitForInitialPositionParameters', + id: 'waitForInitialPositionParameters', + }, + ], + on: { + RECEIVED_INITIAL_POSITION_PARAMETERS: { + target: 'initialized', + actions: ['storePositions'], + }, + + POSITIONS_CHANGED: { + target: 'initializingPositions', internal: true, - actions: 'forwardToInitialParameters', + actions: 'forwardToInitialPositionParameters', }, }, }, @@ -118,21 +163,65 @@ export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPag internal: true, actions: 'storeQuery', }, + TIME_CHANGED: { + target: 'initialized', + internal: true, + actions: ['storeTime', 'forwardToLogPosition'], + }, + POSITIONS_CHANGED: { + target: 'initialized', + internal: true, + actions: ['storePositions'], + }, + JUMP_TO_TARGET_POSITION: { + target: 'initialized', + internal: true, + actions: ['forwardToLogPosition'], + }, + REPORT_VISIBLE_POSITIONS: { + target: 'initialized', + internal: true, + actions: ['forwardToLogPosition'], + }, + UPDATE_TIME_RANGE: { + target: 'initialized', + internal: true, + actions: ['forwardToLogStreamQuery'], + }, + UPDATE_REFRESH_INTERVAL: { + target: 'initialized', + internal: true, + actions: ['forwardToLogStreamQuery'], + }, + PAGE_END_BUFFER_REACHED: { + target: 'initialized', + internal: true, + actions: ['forwardToLogStreamQuery'], + }, }, }, }, - invoke: { - src: 'logStreamQuery', - id: 'logStreamQuery', - }, + invoke: [ + { + src: 'logStreamQuery', + id: 'logStreamQuery', + }, + { + src: 'logStreamPosition', + id: 'logStreamPosition', + }, + ], }, missingLogViewIndices: {}, }, }, { actions: { - forwardToInitialParameters: actions.forwardTo('waitForInitialParameters'), + forwardToInitialQueryParameters: actions.forwardTo('waitForInitialQueryParameters'), + forwardToInitialPositionParameters: actions.forwardTo('waitForInitialPositionParameters'), + forwardToLogPosition: actions.forwardTo('logStreamPosition'), + forwardToLogStreamQuery: actions.forwardTo('logStreamQuery'), storeLogViewError: actions.assign((_context, event) => event.type === 'LOADING_LOG_VIEW_FAILED' ? ({ logViewError: event.error } as LogStreamPageContextWithLogViewError) @@ -147,7 +236,7 @@ export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPag : {} ), storeQuery: actions.assign((_context, event) => - event.type === 'RECEIVED_INITIAL_PARAMETERS' + event.type === 'RECEIVED_INITIAL_QUERY_PARAMETERS' ? ({ parsedQuery: event.validatedQuery, } as LogStreamPageContextWithQuery) @@ -157,6 +246,26 @@ export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPag } as LogStreamPageContextWithQuery) : {} ), + storeTime: actions.assign((_context, event) => { + return 'timeRange' in event && 'refreshInterval' in event && 'timestamps' in event + ? ({ + timeRange: event.timeRange, + refreshInterval: event.refreshInterval, + timestamps: event.timestamps, + } as LogStreamPageContextWithTime) + : {}; + }), + storePositions: actions.assign((_context, event) => { + return 'targetPosition' in event && + 'visiblePositions' in event && + 'latestPosition' in event + ? ({ + targetPosition: event.targetPosition, + visiblePositions: event.visiblePositions, + latestPosition: event.latestPosition, + } as LogStreamPageContextWithPositions) + : {}; + }), }, guards: { hasLogViewIndices: (_context, event) => @@ -169,6 +278,7 @@ export const createPureLogStreamPageStateMachine = (initialContext: LogStreamPag export type LogStreamPageStateMachine = ReturnType; export type LogStreamPageActorRef = OmitDeprecatedState>; export type LogStreamPageState = EmittedFrom; +export type LogStreamPageSend = LogStreamPageActorRef['send']; export type LogStreamPageStateMachineDependencies = { logViewStateNotifications: LogViewNotificationChannel; @@ -181,6 +291,7 @@ export const createLogStreamPageStateMachine = ({ toastsService, filterManagerService, urlStateStorage, + timeFilterService, }: LogStreamPageStateMachineDependencies) => createPureLogStreamPageStateMachine().withConfig({ services: { @@ -190,9 +301,23 @@ export const createLogStreamPageStateMachine = ({ throw new Error('Failed to spawn log stream query service: no LogView in context'); } + const nowTimestamp = Date.now(); + const initialTimeRangeExpression: TimeRange = DEFAULT_TIMERANGE; + const initialRefreshInterval: RefreshInterval = DEFAULT_REFRESH_INTERVAL; + return createLogStreamQueryStateMachine( { dataViews: [context.resolvedLogView.dataViewReference], + timeRange: { + ...initialTimeRangeExpression, + lastChangedCompletely: nowTimestamp, + }, + timestamps: { + startTimestamp: datemathToEpochMillis(initialTimeRangeExpression.from, 'down') ?? 0, + endTimestamp: datemathToEpochMillis(initialTimeRangeExpression.to, 'up') ?? 0, + lastChangedTimestamp: nowTimestamp, + }, + refreshInterval: initialRefreshInterval, }, { kibanaQuerySettings, @@ -200,9 +325,30 @@ export const createLogStreamPageStateMachine = ({ toastsService, filterManagerService, urlStateStorage, + timeFilterService, + } + ); + }, + logStreamPosition: (context) => { + return createLogStreamPositionStateMachine( + { + targetPosition: null, + latestPosition: null, + visiblePositions: { + endKey: null, + middleKey: null, + startKey: null, + pagesBeforeStart: Infinity, + pagesAfterEnd: Infinity, + }, + }, + { + urlStateStorage, + toastsService, } ); }, - waitForInitialParameters: waitForInitialParameters(), + waitForInitialQueryParameters: waitForInitialQueryParameters(), + waitForInitialPositionParameters: waitForInitialPositionParameters(), }, }); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts index 7a970a3e06e70a..eb42dccdf2486c 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_page/state/src/types.ts @@ -5,8 +5,22 @@ * 2.0. */ +import { TimeRange } from '@kbn/es-query'; +import { TimeKey } from '../../../../../common/time'; import type { LogViewStatus } from '../../../../../common/log_views'; -import { ParsedQuery } from '../../../log_stream_query_state'; +import { + JumpToTargetPositionEvent, + LogStreamPositionContext, + ReportVisiblePositionsEvent, + VisiblePositions, +} from '../../../log_stream_position_state'; +import { LogStreamPositionNotificationEvent } from '../../../log_stream_position_state/src/notifications'; +import { + LogStreamQueryContextWithTime, + ParsedQuery, + UpdateRefreshIntervalEvent, + UpdateTimeRangeEvent, +} from '../../../log_stream_query_state'; import { LogStreamQueryNotificationEvent } from '../../../log_stream_query_state/src/notifications'; import type { LogViewContextWithError, @@ -14,13 +28,31 @@ import type { LogViewNotificationEvent, } from '../../../log_view_state'; +export interface ReceivedInitialQueryParametersEvent { + type: 'RECEIVED_INITIAL_QUERY_PARAMETERS'; + validatedQuery: ParsedQuery; + timeRange: LogStreamPageContextWithTime['timeRange']; + refreshInterval: LogStreamPageContextWithTime['refreshInterval']; + timestamps: LogStreamPageContextWithTime['timestamps']; +} + +export interface ReceivedInitialPositionParametersEvent { + type: 'RECEIVED_INITIAL_POSITION_PARAMETERS'; + targetPosition: LogStreamPageContextWithPositions['targetPosition']; + latestPosition: LogStreamPageContextWithPositions['latestPosition']; + visiblePositions: LogStreamPageContextWithPositions['visiblePositions']; +} + export type LogStreamPageEvent = | LogViewNotificationEvent | LogStreamQueryNotificationEvent - | { - type: 'RECEIVED_INITIAL_PARAMETERS'; - validatedQuery: ParsedQuery; - }; + | LogStreamPositionNotificationEvent + | ReceivedInitialQueryParametersEvent + | ReceivedInitialPositionParametersEvent + | JumpToTargetPositionEvent + | ReportVisiblePositionsEvent + | UpdateTimeRangeEvent + | UpdateRefreshIntervalEvent; export interface LogStreamPageContextWithLogView { logViewStatus: LogViewStatus; @@ -35,6 +67,9 @@ export interface LogStreamPageContextWithQuery { parsedQuery: ParsedQuery; } +export type LogStreamPageContextWithTime = LogStreamQueryContextWithTime; +export type LogStreamPageContextWithPositions = LogStreamPositionContext; + export type LogStreamPageTypestate = | { value: 'uninitialized'; @@ -58,7 +93,10 @@ export type LogStreamPageTypestate = } | { value: { hasLogViewIndices: 'initialized' }; - context: LogStreamPageContextWithLogView & LogStreamPageContextWithQuery; + context: LogStreamPageContextWithLogView & + LogStreamPageContextWithQuery & + LogStreamPageContextWithTime & + LogStreamPageContextWithPositions; } | { value: 'missingLogViewIndices'; @@ -67,3 +105,12 @@ export type LogStreamPageTypestate = export type LogStreamPageStateValue = LogStreamPageTypestate['value']; export type LogStreamPageContext = LogStreamPageTypestate['context']; + +export interface LogStreamPageCallbacks { + updateTimeRange: (timeRange: Partial) => void; + jumpToTargetPosition: (targetPosition: TimeKey | null) => void; + jumpToTargetPositionTime: (time: number) => void; + reportVisiblePositions: (visiblePositions: VisiblePositions) => void; + startLiveStreaming: () => void; + stopLiveStreaming: () => void; +} diff --git a/x-pack/plugins/alerting/common/rule_navigation.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/index.ts similarity index 51% rename from x-pack/plugins/alerting/common/rule_navigation.ts rename to x-pack/plugins/infra/public/observability_logs/log_stream_position_state/index.ts index abc109a31c432f..ddc7e818615b67 100644 --- a/x-pack/plugins/alerting/common/rule_navigation.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/index.ts @@ -5,11 +5,5 @@ * 2.0. */ -import { JsonObject } from '@kbn/utility-types'; -export interface RuleUrlNavigation { - path: string; -} -export interface RuleStateNavigation { - state: JsonObject; -} -export type RuleNavigation = RuleUrlNavigation | RuleStateNavigation; +export * from './src/types'; +export * from './src/defaults'; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.ts new file mode 100644 index 00000000000000..15556d8f2b4d78 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/defaults.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DESIRED_BUFFER_PAGES = 2; +export const RELATIVE_END_UPDATE_DELAY = 1000; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts new file mode 100644 index 00000000000000..59eda6dd5da5c7 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/notifications.ts @@ -0,0 +1,44 @@ +/* + * 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 { + LogStreamPositionContext, + LogStreamPositionContextWithLatestPosition, + LogStreamPositionContextWithTargetPosition, + LogStreamPositionContextWithVisiblePositions, +} from './types'; + +export type PositionsChangedEvent = { + type: 'POSITIONS_CHANGED'; +} & LogStreamPositionContextWithTargetPosition & + LogStreamPositionContextWithLatestPosition & + LogStreamPositionContextWithVisiblePositions; + +export interface PageEndBufferReachedEvent { + type: 'PAGE_END_BUFFER_REACHED'; +} + +export type LogStreamPositionNotificationEvent = PositionsChangedEvent | PageEndBufferReachedEvent; + +export const LogStreamPositionNotificationEventSelectors = { + positionsChanged: (context: LogStreamPositionContext) => { + return 'targetPosition' in context && + 'latestPosition' in context && + 'visiblePositions' in context + ? ({ + type: 'POSITIONS_CHANGED', + targetPosition: context.targetPosition, + latestPosition: context.latestPosition, + visiblePositions: context.visiblePositions, + } as LogStreamPositionNotificationEvent) + : undefined; + }, + pageEndBufferReached: (context: LogStreamPositionContext) => + ({ + type: 'PAGE_END_BUFFER_REACHED', + } as LogStreamPositionNotificationEvent), +}; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts new file mode 100644 index 00000000000000..d4053d14ab3041 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/state_machine.ts @@ -0,0 +1,226 @@ +/* + * 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 { IToasts } from '@kbn/core-notifications-browser'; +import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; +import { actions, ActorRefFrom, createMachine, EmittedFrom, SpecialTargets } from 'xstate'; +import { isSameTimeKey } from '../../../../common/time'; +import { OmitDeprecatedState, sendIfDefined } from '../../xstate_helpers'; +import { DESIRED_BUFFER_PAGES, RELATIVE_END_UPDATE_DELAY } from './defaults'; +import { LogStreamPositionNotificationEventSelectors } from './notifications'; +import type { + LogStreamPositionContext, + LogStreamPositionContextWithLatestPosition, + LogStreamPositionContextWithTargetPosition, + LogStreamPositionContextWithVisiblePositions, + LogStreamPositionEvent, + LogStreamPositionTypestate, +} from './types'; +import { initializeFromUrl, updateContextInUrl } from './url_state_storage_service'; + +export const createPureLogStreamPositionStateMachine = (initialContext: LogStreamPositionContext) => + /** @xstate-layout N4IgpgJg5mDOIC5QBsD2UDKAXATmAhgLYAK+M2+WYAdAK4B2Alk1o-sowF6QDEAMgHkAggBEAkgDkA4gH1BsgGpiAogHUZGACpCASpuUiA2gAYAuolAAHVLEatU9CyAAeiALQAmAJzUPHgGwArIEALAAcHmHhXsEhADQgAJ6IAQDM1IHGYQDs2ZnZxl5e-l6pAL5lCWiYuAQkZGAUVHRMLGwc3BD8wuLScgKKKuoAYkJifAYm5kgg1rb2jjOuCJ4hAIzUqZklHgX+xqlrkQnJCKlB1P4loYH+qV7hHoEVVejYeESk5FiUNAzMdnaXF4glEklk8hkSjUGgAqgBheHKAyTMxOOaAhxOZbZNbZajGXLBVIkrJrYInRBHYzUEIeVIhVJhNZZLws7IhF4garvOpfRo-Zr-NrsYFdUG9CEDKFDOGI5EiSZraZWGyYxagHEhEIEwkeI7Zc7GO6UhCZHzZML7MKBDwhQp0zmVblvWqfBpNGhofAQZhQPjoBSMMAAd26YL6kOhIzGEyMaJmGIW2JS4VpJTCWXp5K82Q8pvN1Et1tt9oedq5PLd9W+v2o3t99H9geDYYl4P6gxhGARSJR8ZVszVyaWiEZPnt-m8Ry8xjta38pqN1FK+uy+w8xhCgS8lddHxrArrDb9AagQdD4clnZl3d7CqVg6TjCxo4QISumy2MWNMWiAVNO58WMFkImMOc50CMI9xqA9+U9etUB9U8W1DYZ8EYZAQR6Dso1lLRdH0Ad0WHF8NRcdxvF8AJYgiKIwhiUIC1SDwMgNcC8g5O1nmdKs4I9QUaAAC3wWAzwvEMxHoX0AGM4BaAFWFFToeB0ZQkTEBQDBkSQxE0MQhD4GRiF0IQAFllH0HQMCmEj5jIlMEBnfxqAiYojjWVJCjnJcwnSIIrSuNZZ2CGJyl4-c+QEusRLE1DJOkxg5NgBSRQ6XgFEMsQRBkABFWFlB0ABNGR4QACSEaRUSfUjX01Kl-DyWk1giW0p3tElTTxfFwhCPYQIXXE1idV5YKi2tmli8TWyk2T5OFQFlN4SRMr4bK8oK4rSoqqriMTWryOWBdGtckCQMCEknn8MIl21FcWLxVJDUzfwWv8GDeXdCbhNE6bQ1mpL5MUoEVNW9b8sKkrysqqRqrs9VHMGwJmtagI7QOVICznFd1yebdMgutY1gqZ16FQCA4CcPjxqPKh4ZHeqVkiHwtl-XZjQOTzTTcNk2NtQ4-A5q0PureDBNSxb0ogemHLfOkurpahyXArIbTZIItxF-jvsQ5Cmz+kMZbqiiEF2DJQiuK0bVyH94iSRAmTCTZ3ICPMtj8HjRs+w8EJPfX4vQzDICNw7EGR5k7S8NJGrZNXAJ3IsnvtImt28aCIrGr7aZ+uLzxmxLkpDxHNxpC7dn2K404pe331YrwokNQ1GIF7ItZphCpvigHkolpSpaLt8jjTMv12NKd6+r04nlYgbDjxO0-KnNus4736u4LoG0rFAfGc8qIi0Cck1cCQ1K4LJ4iznS1zjzG0WOXn3xcIRhYFsf28-+jf4H2+zjaOw4XKbijt4YIWRbjZHjhaJ6T1cSwIxiTMoQA */ + createMachine( + { + context: initialContext, + predictableActionArguments: true, + id: 'logStreamPositionState', + initial: 'uninitialized', + states: { + uninitialized: { + meta: { + _DX_warning_: + "The Position machine cannot initializeFromUrl until after the Query machine has initialized, this is due to a dual dependency on the 'logPosition' URL parameter for legacy reasons.", + }, + on: { + RECEIVED_INITIAL_QUERY_PARAMETERS: { + target: 'initializingFromUrl', + }, + }, + }, + initializingFromUrl: { + on: { + INITIALIZED_FROM_URL: [ + { + target: 'initialized', + actions: ['storeTargetPosition', 'storeLatestPosition'], + }, + ], + }, + invoke: { + src: 'initializeFromUrl', + }, + }, + initialized: { + type: 'parallel', + states: { + positions: { + initial: 'initialized', + states: { + initialized: { + entry: ['updateContextInUrl', 'notifyPositionsChanged'], + on: { + JUMP_TO_TARGET_POSITION: { + target: 'initialized', + actions: ['updateTargetPosition'], + }, + REPORT_VISIBLE_POSITIONS: { + target: 'initialized', + actions: ['updateVisiblePositions'], + }, + TIME_CHANGED: { + target: 'initialized', + actions: ['updatePositionsFromTimeChange'], + }, + }, + }, + }, + }, + throttlingPageEndNotifications: { + initial: 'idle', + states: { + idle: { + on: { + REPORT_VISIBLE_POSITIONS: { + target: 'throttling', + }, + }, + }, + throttling: { + after: { + [RELATIVE_END_UPDATE_DELAY]: [ + { + target: 'notifying', + cond: 'hasReachedPageEndBuffer', + }, + { + target: 'idle', + }, + ], + }, + on: { + REPORT_VISIBLE_POSITIONS: { + target: 'throttling', + }, + }, + }, + notifying: { + entry: ['notifyPageEndBufferReached'], + always: 'idle', + }, + }, + }, + }, + }, + }, + }, + { + actions: { + notifyPositionsChanged: actions.pure(() => undefined), + notifyPageEndBufferReached: actions.pure(() => undefined), + storeTargetPosition: actions.assign((_context, event) => + 'targetPosition' in event + ? ({ + targetPosition: event.targetPosition, + } as LogStreamPositionContextWithTargetPosition) + : {} + ), + storeLatestPosition: actions.assign((_context, event) => + 'latestPosition' in event + ? ({ + latestPosition: event.latestPosition, + } as LogStreamPositionContextWithLatestPosition) + : {} + ), + updateTargetPosition: actions.assign((_context, event) => { + if (!('targetPosition' in event)) return {}; + + const nextTargetPosition = event.targetPosition?.time + ? { + time: event.targetPosition.time, + tiebreaker: event.targetPosition.tiebreaker ?? 0, + } + : null; + + const nextLatestPosition = !isSameTimeKey(_context.targetPosition, nextTargetPosition) + ? nextTargetPosition + : _context.latestPosition; + + return { + targetPosition: nextTargetPosition, + latestPosition: nextLatestPosition, + } as LogStreamPositionContextWithLatestPosition & + LogStreamPositionContextWithTargetPosition; + }), + updatePositionsFromTimeChange: actions.assign((_context, event) => { + if (!('timeRange' in event)) return {}; + + // Reset the target position if it doesn't fall within the new range. + const targetPositionShouldReset = + _context.targetPosition && + (event.timestamps.startTimestamp > _context.targetPosition.time || + event.timestamps.endTimestamp < _context.targetPosition.time); + + return { + targetPosition: targetPositionShouldReset ? null : _context.targetPosition, + latestPosition: targetPositionShouldReset ? null : _context.latestPosition, + } as LogStreamPositionContextWithLatestPosition & + LogStreamPositionContextWithTargetPosition; + }), + updateVisiblePositions: actions.assign((_context, event) => + 'visiblePositions' in event + ? ({ + visiblePositions: event.visiblePositions, + latestPosition: !isSameTimeKey( + _context.visiblePositions.middleKey, + event.visiblePositions.middleKey + ) + ? event.visiblePositions.middleKey + : _context.visiblePositions.middleKey, + } as LogStreamPositionContextWithVisiblePositions) + : {} + ), + }, + guards: { + // User is close to the bottom of the page. + hasReachedPageEndBuffer: (context, event) => + context.visiblePositions.pagesAfterEnd < DESIRED_BUFFER_PAGES, + }, + } + ); + +export type LogStreamPositionStateMachine = ReturnType< + typeof createPureLogStreamPositionStateMachine +>; +export type LogStreamPositionActorRef = OmitDeprecatedState< + ActorRefFrom +>; +export type LogStreamPositionState = EmittedFrom; + +export interface LogStreamPositionStateMachineDependencies { + urlStateStorage: IKbnUrlStateStorage; + toastsService: IToasts; +} + +export const createLogStreamPositionStateMachine = ( + initialContext: LogStreamPositionContext, + { urlStateStorage, toastsService }: LogStreamPositionStateMachineDependencies +) => + createPureLogStreamPositionStateMachine(initialContext).withConfig({ + actions: { + updateContextInUrl: updateContextInUrl({ toastsService, urlStateStorage }), + notifyPositionsChanged: sendIfDefined(SpecialTargets.Parent)( + LogStreamPositionNotificationEventSelectors.positionsChanged + ), + notifyPageEndBufferReached: sendIfDefined(SpecialTargets.Parent)( + LogStreamPositionNotificationEventSelectors.pageEndBufferReached + ), + }, + services: { + initializeFromUrl: initializeFromUrl({ toastsService, urlStateStorage }), + }, + }); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/types.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/types.ts new file mode 100644 index 00000000000000..980ca00b7c8e92 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/types.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TimeKey } from '../../../../common/time'; +import { ReceivedInitialQueryParametersEvent } from '../../log_stream_page/state'; +import { TimeChangedEvent } from '../../log_stream_query_state/src/notifications'; + +export interface VisiblePositions { + startKey: TimeKey | null; + middleKey: TimeKey | null; + endKey: TimeKey | null; + pagesAfterEnd: number; + pagesBeforeStart: number; +} + +export interface LogStreamPositionContextWithTargetPosition { + targetPosition: TimeKey | null; +} + +export interface LogStreamPositionContextWithLatestPosition { + latestPosition: TimeKey | null; +} +export interface LogStreamPositionContextWithVisiblePositions { + visiblePositions: VisiblePositions; +} +export type LogStreamPositionState = LogStreamPositionContextWithTargetPosition & + LogStreamPositionContextWithLatestPosition & + LogStreamPositionContextWithVisiblePositions; + +export type LogStreamPositionTypestate = + | { + value: 'uninitialized'; + context: LogStreamPositionState; + } + | { + value: 'initialized'; + context: LogStreamPositionState; + }; +export type LogStreamPositionContext = LogStreamPositionTypestate['context']; +export type LogStreamPositionStateValue = LogStreamPositionTypestate['value']; + +export interface JumpToTargetPositionEvent { + type: 'JUMP_TO_TARGET_POSITION'; + targetPosition: Partial | null; +} + +export interface ReportVisiblePositionsEvent { + type: 'REPORT_VISIBLE_POSITIONS'; + visiblePositions: VisiblePositions; +} + +export type LogStreamPositionEvent = + | { + type: 'INITIALIZED_FROM_URL'; + latestPosition: TimeKey | null; + targetPosition: TimeKey | null; + } + | ReceivedInitialQueryParametersEvent + | JumpToTargetPositionEvent + | ReportVisiblePositionsEvent + | TimeChangedEvent; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts new file mode 100644 index 00000000000000..219a2f0105e077 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_position_state/src/url_state_storage_service.ts @@ -0,0 +1,111 @@ +/* + * 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 { IToasts } from '@kbn/core-notifications-browser'; +import { IKbnUrlStateStorage, withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; +import * as Either from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/function'; +import * as rt from 'io-ts'; +import { InvokeCreator } from 'xstate'; +import { minimalTimeKeyRT, pickTimeKey } from '../../../../common/time'; +import { createPlainError, formatErrors } from '../../../../common/runtime_types'; +import { replaceStateKeyInQueryString } from '../../../utils/url_state'; +import type { LogStreamPositionContext, LogStreamPositionEvent } from './types'; +interface LogStreamPositionUrlStateDependencies { + positionStateKey?: string; + toastsService: IToasts; + urlStateStorage: IKbnUrlStateStorage; +} + +export const defaultPositionStateKey = 'logPosition'; + +export const updateContextInUrl = + ({ + urlStateStorage, + positionStateKey = defaultPositionStateKey, + }: LogStreamPositionUrlStateDependencies) => + (context: LogStreamPositionContext, _event: LogStreamPositionEvent) => { + if (!('latestPosition' in context)) { + throw new Error('Missing keys from context needed to sync to the URL'); + } + + urlStateStorage.set( + positionStateKey, + positionStateInUrlRT.encode({ + position: context.latestPosition ? pickTimeKey(context.latestPosition) : null, + }) + ); + }; + +export const initializeFromUrl = + ({ + positionStateKey = defaultPositionStateKey, + urlStateStorage, + toastsService, + }: LogStreamPositionUrlStateDependencies): InvokeCreator< + LogStreamPositionContext, + LogStreamPositionEvent + > => + (_context, _event) => + (send) => { + const positionQueryValueFromUrl = urlStateStorage.get(positionStateKey) ?? {}; + + const initialUrlValues = pipe( + decodePositionQueryValueFromUrl(positionQueryValueFromUrl), + Either.map(({ position }) => ({ + targetPosition: position?.time + ? { + time: position.time, + tiebreaker: position.tiebreaker ?? 0, + } + : null, + })), + Either.map(({ targetPosition }) => ({ + targetPosition, + latestPosition: targetPosition, + })) + ); + + if (Either.isLeft(initialUrlValues)) { + withNotifyOnErrors(toastsService).onGetError( + createPlainError(formatErrors(initialUrlValues.left)) + ); + + send({ + type: 'INITIALIZED_FROM_URL', + targetPosition: null, + latestPosition: null, + }); + } else { + send({ + type: 'INITIALIZED_FROM_URL', + targetPosition: initialUrlValues.right.targetPosition ?? null, + latestPosition: initialUrlValues.right.latestPosition ?? null, + }); + } + }; + +export const positionStateInUrlRT = rt.partial({ + position: rt.union([rt.partial(minimalTimeKeyRT.props), rt.null]), +}); + +export type PositionStateInUrl = rt.TypeOf; + +const decodePositionQueryValueFromUrl = (queryValueFromUrl: unknown) => { + return positionStateInUrlRT.decode(queryValueFromUrl); +}; + +// Used by linkTo components +export const replaceLogPositionInQueryString = (time: number) => + Number.isNaN(time) + ? (value: string) => value + : replaceStateKeyInQueryString(defaultPositionStateKey, { + position: { + time, + tiebreaker: 0, + }, + }); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts new file mode 100644 index 00000000000000..243b01f4b9570a --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/defaults.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export const DEFAULT_QUERY = { + language: 'kuery', + query: '', +}; + +export const DEFAULT_FILTERS = []; + +export const DEFAULT_TIMERANGE = { + from: 'now-1d', + to: 'now', +}; + +export const DEFAULT_REFRESH_TIME_RANGE = DEFAULT_TIMERANGE; + +export const DEFAULT_REFRESH_INTERVAL = { pause: true, value: 5000 }; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts index 5d89520ed2ac57..b9f6065f990920 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/index.ts @@ -9,3 +9,5 @@ export * from './errors'; export * from './state_machine'; export * from './types'; export * from './url_state_storage_service'; +export * from './time_filter_state_service'; +export * from './defaults'; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts index 3599144d9fd4bb..51fba835c22ad7 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/notifications.ts @@ -5,7 +5,15 @@ * 2.0. */ -import { LogStreamQueryContext, ParsedQuery } from './types'; +import { RefreshInterval } from '@kbn/data-plugin/public'; +import { ExtendedTimeRange, LogStreamQueryContext, ParsedQuery, Timestamps } from './types'; + +export interface TimeChangedEvent { + type: 'TIME_CHANGED'; + timeRange: ExtendedTimeRange; + refreshInterval: RefreshInterval; + timestamps: Timestamps; +} export type LogStreamQueryNotificationEvent = | { @@ -16,7 +24,8 @@ export type LogStreamQueryNotificationEvent = type: 'INVALID_QUERY_CHANGED'; parsedQuery: ParsedQuery; error: Error; - }; + } + | TimeChangedEvent; export const logStreamQueryNotificationEventSelectors = { validQueryChanged: (context: LogStreamQueryContext) => @@ -34,4 +43,14 @@ export const logStreamQueryNotificationEventSelectors = { error: context.validationError, } as LogStreamQueryNotificationEvent) : undefined, + timeChanged: (context: LogStreamQueryContext) => { + return 'timeRange' in context && 'refreshInterval' in context && 'timestamps' in context + ? ({ + type: 'TIME_CHANGED', + timeRange: context.timeRange, + refreshInterval: context.refreshInterval, + timestamps: context.timestamps, + } as LogStreamQueryNotificationEvent) + : undefined; + }, }; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts index 951551534d7422..bbae54bf8803ee 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/state_machine.ts @@ -6,10 +6,14 @@ */ import { IToasts } from '@kbn/core-notifications-browser'; -import type { FilterManager, QueryStringContract } from '@kbn/data-plugin/public'; +import type { + FilterManager, + QueryStringContract, + TimefilterContract, +} from '@kbn/data-plugin/public'; import { EsQueryConfig } from '@kbn/es-query'; import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; -import { actions, ActorRefFrom, createMachine, SpecialTargets } from 'xstate'; +import { actions, ActorRefFrom, createMachine, SpecialTargets, send } from 'xstate'; import { OmitDeprecatedState, sendIfDefined } from '../../xstate_helpers'; import { logStreamQueryNotificationEventSelectors } from './notifications'; import { @@ -24,6 +28,9 @@ import type { LogStreamQueryContextWithFilters, LogStreamQueryContextWithParsedQuery, LogStreamQueryContextWithQuery, + LogStreamQueryContextWithRefreshInterval, + LogStreamQueryContextWithTime, + LogStreamQueryContextWithTimeRange, LogStreamQueryContextWithValidationError, LogStreamQueryEvent, LogStreamQueryTypestate, @@ -31,15 +38,24 @@ import type { import { initializeFromUrl, safeDefaultParsedQuery, - updateFiltersInUrl, - updateQueryInUrl, + updateContextInUrl, } from './url_state_storage_service'; +import { + initializeFromTimeFilterService, + subscribeToTimeFilterServiceChanges, + updateTimeContextFromTimeFilterService, + updateTimeContextFromTimeRangeUpdate, + updateTimeContextFromRefreshIntervalUpdate, + updateTimeInTimeFilterService, + updateTimeContextFromUrl, +} from './time_filter_state_service'; import { showValidationErrorToast, validateQuery } from './validate_query_service'; +import { DEFAULT_REFRESH_INTERVAL, DEFAULT_REFRESH_TIME_RANGE } from './defaults'; export const createPureLogStreamQueryStateMachine = ( - initialContext: LogStreamQueryContextWithDataViews + initialContext: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime ) => - /** @xstate-layout N4IgpgJg5mDOIC5QEUCuYBOBPAdKgdgJZEAuhAhgDaEBekAxANoAMAuoqAA4D2shZ3fBxAAPRAFoATAHZJOAMwBWJQBYAjNIBszAJwAOTZIA0ILBMnyca+Wp2bFenfL1b5zTQF8PJtJlzF+CmoaYigAMQxuAFsAVQxKegBJADlEgBVEgEEAGUSALQBRABEAfTCAJQB5AFkSmPLslnYkEB4+ASEWsQRxeRU5PXdNA001RX1tRRMzBBkdHHVmFWZpHTVJC2ZFFS8fdGwcAAtyWF9semQYgvKATTKq2oBlAszygGEACRKAIVeSz8yyQA4sUmsI2oFBMJupIVNIcLoVHpBoppLJFMZTIh7DgdMsnNINHZlip5LsQGdcMdTvssPQwolsmlro97jUSs9Xp8fn8AcDQWxwbxIZ1QN1tHICWoXJJNDoMfJ5NNsYpcfj5ITVpoSZ5vBTaUcTpT6EVMmlMiUAGqJAoAdVZfJBRTBLQhHWhiDscllKwsKnUOmYajUyoQqysmmkKh00mYbijjkU5MphppfhwGDAADcqIQIOQyPgoPRLTlEqaMpVkmVMoyBc0uML3V1PZHcfK1P6UXY0aG3JZ5Pp1WpRgZJEm9SnqSnMznqPnC8XS7kK4kqxyYm83gVivWhe1CFCWwhB8wFjJRvJJINZZHpH24woh7obKPDBO9um53mC6ES2XV3XR5N23XdnUFV0m0PUVRAkNZcVkUY8UUQxmDjPRQ39NQcCjNENUkWwVEUJZpGTA1vwXP9l3LM012rMJa2yPdIIPI8xQkaRLB0CZiO2aQ9EkJxQxQ1UBKUZg9HWUl1FI8l8G4CA4GESl9xFD0elPHBBk0YYdLGCYtlDKRtARcYtivFw0S0Mj0wIAIyFzOgIFU5t2J6QS9BwDYVmlHRYR0rZNCMjRsJHST-RE8dOJ2ScDXsoJaFCCJojiSgXOg9Ten6LzI1GawrKvWFQ07SxZE41Y1jsawP31dNp1pdK2NghBbHmRFkS2NFx0xGZxA0ORFDMyMPNWcYbIOeqv1zZyWLU48NWwyqtTcXQ9FJTDlgQ-pkW1HbJPGqkjTi-AKMamDuj8lQEWlBwVAlWUrw2s8Y22gwkQMfbYrqo701nabfyLM71NjbCBOWCTfLhdxQ1hM9ZScPQNW4xQR2sA6cAogGoCB49eiULTL1RPQMUDQcpixBB-WeqNx2lIlEdkrwgA */ + /** @xstate-layout N4IgpgJg5mDOIC5QEUCuYBOBPAdKgdgJZEAuhAhgDaEBekAxANoAMAuoqAA4D2shZ3fBxAAPRAEYAHAGYck8QCYArAoAsC8QHZNygJySANCCwTpszc2njpANnH2FN1UtUBfV0bSZcxfhWo0xFAAYhjcALYAqhiU9ACSAHJxACpxAIIAMnEAWgCiACIA+sEASgDyALKFkSUZLOxIIDx8AkKNYghKzJJyCvJOurqqA4bGiPI4XczTdjbM2kq64u6e6Ng4vmRUtEGhEdGxiSnpWXlFpZXVtYziDVy8foLCHSpGJgjizj02SjYa3X0dH8ViAvOtNv4dvgQmFwslCOEwMFCJQSJgAMqYABuhAAxmB4klUpkcgViuUqqkKrlinEMslciVCujGQA1OIAYVy9WEzUebVAHWkkhsOGmmnkqnUumkzBsmmkb0Quk0ot0coUZnscukSkkILBPlIkLoEBwAEc1lh6MhIoyAJrky4stIlDkACUKACFXYUPWkEgBxAo8xp81rPcbiJQ4GzSPoKOXMX7RxVjD7MVTiOTyxOSVT5zRKCUGq0bY3bU0Wq30YJ0hkldFOqout2en1M-1BkNsXkPCPtKMxuMJpMppRp95LHrDZi6CfSbQ2STF0vect+SuQaveej5NLJNKFdm5ADqTa7wfyofuLUIT0HCHkw-jkkTc3Hk-GCgUYvm8kGAtCzXcEKwCbdLXXLFtggcgyGhehWRJfdUjKBJmUiDkuQKHs7iaft7wFUQJCzVQcGkdU7GjOdxF0JUECGZhyMUJRFGYBMVX1DxQTLCEtzNSD1mg6hYPgqBEOQg84jQ4o0jpXC+zvB9BRIz5yMo+wuiWOj03sOYcC0Wi+gA7RkxAo1N3AgSywwMBhMIUSggkrIUOk9DgjkjIFLDAjlOIj5SPUuVNJonT3nESxRVVX4FU0RQbH0aRzI3LYrJ3dZbPsxyEKQlypJk9FMOw-JvNvflIwCtSKOC6jtPo-ocEo5QEo0H9fmSvi0rIRF6CpGkLkpOJqVpelGWZNlORpS9SvwpSiI6Z9Y1fd9kzsCd6KkVRNFjX5-l0BQLCLLjVnXTraG3bqCUiAAFFCaT6woSgDYMb1m8rH0Wkc3zHNavw+eUmOkVRF2XFVhjmGwOrA86zUu+gbrux7clKXJ0U9RIG1y17w0IirPuWn7Uw21QZTFKx4wsH81CUJQocsmGcEulKTQYbHfPm0ws0mTVweBiV51UDadF0SYZDMYHJE0KUtrp1KGaZs7TSYW5FPelSPiB7MVCBmwnEXSQBaFyQem6LUpYogsdHcbj8G4CA4GEQ1VYHdWAFobHo12Y0GH3fb9pLuMNPAiGh01ndxx91A2+McAsKw7F1I7AVlk1dlhA5w78joDp6A383lRctC0wXdLnHBEysTU40UA2ZcD3jQ7TiJ4URZFUQxbE8TATOOYQeV6MGQHFkXRd51owYU-4nuKrikWvpWz96JJpimrsRwJQLaNJ7SwT3jKl3-NVbb58J9b02LGcNXJn8Cx+beGd3nAsrgoJp8fexJfL+Q2q0AtbBLqcLhJgUQiuIP4zgwHHR4qdUOEEyxZTfurMButYzzllBROYUo-j1WcDgKUjhjaEMsNYe+VZH7EAQT5OaFVkGigShOSwuhMHDAUBtOUMZZQaGBrqXUIo3D1xgfTMhNk7IwRftCRB-kP7bT6IoZQv8ZBOBwWROYMoZQ-klpITMpCLoIm7lQtWh95RLVHB+X60cY4TmsOqQuqot4CNAkI3RiJmZTwMQfDoigtCNWilote0wlBCyBuXEm+hpQWF1jo2GeicCwBIC-XEkjPGsTIrRCcE5dYS1okbUUZgzAHWTEDSwUTGYxLibZcg4RX7uIjkglJBk0EZL1gBIWB05B5OjFLYs+hNDW1cEAA */ createMachine( { context: initialContext, @@ -50,93 +66,161 @@ export const createPureLogStreamQueryStateMachine = ( states: { uninitialized: { always: { - target: 'initializingFromUrl', + target: 'initializingFromTimeFilterService', }, }, initializingFromUrl: { on: { INITIALIZED_FROM_URL: { - target: 'validating', - actions: ['storeQuery', 'storeFilters'], + target: 'initialized', + actions: ['storeQuery', 'storeFilters', 'updateTimeContextFromUrl'], }, }, - invoke: { src: 'initializeFromUrl', }, }, - - hasQuery: { - entry: ['updateQueryInUrl', 'updateQueryInSearchBar', 'updateFiltersInSearchBar'], - invoke: [ - { - src: 'subscribeToQuerySearchBarChanges', - }, - { - src: 'subscribeToFilterSearchBarChanges', + initializingFromTimeFilterService: { + on: { + INITIALIZED_FROM_TIME_FILTER_SERVICE: { + target: 'initializingFromUrl', + actions: ['updateTimeContextFromTimeFilterService'], }, - ], - initial: 'revalidating', + }, + invoke: { + src: 'initializeFromTimeFilterService', + }, + }, + initialized: { + type: 'parallel', states: { - valid: { - entry: 'notifyValidQueryChanged', - }, - invalid: { - entry: 'notifyInvalidQueryChanged', - }, - revalidating: { - invoke: { - src: 'validateQuery', - }, - on: { - VALIDATION_FAILED: { - target: 'invalid', - actions: ['storeValidationError', 'showValidationErrorToast'], + query: { + entry: ['updateContextInUrl', 'updateQueryInSearchBar', 'updateFiltersInSearchBar'], + invoke: [ + { + src: 'subscribeToQuerySearchBarChanges', }, - VALIDATION_SUCCEEDED: { - target: 'valid', - actions: ['clearValidationError', 'storeParsedQuery'], + { + src: 'subscribeToFilterSearchBarChanges', + }, + ], + initial: 'validating', + states: { + validating: { + invoke: { + src: 'validateQuery', + }, + on: { + VALIDATION_SUCCEEDED: { + target: 'valid', + actions: 'storeParsedQuery', + }, + + VALIDATION_FAILED: { + target: 'invalid', + actions: [ + 'storeValidationError', + 'storeDefaultParsedQuery', + 'showValidationErrorToast', + ], + }, + }, + }, + valid: { + entry: 'notifyValidQueryChanged', + }, + invalid: { + entry: 'notifyInvalidQueryChanged', + }, + revalidating: { + invoke: { + src: 'validateQuery', + }, + on: { + VALIDATION_FAILED: { + target: 'invalid', + actions: ['storeValidationError', 'showValidationErrorToast'], + }, + VALIDATION_SUCCEEDED: { + target: 'valid', + actions: ['clearValidationError', 'storeParsedQuery'], + }, + }, }, }, - }, - }, - on: { - QUERY_FROM_SEARCH_BAR_CHANGED: { - target: '.revalidating', - actions: ['storeQuery', 'updateQueryInUrl'], - }, + on: { + QUERY_FROM_SEARCH_BAR_CHANGED: { + target: '.revalidating', + actions: ['storeQuery', 'updateContextInUrl'], + }, - FILTERS_FROM_SEARCH_BAR_CHANGED: { - target: '.revalidating', - actions: ['storeFilters', 'updateFiltersInUrl'], - }, + FILTERS_FROM_SEARCH_BAR_CHANGED: { + target: '.revalidating', + actions: ['storeFilters', 'updateContextInUrl'], + }, - DATA_VIEWS_CHANGED: { - target: '.revalidating', - actions: 'storeDataViews', + DATA_VIEWS_CHANGED: { + target: '.revalidating', + actions: 'storeDataViews', + }, + }, }, - }, - }, - - validating: { - invoke: { - src: 'validateQuery', - }, + time: { + initial: 'initialized', + entry: ['notifyTimeChanged', 'updateTimeInTimeFilterService'], + invoke: [ + { + src: 'subscribeToTimeFilterServiceChanges', + }, + ], + states: { + initialized: { + always: [{ target: 'streaming', cond: 'isStreaming' }, { target: 'static' }], + }, + static: { + on: { + PAGE_END_BUFFER_REACHED: { + actions: ['expandPageEnd'], + }, + }, + }, + streaming: { + after: { + refresh: { target: 'streaming', actions: ['refreshTime'] }, + }, + }, + }, + on: { + TIME_FROM_TIME_FILTER_SERVICE_CHANGED: { + target: '.initialized', + actions: [ + 'updateTimeContextFromTimeFilterService', + 'notifyTimeChanged', + 'updateContextInUrl', + ], + }, - on: { - VALIDATION_SUCCEEDED: { - target: 'hasQuery.valid', - actions: 'storeParsedQuery', - }, + UPDATE_TIME_RANGE: { + target: '.initialized', + actions: [ + 'updateTimeContextFromTimeRangeUpdate', + 'notifyTimeChanged', + 'updateTimeInTimeFilterService', + 'updateContextInUrl', + ], + }, - VALIDATION_FAILED: { - target: 'hasQuery.invalid', - actions: [ - 'storeValidationError', - 'storeDefaultParsedQuery', - 'showValidationErrorToast', - ], + UPDATE_REFRESH_INTERVAL: { + target: '.initialized', + actions: [ + 'updateTimeContextFromRefreshIntervalUpdate', + 'notifyTimeChanged', + 'updateTimeInTimeFilterService', + 'updateContextInUrl', + ], + }, + }, }, }, }, @@ -146,12 +230,25 @@ export const createPureLogStreamQueryStateMachine = ( actions: { notifyInvalidQueryChanged: actions.pure(() => undefined), notifyValidQueryChanged: actions.pure(() => undefined), + notifyTimeChanged: actions.pure(() => undefined), storeQuery: actions.assign((_context, event) => { return 'query' in event ? ({ query: event.query } as LogStreamQueryContextWithQuery) : {}; }), storeFilters: actions.assign((_context, event) => 'filters' in event ? ({ filters: event.filters } as LogStreamQueryContextWithFilters) : {} ), + storeTimeRange: actions.assign((_context, event) => + 'timeRange' in event + ? ({ timeRange: event.timeRange } as LogStreamQueryContextWithTimeRange) + : {} + ), + storeRefreshInterval: actions.assign((_context, event) => + 'refreshInterval' in event + ? ({ + refreshInterval: event.refreshInterval, + } as LogStreamQueryContextWithRefreshInterval) + : {} + ), storeDataViews: actions.assign((_context, event) => 'dataViews' in event ? ({ dataViews: event.dataViews } as LogStreamQueryContextWithDataViews) @@ -180,6 +277,22 @@ export const createPureLogStreamQueryStateMachine = ( 'validationError' >) ), + updateTimeContextFromTimeFilterService, + updateTimeContextFromTimeRangeUpdate, + updateTimeContextFromRefreshIntervalUpdate, + refreshTime: send({ type: 'UPDATE_TIME_RANGE', timeRange: DEFAULT_REFRESH_TIME_RANGE }), + expandPageEnd: send({ type: 'UPDATE_TIME_RANGE', timeRange: { to: 'now' } }), + updateTimeContextFromUrl, + }, + guards: { + isStreaming: (context, event) => + 'refreshInterval' in context ? !context.refreshInterval.pause : false, + }, + delays: { + refresh: (context, event) => + 'refreshInterval' in context + ? context.refreshInterval.value + : DEFAULT_REFRESH_INTERVAL.value, }, } ); @@ -190,20 +303,24 @@ export interface LogStreamQueryStateMachineDependencies { filterManagerService: FilterManager; urlStateStorage: IKbnUrlStateStorage; toastsService: IToasts; + timeFilterService: TimefilterContract; } export const createLogStreamQueryStateMachine = ( - initialContext: LogStreamQueryContextWithDataViews, + initialContext: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime, { kibanaQuerySettings, queryStringService, toastsService, filterManagerService, urlStateStorage, + timeFilterService, }: LogStreamQueryStateMachineDependencies ) => createPureLogStreamQueryStateMachine(initialContext).withConfig({ actions: { + updateContextInUrl: updateContextInUrl({ toastsService, urlStateStorage }), + // Query notifyInvalidQueryChanged: sendIfDefined(SpecialTargets.Parent)( logStreamQueryNotificationEventSelectors.invalidQueryChanged ), @@ -211,13 +328,17 @@ export const createLogStreamQueryStateMachine = ( logStreamQueryNotificationEventSelectors.validQueryChanged ), showValidationErrorToast: showValidationErrorToast({ toastsService }), - updateQueryInUrl: updateQueryInUrl({ toastsService, urlStateStorage }), updateQueryInSearchBar: updateQueryInSearchBar({ queryStringService }), - updateFiltersInUrl: updateFiltersInUrl({ toastsService, urlStateStorage }), updateFiltersInSearchBar: updateFiltersInSearchBar({ filterManagerService }), + // Time + updateTimeInTimeFilterService: updateTimeInTimeFilterService({ timeFilterService }), + notifyTimeChanged: sendIfDefined(SpecialTargets.Parent)( + logStreamQueryNotificationEventSelectors.timeChanged + ), }, services: { initializeFromUrl: initializeFromUrl({ toastsService, urlStateStorage }), + initializeFromTimeFilterService: initializeFromTimeFilterService({ timeFilterService }), validateQuery: validateQuery({ kibanaQuerySettings }), subscribeToQuerySearchBarChanges: subscribeToQuerySearchBarChanges({ queryStringService, @@ -225,6 +346,9 @@ export const createLogStreamQueryStateMachine = ( subscribeToFilterSearchBarChanges: subscribeToFilterSearchBarChanges({ filterManagerService, }), + subscribeToTimeFilterServiceChanges: subscribeToTimeFilterServiceChanges({ + timeFilterService, + }), }, }); diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts new file mode 100644 index 00000000000000..aaa610ea1ef120 --- /dev/null +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/time_filter_state_service.ts @@ -0,0 +1,188 @@ +/* + * 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 { RefreshInterval, TimefilterContract } from '@kbn/data-plugin/public'; +import { TimeRange } from '@kbn/es-query'; +import { map, merge } from 'rxjs'; +import { actions, InvokeCreator } from 'xstate'; +import { datemathToEpochMillis } from '../../../utils/datemath'; +import { DEFAULT_REFRESH_TIME_RANGE } from './defaults'; +import { LogStreamQueryContext, LogStreamQueryEvent } from './types'; + +export interface TimefilterState { + timeRange: TimeRange; + refreshInterval: RefreshInterval; +} + +export const initializeFromTimeFilterService = + ({ + timeFilterService, + }: { + timeFilterService: TimefilterContract; + }): InvokeCreator => + (_context, _event) => + (send) => { + const timeRange = timeFilterService.getTime(); + const refreshInterval = timeFilterService.getRefreshInterval(); + + send({ + type: 'INITIALIZED_FROM_TIME_FILTER_SERVICE', + timeRange, + refreshInterval, + }); + }; + +export const updateTimeInTimeFilterService = + ({ timeFilterService }: { timeFilterService: TimefilterContract }) => + (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if ('timeRange' in context) { + timeFilterService.setTime(context.timeRange); + } + + if ('refreshInterval' in context) { + timeFilterService.setRefreshInterval(context.refreshInterval); + } + }; + +export const subscribeToTimeFilterServiceChanges = + ({ + timeFilterService, + }: { + timeFilterService: TimefilterContract; + }): InvokeCreator => + (context) => + merge(timeFilterService.getTimeUpdate$(), timeFilterService.getRefreshIntervalUpdate$()).pipe( + map(() => getTimefilterState(timeFilterService)), + map((timeState): LogStreamQueryEvent => { + return { + type: 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED', + ...timeState, + }; + }) + ); + +const getTimefilterState = (timeFilterService: TimefilterContract): TimefilterState => ({ + timeRange: timeFilterService.getTime(), + refreshInterval: timeFilterService.getRefreshInterval(), +}); + +export const updateTimeContextFromTimeFilterService = actions.assign( + (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if ( + event.type === 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED' || + event.type === 'INITIALIZED_FROM_TIME_FILTER_SERVICE' + ) { + return { + ...getTimeFromEvent(context, event), + refreshInterval: event.refreshInterval, + }; + } else { + return {}; + } + } +); + +export const updateTimeContextFromUrl = actions.assign( + (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if (event.type === 'INITIALIZED_FROM_URL') { + return { + ...('timeRange' in event && event.timeRange ? { ...getTimeFromEvent(context, event) } : {}), + ...('refreshInterval' in event && event.refreshInterval + ? { refreshInterval: event.refreshInterval } + : {}), + }; + } else { + return {}; + } + } +); + +export const updateTimeContextFromTimeRangeUpdate = actions.assign( + (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if ('timeRange' in event && event.type === 'UPDATE_TIME_RANGE') { + return getTimeFromEvent(context, event); + } else { + return {}; + } + } +); + +export const updateTimeContextFromRefreshIntervalUpdate = actions.assign( + (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if ( + 'refreshInterval' in event && + 'refreshInterval' in context && + event.type === 'UPDATE_REFRESH_INTERVAL' + ) { + const pause = event.refreshInterval.pause ?? context.refreshInterval.pause; + const value = event.refreshInterval.value ?? context.refreshInterval.value; + + const nowTimestamp = Date.now(); + + const draftContext = { + refreshInterval: { + pause, + value, + }, + ...(!pause + ? { + timeRange: { + ...DEFAULT_REFRESH_TIME_RANGE, + lastChangedCompletely: nowTimestamp, + }, + } + : {}), + ...(!pause + ? { + timestamps: { + startTimestamp: datemathToEpochMillis(DEFAULT_REFRESH_TIME_RANGE.from, 'down') ?? 0, + endTimestamp: datemathToEpochMillis(DEFAULT_REFRESH_TIME_RANGE.to, 'down') ?? 0, + lastChangedTimestamp: nowTimestamp, + }, + } + : {}), + }; + + return draftContext; + } else { + return {}; + } + } +); + +const getTimeFromEvent = (context: LogStreamQueryContext, event: LogStreamQueryEvent) => { + if (!('timeRange' in event) || !('timeRange' in context) || !('timestamps' in context)) { + throw new Error('Missing keys to get time from event'); + } + + const nowTimestamp = Date.now(); + const from = event.timeRange?.from ?? context.timeRange.from; + const to = event.timeRange?.to ?? context.timeRange.to; + + const fromTimestamp = event.timeRange?.from + ? datemathToEpochMillis(from, 'down') + : context.timestamps.startTimestamp; + const toTimestamp = event.timeRange?.to + ? datemathToEpochMillis(to, 'down') + : context.timestamps.endTimestamp; + + return { + timeRange: { + from, + to, + lastChangedCompletely: + event.timeRange?.from && event.timeRange?.to + ? nowTimestamp + : context.timeRange.lastChangedCompletely, + }, + timestamps: { + startTimestamp: fromTimestamp ?? 0, + endTimestamp: toTimestamp ?? 0, + lastChangedTimestamp: nowTimestamp, + }, + }; +}; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts index 46706254f446f0..b56ce2148a17e5 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/types.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { AggregateQuery, BoolQuery, DataViewBase, Query, Filter } from '@kbn/es-query'; +import { RefreshInterval } from '@kbn/data-plugin/public'; +import { AggregateQuery, BoolQuery, DataViewBase, Query, Filter, TimeRange } from '@kbn/es-query'; +import { PageEndBufferReachedEvent } from '../../log_stream_position_state/src/notifications'; export type AnyQuery = Query | AggregateQuery; @@ -36,38 +38,78 @@ export interface LogStreamQueryContextWithValidationError { validationError: Error; } +export type ExtendedTimeRange = TimeRange & { lastChangedCompletely: number }; +export interface LogStreamQueryContextWithTimeRange { + timeRange: ExtendedTimeRange; +} + +export interface LogStreamQueryContextWithRefreshInterval { + refreshInterval: RefreshInterval; +} + +export interface Timestamps { + startTimestamp: number; + endTimestamp: number; + lastChangedTimestamp: number; +} + +export interface LogStreamQueryContextWithTimestamps { + timestamps: Timestamps; +} + +export type LogStreamQueryContextWithTime = LogStreamQueryContextWithTimeRange & + LogStreamQueryContextWithRefreshInterval & + LogStreamQueryContextWithTimestamps; + export type LogStreamQueryTypestate = | { value: 'uninitialized'; - context: LogStreamQueryContextWithDataViews; + context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime; } | { - value: 'hasQuery' | { hasQuery: 'validating' }; + value: 'query' | { query: 'validating' }; context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithParsedQuery & LogStreamQueryContextWithQuery & - LogStreamQueryContextWithFilters; + LogStreamQueryContextWithFilters & + LogStreamQueryContextWithTime; } | { - value: { hasQuery: 'valid' }; + value: { query: 'valid' }; context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithParsedQuery & LogStreamQueryContextWithQuery & - LogStreamQueryContextWithFilters; + LogStreamQueryContextWithFilters & + LogStreamQueryContextWithTime; } | { - value: { hasQuery: 'invalid' }; + value: { query: 'invalid' }; context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithParsedQuery & LogStreamQueryContextWithQuery & LogStreamQueryContextWithFilters & + LogStreamQueryContextWithTime & LogStreamQueryContextWithValidationError; + } + | { + value: 'time' | { time: 'initialized' } | { time: 'streaming' } | { time: 'static' }; + context: LogStreamQueryContextWithDataViews & LogStreamQueryContextWithTime; }; export type LogStreamQueryContext = LogStreamQueryTypestate['context']; export type LogStreamQueryStateValue = LogStreamQueryTypestate['value']; +export interface UpdateTimeRangeEvent { + type: 'UPDATE_TIME_RANGE'; + timeRange: Partial; +} + +export interface UpdateRefreshIntervalEvent { + type: 'UPDATE_REFRESH_INTERVAL'; + refreshInterval: Partial; +} + export type LogStreamQueryEvent = | { type: 'QUERY_FROM_SEARCH_BAR_CHANGED'; @@ -93,4 +135,19 @@ export type LogStreamQueryEvent = type: 'INITIALIZED_FROM_URL'; query: AnyQuery; filters: Filter[]; - }; + timeRange: TimeRange | null; + refreshInterval: RefreshInterval | null; + } + | { + type: 'INITIALIZED_FROM_TIME_FILTER_SERVICE'; + timeRange: TimeRange; + refreshInterval: RefreshInterval; + } + | { + type: 'TIME_FROM_TIME_FILTER_SERVICE_CHANGED'; + timeRange: TimeRange; + refreshInterval: RefreshInterval; + } + | UpdateTimeRangeEvent + | UpdateRefreshIntervalEvent + | PageEndBufferReachedEvent; diff --git a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts index fabd26cc03d221..3a8d08635dca7b 100644 --- a/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts +++ b/x-pack/plugins/infra/public/observability_logs/log_stream_query_state/src/url_state_storage_service.ts @@ -10,28 +10,53 @@ import { Query } from '@kbn/es-query'; import { IKbnUrlStateStorage, withNotifyOnErrors } from '@kbn/kibana-utils-plugin/public'; import * as Array from 'fp-ts/lib/Array'; import * as Either from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/function'; +import { identity, pipe } from 'fp-ts/lib/function'; import * as rt from 'io-ts'; import { InvokeCreator } from 'xstate'; +import { DurationInputObject } from 'moment'; +import moment from 'moment'; +import { minimalTimeKeyRT } from '../../../../common/time'; +import { datemathStringRT } from '../../../utils/datemath'; import { createPlainError, formatErrors } from '../../../../common/runtime_types'; import { replaceStateKeyInQueryString } from '../../../utils/url_state'; import type { LogStreamQueryContext, LogStreamQueryEvent, ParsedQuery } from './types'; +import { + DEFAULT_FILTERS, + DEFAULT_QUERY, + DEFAULT_REFRESH_INTERVAL, + DEFAULT_TIMERANGE, +} from './defaults'; interface LogStreamQueryUrlStateDependencies { filterStateKey?: string; + positionStateKey?: string; savedQueryIdKey?: string; toastsService: IToasts; urlStateStorage: IKbnUrlStateStorage; } const defaultFilterStateKey = 'logFilter'; -const defaultFilterStateValue: Required = { - query: { - language: 'kuery', - query: '', - }, - filters: [], +const defaultPositionStateKey = 'logPosition'; // NOTE: Provides backwards compatibility for start / end / streamLive previously stored under the logPosition key. + +type RequiredDefaults = Required>; +type OptionalDefaults = Pick; +type FullDefaults = Required; + +const requiredDefaultFilterStateValue: RequiredDefaults = { + query: DEFAULT_QUERY, + filters: DEFAULT_FILTERS, +}; + +const optionalDefaultFilterStateValue = { + timeRange: DEFAULT_TIMERANGE, + refreshInterval: DEFAULT_REFRESH_INTERVAL, }; + +const defaultFilterStateValue: FullDefaults = { + ...requiredDefaultFilterStateValue, + ...optionalDefaultFilterStateValue, +}; + export const safeDefaultParsedQuery: ParsedQuery = { bool: { must: [], @@ -41,33 +66,19 @@ export const safeDefaultParsedQuery: ParsedQuery = { }, }; -export const updateQueryInUrl = - ({ - urlStateStorage, - filterStateKey = defaultFilterStateKey, - }: LogStreamQueryUrlStateDependencies) => - (context: LogStreamQueryContext, _event: LogStreamQueryEvent) => { - if (!('query' in context)) { - throw new Error(); - } - - urlStateStorage.set( - filterStateKey, - filterStateInUrlRT.encode({ - query: context.query, - filters: context.filters, - }) - ); - }; - -export const updateFiltersInUrl = +export const updateContextInUrl = ({ urlStateStorage, filterStateKey = defaultFilterStateKey, }: LogStreamQueryUrlStateDependencies) => (context: LogStreamQueryContext, _event: LogStreamQueryEvent) => { - if (!('filters' in context)) { - throw new Error(); + if ( + !('query' in context) || + !('filters' in context) || + !('timeRange' in context) || + !('refreshInterval' in context) + ) { + throw new Error('Missing keys from context needed to sync to the URL'); } urlStateStorage.set( @@ -75,6 +86,8 @@ export const updateFiltersInUrl = filterStateInUrlRT.encode({ query: context.query, filters: context.filters, + timeRange: context.timeRange, + refreshInterval: context.refreshInterval, }) ); }; @@ -82,6 +95,7 @@ export const updateFiltersInUrl = export const initializeFromUrl = ({ filterStateKey = defaultFilterStateKey, + positionStateKey = defaultPositionStateKey, toastsService, urlStateStorage, }: LogStreamQueryUrlStateDependencies): InvokeCreator< @@ -90,23 +104,92 @@ export const initializeFromUrl = > => (_context, _event) => (send) => { - const queryValueFromUrl = urlStateStorage.get(filterStateKey) ?? defaultFilterStateValue; + const filterQueryValueFromUrl = + urlStateStorage.get(filterStateKey) ?? requiredDefaultFilterStateValue; + const filterQueryE = decodeFilterQueryValueFromUrl(filterQueryValueFromUrl); - const queryE = decodeQueryValueFromUrl(queryValueFromUrl); + // NOTE: Access logPosition for backwards compatibility with values previously stored under that key. + const positionQueryValueFromUrl = urlStateStorage.get(positionStateKey) ?? {}; + const positionQueryE = decodePositionQueryValueFromUrl(positionQueryValueFromUrl); - if (Either.isLeft(queryE)) { - withNotifyOnErrors(toastsService).onGetError(createPlainError(formatErrors(queryE.left))); + if (Either.isLeft(filterQueryE) || Either.isLeft(positionQueryE)) { + withNotifyOnErrors(toastsService).onGetError( + createPlainError( + formatErrors([ + ...(Either.isLeft(filterQueryE) ? filterQueryE.left : []), + ...(Either.isLeft(positionQueryE) ? positionQueryE.left : []), + ]) + ) + ); send({ type: 'INITIALIZED_FROM_URL', query: defaultFilterStateValue.query, filters: defaultFilterStateValue.filters, + timeRange: null, + refreshInterval: null, }); } else { send({ type: 'INITIALIZED_FROM_URL', - query: queryE.right.query ?? defaultFilterStateValue.query, - filters: queryE.right.filters ?? defaultFilterStateValue.filters, + query: filterQueryE.right.query ?? defaultFilterStateValue.query, + filters: filterQueryE.right.filters ?? defaultFilterStateValue.filters, + timeRange: pipe( + // Via the logFilter key + pipe( + filterQueryE.right.timeRange, + Either.fromNullable(null), + Either.chain(({ from, to }) => + from && to ? Either.right({ from, to }) : Either.left(null) + ) + ), + // Via the legacy logPosition key, and start / end timeRange parameters + Either.alt(() => + pipe( + positionQueryE.right, + Either.fromNullable(null), + Either.chain(({ start, end }) => + start && end ? Either.right({ from: start, to: end }) : Either.left(null) + ) + ) + ), + // Via the legacy logPosition key, and deriving from / to from position.time + Either.alt(() => + pipe( + positionQueryE.right, + Either.fromNullable(null), + Either.chain(({ position }) => + position && position.time + ? Either.right({ + from: getTimeRangeStartFromTime(position.time), + to: getTimeRangeEndFromTime(position.time), + }) + : Either.left(null) + ) + ) + ), + Either.fold(identity, identity) + ), + refreshInterval: pipe( + // Via the logFilter key + pipe(filterQueryE.right.refreshInterval, Either.fromNullable(null)), + // Via the legacy logPosition key, and the boolean streamLive parameter + Either.alt(() => + pipe( + positionQueryE.right, + Either.fromNullable(null), + Either.chain(({ streamLive }) => + typeof streamLive === 'boolean' + ? Either.right({ + pause: !streamLive, + value: defaultFilterStateValue.refreshInterval.value, // NOTE: Was not previously synced to the URL, so falls straight to the default. + }) + : Either.left(null) + ) + ) + ), + Either.fold(identity, identity) + ), }); } }; @@ -148,9 +231,17 @@ const filterStateInUrlRT = rt.partial({ }), ]), filters: rt.array(filter), + timeRange: rt.strict({ + from: rt.string, + to: rt.string, + }), + refreshInterval: rt.strict({ + pause: rt.boolean, + value: rt.number, + }), }); -type FilterStateInUrl = rt.TypeOf; +export type FilterStateInUrl = rt.TypeOf; const legacyFilterStateInUrlRT = rt.union([ rt.strict({ @@ -170,7 +261,14 @@ const legacyLegacyFilterStateWithExpressionInUrlRT = rt.type({ expression: rt.string, }); -const decodeQueryValueFromUrl = (queryValueFromUrl: unknown) => +export const legacyPositionStateInUrlRT = rt.partial({ + streamLive: rt.boolean, + start: datemathStringRT, + end: datemathStringRT, + position: rt.union([rt.partial(minimalTimeKeyRT.props), rt.null]), +}); + +const decodeFilterQueryValueFromUrl = (queryValueFromUrl: unknown) => Either.getAltValidation(Array.getMonoid()).alt( pipe( pipe( @@ -187,5 +285,29 @@ const decodeQueryValueFromUrl = (queryValueFromUrl: unknown) => () => filterStateInUrlRT.decode(queryValueFromUrl) ); -export const replaceLogFilterInQueryString = (query: Query) => - replaceStateKeyInQueryString(defaultFilterStateKey, query); +const decodePositionQueryValueFromUrl = (queryValueFromUrl: unknown) => { + return legacyPositionStateInUrlRT.decode(queryValueFromUrl); +}; + +const ONE_HOUR = 3600000; +export const replaceLogFilterInQueryString = (query: Query, time?: number) => + replaceStateKeyInQueryString(defaultFilterStateKey, { + query, + ...(time && !Number.isNaN(time) + ? { + timeRange: { + from: new Date(time - ONE_HOUR).toISOString(), + to: new Date(time + ONE_HOUR).toISOString(), + }, + } + : {}), + refreshInterval: DEFAULT_REFRESH_INTERVAL, + }); + +const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 }; + +const getTimeRangeStartFromTime = (time: number): string => + moment(time).subtract(defaultTimeRangeFromPositionOffset).toISOString(); + +const getTimeRangeEndFromTime = (time: number): string => + moment(time).add(defaultTimeRangeFromPositionOffset).toISOString(); diff --git a/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx b/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx index 0345b256885860..c6af835dad803a 100644 --- a/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/link_to_logs.test.tsx @@ -73,10 +73,10 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'FILTER_FIELD:FILTER_VALUE')"` + `"(query:(language:kuery,query:'FILTER_FIELD:FILTER_VALUE'),refreshInterval:(pause:!t,value:5000),timeRange:(from:'2019-02-20T12:58:09.404Z',to:'2019-02-20T14:58:09.404Z'))"` ); expect(searchParams.get('logPosition')).toMatchInlineSnapshot( - `"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"` + `"(position:(tiebreaker:0,time:1550671089404))"` ); }); @@ -93,7 +93,9 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE'); - expect(searchParams.get('logFilter')).toMatchInlineSnapshot(`"(language:kuery,query:'')"`); + expect(searchParams.get('logFilter')).toMatchInlineSnapshot( + `"(query:(language:kuery,query:''),refreshInterval:(pause:!t,value:5000))"` + ); expect(searchParams.get('logPosition')).toEqual(null); }); }); @@ -113,10 +115,10 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'FILTER_FIELD:FILTER_VALUE')"` + `"(query:(language:kuery,query:'FILTER_FIELD:FILTER_VALUE'),refreshInterval:(pause:!t,value:5000),timeRange:(from:'2019-02-20T12:58:09.404Z',to:'2019-02-20T14:58:09.404Z'))"` ); expect(searchParams.get('logPosition')).toMatchInlineSnapshot( - `"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"` + `"(position:(tiebreaker:0,time:1550671089404))"` ); }); @@ -133,7 +135,9 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE'); - expect(searchParams.get('logFilter')).toMatchInlineSnapshot(`"(language:kuery,query:'')"`); + expect(searchParams.get('logFilter')).toMatchInlineSnapshot( + `"(query:(language:kuery,query:''),refreshInterval:(pause:!t,value:5000))"` + ); expect(searchParams.get('logPosition')).toEqual(null); }); }); @@ -153,7 +157,7 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'host.name: HOST_NAME')"` + `"(query:(language:kuery,query:'host.name: HOST_NAME'),refreshInterval:(pause:!t,value:5000))"` ); expect(searchParams.get('logPosition')).toEqual(null); }); @@ -174,10 +178,10 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'(host.name: HOST_NAME) and (FILTER_FIELD:FILTER_VALUE)')"` + `"(query:(language:kuery,query:'(host.name: HOST_NAME) and (FILTER_FIELD:FILTER_VALUE)'),refreshInterval:(pause:!t,value:5000),timeRange:(from:'2019-02-20T12:58:09.404Z',to:'2019-02-20T14:58:09.404Z'))"` ); expect(searchParams.get('logPosition')).toMatchInlineSnapshot( - `"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"` + `"(position:(tiebreaker:0,time:1550671089404))"` ); }); @@ -195,7 +199,7 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('OTHER_SOURCE'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'host.name: HOST_NAME')"` + `"(query:(language:kuery,query:'host.name: HOST_NAME'),refreshInterval:(pause:!t,value:5000))"` ); expect(searchParams.get('logPosition')).toEqual(null); }); @@ -231,7 +235,7 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'container.id: CONTAINER_ID')"` + `"(query:(language:kuery,query:'container.id: CONTAINER_ID'),refreshInterval:(pause:!t,value:5000))"` ); expect(searchParams.get('logPosition')).toEqual(null); }); @@ -252,10 +256,10 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'(container.id: CONTAINER_ID) and (FILTER_FIELD:FILTER_VALUE)')"` + `"(query:(language:kuery,query:'(container.id: CONTAINER_ID) and (FILTER_FIELD:FILTER_VALUE)'),refreshInterval:(pause:!t,value:5000),timeRange:(from:'2019-02-20T12:58:09.404Z',to:'2019-02-20T14:58:09.404Z'))"` ); expect(searchParams.get('logPosition')).toMatchInlineSnapshot( - `"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"` + `"(position:(tiebreaker:0,time:1550671089404))"` ); }); @@ -289,7 +293,7 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'kubernetes.pod.uid: POD_UID')"` + `"(query:(language:kuery,query:'kubernetes.pod.uid: POD_UID'),refreshInterval:(pause:!t,value:5000))"` ); expect(searchParams.get('logPosition')).toEqual(null); }); @@ -308,10 +312,10 @@ describe('LinkToLogsPage component', () => { const searchParams = new URLSearchParams(history.location.search); expect(searchParams.get('sourceId')).toEqual('default'); expect(searchParams.get('logFilter')).toMatchInlineSnapshot( - `"(language:kuery,query:'(kubernetes.pod.uid: POD_UID) and (FILTER_FIELD:FILTER_VALUE)')"` + `"(query:(language:kuery,query:'(kubernetes.pod.uid: POD_UID) and (FILTER_FIELD:FILTER_VALUE)'),refreshInterval:(pause:!t,value:5000),timeRange:(from:'2019-02-20T12:58:09.404Z',to:'2019-02-20T14:58:09.404Z'))"` ); expect(searchParams.get('logPosition')).toMatchInlineSnapshot( - `"(end:'2019-02-20T14:58:09.404Z',position:(tiebreaker:0,time:1550671089404),start:'2019-02-20T12:58:09.404Z',streamLive:!f)"` + `"(position:(tiebreaker:0,time:1550671089404))"` ); }); diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx index 39f276b982d760..58ba0df004f265 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx @@ -20,7 +20,7 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); }); @@ -34,7 +34,7 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); }); @@ -46,7 +46,7 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); }); diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx index f5a4ed2f9462cd..32bc4c909284d7 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { flowRight } from 'lodash'; import React from 'react'; import { match as RouteMatch, Redirect, RouteComponentProps } from 'react-router-dom'; -import { replaceLogPositionInQueryString } from '../../containers/logs/log_position'; +import { flowRight } from 'lodash'; import { replaceSourceIdInQueryString } from '../../containers/source_id'; +import { replaceLogPositionInQueryString } from '../../observability_logs/log_stream_position_state/src/url_state_storage_service'; import { replaceLogFilterInQueryString } from '../../observability_logs/log_stream_query_state'; import { getFilterFromLocation, getTimeFromLocation } from './query_params'; @@ -24,9 +24,10 @@ interface RedirectToLogsProps extends RedirectToLogsType { export const RedirectToLogs = ({ location, match }: RedirectToLogsProps) => { const sourceId = match.params.sourceId || 'default'; const filter = getFilterFromLocation(location); + const time = getTimeFromLocation(location); const searchString = flowRight( - replaceLogFilterInQueryString({ language: 'kuery', query: filter }), - replaceLogPositionInQueryString(getTimeFromLocation(location)), + replaceLogFilterInQueryString({ language: 'kuery', query: filter }, time), + replaceLogPositionInQueryString(time), replaceSourceIdInQueryString(sourceId) )(''); diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx index eb439e63588690..4f5fb79acc76f0 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx @@ -7,19 +7,19 @@ import { i18n } from '@kbn/i18n'; import { LinkDescriptor } from '@kbn/observability-plugin/public'; -import { flowRight } from 'lodash'; import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import useMount from 'react-use/lib/useMount'; +import { flowRight } from 'lodash'; import { findInventoryFields } from '../../../common/inventory_models'; import { InventoryItemType } from '../../../common/inventory_models/types'; import { LoadingPage } from '../../components/loading_page'; -import { replaceLogPositionInQueryString } from '../../containers/logs/log_position'; import { replaceSourceIdInQueryString } from '../../containers/source_id'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { useLogView } from '../../hooks/use_log_view'; import { replaceLogFilterInQueryString } from '../../observability_logs/log_stream_query_state'; import { getFilterFromLocation, getTimeFromLocation } from './query_params'; +import { replaceLogPositionInQueryString } from '../../observability_logs/log_stream_position_state/src/url_state_storage_service'; type RedirectToNodeLogsType = RouteComponentProps<{ nodeId: string; @@ -60,10 +60,11 @@ export const RedirectToNodeLogs = ({ const nodeFilter = `${findInventoryFields(nodeType).id}: ${nodeId}`; const userFilter = getFilterFromLocation(location); const filter = userFilter ? `(${nodeFilter}) and (${userFilter})` : nodeFilter; + const time = getTimeFromLocation(location); const searchString = flowRight( - replaceLogFilterInQueryString({ language: 'kuery', query: filter }), - replaceLogPositionInQueryString(getTimeFromLocation(location)), + replaceLogFilterInQueryString({ language: 'kuery', query: filter }, time), + replaceLogPositionInQueryString(time), replaceSourceIdInQueryString(sourceId) )(''); diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page.tsx index 562c0ef1b9c373..326bc3906e5c5b 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page.tsx @@ -31,7 +31,11 @@ export const StreamPage = () => { const { services: { data: { - query: { queryString: queryStringService, filterManager: filterManagerService }, + query: { + queryString: queryStringService, + filterManager: filterManagerService, + timefilter: { timefilter: timeFilterService }, + }, }, notifications: { toasts: toastsService }, }, @@ -49,6 +53,7 @@ export const StreamPage = () => { toastsService={toastsService} filterManagerService={filterManagerService} urlStateStorage={urlStateStorage} + timeFilterService={timeFilterService} > diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_content.tsx index 485a099a7a6e16..6fb2475d3d1e86 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_content.tsx @@ -5,10 +5,14 @@ * 2.0. */ +import { TimeRange } from '@kbn/es-query'; import { useActor } from '@xstate/react'; -import React from 'react'; +import React, { useMemo } from 'react'; +import { VisiblePositions } from '../../../observability_logs/log_stream_position_state'; +import { TimeKey } from '../../../../common/time'; import { SourceLoadingPage } from '../../../components/source_loading_page'; import { + LogStreamPageCallbacks, LogStreamPageState, useLogStreamPageStateContext, } from '../../../observability_logs/log_stream_page/state'; @@ -20,16 +24,54 @@ import { LogStreamPageContentProviders } from './page_providers'; export const ConnectedStreamPageContent: React.FC = () => { const logStreamPageStateService = useLogStreamPageStateContext(); + const [logStreamPageState, logStreamPageSend] = useActor(logStreamPageStateService); - const [logStreamPageState] = useActor(logStreamPageStateService); + const pageStateCallbacks = useMemo(() => { + return { + updateTimeRange: (timeRange: Partial) => { + logStreamPageSend({ + type: 'UPDATE_TIME_RANGE', + timeRange, + }); + }, + jumpToTargetPosition: (targetPosition: TimeKey | null) => { + logStreamPageSend({ type: 'JUMP_TO_TARGET_POSITION', targetPosition }); + }, + jumpToTargetPositionTime: (time: number) => { + logStreamPageSend({ type: 'JUMP_TO_TARGET_POSITION', targetPosition: { time } }); + }, + reportVisiblePositions: (visiblePositions: VisiblePositions) => { + logStreamPageSend({ + type: 'REPORT_VISIBLE_POSITIONS', + visiblePositions, + }); + }, + startLiveStreaming: () => { + logStreamPageSend({ type: 'UPDATE_REFRESH_INTERVAL', refreshInterval: { pause: false } }); + }, + stopLiveStreaming: () => { + logStreamPageSend({ type: 'UPDATE_REFRESH_INTERVAL', refreshInterval: { pause: true } }); + }, + }; + }, [logStreamPageSend]); - return ; + return ( + + ); }; -export const StreamPageContentForState: React.FC<{ logStreamPageState: LogStreamPageState }> = ({ - logStreamPageState, -}) => { - if (logStreamPageState.matches('uninitialized') || logStreamPageState.matches('loadingLogView')) { +export const StreamPageContentForState: React.FC<{ + logStreamPageState: LogStreamPageState; + logStreamPageCallbacks: LogStreamPageCallbacks; +}> = ({ logStreamPageState, logStreamPageCallbacks }) => { + if ( + logStreamPageState.matches('uninitialized') || + logStreamPageState.matches({ hasLogViewIndices: 'uninitialized' }) || + logStreamPageState.matches('loadingLogView') + ) { return ; } else if (logStreamPageState.matches('loadingLogViewFailed')) { return ; @@ -37,8 +79,14 @@ export const StreamPageContentForState: React.FC<{ logStreamPageState: LogStream return ; } else if (logStreamPageState.matches({ hasLogViewIndices: 'initialized' })) { return ( - - + + ); } else { diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index bdfc4d1cb2cc86..43f692cf9af8c0 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -31,7 +31,10 @@ import { useViewLogInProviderContext } from '../../../containers/logs/view_log_i import { WithLogTextviewUrlState } from '../../../containers/logs/with_log_textview'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useLogViewContext } from '../../../hooks/use_log_view'; -import { LogStreamPageActorRef } from '../../../observability_logs/log_stream_page/state'; +import { + LogStreamPageActorRef, + LogStreamPageCallbacks, +} from '../../../observability_logs/log_stream_page/state'; import { type ParsedQuery } from '../../../observability_logs/log_stream_query_state'; import { MatchedStateFromActor } from '../../../observability_logs/xstate_helpers'; import { datemathToEpochMillis, isValidDatemath } from '../../../utils/datemath'; @@ -43,7 +46,8 @@ const PAGE_THRESHOLD = 2; export const StreamPageLogsContent = React.memo<{ filterQuery: ParsedQuery; -}>(({ filterQuery }) => { + logStreamPageCallbacks: LogStreamPageCallbacks; +}>(({ filterQuery, logStreamPageCallbacks }) => { const { data: { query: { queryString }, @@ -291,12 +295,18 @@ type InitializedLogStreamPageState = MatchedStateFromActor< export const StreamPageLogsContentForState = React.memo<{ logStreamPageState: InitializedLogStreamPageState; -}>(({ logStreamPageState }) => { + logStreamPageCallbacks: LogStreamPageCallbacks; +}>(({ logStreamPageState, logStreamPageCallbacks }) => { const { context: { parsedQuery }, } = logStreamPageState; - return ; + return ( + + ); }); const LogPageMinimapColumn = euiStyled.div` diff --git a/x-pack/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/plugins/infra/public/pages/logs/stream/page_providers.tsx index 4ec53a9cd11efa..3260411aa4ed02 100644 --- a/x-pack/plugins/infra/public/pages/logs/stream/page_providers.tsx +++ b/x-pack/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -7,7 +7,10 @@ import stringify from 'json-stable-stringify'; import React, { useMemo } from 'react'; -import { LogStreamPageActorRef } from '../../../observability_logs/log_stream_page/state'; +import { + LogStreamPageActorRef, + LogStreamPageCallbacks, +} from '../../../observability_logs/log_stream_page/state'; import { LogEntryFlyoutProvider } from '../../../containers/logs/log_flyout'; import { LogHighlightsStateProvider } from '../../../containers/logs/log_highlights/log_highlights'; import { @@ -90,11 +93,15 @@ const LogHighlightsState: React.FC<{ export const LogStreamPageContentProviders: React.FC<{ logStreamPageState: InitializedLogStreamPageState; -}> = ({ children, logStreamPageState }) => { + logStreamPageCallbacks: LogStreamPageCallbacks; +}> = ({ children, logStreamPageState, logStreamPageCallbacks }) => { return ( - + diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/enable_hosts_view_page.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/enable_hosts_view_page.tsx index 886de82f1e9b85..ccdcb30e65821f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/enable_hosts_view_page.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/enable_hosts_view_page.tsx @@ -11,8 +11,10 @@ import { css } from '@emotion/react'; import { useEuiBackgroundColor } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useTrackPageview } from '@kbn/observability-plugin/public'; +import { useUiSetting } from '@kbn/kibana-react-plugin/public'; import { MetricsPageTemplate } from '../../../page_template'; -import hostsLandingBeta from './hosts_landing_beta.svg'; +import hostsLandingBetaLight from './hosts_landing_beta_light.svg'; +import hostsLandingBetaDark from './hosts_landing_beta_dark.svg'; import { ExperimentalBadge } from '../../../../../components/experimental_badge'; interface Props { @@ -21,6 +23,7 @@ interface Props { export const EnableHostsViewPage = ({ actions }: Props) => { const backgroundColor = useEuiBackgroundColor('subdued'); + const isDarkMode = useUiSetting('theme:darkMode'); useTrackPageview({ app: 'infra_metrics', path: 'hosts_feature_enable_landing_page' }); useTrackPageview({ @@ -41,7 +44,13 @@ export const EnableHostsViewPage = ({ actions }: Props) => { } alignment="center" - icon={} + icon={ + + } color="plain" layout="horizontal" body={ diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta.svg b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta.svg deleted file mode 100644 index 832b7fd689bcef..00000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta.svg +++ /dev/null @@ -1,920 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_dark.svg b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_dark.svg new file mode 100644 index 00000000000000..221076d4fe2903 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_light.svg b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_light.svg new file mode 100644 index 00000000000000..00d5aa123db8ea --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/enable_hosts_view_page/hosts_landing_beta_light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx index de2d046c08d198..7c3441809b9ea0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx @@ -22,7 +22,7 @@ const HOST_TABLE_METRICS: Array<{ type: SnapshotMetricType }> = [ { type: 'rx' }, { type: 'tx' }, { type: 'memory' }, - { type: 'cpuCores' }, + { type: 'cpu' }, { type: 'diskLatency' }, { type: 'memoryTotal' }, ]; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts index d85b367ba6fceb..6d7b196bfed36e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts @@ -27,8 +27,8 @@ describe('useHostTable hook', () => { avg: 0.94525, }, { - name: 'cpuCores', - value: 10, + name: 'cpu', + value: 0.6353277777777777, }, { name: 'memoryTotal', @@ -53,8 +53,8 @@ describe('useHostTable hook', () => { avg: 0.5400000214576721, }, { - name: 'cpuCores', - value: 8, + name: 'cpu', + value: 0.8647805555555556, }, { name: 'memoryTotal', @@ -89,9 +89,9 @@ describe('useHostTable hook', () => { name: 'memory', avg: 0.94525, }, - cpuCores: { - name: 'cpuCores', - value: 10, + cpu: { + name: 'cpu', + value: 0.6353277777777777, }, memoryTotal: { name: 'memoryTotal', @@ -118,9 +118,9 @@ describe('useHostTable hook', () => { name: 'memory', avg: 0.5400000214576721, }, - cpuCores: { - name: 'cpuCores', - value: 8, + cpu: { + name: 'cpu', + value: 0.8647805555555556, }, memoryTotal: { name: 'memoryTotal', diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx index ac9096504d0718..558a7bac920b70 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx @@ -24,7 +24,7 @@ import type { */ export type CloudProvider = 'gcp' | 'aws' | 'azure' | 'unknownProvider'; -type HostMetric = 'cpuCores' | 'diskLatency' | 'rx' | 'tx' | 'memory' | 'memoryTotal'; +type HostMetric = 'cpu' | 'diskLatency' | 'rx' | 'tx' | 'memory' | 'memoryTotal'; type HostMetrics = Record; @@ -74,9 +74,12 @@ const osLabel = i18n.translate('xpack.infra.hostsViewPage.table.operatingSystemC defaultMessage: 'Operating System', }); -const cpuCountLabel = i18n.translate('xpack.infra.hostsViewPage.table.numberOfCpusColumnHeader', { - defaultMessage: '# of CPUs', -}); +const averageCpuUsageLabel = i18n.translate( + 'xpack.infra.hostsViewPage.table.averageCpuUsageColumnHeader', + { + defaultMessage: 'CPU usage (avg.)', + } +); const diskLatencyLabel = i18n.translate('xpack.infra.hostsViewPage.table.diskLatencyColumnHeader', { defaultMessage: 'Disk Latency (avg.)', @@ -146,11 +149,10 @@ export const useHostsTable = (nodes: SnapshotNode[], { time }: HostTableParams) render: (os: string) => {os}, }, { - name: cpuCountLabel, - field: 'cpuCores', + name: averageCpuUsageLabel, + field: 'cpu.avg', sortable: true, - render: (cpuCores: SnapshotNodeMetric) => - formatMetric('cpuCores', cpuCores?.value ?? cpuCores?.max), + render: (avg: number) => formatMetric('cpu', avg), align: 'right', }, { diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx index 4168d4bf642896..6fca2e5ced98a7 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx @@ -5,12 +5,13 @@ * 2.0. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import useInterval from 'react-use/lib/useInterval'; import { css } from '@emotion/react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { i18n } from '@kbn/i18n'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; import { SnapshotNode } from '../../../../../common/http_api'; import { SavedView } from '../../../../containers/saved_view/saved_view'; import { AutoSizer } from '../../../../components/auto_sizer'; @@ -49,6 +50,8 @@ interface LegendControlOptions { legend: WaffleLegendOptions; } +const HOSTS_LINK_LOCAL_STORAGE_KEY = 'inventoryUI:hostsLinkClicked'; + export const Layout = React.memo( ({ shouldLoadDefault, currentView, reload, interval, nodes, loading }: Props) => { const [showLoading, setShowLoading] = useState(true); @@ -72,6 +75,12 @@ export const Layout = React.memo( const legendSteps = legend?.steps ?? DEFAULT_LEGEND.steps; const legendReverseColors = legend?.reverseColors ?? DEFAULT_LEGEND.reverseColors; + const [hostsLinkClicked, setHostsLinkClicked] = useLocalStorage( + HOSTS_LINK_LOCAL_STORAGE_KEY, + false + ); + const hostsLinkClickedRef = useRef(hostsLinkClicked); + const options = { formatter: InfraFormatterType.percent, formatTemplate: '{{value}}', @@ -172,17 +181,22 @@ export const Layout = React.memo( - + {!hostsLinkClickedRef.current && ( + { + setHostsLinkClicked(true); + }} + /> + )} {'target_field'}, - allowedFormats: ( - <> - {'ISO8601'},{'UNIX'}, - {'UNIX_MS'},{'TAI64N'} - - ), defaultFormat: {`yyyy-MM-dd'T'HH:mm:ss.SSSXXX`}, }} /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss index 34829f8323131a..88ecee001dab1a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss @@ -8,7 +8,6 @@ @include euiYScroll; max-height: $euiSize * 20; width: $euiSize * 16; - overflow-wrap: break-word; } .lnsWorkspaceWarningList__item { @@ -18,3 +17,8 @@ border-top: $euiBorderThin; } } + +.lnsWorkspaceWarningList__description { + overflow-wrap: break-word; + min-width: 0; +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx index e1858d0f22b57c..c03a6a61e437e8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx @@ -124,7 +124,7 @@ export const MessageList = ({ )} - + {message.longMessage} diff --git a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx b/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx index c5baced9bb4bf8..b110b515750776 100644 --- a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx +++ b/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.test.tsx @@ -11,6 +11,15 @@ import { mountWithIntl as mount } from '@kbn/test-jest-helpers'; import { AxisTitleSettings, AxisTitleSettingsProps } from './axis_title_settings'; import { Label, VisLabel } from '../../vis_label'; +jest.mock('lodash', () => { + const original = jest.requireActual('lodash'); + + return { + ...original, + debounce: (fn: unknown) => fn, + }; +}); + describe('Axes Title settings', () => { let props: AxisTitleSettingsProps; beforeEach(() => { @@ -68,4 +77,24 @@ describe('Axes Title settings', () => { ); expect(component.find('[data-test-subj="lnsxAxisTitle"]').last().prop('value')).toBe(''); }); + + it('should reset the label when moving from custom to auto', () => { + let component = mount( + + ); + + // switch mode + // Perform the change down one level to check the actual value swap + act(() => { + component.find(VisLabel).find('EuiSelect').prop('onChange')!({ + target: { value: 'auto' }, + } as React.ChangeEvent); + }); + component = component.update(); + expect(component.find('[data-test-subj="lnsxAxisTitle-select"]').last().prop('value')).toBe( + 'auto' + ); + expect(component.find('[data-test-subj="lnsxAxisTitle"]').last().prop('value')).toBe(''); + expect(props.updateTitleState).toHaveBeenCalledWith({ title: undefined, visible: true }, 'x'); + }); }); diff --git a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx b/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx index 8a7e203d65f996..d46b99cd817d5a 100644 --- a/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx +++ b/x-pack/plugins/lens/public/shared_components/axis/title/axis_title_settings.tsx @@ -83,7 +83,7 @@ export const AxisTitleSettings: React.FunctionComponent defaultMessage: 'Axis title', })} dataTestSubj={`lns${axis}AxisTitle`} - label={localAxisState.title || ''} + label={localAxisState.title} mode={localAxisState.visibility} placeholder={i18n.translate('xpack.lens.shared.overwriteAxisTitle', { defaultMessage: 'Overwrite axis title', diff --git a/x-pack/plugins/lens/public/shared_components/vis_label.tsx b/x-pack/plugins/lens/public/shared_components/vis_label.tsx index 79bab27bbcb6f4..6d54d1633d4395 100644 --- a/x-pack/plugins/lens/public/shared_components/vis_label.tsx +++ b/x-pack/plugins/lens/public/shared_components/vis_label.tsx @@ -13,11 +13,11 @@ export type LabelMode = 'auto' | 'custom' | 'none'; export interface Label { mode: LabelMode; - label: string; + label: string | undefined; } export interface VisLabelProps { - label: string; + label: string | undefined; mode: LabelMode; handleChange: (label: Label) => void; placeholder?: string; @@ -76,11 +76,12 @@ export function VisLabel({ data-test-subj={`${dataTestSubj}-select`} aria-label="Label" onChange={({ target }) => { - if (target.value === 'custom') { - handleChange({ label: '', mode: target.value as LabelMode }); - return; - } - handleChange({ label: '', mode: target.value as LabelMode }); + const title = + target.value === 'custom' ? '' : target.value === 'auto' ? undefined : label; + handleChange({ + label: title, + mode: target.value as LabelMode, + }); }} options={hasAutoOption ? modeEnhancedOptions : modeDefaultOptions} value={mode} diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 5a50e9068d67b7..4592bf5bfddcd1 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { set, uniq, cloneDeep } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { uniq, cloneDeep } from 'lodash'; import { i18n } from '@kbn/i18n'; import moment from 'moment-timezone'; import type { Serializable } from '@kbn/utility-types'; diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts index 2cb28693396976..596c334aeac9e2 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.test.ts @@ -572,8 +572,6 @@ describe('heatmap', () => { // X-axis isXAxisLabelVisible: [false], isXAxisTitleVisible: [false], - xTitle: [''], - yTitle: [''], }, }, ], diff --git a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx index 4450ec558db8b5..91c9e60f38d8f6 100644 --- a/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/heatmap/visualization.tsx @@ -406,11 +406,11 @@ export const getHeatmapVisualization = ({ // Y-axis isYAxisLabelVisible: false, isYAxisTitleVisible: false, - yTitle: state.gridConfig.yTitle ?? '', + yTitle: state.gridConfig.yTitle, // X-axis isXAxisLabelVisible: false, isXAxisTitleVisible: false, - xTitle: state.gridConfig.xTitle ?? '', + xTitle: state.gridConfig.xTitle, } ); diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 3732371c9fd213..b80f702125d3c2 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -63,6 +63,7 @@ "@kbn/core-saved-objects-common", "@kbn/core-ui-settings-browser", "@kbn/core-saved-objects-server", + "@kbn/safer-lodash-set", "@kbn/shared-ux-router", ], "exclude": [ diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx index d4319f13e9b0f7..863c812c041161 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx @@ -913,7 +913,7 @@ describe('BuilderEntryItem', () => { ).onBlur(); }); - expect(mockSetErrorExists).toHaveBeenCalledWith(true); + expect(mockSetErrorExists).toHaveBeenCalledWith({ '123': true }); }); test('it invokes "setErrorsExist" when invalid value inputted for field value input', async () => { @@ -960,7 +960,7 @@ describe('BuilderEntryItem', () => { ).onSearchChange('hellooo'); }); - expect(mockSetErrorExists).toHaveBeenCalledWith(true); + expect(mockSetErrorExists).toHaveBeenCalledWith({ '123': true }); }); test('it invokes "setWarningsExist" when invalid value in field value input', async () => { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx index 1551f4248a41b7..a0bb82306f2e25 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx @@ -60,6 +60,7 @@ import { HttpStart } from '@kbn/core/public'; import { getEmptyValue } from '../../../common/empty_value'; import * as i18n from './translations'; +import { EntryFieldError } from './reducer'; const FieldFlexItem = styled(EuiFlexItem)` overflow: hidden; @@ -81,7 +82,7 @@ export interface EntryItemProps { ) => DataViewBase; onChange: (arg: BuilderEntry, i: number) => void; onlyShowListOperators?: boolean; - setErrorsExist: (arg: boolean) => void; + setErrorsExist: (arg: EntryFieldError) => void; setWarningsExist: (arg: boolean) => void; isDisabled?: boolean; operatorsList?: OperatorOption[]; @@ -110,9 +111,9 @@ export const BuilderEntryItem: React.FC = ({ const handleError = useCallback( (err: boolean): void => { - setErrorsExist(err); + setErrorsExist({ [entry.id]: err }); }, - [setErrorsExist] + [setErrorsExist, entry.id] ); const handleWarning = useCallback( (warn: boolean): void => { 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 d891c1a5eea087..8d872cd23cbbfb 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 @@ -24,6 +24,7 @@ import { DataViewBase } from '@kbn/es-query'; import { BuilderAndBadgeComponent } from './and_badge'; import { BuilderEntryDeleteButtonComponent } from './entry_delete_button'; import { BuilderEntryItem } from './entry_renderer'; +import { EntryFieldError } from './reducer'; const MyBeautifulLine = styled(EuiFlexItem)` &:after { @@ -58,7 +59,7 @@ interface BuilderExceptionListItemProps { ) => DataViewBase; onDeleteExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void; onChangeExceptionItem: (item: ExceptionsBuilderExceptionItem, index: number) => void; - setErrorsExist: (arg: boolean) => void; + setErrorsExist: (arg: EntryFieldError) => void; setWarningsExist: (arg: boolean) => void; onlyShowListOperators?: boolean; isDisabled?: boolean; diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx index d82f0901a24ccd..4c11c89d80618c 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx @@ -38,7 +38,8 @@ import { AndOrBadge } from '../and_or_badge'; import { BuilderExceptionListItemComponent } from './exception_item_renderer'; import { BuilderLogicButtons } from './logic_buttons'; -import { State, exceptionsBuilderReducer } from './reducer'; +import { getTotalErrorExist } from './selectors'; +import { EntryFieldError, State, exceptionsBuilderReducer } from './reducer'; const MyInvisibleAndBadge = styled(EuiFlexItem)` visibility: hidden; @@ -60,7 +61,7 @@ const initialState: State = { disableAnd: false, disableNested: false, disableOr: false, - errorExists: 0, + errors: {}, exceptions: [], exceptionsToDelete: [], warningExists: 0, @@ -121,30 +122,30 @@ export const ExceptionBuilderComponent = ({ operatorsList, allowCustomFieldOptions = false, }: ExceptionBuilderProps): JSX.Element => { - const [ - { - addNested, - andLogicIncluded, - disableAnd, - disableNested, - disableOr, - errorExists, - warningExists, - exceptions, - exceptionsToDelete, - }, - dispatch, - ] = useReducer(exceptionsBuilderReducer(), { + const [state, dispatch] = useReducer(exceptionsBuilderReducer(), { ...initialState, disableAnd: isAndDisabled, disableNested: isNestedDisabled, disableOr: isOrDisabled, }); + const { + addNested, + andLogicIncluded, + disableAnd, + disableNested, + disableOr, + warningExists, + exceptions, + exceptionsToDelete, + } = state; + + const errorExists = getTotalErrorExist(state); + const setErrorsExist = useCallback( - (hasErrors: boolean): void => { + (error: EntryFieldError): void => { dispatch({ - errorExists: hasErrors, + error, type: 'setErrorsExist', }); }, diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts b/x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts index ba3b77fb24ed14..1a95fd791953ab 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts +++ b/x-pack/plugins/lists/public/exceptions/components/builder/reducer.ts @@ -16,6 +16,8 @@ import { export type ViewerModalName = 'addModal' | 'editModal' | null; +export type EntryFieldError = Record; + export interface State { disableAnd: boolean; disableNested: boolean; @@ -24,7 +26,7 @@ export interface State { addNested: boolean; exceptions: ExceptionsBuilderExceptionItem[]; exceptionsToDelete: ExceptionListItemSchema[]; - errorExists: number; + errors: EntryFieldError; warningExists: number; } @@ -56,7 +58,7 @@ export type Action = } | { type: 'setErrorsExist'; - errorExists: boolean; + error: EntryFieldError; } | { type: 'setWarningsExist'; @@ -125,12 +127,14 @@ export const exceptionsBuilderReducer = }; } case 'setErrorsExist': { - const { errorExists } = state; - const errTotal = action.errorExists ? errorExists + 1 : errorExists - 1; + const newErrorsState = { + ...state.errors, + ...action.error, + }; return { ...state, - errorExists: errTotal < 0 ? 0 : errTotal, + errors: newErrorsState, }; } case 'setWarningsExist': { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/selectors.ts b/x-pack/plugins/lists/public/exceptions/components/builder/selectors.ts new file mode 100644 index 00000000000000..aa2e5b6fc51291 --- /dev/null +++ b/x-pack/plugins/lists/public/exceptions/components/builder/selectors.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { State } from './reducer'; + +export const getTotalErrorExist = (state: State): number => { + const { exceptions, errors } = state; + const allEntryIds = exceptions + .map((exception) => exception.entries.map((entry) => entry.id)) + .flat(); + const errTotal = Object.keys(errors).filter( + (id) => allEntryIds.includes(id) && errors[id] + ).length; + return errTotal; +}; diff --git a/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts b/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts index 75aea773f662bb..86446dfb1012e1 100644 --- a/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts +++ b/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts @@ -149,6 +149,6 @@ export function registerNavigation(alerting: AlertingSetup) { ]), ]; - return formatExplorerUrl('', { jobIds }); + return formatExplorerUrl('/app/ml', { jobIds }); }); } diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index ffd3fa9e8d6543..b5dafed765ff46 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -20,6 +20,7 @@ import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { StorageContextProvider } from '@kbn/ml-local-storage'; +import { mlCapabilities } from './capabilities/check_capabilities'; import { ML_STORAGE_KEYS } from '../../common/types/storage'; import { ML_APP_LOCATOR, ML_PAGES } from '../../common/constants/locator'; import type { MlSetupDependencies, MlStartDependencies } from '../plugin'; @@ -61,6 +62,7 @@ export function getMlGlobalServices(httpStart: HttpStart, usageCollection?: Usag mlApiServices: mlApiServicesProvider(httpService), mlUsageCollection: mlUsageCollectionProvider(usageCollection), isServerless, + mlCapabilities, }; } diff --git a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts index c5a69d5da12a03..3bae8b63261fec 100644 --- a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts @@ -6,7 +6,11 @@ */ import { i18n } from '@kbn/i18n'; - +import { BehaviorSubject } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; +import { isEqual } from 'lodash'; +import useObservable from 'react-use/lib/useObservable'; +import { useMlKibana } from '../contexts/kibana'; import { hasLicenseExpired } from '../license'; import { MlCapabilities, getDefaultCapabilities } from '../../../common/types/capabilities'; @@ -15,11 +19,52 @@ import type { MlApiServices } from '../services/ml_api_service'; let _capabilities: MlCapabilities = getDefaultCapabilities(); +export class MlCapabilitiesService { + private _capabilities$ = new BehaviorSubject(getDefaultCapabilities()); + + public capabilities$ = this._capabilities$.pipe(distinctUntilChanged(isEqual)); + + public getCapabilities(): MlCapabilities { + return this._capabilities$.getValue(); + } + + public updateCapabilities(update: MlCapabilities) { + this._capabilities$.next(update); + } +} + +/** + * TODO should be initialized in getMlGlobalServices + * Temp solution to make it work with the current setup. + */ +export const mlCapabilities = new MlCapabilitiesService(); + +/** + * Check the privilege type and the license to see whether a user has permission to access a feature. + * + * @param capability + */ +export function usePermissionCheck(capability: keyof MlCapabilities) { + const { + services: { + mlServices: { mlCapabilities: mlCapabilitiesService }, + }, + } = useMlKibana(); + + const licenseHasExpired = hasLicenseExpired(); + const capabilities = useObservable( + mlCapabilitiesService.capabilities$, + mlCapabilitiesService.getCapabilities() + ); + return capabilities[capability] && !licenseHasExpired; +} + export function checkGetManagementMlJobsResolver({ checkMlCapabilities }: MlApiServices) { return new Promise<{ mlFeatureEnabledInSpace: boolean }>((resolve, reject) => { checkMlCapabilities() .then(({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }) => { _capabilities = capabilities; + mlCapabilities.updateCapabilities(capabilities); // Loop through all capabilities to ensure they are all set to true. const isManageML = Object.values(_capabilities).every((p) => p === true); @@ -42,6 +87,7 @@ export function checkGetJobsCapabilitiesResolver( getCapabilities() .then(async ({ capabilities, isPlatinumOrTrialLicense }) => { _capabilities = capabilities; + mlCapabilities.updateCapabilities(capabilities); // the minimum privilege for using ML with a platinum or trial license is being able to get the transforms list. // all other functionality is controlled by the return capabilities object. // if the license is basic (isPlatinumOrTrialLicense === false) then do not redirect, @@ -68,6 +114,7 @@ export function checkCreateJobsCapabilitiesResolver( getCapabilities() .then(async ({ capabilities, isPlatinumOrTrialLicense }) => { _capabilities = capabilities; + mlCapabilities.updateCapabilities(capabilities); // if the license is basic (isPlatinumOrTrialLicense === false) then do not redirect, // allow the promise to resolve as the separate license check will redirect then user to // a basic feature @@ -94,6 +141,7 @@ export function checkFindFileStructurePrivilegeResolver( getCapabilities() .then(async ({ capabilities }) => { _capabilities = capabilities; + mlCapabilities.updateCapabilities(capabilities); // the minimum privilege for using ML with a basic license is being able to use the datavisualizer. // all other functionality is controlled by the return _capabilities object if (_capabilities.canFindFileStructure) { @@ -110,8 +158,10 @@ export function checkFindFileStructurePrivilegeResolver( }); } -// check the privilege type and the license to see whether a user has permission to access a feature. -// takes the name of the privilege variable as specified in get_privileges.js +/** + * @deprecated use {@link usePermissionCheck} instead. + * @param capability + */ export function checkPermission(capability: keyof MlCapabilities) { const licenseHasExpired = hasLicenseExpired(); return _capabilities[capability] === true && licenseHasExpired !== true; diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js index a0a364e3af0f8d..f46de2a913e058 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js +++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js @@ -482,87 +482,87 @@ class AnnotationsTableUI extends Component { } const actions = []; - - actions.push({ - name: editAnnotationsText, - description: editAnnotationsText, - icon: 'pencil', - type: 'icon', - onClick: (annotation) => { - const annotationId = annotation._id; - const originalAnnotation = annotations.find((d) => d._id === annotationId); - - annotationUpdatesService.setValue(originalAnnotation ?? annotation); - }, - 'data-test-subj': `mlAnnotationsActionEdit`, - }); - - if (this.state.jobId && this.props.jobs[0].analysis_config.bucket_span) { - // add datafeed modal action + if (this.props.jobs === undefined || this.props.jobs[0]?.blocked === undefined) { actions.push({ - name: viewDataFeedText, - description: viewDataFeedText, - icon: 'visAreaStacked', + name: editAnnotationsText, + description: editAnnotationsText, + icon: 'pencil', type: 'icon', onClick: (annotation) => { - this.setState({ - datafeedFlyoutVisible: true, - datafeedEnd: annotation.end_timestamp, - }); + const annotationId = annotation._id; + const originalAnnotation = annotations.find((d) => d._id === annotationId); + + annotationUpdatesService.setValue(originalAnnotation ?? annotation); }, - 'data-test-subj': `mlAnnotationsActionViewDatafeed`, + 'data-test-subj': `mlAnnotationsActionEdit`, }); - } - if (isSingleMetricViewerLinkVisible) { - actions.push({ - name: (annotation) => { - const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); + if (this.state.jobId && this.props.jobs[0].analysis_config.bucket_span) { + // add datafeed modal action + actions.push({ + name: viewDataFeedText, + description: viewDataFeedText, + icon: 'visAreaStacked', + type: 'icon', + onClick: (annotation) => { + this.setState({ + datafeedFlyoutVisible: true, + datafeedEnd: annotation.end_timestamp, + }); + }, + 'data-test-subj': `mlAnnotationsActionViewDatafeed`, + }); + } - if (isDrillDownAvailable) { - return ( - - ); - } - return ( - { + const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); + + if (isDrillDownAvailable) { + return ( - } - > - - - ); - }, - description: (annotation) => { - const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); - - return isDrillDownAvailable - ? i18n.translate('xpack.ml.annotationsTable.openInSingleMetricViewerAriaLabel', { - defaultMessage: 'Open in Single Metric Viewer', - }) - : i18n.translate( - 'xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerAriaLabel', - { defaultMessage: 'Job configuration not supported in Single Metric Viewer' } ); - }, - enabled: (annotation) => isTimeSeriesViewJob(this.getJob(annotation.job_id)), - icon: 'visLine', - type: 'icon', - onClick: (annotation) => this.openSingleMetricView(annotation), - 'data-test-subj': `mlAnnotationsActionOpenInSingleMetricViewer`, - }); + } + return ( + + } + > + + + ); + }, + description: (annotation) => { + const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id)); + + return isDrillDownAvailable + ? i18n.translate('xpack.ml.annotationsTable.openInSingleMetricViewerAriaLabel', { + defaultMessage: 'Open in Single Metric Viewer', + }) + : i18n.translate( + 'xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerAriaLabel', + { defaultMessage: 'Job configuration not supported in Single Metric Viewer' } + ); + }, + enabled: (annotation) => isTimeSeriesViewJob(this.getJob(annotation.job_id)), + icon: 'visLine', + type: 'icon', + onClick: (annotation) => this.openSingleMetricView(annotation), + 'data-test-subj': `mlAnnotationsActionOpenInSingleMetricViewer`, + }); + } } - const getRowProps = (item) => { return { 'data-test-subj': `mlAnnotationsTableRow row-${item._id}`, diff --git a/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx b/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx index f3270068740d05..d14e0db3518e1d 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx @@ -16,7 +16,7 @@ import { useMlLocator, useNavigateToPath } from '../../contexts/kibana'; import { isFullLicense } from '../../license'; import type { MlRoute } from '../../routing'; import { ML_PAGES } from '../../../../common/constants/locator'; -import { checkPermission } from '../../capabilities/check_capabilities'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; export interface Tab { id: string; @@ -37,7 +37,7 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) { const navigateToPath = useNavigateToPath(); const mlFeaturesDisabled = !isFullLicense(); - const canViewMlNodes = checkPermission('canViewMlNodes'); + const canViewMlNodes = usePermissionCheck('canViewMlNodes'); const [globalState] = useUrlState('_g'); diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/model_snapshots_table.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/model_snapshots_table.tsx index cfd586b3a33964..414e7faca56915 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/model_snapshots_table.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/model_snapshots_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useEffect, useCallback, useState, useRef } from 'react'; +import React, { FC, useEffect, useCallback, useState, useRef, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { @@ -50,6 +50,7 @@ export const ModelSnapshotTable: FC = ({ job, refreshJobList }) => { const [revertSnapshot, setRevertSnapshot] = useState(null); const [closeJobModalVisible, setCloseJobModalVisible] = useState(null); const [combinedJobState, setCombinedJobState] = useState(null); + const actionsEnabled = useMemo(() => job.blocked === undefined, [job]); const isMounted = useRef(true); useEffect(() => { @@ -185,7 +186,7 @@ export const ModelSnapshotTable: FC = ({ job, refreshJobList }) => { description: i18n.translate('xpack.ml.modelSnapshotTable.actions.revert.description', { defaultMessage: 'Revert to this snapshot', }), - enabled: () => canCreateJob && canStartStopDatafeed, + enabled: () => actionsEnabled && canCreateJob && canStartStopDatafeed, type: 'icon', icon: 'crosshairs', onClick: checkJobIsClosed, @@ -197,7 +198,7 @@ export const ModelSnapshotTable: FC = ({ job, refreshJobList }) => { description: i18n.translate('xpack.ml.modelSnapshotTable.actions.edit.description', { defaultMessage: 'Edit this snapshot', }), - enabled: () => canCreateJob, + enabled: () => actionsEnabled && canCreateJob, type: 'icon', icon: 'pencil', onClick: setEditSnapshot, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx index 18b93e35a3f364..d52265634cc23e 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx @@ -71,8 +71,8 @@ const mockNavigateToPath = jest.fn(); jest.mock('../../../../../contexts/kibana', () => ({ useMlKibana: () => ({ services: { - savedObjects: {}, uiSettings: {}, + http: {}, }, }), useNavigateToPath: () => mockNavigateToPath, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index 870715401d7094..ed327eb7dc71bc 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -14,11 +14,11 @@ import { EuiPageContent_Deprecated as EuiPageContent, } from '@elastic/eui'; -import type { SimpleSavedObject } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { getNestedProperty } from '@kbn/ml-nested-property'; import { SavedObjectFinderUi } from '@kbn/saved-objects-plugin/public'; +import { SavedObjectCommon } from '@kbn/saved-objects-plugin/common'; import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; import { useToastNotificationService } from '../../../../../services/toast_notification_service'; import { getDataViewAndSavedSearch, isCcsIndexPattern } from '../../../../../util/index_utils'; @@ -27,7 +27,7 @@ const fixedPageSize: number = 20; export const SourceSelection: FC = () => { const { - services: { savedObjects, uiSettings }, + services: { http, uiSettings }, } = useMlKibana(); const navigateToPath = useNavigateToPath(); @@ -39,7 +39,7 @@ export const SourceSelection: FC = () => { id: string, type: string, fullName: string, - savedObject: SimpleSavedObject + savedObject: SavedObjectCommon ) => { // Kibana data views including `:` are cross-cluster search indices // and are not supported by Data Frame Analytics yet. For saved searches @@ -152,7 +152,7 @@ export const SourceSelection: FC = () => { ]} fixedPageSize={fixedPageSize} uiSettings={uiSettings} - savedObjects={savedObjects} + http={http} /> diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js index 593a09d377057d..69e036abf4d2c4 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js @@ -311,7 +311,10 @@ export class ForecastsTableUI extends Component { return ( this.openSingleMetricView(forecast)} - isDisabled={forecast.forecast_status !== FORECAST_REQUEST_STATE.FINISHED} + isDisabled={ + this.props.job.blocked !== undefined || + forecast.forecast_status !== FORECAST_REQUEST_STATE.FINISHED + } iconType="visLine" aria-label={viewForecastAriaLabel} /> diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/job_details.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/job_details.js index 8d98052eab26ce..4eec95106eca2a 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/job_details.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/job_details.js @@ -83,22 +83,24 @@ export class JobDetailsUI extends Component { alertRules, } = extractJobDetails(job, basePath, refreshJobList); - datafeed.titleAction = ( - - this.setState({ - datafeedChartFlyoutVisible: true, - }) - } - iconType="visAreaStacked" - size="s" - > - - - ); + if (job.blocked === undefined) { + datafeed.titleAction = ( + + this.setState({ + datafeedChartFlyoutVisible: true, + }) + } + iconType="visAreaStacked" + size="s" + > + + + ); + } const tabs = [ { @@ -216,6 +218,7 @@ export class JobDetailsUI extends Component { tabs.push( { id: 'datafeed-preview', + disabled: job.blocked !== undefined, 'data-test-subj': 'mlJobListTab-datafeed-preview', name: i18n.translate('xpack.ml.jobsList.jobDetails.tabs.datafeedPreviewLabel', { defaultMessage: 'Datafeed preview', @@ -224,6 +227,7 @@ export class JobDetailsUI extends Component { }, { id: 'forecasts', + disabled: job.blocked !== undefined, 'data-test-subj': 'mlJobListTab-forecasts', name: i18n.translate('xpack.ml.jobsList.jobDetails.tabs.forecastsLabel', { defaultMessage: 'Forecasts', @@ -235,6 +239,7 @@ export class JobDetailsUI extends Component { tabs.push({ id: 'annotations', + disabled: job.blocked !== undefined, 'data-test-subj': 'mlJobListTab-annotations', name: i18n.translate('xpack.ml.jobsList.jobDetails.tabs.annotationsLabel', { defaultMessage: 'Annotations', @@ -249,6 +254,7 @@ export class JobDetailsUI extends Component { tabs.push({ id: 'modelSnapshots', + disabled: job.blocked !== undefined, 'data-test-subj': 'mlJobListTab-modelSnapshots', name: i18n.translate('xpack.ml.jobsList.jobDetails.tabs.modelSnapshotsLabel', { defaultMessage: 'Model snapshots', diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js index d5459fd5b8e33b..a2a03ef7ce69c2 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js @@ -141,7 +141,6 @@ export class JobsList extends Component { render: (item) => ( this.toggleRow(item)} - isDisabled={item.blocked !== undefined} iconType={this.state.itemIdToExpandedRowMap[item.id] ? 'arrowDown' : 'arrowRight'} aria-label={ this.state.itemIdToExpandedRowMap[item.id] diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js index b186192b64744d..179d5d48b3fe5c 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js @@ -342,12 +342,6 @@ export class JobsListView extends Component { this.updateFunctions[j](fullJobsList[j]); }); - jobs.forEach((job) => { - if (job.blocked !== undefined && this.state.itemIdToExpandedRowMap[job.id]) { - this.toggleRow(job.id); - } - }); - this.isDoneRefreshing(); if (jobsSummaryList.some((j) => j.blocked !== undefined)) { // if there are some jobs in a deleting state, start polling for diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx index cc3b20966935b8..40a8a3f5a5c4c0 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx @@ -54,7 +54,7 @@ interface Props { export const ChangeDataViewModal: FC = ({ onClose }) => { const { services: { - savedObjects, + http, uiSettings, data: { dataViews }, }, @@ -171,7 +171,7 @@ export const ChangeDataViewModal: FC = ({ onClose }) => { ]} fixedPageSize={fixedPageSize} uiSettings={uiSettings} - savedObjects={savedObjects} + http={http} /> )} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx index 5ece063f9df84b..352a2a390fe28f 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx @@ -19,7 +19,7 @@ export interface PageProps { export const Page: FC = ({ nextStepPath }) => { const RESULTS_PER_PAGE = 20; - const { uiSettings, savedObjects } = useMlKibana().services; + const { uiSettings, http } = useMlKibana().services; const navigateToPath = useNavigateToPath(); const onObjectSelection = (id: string, type: string) => { @@ -72,7 +72,7 @@ export const Page: FC = ({ nextStepPath }) => { ]} fixedPageSize={RESULTS_PER_PAGE} uiSettings={uiSettings} - savedObjects={savedObjects} + http={http} /> diff --git a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx index 99dc3f687a7e00..4d6a3c744408ad 100644 --- a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx @@ -313,23 +313,25 @@ export const ExpandedRow: FC = ({ item }) => {
+ {!!modelItems?.length ? ( + <> + + +
+ +
+
+ + +
+ + + ) : null} + - {!!modelItems?.length ? ( - - - -
- -
-
- - -
-
- ) : null} {stats.inference_stats ? ( diff --git a/x-pack/plugins/ml/server/saved_objects/service.ts b/x-pack/plugins/ml/server/saved_objects/service.ts index 1c31b6d0d088dc..d05972a1368ee3 100644 --- a/x-pack/plugins/ml/server/saved_objects/service.ts +++ b/x-pack/plugins/ml/server/saved_objects/service.ts @@ -63,6 +63,12 @@ export function mlSavedObjectServiceFactory( (options: SavedObjectsFindOptions) => JSON.stringify(options) ); + function _clearSavedObjectsClientCache() { + if (_savedObjectsClientFindMemo.cache.clear) { + _savedObjectsClientFindMemo.cache.clear(); + } + } + async function _getJobObjects( jobType?: JobType, jobId?: string, @@ -118,6 +124,7 @@ export function mlSavedObjectServiceFactory( } else { // the saved object has no spaces, this is unexpected, attempt a normal delete await savedObjectsClient.delete(ML_JOB_SAVED_OBJECT_TYPE, id, { force: true }); + _clearSavedObjectsClientCache(); } } } catch (error) { @@ -128,11 +135,12 @@ export function mlSavedObjectServiceFactory( await savedObjectsClient.create(ML_JOB_SAVED_OBJECT_TYPE, job, { id, }); + _clearSavedObjectsClientCache(); } async function _bulkCreateJobs(jobs: Array<{ job: JobObject; namespaces: string[] }>) { await isMlReady(); - return await savedObjectsClient.bulkCreate( + const results = await savedObjectsClient.bulkCreate( jobs.map((j) => ({ type: ML_JOB_SAVED_OBJECT_TYPE, id: _jobSavedObjectId(j.job), @@ -140,6 +148,8 @@ export function mlSavedObjectServiceFactory( initialNamespaces: j.namespaces, })) ); + _clearSavedObjectsClientCache(); + return results; } function _jobSavedObjectId(job: JobObject) { @@ -154,6 +164,7 @@ export function mlSavedObjectServiceFactory( } await savedObjectsClient.delete(ML_JOB_SAVED_OBJECT_TYPE, job.id, { force: true }); + _clearSavedObjectsClientCache(); } async function _forceDeleteJob(jobType: JobType, jobId: string, namespace: string) { @@ -169,6 +180,7 @@ export function mlSavedObjectServiceFactory( namespace: namespace === '*' ? undefined : namespace, force: true, }); + _clearSavedObjectsClientCache(); } async function createAnomalyDetectionJob(jobId: string, datafeedId?: string) { @@ -250,6 +262,7 @@ export function mlSavedObjectServiceFactory( const jobObject = job.attributes; jobObject.datafeed_id = datafeedId; await savedObjectsClient.update(ML_JOB_SAVED_OBJECT_TYPE, job.id, jobObject); + _clearSavedObjectsClientCache(); } async function deleteDatafeed(datafeedId: string) { @@ -262,6 +275,7 @@ export function mlSavedObjectServiceFactory( const jobObject = job.attributes; jobObject.datafeed_id = null; await savedObjectsClient.update(ML_JOB_SAVED_OBJECT_TYPE, job.id, jobObject); + _clearSavedObjectsClientCache(); } async function _getIds(jobType: JobType, idType: keyof JobObject) { @@ -372,6 +386,8 @@ export function mlSavedObjectServiceFactory( spacesToAdd, spacesToRemove ); + _clearSavedObjectsClientCache(); + updateResult.objects.forEach(({ id: objectId, error }) => { const jobId = jobObjectIdMap.get(objectId)!; if (error) { @@ -492,6 +508,7 @@ export function mlSavedObjectServiceFactory( await savedObjectsClient.delete(ML_TRAINED_MODEL_SAVED_OBJECT_TYPE, modelId, { force: true, }); + _clearSavedObjectsClientCache(); } } } catch (error) { @@ -518,6 +535,7 @@ export function mlSavedObjectServiceFactory( ...(initialNamespaces ? { initialNamespaces } : {}), } ); + _clearSavedObjectsClientCache(); } async function _bulkCreateTrainedModel(models: TrainedModelObject[], namespaceFallback?: string) { @@ -528,7 +546,7 @@ export function mlSavedObjectServiceFactory( return acc; }, {} as Record); - return await savedObjectsClient.bulkCreate( + const results = await savedObjectsClient.bulkCreate( models.map((m) => { let initialNamespaces = m.job && namespacesPerJob[m.job.job_id]; if (!initialNamespaces?.length && namespaceFallback) { @@ -546,6 +564,8 @@ export function mlSavedObjectServiceFactory( }; }) ); + _clearSavedObjectsClientCache(); + return results; } async function getAllTrainedModelObjectsForAllSpaces(modelIds?: string[]) { @@ -577,6 +597,7 @@ export function mlSavedObjectServiceFactory( } await savedObjectsClient.delete(ML_TRAINED_MODEL_SAVED_OBJECT_TYPE, model.id, { force: true }); + _clearSavedObjectsClientCache(); } async function _forceDeleteTrainedModel(modelId: string, namespace: string) { @@ -586,6 +607,7 @@ export function mlSavedObjectServiceFactory( namespace: namespace === '*' ? undefined : namespace, force: true, }); + _clearSavedObjectsClientCache(); } async function filterTrainedModelsForSpace(list: T[], field: keyof T): Promise { @@ -729,6 +751,8 @@ export function mlSavedObjectServiceFactory( spacesToAdd, spacesToRemove ); + _clearSavedObjectsClientCache(); + updateResult.objects.forEach(({ id: objectId, error }) => { const model = trainedModelObjectIdMap.get(objectId)!; if (error) { diff --git a/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js b/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js index 612b6e91546896..4df463d5ef3839 100644 --- a/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js +++ b/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js @@ -230,6 +230,14 @@ const getColumns = ( ); }, }, + { + name: i18n.translate('xpack.monitoring.cluster.listing.versionColumnTitle', { + defaultMessage: 'Version', + }), + field: 'version', + 'data-test-subj': 'clusterVersion', + sortable: true, + }, ]; }; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts index 50410f4ef0ea5e..356dbfaa29d419 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts @@ -6,7 +6,8 @@ */ import moment from 'moment'; -import { set, unset } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { unset } from 'lodash'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; import { handleResponse, getNodeInfo } from './get_node_info'; import { LegacyRequest } from '../../types'; diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts index c82d4fbe6faedc..60bb04b3c733d8 100644 --- a/x-pack/plugins/observability/common/index.ts +++ b/x-pack/plugins/observability/common/index.ts @@ -38,6 +38,8 @@ export { getProbabilityFromProgressiveLoadingQuality, } from './progressive_loading'; +export const sloFeatureId = 'slo'; + export const casesFeatureId = 'observabilityCases'; // The ID of the observability app. Should more appropriately be called diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc index f35b6392d0ad8a..ad5fac050d671e 100644 --- a/x-pack/plugins/observability/kibana.jsonc +++ b/x-pack/plugins/observability/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/observability-plugin", - "owner": "@elastic/observability-ui", + "owner": "@elastic/actionable-observability", "plugin": { "id": "observability", "server": true, diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/embeddable.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/embeddable.tsx index c602f4b0d14b09..be9a04e05e73bf 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/embeddable.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/embeddable.tsx @@ -32,6 +32,7 @@ import { AddToCaseAction } from '../header/add_to_case_action'; import { observabilityFeatureId } from '../../../../../common'; export interface ExploratoryEmbeddableProps { + id?: string; appId?: 'securitySolutionUI' | 'observability'; appendTitle?: JSX.Element; attributes?: AllSeries; @@ -46,6 +47,7 @@ export interface ExploratoryEmbeddableProps { legendPosition?: Position; hideTicks?: boolean; onBrushEnd?: (param: { range: number[] }) => void; + onLoad?: (loading: boolean) => void; caseOwner?: string; reportConfigMap?: ReportConfigMap; reportType: ReportViewType; @@ -58,6 +60,7 @@ export interface ExploratoryEmbeddableProps { fontSize?: number; lineHeight?: number; dataTestSubj?: string; + searchSessionId?: string; } export interface ExploratoryEmbeddableComponentProps extends ExploratoryEmbeddableProps { @@ -93,6 +96,8 @@ export default function Embeddable({ noLabel, fontSize = 27, lineHeight = 32, + searchSessionId, + onLoad, }: ExploratoryEmbeddableComponentProps) { const LensComponent = lens?.EmbeddableComponent; const LensSaveModalComponent = lens?.SaveModalComponent; @@ -188,6 +193,9 @@ export default function Embeddable({ return No lens component; } + attributesJSON.state.searchSessionId = searchSessionId; + attributesJSON.searchSessionId = searchSessionId; + return ( {isSaveOpen && attributesJSON && ( | null = null; + const lastRefreshed: Record = {}; + + const hasSameTimeRange = (props: ExploratoryEmbeddableProps) => { + const { attributes } = props; + if (!attributes || attributes?.length === 0) { + return false; + } + const series = attributes[0]; + const { time } = series; + const { from, to } = time; + return attributes.every((seriesT) => { + const { time: timeT } = seriesT; + return timeT.from === from && timeT.to === to; + }); + }; + return (props: ExploratoryEmbeddableProps) => { + if (!services.data.search.session.getSessionId()) { + services.data.search.session.start(); + } const { dataTypesIndexPatterns, attributes, customHeight } = props; if (!dataViewsService || !lens || !attributes || attributes?.length === 0) { @@ -56,6 +75,18 @@ export function getExploratoryViewEmbeddable( return lens.stateHelperApi(); }, []); + const [loadCount, setLoadCount] = useState(0); + + const onLensLoaded = useCallback( + (lensLoaded: boolean) => { + if (lensLoaded && props.id && hasSameTimeRange(props) && !lastRefreshed[props.id]) { + lastRefreshed[props.id] = series.time; + } + setLoadCount((prev) => prev + 1); + }, + [props, series.time] + ); + const { dataViews, loading } = useAppDataView({ dataViewCache, dataViewsService, @@ -63,6 +94,24 @@ export function getExploratoryViewEmbeddable( seriesDataType: series?.dataType, }); + const embedProps = useMemo(() => { + const newProps = { ...props }; + if (props.sparklineMode) { + newProps.axisTitlesVisibility = { x: false, yRight: false, yLeft: false }; + newProps.legendIsVisible = false; + newProps.hideTicks = true; + } + if (props.id && lastRefreshed[props.id] && loadCount < 2) { + newProps.attributes = props.attributes?.map((seriesT) => ({ + ...seriesT, + time: lastRefreshed[props.id!], + })); + } else if (props.id) { + lastRefreshed[props.id] = series.time; + } + return newProps; + }, [loadCount, props, series.time]); + if (Object.keys(dataViews).length === 0 || loading || !lensHelper || lensLoading) { return ( @@ -75,13 +124,6 @@ export function getExploratoryViewEmbeddable( return ; } - const embedProps = { ...props }; - if (props.sparklineMode) { - embedProps.axisTitlesVisibility = { x: false, yRight: false, yLeft: false }; - embedProps.legendIsVisible = false; - embedProps.hideTicks = true; - } - return ( @@ -92,6 +134,8 @@ export function getExploratoryViewEmbeddable( dataViewState={dataViews} lens={lens} lensFormulaHelper={lensHelper.formula} + searchSessionId={services.data.search.session.getSessionId()} + onLoad={onLensLoaded} /> diff --git a/x-pack/plugins/observability/public/config/alert_feature_ids.ts b/x-pack/plugins/observability/public/config/alert_feature_ids.ts index f0900c8aa408ed..4e9c1ee26d07c0 100644 --- a/x-pack/plugins/observability/public/config/alert_feature_ids.ts +++ b/x-pack/plugins/observability/public/config/alert_feature_ids.ts @@ -13,4 +13,5 @@ export const observabilityAlertFeatureIds: ValidFeatureId[] = [ AlertConsumers.INFRASTRUCTURE, AlertConsumers.LOGS, AlertConsumers.UPTIME, + AlertConsumers.SLO, ]; diff --git a/x-pack/plugins/observability/public/hooks/slo/use_capabilities.ts b/x-pack/plugins/observability/public/hooks/slo/use_capabilities.ts new file mode 100644 index 00000000000000..b2bc20d11fcbdf --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/slo/use_capabilities.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { sloFeatureId } from '../../../common'; +import { useKibana } from '../../utils/kibana_react'; + +export function useCapabilities() { + const { + application: { capabilities }, + } = useKibana().services; + + return { + hasReadCapabilities: !!capabilities[sloFeatureId].read ?? false, + hasWriteCapabilities: !!capabilities[sloFeatureId].write ?? false, + }; +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx index 03d5b5326e3a61..2cfa04e37755d4 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx @@ -19,6 +19,7 @@ import { import { i18n } from '@kbn/i18n'; import { HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { useCapabilities } from '../../../hooks/slo/use_capabilities'; import { useKibana } from '../../../utils/kibana_react'; import { useCreateOrUpdateSlo } from '../../../hooks/slo/use_create_slo'; import { SloSummary } from './slo_summary'; @@ -53,6 +54,7 @@ export function SloListItem({ application: { navigateToUrl }, http: { basePath }, } = useKibana().services; + const { hasWriteCapabilities } = useCapabilities(); const { createSlo, loading: isCloning, success: isCloned } = useCreateOrUpdateSlo(); @@ -158,6 +160,7 @@ export function SloListItem({ @@ -167,6 +170,7 @@ export function SloListItem({ , diff --git a/x-pack/plugins/observability/public/pages/slos/index.test.tsx b/x-pack/plugins/observability/public/pages/slos/index.test.tsx index 0f98521f409ea7..9ff4567d40b676 100644 --- a/x-pack/plugins/observability/public/pages/slos/index.test.tsx +++ b/x-pack/plugins/observability/public/pages/slos/index.test.tsx @@ -23,6 +23,7 @@ import { emptySloList, sloList } from '../../data/slo/slo'; import type { ConfigSchema } from '../../plugin'; import type { Subset } from '../../typings'; import { historicalSummaryData } from '../../data/slo/historical_summary_data'; +import { useCapabilities } from '../../hooks/slo/use_capabilities'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -36,6 +37,7 @@ jest.mock('../../hooks/slo/use_fetch_slo_list'); jest.mock('../../hooks/slo/use_create_slo'); jest.mock('../../hooks/slo/use_delete_slo'); jest.mock('../../hooks/slo/use_fetch_historical_summary'); +jest.mock('../../hooks/slo/use_capabilities'); const useKibanaMock = useKibana as jest.Mock; const useLicenseMock = useLicense as jest.Mock; @@ -43,6 +45,7 @@ const useFetchSloListMock = useFetchSloList as jest.Mock; const useCreateOrUpdateSloMock = useCreateOrUpdateSlo as jest.Mock; const useDeleteSloMock = useDeleteSlo as jest.Mock; const useFetchHistoricalSummaryMock = useFetchHistoricalSummary as jest.Mock; +const useCapabilitiesMock = useCapabilities as jest.Mock; const mockCreateSlo = jest.fn(); useCreateOrUpdateSloMock.mockReturnValue({ createSlo: mockCreateSlo }); @@ -84,6 +87,7 @@ describe('SLOs Page', () => { beforeEach(() => { jest.clearAllMocks(); mockKibana(); + useCapabilitiesMock.mockReturnValue({ hasWriteCapabilities: true, hasReadCapabilities: true }); }); describe('when the feature flag is not enabled', () => { diff --git a/x-pack/plugins/observability/public/pages/slos/index.tsx b/x-pack/plugins/observability/public/pages/slos/index.tsx index 3212e27b6655e9..273cb403b255b3 100644 --- a/x-pack/plugins/observability/public/pages/slos/index.tsx +++ b/x-pack/plugins/observability/public/pages/slos/index.tsx @@ -20,6 +20,7 @@ import PageNotFound from '../404'; import { paths } from '../../config'; import { isSloFeatureEnabled } from './helpers/is_slo_feature_enabled'; import type { ObservabilityAppServices } from '../../application/types'; +import { useCapabilities } from '../../hooks/slo/use_capabilities'; export function SlosPage() { const { @@ -27,7 +28,7 @@ export function SlosPage() { http: { basePath }, } = useKibana().services; const { ObservabilityPageTemplate, config } = usePluginContext(); - + const { hasWriteCapabilities } = useCapabilities(); const { hasAtLeast } = useLicense(); const { @@ -68,6 +69,7 @@ export function SlosPage() { }), rightSideItems: [ link.navLinkStatus === AppNavLinkStatus.visible) - .filter((link) => (link.id === 'slos' ? config.unsafe.slo.enabled : link)) + .filter((link) => (link.id === 'slos' ? config.unsafe.slo.enabled : link)) // might not be useful anymore .map((link) => ({ app: observabilityAppId, label: link.title, diff --git a/x-pack/plugins/observability/public/update_global_navigation.test.tsx b/x-pack/plugins/observability/public/update_global_navigation.test.tsx index 344afcb239ef21..fa833887609574 100644 --- a/x-pack/plugins/observability/public/update_global_navigation.test.tsx +++ b/x-pack/plugins/observability/public/update_global_navigation.test.tsx @@ -7,7 +7,7 @@ import { Subject } from 'rxjs'; import { App, AppDeepLink, ApplicationStart, AppNavLinkStatus, AppUpdater } from '@kbn/core/public'; -import { casesFeatureId } from '../common'; +import { casesFeatureId, sloFeatureId } from '../common'; import { updateGlobalNavigation } from './update_global_navigation'; // Used in updater callback @@ -163,11 +163,45 @@ describe('updateGlobalNavigation', () => { }); }); + it("hides the slo link when the capabilities don't include it", () => { + const capabilities = { + navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + } as unknown as ApplicationStart['capabilities']; + + const sloRoute = { + id: 'slos', + title: 'SLOs', + order: 8002, + path: '/slos', + navLinkStatus: AppNavLinkStatus.hidden, + }; + + const deepLinks = [sloRoute]; + + const callback = jest.fn(); + const updater$ = { + next: (cb: AppUpdater) => callback(cb(app)), + } as unknown as Subject; + + updateGlobalNavigation({ capabilities, deepLinks, updater$ }); + + expect(callback).toHaveBeenCalledWith({ + deepLinks: [ + { + ...sloRoute, + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + navLinkStatus: AppNavLinkStatus.visible, + }); + }); + describe('when slos are enabled', () => { it('shows the slos deep link', () => { const capabilities = { [casesFeatureId]: { read_cases: true }, - navLinks: { apm: true, logs: false, metrics: false, uptime: false }, + [sloFeatureId]: { read: true }, + navLinks: { apm: false, logs: false, metrics: false, uptime: false }, } as unknown as ApplicationStart['capabilities']; const sloRoute = { diff --git a/x-pack/plugins/observability/public/update_global_navigation.tsx b/x-pack/plugins/observability/public/update_global_navigation.tsx index 5a1bc87bbc7539..26e3f191ac5694 100644 --- a/x-pack/plugins/observability/public/update_global_navigation.tsx +++ b/x-pack/plugins/observability/public/update_global_navigation.tsx @@ -8,7 +8,7 @@ import { Subject } from 'rxjs'; import { AppNavLinkStatus, AppUpdater, ApplicationStart, AppDeepLink } from '@kbn/core/public'; import { CasesDeepLinkId } from '@kbn/cases-plugin/public'; -import { casesFeatureId } from '../common'; +import { casesFeatureId, sloFeatureId } from '../common'; export function updateGlobalNavigation({ capabilities, @@ -20,7 +20,12 @@ export function updateGlobalNavigation({ updater$: Subject; }) { const { apm, logs, metrics, uptime } = capabilities.navLinks; - const someVisible = Object.values({ apm, logs, metrics, uptime }).some((visible) => visible); + const someVisible = Object.values({ + apm, + logs, + metrics, + uptime, + }).some((visible) => visible); const updatedDeepLinks = deepLinks.map((link) => { switch (link.id) { @@ -37,15 +42,17 @@ export function updateGlobalNavigation({ ...link, navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, }; - case 'slos': + case 'rules': return { ...link, navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, }; - case 'rules': + case 'slos': return { ...link, - navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus: !!capabilities[sloFeatureId]?.read + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, }; default: return link; @@ -54,6 +61,9 @@ export function updateGlobalNavigation({ updater$.next(() => ({ deepLinks: updatedDeepLinks, - navLinkStatus: someVisible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus: + someVisible || !!capabilities[sloFeatureId]?.read + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, })); } diff --git a/x-pack/plugins/observability/server/common/constants.ts b/x-pack/plugins/observability/server/common/constants.ts index 9ee876d1948a4c..deaf49e3a42f1c 100644 --- a/x-pack/plugins/observability/server/common/constants.ts +++ b/x-pack/plugins/observability/server/common/constants.ts @@ -5,5 +5,4 @@ * 2.0. */ -export const OBSERVABILITY_FEATURE_ID = 'observability'; -export const RULE_REGISTRATION_CONTEXT = 'observability.slo'; +export const SLO_RULE_REGISTRATION_CONTEXT = 'observability.slo'; diff --git a/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/register.ts b/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/register.ts index b85f70413e3cbb..6a2351435e9aaf 100644 --- a/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/register.ts +++ b/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/register.ts @@ -37,7 +37,7 @@ export function sloBurnRateRuleType(createLifecycleRuleExecutor: CreateLifecycle }, defaultActionGroupId: FIRED_ACTION.id, actionGroups: [FIRED_ACTION], - producer: 'observability', + producer: 'slo', minimumLicenseRequired: 'basic' as LicenseType, isExportable: true, executor: createLifecycleRuleExecutor(getRuleExecutor()), diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts index 0b8d3083126a41..dda71f7a4a60dd 100644 --- a/x-pack/plugins/observability/server/plugin.ts +++ b/x-pack/plugins/observability/server/plugin.ts @@ -37,10 +37,11 @@ import { import { uiSettings } from './ui_settings'; import { registerRoutes } from './routes/register_routes'; import { getGlobalObservabilityServerRouteRepository } from './routes/get_global_observability_server_route_repository'; -import { casesFeatureId, observabilityFeatureId } from '../common'; -import { slo } from './saved_objects'; -import { OBSERVABILITY_FEATURE_ID, RULE_REGISTRATION_CONTEXT } from './common/constants'; +import { casesFeatureId, observabilityFeatureId, sloFeatureId } from '../common'; +import { slo, SO_SLO_TYPE } from './saved_objects'; +import { SLO_RULE_REGISTRATION_CONTEXT } from './common/constants'; import { registerRuleTypes } from './lib/rules/register_rule_types'; +import { SLO_BURN_RATE_RULE_ID } from '../common/constants'; import { registerSloUsageCollector } from './lib/collectors/register'; export type ObservabilityPluginSetup = ReturnType; @@ -161,11 +162,61 @@ export class ObservabilityPlugin implements Plugin { const { ruleDataService } = plugins.ruleRegistry; if (config.unsafe.slo.enabled) { + plugins.features.registerKibanaFeature({ + id: sloFeatureId, + name: i18n.translate('xpack.observability.featureRegistry.linkSloTitle', { + defaultMessage: 'SLOs', + }), + order: 1200, + category: DEFAULT_APP_CATEGORIES.observability, + app: [sloFeatureId, 'kibana'], + catalogue: [sloFeatureId, 'observability'], + alerting: [SLO_BURN_RATE_RULE_ID], + privileges: { + all: { + app: [sloFeatureId, 'kibana'], + catalogue: [sloFeatureId, 'observability'], + api: ['slo_write', 'slo_read', 'rac'], + savedObject: { + all: [SO_SLO_TYPE], + read: [], + }, + alerting: { + rule: { + all: [SLO_BURN_RATE_RULE_ID], + }, + alert: { + all: [SLO_BURN_RATE_RULE_ID], + }, + }, + ui: ['read', 'write'], + }, + read: { + app: [sloFeatureId, 'kibana'], + catalogue: [sloFeatureId, 'observability'], + api: ['slo_read', 'rac'], + savedObject: { + all: [], + read: [SO_SLO_TYPE], + }, + alerting: { + rule: { + read: [SLO_BURN_RATE_RULE_ID], + }, + alert: { + read: [SLO_BURN_RATE_RULE_ID], + }, + }, + ui: ['read'], + }, + }, + }); + core.savedObjects.registerType(slo); const ruleDataClient = ruleDataService.initializeIndex({ - feature: OBSERVABILITY_FEATURE_ID, - registrationContext: RULE_REGISTRATION_CONTEXT, + feature: sloFeatureId, + registrationContext: SLO_RULE_REGISTRATION_CONTEXT, dataset: Dataset.alerts, componentTemplateRefs: [ECS_COMPONENT_TEMPLATE_NAME], componentTemplates: [ diff --git a/x-pack/plugins/observability/server/routes/slo/route.ts b/x-pack/plugins/observability/server/routes/slo/route.ts index dc3a51250f6a78..8e876b81015229 100644 --- a/x-pack/plugins/observability/server/routes/slo/route.ts +++ b/x-pack/plugins/observability/server/routes/slo/route.ts @@ -52,7 +52,7 @@ const isLicenseAtLeastPlatinum = async (context: ObservabilityRequestHandlerCont const createSLORoute = createObservabilityServerRoute({ endpoint: 'POST /api/observability/slos', options: { - tags: [], + tags: ['access:slo_write'], }, params: createSLOParamsSchema, handler: async ({ context, params, logger }) => { @@ -77,7 +77,7 @@ const createSLORoute = createObservabilityServerRoute({ const updateSLORoute = createObservabilityServerRoute({ endpoint: 'PUT /api/observability/slos/{id}', options: { - tags: [], + tags: ['access:slo_write'], }, params: updateSLOParamsSchema, handler: async ({ context, params, logger }) => { @@ -101,7 +101,7 @@ const updateSLORoute = createObservabilityServerRoute({ const deleteSLORoute = createObservabilityServerRoute({ endpoint: 'DELETE /api/observability/slos/{id}', options: { - tags: [], + tags: ['access:slo_write'], }, params: deleteSLOParamsSchema, handler: async ({ context, params, logger }) => { @@ -124,7 +124,7 @@ const deleteSLORoute = createObservabilityServerRoute({ const getSLORoute = createObservabilityServerRoute({ endpoint: 'GET /api/observability/slos/{id}', options: { - tags: [], + tags: ['access:slo_read'], }, params: getSLOParamsSchema, handler: async ({ context, params }) => { @@ -147,7 +147,7 @@ const getSLORoute = createObservabilityServerRoute({ const enableSLORoute = createObservabilityServerRoute({ endpoint: 'POST /api/observability/slos/{id}/enable', options: { - tags: [], + tags: ['access:slo_write'], }, params: manageSLOParamsSchema, handler: async ({ context, params, logger }) => { @@ -171,7 +171,7 @@ const enableSLORoute = createObservabilityServerRoute({ const disableSLORoute = createObservabilityServerRoute({ endpoint: 'POST /api/observability/slos/{id}/disable', options: { - tags: [], + tags: ['access:slo_write'], }, params: manageSLOParamsSchema, handler: async ({ context, params, logger }) => { @@ -195,7 +195,7 @@ const disableSLORoute = createObservabilityServerRoute({ const findSLORoute = createObservabilityServerRoute({ endpoint: 'GET /api/observability/slos', options: { - tags: [], + tags: ['access:slo_read'], }, params: findSLOParamsSchema, handler: async ({ context, params }) => { @@ -218,7 +218,7 @@ const findSLORoute = createObservabilityServerRoute({ const fetchHistoricalSummary = createObservabilityServerRoute({ endpoint: 'POST /internal/observability/slos/_historical_summary', options: { - tags: [], + tags: ['access:slo_read'], }, params: fetchHistoricalSummaryParamsSchema, handler: async ({ context, params }) => { diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts.cy.ts index e772217819e7d3..fbb8722e54df88 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts.cy.ts @@ -69,7 +69,7 @@ describe('Alert Event Details', () => { it('adds response actions with osquery with proper validation and form values', () => { cy.visit('/app/security/rules'); cy.contains(RULE_NAME).click(); - cy.contains('Edit rule settings').click(); + cy.contains('Edit rule settings').click({ force: true }); cy.getBySel('edit-rule-actions-tab').wait(500).click(); cy.contains('Response actions are run on each rule execution'); cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); @@ -114,7 +114,7 @@ describe('Alert Event Details', () => { cy.contains('Save changes').click(); cy.contains(`${RULE_NAME} was saved`).should('exist'); cy.getBySel('toastCloseButton').click(); - cy.contains('Edit rule settings').click(); + cy.contains('Edit rule settings').click({ force: true }); cy.getBySel('edit-rule-actions-tab').wait(500).click(); cy.contains('select * from uptime'); cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { @@ -158,7 +158,7 @@ describe('Alert Event Details', () => { cy.contains(`${RULE_NAME} was saved`).should('exist'); cy.getBySel('toastCloseButton').click(); - cy.contains('Edit rule settings').click(); + cy.contains('Edit rule settings').click({ force: true }); cy.getBySel('edit-rule-actions-tab').wait(500).click(); cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { cy.contains('testpack'); @@ -198,7 +198,7 @@ describe('Alert Event Details', () => { 'You have queries in the investigation guide. Add them as response actions?'; cy.visit('/app/security/rules'); cy.contains(RULE_NAME).click(); - cy.contains('Edit rule settings').click(); + cy.contains('Edit rule settings').click({ force: true }); cy.getBySel('edit-rule-actions-tab').wait(500).click(); cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { diff --git a/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx b/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx index cf736d4fe2f577..34090e8e966d26 100644 --- a/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx +++ b/x-pack/plugins/osquery/public/fleet_integration/osquery_managed_policy_create_import_extension.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import { pickBy, get, isEmpty, isString, unset, set, intersection } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { pickBy, get, isEmpty, isString, unset, intersection } from 'lodash'; import satisfies from 'semver/functions/satisfies'; import { EuiFlexGroup, diff --git a/x-pack/plugins/osquery/public/live_queries/form/index.tsx b/x-pack/plugins/osquery/public/live_queries/form/index.tsx index 2449195300910f..7868c1bb3a4716 100644 --- a/x-pack/plugins/osquery/public/live_queries/form/index.tsx +++ b/x-pack/plugins/osquery/public/live_queries/form/index.tsx @@ -8,10 +8,14 @@ import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { ECSMapping } from '@kbn/osquery-io-ts-types'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useForm as useHookForm, FormProvider } from 'react-hook-form'; import { isEmpty, find, pickBy } from 'lodash'; +import { + containsDynamicQuery, + replaceParamsQuery, +} from '../../../common/utils/replace_params_query'; import { PLUGIN_NAME as OSQUERY_PLUGIN_NAME } from '../../../common'; import { QueryPackSelectable } from './query_pack_selectable'; import type { SavedQuerySOFormData } from '../../saved_queries/form/use_saved_query_form'; @@ -26,6 +30,7 @@ import { LiveQueryQueryField } from './live_query_query_field'; import { AgentsTableField } from './agents_table_field'; import { savedQueryDataSerializer } from '../../saved_queries/form/use_saved_query_form'; import { PackFieldWrapper } from '../../shared_components/osquery_response_action_type/pack_field_wrapper'; +import { AlertAttachmentContext } from '../../common/contexts'; export interface LiveQueryFormFields { alertIds?: string[]; @@ -66,6 +71,8 @@ const LiveQueryFormComponent: React.FC = ({ enabled = true, hideAgentsField = false, }) => { + const alertAttachmentContext = useContext(AlertAttachmentContext); + const { application, appName } = useKibana().services; const permissions = application.capabilities.osquery; const canRunPacks = useMemo( @@ -138,11 +145,17 @@ const LiveQueryFormComponent: React.FC = ({ const onSubmit = useCallback( async (values: LiveQueryFormFields) => { + // Temporary, frontend solution for params substitution. To be removed once alert_ids refactored in create_live_query_route + const query = + values.query && containsDynamicQuery(values.query) && alertAttachmentContext + ? replaceParamsQuery(values.query, alertAttachmentContext).result + : values.query; + const serializedData = pickBy( { agentSelection: values.agentSelection, saved_query_id: values.savedQueryId, - query: values.query, + query, alert_ids: values.alertIds, pack_id: values?.packId?.length ? values?.packId[0] : undefined, ecs_mapping: values.ecs_mapping, @@ -152,7 +165,7 @@ const LiveQueryFormComponent: React.FC = ({ await mutateAsync(serializedData); }, - [mutateAsync] + [alertAttachmentContext, mutateAsync] ); const serializedData: SavedQuerySOFormData = useMemo( diff --git a/x-pack/plugins/osquery/server/lib/update_global_packs.ts b/x-pack/plugins/osquery/server/lib/update_global_packs.ts index 523e79443fbdb0..1f806c06f79779 100644 --- a/x-pack/plugins/osquery/server/lib/update_global_packs.ts +++ b/x-pack/plugins/osquery/server/lib/update_global_packs.ts @@ -6,7 +6,8 @@ */ import type { SavedObjectsClient, SavedObjectsFindResponse } from '@kbn/core/server'; -import { has, map, mapKeys, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { has, map, mapKeys } from 'lodash'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common'; import produce from 'immer'; diff --git a/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts b/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts index 91f3594c5b72a5..92ebddf7642e7d 100644 --- a/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts +++ b/x-pack/plugins/osquery/server/routes/live_query/create_live_query_route.ts @@ -7,7 +7,7 @@ import type { IRouter } from '@kbn/core/server'; import unified from 'unified'; -import markdown from 'remark-parse'; +import markdown from 'remark-parse-no-trim'; import { some, filter } from 'lodash'; import deepEqual from 'fast-deep-equal'; import type { ECSMappingOrUndefined } from '@kbn/osquery-io-ts-types'; diff --git a/x-pack/plugins/osquery/server/routes/pack/create_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/create_pack_route.ts index 37d61b908f150c..ff4ffe5b28287d 100644 --- a/x-pack/plugins/osquery/server/routes/pack/create_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/create_pack_route.ts @@ -6,7 +6,8 @@ */ import moment from 'moment-timezone'; -import { has, set, unset, find, some, mapKeys } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { has, unset, find, some, mapKeys } from 'lodash'; import { schema } from '@kbn/config-schema'; import { produce } from 'immer'; import type { PackagePolicy } from '@kbn/fleet-plugin/common'; diff --git a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts index c8d053d8d92dab..485ecffce3cd32 100644 --- a/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts +++ b/x-pack/plugins/osquery/server/routes/pack/update_pack_route.ts @@ -6,19 +6,8 @@ */ import moment from 'moment-timezone'; -import { - set, - unset, - has, - difference, - filter, - find, - map, - mapKeys, - uniq, - some, - isEmpty, -} from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { unset, has, difference, filter, find, map, mapKeys, uniq, some, isEmpty } from 'lodash'; import { schema } from '@kbn/config-schema'; import { produce } from 'immer'; import type { PackagePolicy } from '@kbn/fleet-plugin/common'; diff --git a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts index 700ea77f224454..785b9540e173ff 100644 --- a/x-pack/plugins/osquery/server/routes/status/create_status_route.ts +++ b/x-pack/plugins/osquery/server/routes/status/create_status_route.ts @@ -7,7 +7,8 @@ import { produce } from 'immer'; import { satisfies } from 'semver'; -import { filter, reduce, mapKeys, each, set, unset, uniq, map, has } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { filter, reduce, mapKeys, each, unset, uniq, map, has } from 'lodash'; import type { PackagePolicyInputStream } from '@kbn/fleet-plugin/common'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/osquery/tsconfig.json b/x-pack/plugins/osquery/tsconfig.json index 678f4900134cfc..226519bb10711d 100644 --- a/x-pack/plugins/osquery/tsconfig.json +++ b/x-pack/plugins/osquery/tsconfig.json @@ -68,6 +68,7 @@ "@kbn/core-elasticsearch-server", "@kbn/core-saved-objects-api-server", "@kbn/logging", + "@kbn/safer-lodash-set", "@kbn/shared-ux-router", ] } diff --git a/x-pack/plugins/profiling/public/components/flame_graphs_view/normalization_menu.tsx b/x-pack/plugins/profiling/public/components/flame_graphs_view/normalization_menu.tsx index 72bc72aa64e78e..9a6eaba2af677b 100644 --- a/x-pack/plugins/profiling/public/components/flame_graphs_view/normalization_menu.tsx +++ b/x-pack/plugins/profiling/public/components/flame_graphs_view/normalization_menu.tsx @@ -148,13 +148,32 @@ export function NormalizationMenu(props: Props) { + + + {i18n.translate( + 'xpack.profiling.flameGraphNormalizationMenu.normalizeByTimeTooltip', + { + defaultMessage: + 'Select Normalize by Scale factor and set your Baseline and Comparison scale factors to compare a set of machines of different sizes. For example, you can compare a deployment of 10% of machines to a deployment of 90% of machines.', + } + )} + + + + + {i18n.translate( + 'xpack.profiling.flameGraphNormalizationMenu.normalizeByScaleTooltip', + { + defaultMessage: + 'Select Normalize by Time to compare a set of machines across different time periods. For example, if you compare the last hour to the last 24 hours, the shorter timeframe (1 hour) is multiplied to match the longer timeframe (24 hours).', + } + )} + + + + } position="right" /> diff --git a/x-pack/plugins/profiling/public/components/flamegraph.tsx b/x-pack/plugins/profiling/public/components/flamegraph.tsx index a1654c9bfbbd58..f3ddc01e688172 100644 --- a/x-pack/plugins/profiling/public/components/flamegraph.tsx +++ b/x-pack/plugins/profiling/public/components/flamegraph.tsx @@ -5,7 +5,15 @@ * 2.0. */ -import { Chart, Datum, Flame, FlameLayerValue, PartialTheme, Settings } from '@elastic/charts'; +import { + Chart, + Datum, + Flame, + FlameLayerValue, + PartialTheme, + Settings, + TooltipContainer, +} from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, @@ -112,60 +120,62 @@ function FlameGraphTooltip({ comparisonTotalSamples?: number; }) { return ( - - - {label} - - - {isRoot === false && ( - <> - - - - )} - - - - - + + + + {label} + + + {isRoot === false && ( + <> + + + + )} + + + + + + ); } diff --git a/x-pack/plugins/profiling/public/components/stacked_bar_chart.tsx b/x-pack/plugins/profiling/public/components/stacked_bar_chart.tsx index b6b7e8d8940cda..ac74141f19040a 100644 --- a/x-pack/plugins/profiling/public/components/stacked_bar_chart.tsx +++ b/x-pack/plugins/profiling/public/components/stacked_bar_chart.tsx @@ -17,6 +17,8 @@ import { Tooltip, TooltipInfo, XYChartElementEvent, + CustomTooltip, + TooltipContainer, } from '@elastic/charts'; import { EuiPanel } from '@elastic/eui'; import React from 'react'; @@ -87,14 +89,16 @@ export const StackedBarChart: React.FC = ({ const { chartsBaseTheme, chartsTheme } = useProfilingChartsTheme(); - const customTooltip = highlightedSubchart - ? (props: TooltipInfo) => ( - + const customTooltip: CustomTooltip = highlightedSubchart + ? (props) => ( + + + ) : () => <>; diff --git a/x-pack/plugins/reporting/server/lib/content_stream.test.ts b/x-pack/plugins/reporting/server/lib/content_stream.test.ts index aa0d5c85acedf7..288d528c722bfc 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.test.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.test.ts @@ -6,7 +6,7 @@ */ import type { Logger } from '@kbn/core/server'; -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { ContentStream } from './content_stream'; diff --git a/x-pack/plugins/reporting/server/routes/lib/jobs_query.test.ts b/x-pack/plugins/reporting/server/routes/lib/jobs_query.test.ts index 0f72863ee03dd5..202fa55049b3df 100644 --- a/x-pack/plugins/reporting/server/routes/lib/jobs_query.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/jobs_query.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import { ElasticsearchClient } from '@kbn/core/server'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { statuses } from '../../lib'; diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json index 48b2f20a3c1e00..254c115322fd0d 100644 --- a/x-pack/plugins/reporting/tsconfig.json +++ b/x-pack/plugins/reporting/tsconfig.json @@ -36,6 +36,7 @@ "@kbn/core-http-server", "@kbn/core-test-helpers-test-utils", "@kbn/expressions-plugin", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/screenshotting/server/config/create_config.ts b/x-pack/plugins/screenshotting/server/config/create_config.ts index 1b7076d05e4782..c2ab86b5de76ef 100644 --- a/x-pack/plugins/screenshotting/server/config/create_config.ts +++ b/x-pack/plugins/screenshotting/server/config/create_config.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { cloneDeep, set, upperFirst } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep, upperFirst } from 'lodash'; import type { Logger } from '@kbn/core/server'; import { getDefaultChromiumSandboxDisabled } from './default_chromium_sandbox_disabled'; import { ConfigType } from './schema'; diff --git a/x-pack/plugins/screenshotting/tsconfig.json b/x-pack/plugins/screenshotting/tsconfig.json index 71bbdc7de73967..b2e1fd6ed184fe 100644 --- a/x-pack/plugins/screenshotting/tsconfig.json +++ b/x-pack/plugins/screenshotting/tsconfig.json @@ -21,6 +21,7 @@ "@kbn/std", "@kbn/i18n", "@kbn/utils", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security/public/components/use_form.ts b/x-pack/plugins/security/public/components/use_form.ts index 2b42fda5ba5617..b943cfd507249f 100644 --- a/x-pack/plugins/security/public/components/use_form.ts +++ b/x-pack/plugins/security/public/components/use_form.ts @@ -5,11 +5,13 @@ * 2.0. */ -import { cloneDeep, cloneDeepWith, get, set } from 'lodash'; +import { cloneDeep, cloneDeepWith, get } from 'lodash'; import type { ChangeEventHandler, FocusEventHandler, ReactEventHandler } from 'react'; import { useState } from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; +import { set } from '@kbn/safer-lodash-set'; + export type FormReturnTuple = [FormState, FormProps]; export interface FormProps { diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index 6106c3e34792b2..7278e39b182491 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -56,6 +56,7 @@ "@kbn/core-custom-branding-common", "@kbn/core-custom-branding-server-mocks", "@kbn/ecs", + "@kbn/safer-lodash-set", "@kbn/shared-ux-router", ], "exclude": [ diff --git a/x-pack/plugins/security_solution/public/common/components/data_table/column_headers/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/data_table/column_headers/helpers.test.tsx index 9320a0270f5aaf..34f3320513b478 100644 --- a/x-pack/plugins/security_solution/public/common/components/data_table/column_headers/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/data_table/column_headers/helpers.test.tsx @@ -5,7 +5,8 @@ * 2.0. */ import { mount } from 'enzyme'; -import { omit, set } from 'lodash/fp'; +import { set } from '@kbn/safer-lodash-set/fp'; +import { omit } from 'lodash/fp'; import React from 'react'; import type { BUILT_IN_SCHEMA } from './helpers'; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts b/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts index 5f3ca6feb6cf12..8e35d3a7881b15 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts @@ -29,7 +29,7 @@ import { getDisplayValue } from '../../../../timelines/components/timeline/data_ import { PORT_NAMES } from '../../../../explore/network/components/port/helpers'; import { INDICATOR_REFERENCE } from '../../../../../common/cti/constants'; import type { BrowserField } from '../../../containers/source'; -import type { DataProvider, QueryOperator } from '../../../../../common/types'; +import type { DataProvider, DataProvidersAnd, QueryOperator } from '../../../../../common/types'; import { IS_OPERATOR } from '../../../../../common/types'; export interface UseActionCellDataProvider { @@ -69,6 +69,16 @@ export const getDataProvider = ( }, }); +export const getDataProviderAnd = ( + field: string, + id: string, + value: string | string[], + operator: QueryOperator = IS_OPERATOR +): DataProvidersAnd => { + const { and, ...dataProvider } = getDataProvider(field, id, value, operator); + return dataProvider; +}; + export const useActionCellDataProvider = ({ contextId, eventId, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts index da0761d5160c7c..4c8ee37e3e211f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts @@ -35,6 +35,9 @@ export const useFetchRuleByIdQuery = (id: string, options?: UseQueryOptions = ({ field, messageVariables }) = triggersActionsUi: { getActionForm }, } = useKibana().services; + // Workaround for setAlertActionsProperty being fired with prevProps when followed by setActionIdByIndex + // For details see: https://github.com/elastic/kibana/issues/142217 + const [isInitializingAction, setIsInitializingAction] = useState(false); + const actions: RuleAction[] = useMemo( () => (!isEmpty(field.value) ? (field.value as RuleAction[]) : []), [field.value] @@ -83,6 +87,9 @@ export const RuleActionsField: React.FC = ({ field, messageVariables }) = const setActionIdByIndex = useCallback( (id: string, index: number) => { const updatedActions = [...(actions as Array>)]; + if (isEmpty(updatedActions[index].params)) { + setIsInitializingAction(true); + } updatedActions[index] = deepMerge(updatedActions[index], { id }); field.setValue(updatedActions); }, @@ -98,24 +105,30 @@ export const RuleActionsField: React.FC = ({ field, messageVariables }) = (key: string, value: RuleActionParam, index: number) => { // validation is not triggered correctly when actions params updated (more details in https://github.com/elastic/kibana/issues/142217) // wrapping field.setValue in setTimeout fixes the issue above - // and triggers validation after params have been updated - setTimeout( - () => - field.setValue((prevValue: RuleAction[]) => { - const updatedActions = [...prevValue]; - updatedActions[index] = { - ...updatedActions[index], - params: { - ...updatedActions[index].params, - [key]: value, - }, - }; - return updatedActions; - }), - 0 - ); + // and triggers validation after params have been updated, however it introduced a new issue where any additional input + // would result in the cursor jumping to the end of the text area (https://github.com/elastic/kibana/issues/149885) + const updateValue = () => { + field.setValue((prevValue: RuleAction[]) => { + const updatedActions = [...prevValue]; + updatedActions[index] = { + ...updatedActions[index], + params: { + ...updatedActions[index].params, + [key]: value, + }, + }; + return updatedActions; + }); + }; + + if (isInitializingAction) { + setTimeout(updateValue, 0); + setIsInitializingAction(false); + } else { + updateValue(); + } }, - [field] + [field, isInitializingAction] ); const actionForm = useMemo( diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx index ac5e6c559d0d96..4d9c23240a9b2f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx @@ -17,9 +17,10 @@ import { EuiResizeObserver, } from '@elastic/eui'; import { isEmpty } from 'lodash'; +import type { PropsWithChildren } from 'react'; import React, { memo, useCallback, useMemo, useState } from 'react'; -import styled from 'styled-components'; +import { css } from '@emotion/react'; import { HeaderSection } from '../../../../common/components/header_section'; import { MarkdownRenderer } from '../../../../common/components/markdown_editor'; import type { @@ -28,28 +29,7 @@ import type { } from '../../../pages/detection_engine/rules/types'; import * as i18n from './translations'; import { StepAboutRule } from '../step_about_rule'; - -const MyPanel = styled(EuiPanel)` - position: relative; -`; - -const FlexGroupFullHeight = styled(EuiFlexGroup)` - height: 100%; -`; - -const VerticalOverflowContainer = styled.div((props: { maxHeight: number }) => ({ - 'max-height': `${props.maxHeight}px`, - 'overflow-y': 'hidden', - 'word-break': 'break-word', -})); - -const VerticalOverflowContent = styled.div((props: { maxHeight: number }) => ({ - 'max-height': `${props.maxHeight}px`, -})); - -const AboutContent = styled.div` - height: 100%; -`; +import { fullHeight } from './styles'; const detailsOption: EuiButtonGroupOptionProps = { id: 'details', @@ -99,7 +79,12 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ }, [stepDataDetails]); return ( - + {loading && ( <> @@ -107,7 +92,7 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ )} {stepData != null && stepDataDetails != null && ( - + {toggleOptions.length > 0 && ( @@ -127,9 +112,9 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ {selectedToggleOption === 'details' && ( {(resizeRef) => ( - +
- + = ({ isLoading={false} defaultValues={stepData} /> - +
)}
)} @@ -154,10 +139,7 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ data-test-subj="stepAboutDetailsNoteContent" maxHeight={aboutPanelHeight} > - + {stepDataDetails.note} @@ -167,19 +149,61 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ data-test-subj="stepAboutDetailsSetupContent" maxHeight={aboutPanelHeight} > - + {stepDataDetails.setup} )}
-
+ )} -
+ ); }; export const StepAboutRuleToggleDetails = memo(StepAboutRuleToggleDetailsComponent); + +interface VerticalOverflowContainerProps { + maxHeight: number; + 'data-test-subj'?: string; +} + +function VerticalOverflowContainer({ + maxHeight, + 'data-test-subj': dataTestSubject, + children, +}: PropsWithChildren): JSX.Element { + return ( +
+ {children} +
+ ); +} + +interface VerticalOverflowContentProps { + maxHeight: number; +} + +function VerticalOverflowContent({ + maxHeight, + + children, +}: PropsWithChildren): JSX.Element { + return ( +
+ {children} +
+ ); +} diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.ts b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/styles.ts similarity index 59% rename from x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.ts rename to x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/styles.ts index 3cc90ebfdca957..598e146b9b245c 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu_cores.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/styles.ts @@ -5,12 +5,8 @@ * 2.0. */ -import { MetricsUIAggregation } from '../../../types'; +import { css } from '@emotion/react'; -export const cpuCores: MetricsUIAggregation = { - cpuCores: { - max: { - field: 'system.cpu.cores', - }, - }, -}; +export const fullHeight = css` + height: 100%; +`; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts index e5eec8392b0e16..4bc6896c104671 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/get_schema.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import type { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; -import { validateRuleActionsField } from '../../../containers/detection_engine/rules/validate_rule_actions_field'; +import { debouncedValidateRuleActionsField } from '../../../containers/detection_engine/rules/validate_rule_actions_field'; import type { FormSchema } from '../../../../shared_imports'; import type { ActionsStepRule } from '../../../pages/detection_engine/rules/types'; @@ -21,7 +21,9 @@ export const getSchema = ({ actions: { validations: [ { - validator: validateRuleActionsField(actionTypeRegistry), + // Debounced validator is necessary here to prevent error validation + // flashing when first adding an action. Also prevents additional renders + validator: debouncedValidateRuleActionsField(actionTypeRegistry), }, ], }, diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx index 22d05080a408b9..141d3f96ab987b 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/index.tsx @@ -6,3 +6,4 @@ */ export { validateRuleActionsField } from './validate_rule_actions_field'; +export { debouncedValidateRuleActionsField } from './validate_rule_actions_field'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts index 18aa758d0a4995..8d04ed43e05387 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/validate_rule_actions_field/validate_rule_actions_field.ts @@ -7,13 +7,22 @@ /* istanbul ignore file */ +import type { + ValidationCancelablePromise, + ValidationFuncArg, + ValidationResponsePromise, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { RuleAction, ActionTypeRegistryContract, } from '@kbn/triggers-actions-ui-plugin/public'; -import type { ValidationFunc, ERROR_CODE, ValidationError } from '../../../../../shared_imports'; +import type { RuleActionsFormData } from '../../../../../detection_engine/rule_management_ui/components/rules_table/bulk_actions/forms/rule_actions_form'; +import type { ActionsStepRule } from '../../../../pages/detection_engine/rules/types'; +import type { ValidationFunc, ERROR_CODE } from '../../../../../shared_imports'; import { getActionTypeName, validateMustache, validateActionParams } from './utils'; +export const DEFAULT_VALIDATION_TIMEOUT = 100; + export const validateSingleAction = async ( actionItem: RuleAction, actionTypeRegistry: ActionTypeRegistryContract @@ -26,9 +35,7 @@ export const validateSingleAction = async ( export const validateRuleActionsField = (actionTypeRegistry: ActionTypeRegistryContract) => - async ( - ...data: Parameters - ): Promise | void | undefined> => { + async (...data: Parameters): ValidationResponsePromise => { const [{ value, path }] = data as [{ value: RuleAction[]; path: string }]; const errors = []; @@ -51,3 +58,40 @@ export const validateRuleActionsField = }; } }; + +/** + * Debounces validation by canceling previous validation requests. Essentially leveraging the async validation + * cancellation behavior from the hook_form_lib. Necessary to prevent error validation flashing when first adding an + * action until root cause of https://github.com/elastic/kibana/issues/142217 is found + * + * See docs for details: + * https://docs.elastic.dev/form-lib/examples/validation#cancel-asynchronous-validation + * + * Note: _.throttle/debounce does not have async support, and so not used https://github.com/lodash/lodash/issues/4815. + * + * @param actionTypeRegistry + * @param defaultValidationTimeout + */ +export const debouncedValidateRuleActionsField = + ( + actionTypeRegistry: ActionTypeRegistryContract, + defaultValidationTimeout = DEFAULT_VALIDATION_TIMEOUT + ) => + (data: ValidationFuncArg): ValidationResponsePromise => { + let isCanceled = false; + const promise: ValidationCancelablePromise = new Promise((resolve) => { + setTimeout(() => { + if (isCanceled) { + resolve(); + } else { + resolve(validateRuleActionsField(actionTypeRegistry)(data)); + } + }, defaultValidationTimeout); + }); + + promise.cancel = () => { + isCanceled = true; + }; + + return promise; + }; diff --git a/x-pack/plugins/security_solution/public/explore/network/store/reducer.ts b/x-pack/plugins/security_solution/public/explore/network/store/reducer.ts index b55774ef90197a..263f0b990280d0 100644 --- a/x-pack/plugins/security_solution/public/explore/network/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/explore/network/store/reducer.ts @@ -6,7 +6,8 @@ */ import { reducerWithInitialState } from 'typescript-fsa-reducers'; -import { get, set } from 'lodash/fp'; +import { set } from '@kbn/safer-lodash-set/fp'; +import { get } from 'lodash/fp'; import { Direction, FlowTarget, diff --git a/x-pack/plugins/security_solution/public/explore/users/store/reducer.ts b/x-pack/plugins/security_solution/public/explore/users/store/reducer.ts index 5bb7615ff198a8..9ac2fdce4c20db 100644 --- a/x-pack/plugins/security_solution/public/explore/users/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/explore/users/store/reducer.ts @@ -6,7 +6,7 @@ */ import { reducerWithInitialState } from 'typescript-fsa-reducers'; -import { set } from 'lodash/fp'; +import { set } from '@kbn/safer-lodash-set/fp'; import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../../common/store/constants'; import { diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/mock_data.ts b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/mock_data.ts index a18546a77fe275..0c2ced6d3ad983 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/mock_data.ts +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/mock_data.ts @@ -47,7 +47,6 @@ export const dataProviderWithAndFilters = [ { and: [ { - and: [], enabled: true, excluded: false, id: 'mock-id', @@ -80,7 +79,6 @@ export const dataProviderWithOrFilters = [ { and: [ { - and: [], enabled: true, id: 'mock-id', name: 'kibana.alerts.workflow_status', @@ -109,7 +107,6 @@ export const dataProviderWithOrFilters = [ { and: [ { - and: [], enabled: true, id: 'mock-id', name: 'kibana.alerts.workflow_status', @@ -138,7 +135,6 @@ export const dataProviderWithOrFilters = [ { and: [ { - and: [], enabled: true, id: 'mock-id', name: 'kibana.alerts.workflow_status', diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx index d40ccada2a3989..793105b46299d4 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx @@ -12,7 +12,10 @@ import { v4 as uuidv4 } from 'uuid'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { sourcererActions } from '../../../../common/store/sourcerer'; -import { getDataProvider } from '../../../../common/components/event_details/table/use_action_cell_data_provider'; +import { + getDataProvider, + getDataProviderAnd, +} from '../../../../common/components/event_details/table/use_action_cell_data_provider'; import type { DataProvider, QueryOperator } from '../../../../../common/types/timeline'; import { TimelineId, TimelineType } from '../../../../../common/types/timeline'; import { useCreateTimeline } from '../../../../timelines/components/timeline/properties/use_create_timeline'; @@ -90,12 +93,13 @@ export const useNavigateToTimeline = () => { for (const filter of orFilterGroup.slice(1)) { dataProvider.and.push( - getDataProvider(filter.field, uuidv4(), filter.value, filter.operator) + getDataProviderAnd(filter.field, uuidv4(), filter.value, filter.operator) ); } dataProviders.push(dataProvider); } } + navigateToTimeline(dataProviders, timeRange); }, [navigateToTimeline] diff --git a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts index 93816e06bb7fbd..c451198a272083 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/agent_emulator/services/action_responder.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; import type { Client } from '@elastic/elasticsearch'; import type { ToolingLog } from '@kbn/tooling-log'; import type { KbnClient } from '@kbn/test'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts index 156d1c99fde5db..af35f7881bd00a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations/api/get_installed_integrations/installed_integration_set.ts @@ -126,7 +126,7 @@ const getIntegrationsInfoFromPolicy = ( packageInfo: InstalledPackageBasicInfo ): InstalledIntegrationBasicInfo[] => { return policy.inputs.map((input) => { - const integrationName = normalizeString(input.policy_template); // e.g. 'cloudtrail' + const integrationName = normalizeString(input.policy_template ?? input.type); // e.g. 'cloudtrail' const integrationTitle = `${packageInfo.package_title} ${capitalize(integrationName)}`; // e.g. 'AWS Cloudtrail' return { integration_name: integrationName, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/host_risk.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/host_risk.ts index c621c83f49ecde..fb061d06ce1e23 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/host_risk.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/host_risk.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { set, cloneDeep } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep } from 'lodash'; import { getHostRiskIndex } from '../../../../../../common/search_strategy/security_solution/risk_score/common'; import { RiskScoreFields } from '../../../../../../common/search_strategy/security_solution/risk_score/all'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/user_risk.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/user_risk.ts index d6499e9977d543..db959a76715467 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/user_risk.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/enrichment_by_type/user_risk.ts @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { set, cloneDeep } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep } from 'lodash'; import { getUserRiskIndex } from '../../../../../../common/search_strategy/security_solution/risk_score/common'; import { RiskScoreFields } from '../../../../../../common/search_strategy/security_solution/risk_score/all'; import { createSingleFieldMatchEnrichment } from '../create_single_field_match_enrichment'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/utils/transforms.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/utils/transforms.test.ts index 088916ef45598a..0e6de54014c3c9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/utils/transforms.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/enrichments/utils/transforms.test.ts @@ -9,7 +9,7 @@ import { applyEnrichmentsToEvents, mergeEnrichments } from './transforms'; import { ruleExecutionLogMock } from '../../../rule_monitoring/mocks'; import { createAlert } from '../__mocks__/alerts'; import type { EnrichmentFunction } from '../types'; -import { set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; const createEnrichment = (field: string, value: string): EnrichmentFunction => 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 29a4158a77d003..4e3db8c657e047 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 @@ -28,7 +28,8 @@ import { } from './helpers'; import type { ESClusterInfo, ESLicense, ExceptionListItem } from './types'; import type { PolicyConfig, PolicyData } from '../../../common/endpoint/types'; -import { cloneDeep, set } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep } from 'lodash'; import { loggingSystemMock } from '@kbn/core/server/mocks'; describe('test diagnostic telemetry scheduled task timing helper', () => { diff --git a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts index bac84bd4a4b285..8e53736b23963f 100644 --- a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts +++ b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts @@ -63,6 +63,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, @@ -111,6 +112,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, @@ -160,6 +162,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, @@ -210,6 +213,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, @@ -272,6 +276,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, @@ -320,6 +325,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'desc', }, }, @@ -368,6 +374,7 @@ describe('buildSortedEventsQuery', () => { sort: [ { timefield: { + format: 'strict_date_optional_time||epoch_millis', order: 'asc', }, }, diff --git a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts index 7b92374b8fb331..5253fb8eb74eed 100644 --- a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts +++ b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts @@ -80,6 +80,7 @@ export const buildSortedEventsQuery = ({ { [sortField]: { order: sortOrder ?? 'asc', + format: 'strict_date_optional_time||epoch_millis', }, }, ], diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts b/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts index 87be947c22f90f..b3358ffad5bc17 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/index.ts @@ -48,7 +48,7 @@ function registerNavigation(alerting: AlertingSetup) { PLUGIN_ID, ES_QUERY_ALERT_TYPE, (alert: SanitizedRule>) => { - return `#/viewAlert/${alert.id}`; + return `/app/discover#/viewAlert/${alert.id}`; } ); } diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_es_query.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_es_query.test.ts index 10e8278f1976aa..193f559ce2d621 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_es_query.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_es_query.test.ts @@ -130,6 +130,7 @@ describe('fetchEsQuery', () => { sort: [ { '@timestamp': { + format: 'strict_date_optional_time||epoch_millis', order: 'desc', }, }, @@ -194,6 +195,7 @@ describe('fetchEsQuery', () => { sort: [ { '@timestamp': { + format: 'strict_date_optional_time||epoch_millis', order: 'desc', }, }, @@ -258,6 +260,7 @@ describe('fetchEsQuery', () => { sort: [ { '@timestamp': { + format: 'strict_date_optional_time||epoch_millis', order: 'desc', }, }, @@ -349,6 +352,7 @@ describe('fetchEsQuery', () => { sort: [ { '@timestamp': { + format: 'strict_date_optional_time||epoch_millis', order: 'desc', }, }, diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts index ac9df7a0c0f8d5..e033f9c6ef4a8d 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/lib/fetch_search_source_query.ts @@ -129,7 +129,14 @@ export function updateSearchSource( const searchSourceChild = searchSource.createChild(); searchSourceChild.setField('filter', filters as Filter[]); - searchSourceChild.setField('sort', [{ [timeFieldName]: SortDirection.desc }]); + searchSourceChild.setField('sort', [ + { + [timeFieldName]: { + order: SortDirection.desc, + format: 'strict_date_optional_time||epoch_millis', + }, + }, + ]); searchSourceChild.setField( 'aggs', buildAggregation({ @@ -188,7 +195,7 @@ async function generateLink( } function updateFilterReferences(filters: Filter[], fromDataView: string, toDataView: string) { - return filters.map((filter) => { + return (filters || []).map((filter) => { if (filter.meta.index === fromDataView) { return { ...filter, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts index eb84d6c2b0d8f7..14670fe162ca67 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/render_template_variables.ts @@ -8,7 +8,8 @@ import { renderMustacheObject } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { ExecutorParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; -import { set, cloneDeep, get, isString } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; +import { cloneDeep, get, isString } from 'lodash'; import { RULE_TAGS_TEMPLATE } from '../../../common/opsgenie'; import { OpsgenieSubActions } from '../../../common'; import { CreateAlertSubActionParams } from './types'; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.test.ts index 6abed325bbc459..0c89017088af94 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash/fp'; +import { set } from '@kbn/safer-lodash-set/fp'; import { renderParameterTemplates } from './render'; const params = { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts index 2ba3f120e316d1..ca3fdf7de5b6c0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/render.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set } from 'lodash/fp'; +import { set } from '@kbn/safer-lodash-set/fp'; import { ExecutorParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/tines/constants'; diff --git a/x-pack/plugins/stack_connectors/tsconfig.json b/x-pack/plugins/stack_connectors/tsconfig.json index cb7b2687aea88e..f95d55265cebf4 100644 --- a/x-pack/plugins/stack_connectors/tsconfig.json +++ b/x-pack/plugins/stack_connectors/tsconfig.json @@ -26,6 +26,7 @@ "@kbn/kibana-react-plugin", "@kbn/test-jest-helpers", "@kbn/securitysolution-io-ts-utils", + "@kbn/safer-lodash-set", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/synthetics/common/constants/synthetics/client_defaults.ts b/x-pack/plugins/synthetics/common/constants/synthetics/client_defaults.ts index 3ea9546a1bfaca..6ae9dbfef955f0 100644 --- a/x-pack/plugins/synthetics/common/constants/synthetics/client_defaults.ts +++ b/x-pack/plugins/synthetics/common/constants/synthetics/client_defaults.ts @@ -14,4 +14,13 @@ export const CLIENT_DEFAULTS_SYNTHETICS = { * The end of the default date range is now. */ DATE_RANGE_END: 'now', + + /** + * The application auto refreshes every 30s by default. + */ + AUTOREFRESH_INTERVAL_SECONDS: 60, + /** + * The application's autorefresh feature is enabled. + */ + AUTOREFRESH_IS_PAUSED: false, }; diff --git a/x-pack/plugins/synthetics/e2e/journeys/synthetics/alert_rules/default_status_alert.journey.ts b/x-pack/plugins/synthetics/e2e/journeys/synthetics/alert_rules/default_status_alert.journey.ts index 3e1c7a8430afb5..666366b9555e43 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/synthetics/alert_rules/default_status_alert.journey.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/synthetics/alert_rules/default_status_alert.journey.ts @@ -50,7 +50,7 @@ journey(`DefaultStatusAlert`, async ({ page, params }) => { }); step('Go to monitors page', async () => { - await syntheticsApp.navigateToOverview(true); + await syntheticsApp.navigateToOverview(true, 15); }); step('should create default status alert', async () => { @@ -194,6 +194,7 @@ journey(`DefaultStatusAlert`, async ({ page, params }) => { await page.click(byTestId('alert-status-filter-active-button')); await syntheticsApp.waitForLoadingToFinish(); + await page.waitForTimeout(10 * 1000); await page.click('[aria-label="View in app"]'); await page.click(byTestId('syntheticsMonitorOverviewTab')); diff --git a/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts b/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts index b3dcd9aaa4421c..bf4ecd526e9115 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/synthetics/index.ts @@ -17,7 +17,7 @@ export * from './private_locations.journey'; export * from './alerting_default.journey'; export * from './global_parameters.journey'; export * from './detail_flyout'; -// export * from './alert_rules/default_status_alert.journey'; +export * from './alert_rules/default_status_alert.journey'; export * from './test_now_mode.journey'; export * from './data_retention.journey'; export * from './monitor_details_page/monitor_summary.journey'; diff --git a/x-pack/plugins/synthetics/e2e/journeys/synthetics/overview_sorting.journey.ts b/x-pack/plugins/synthetics/e2e/journeys/synthetics/overview_sorting.journey.ts index 1809fd66d19789..bed3e5f55d056a 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/synthetics/overview_sorting.journey.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/synthetics/overview_sorting.journey.ts @@ -32,7 +32,7 @@ journey('OverviewSorting', async ({ page, params }) => { }); step('Go to monitor-management', async () => { - await syntheticsApp.navigateToOverview(true); + await syntheticsApp.navigateToOverview(true, 15); }); step('sort alphabetical asc', async () => { diff --git a/x-pack/plugins/synthetics/e2e/journeys/uptime/private_locations/add_monitor_private_location.ts b/x-pack/plugins/synthetics/e2e/journeys/uptime/private_locations/add_monitor_private_location.ts index 19a2d54a794584..9960ff1cc207af 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/uptime/private_locations/add_monitor_private_location.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/uptime/private_locations/add_monitor_private_location.ts @@ -7,15 +7,34 @@ import { journey, step, expect, before } from '@elastic/synthetics'; import { assertText, byTestId, TIMEOUT_60_SEC } from '@kbn/observability-plugin/e2e/utils'; import { recordVideo } from '@kbn/observability-plugin/e2e/record_video'; +import { cleanTestMonitors } from '../../synthetics/services/add_monitor'; import { monitorManagementPageProvider } from '../../../page_objects/uptime/monitor_management'; -journey('AddPrivateLocationMonitor', async ({ page, params: { kibanaUrl } }) => { +journey('AddPrivateLocationMonitor', async ({ page, params }) => { recordVideo(page); + page.setDefaultTimeout(TIMEOUT_60_SEC.timeout); + const kibanaUrl = params.kibanaUrl; + const uptime = monitorManagementPageProvider({ page, kibanaUrl }); + let monitorId: string; + before(async () => { - await uptime.waitForLoadingToFinish(); + await cleanTestMonitors(params); + page.on('request', (evt) => { + if ( + evt.resourceType() === 'fetch' && + evt.url().includes('/internal/uptime/service/monitors?preserve_namespace=true') + ) { + evt + .response() + ?.then((res) => res?.json()) + .then((res) => { + monitorId = res.id; + }); + } + }); }); step('Go to monitor-management', async () => { @@ -39,7 +58,7 @@ journey('AddPrivateLocationMonitor', async ({ page, params: { kibanaUrl } }) => await page.click('input[name="name"]'); await page.fill('input[name="name"]', 'Private location monitor'); - await page.click('label:has-text("Test private location Private")', TIMEOUT_60_SEC); + await page.click('label:has-text("Test private location Private")'); await page.selectOption('select', 'http'); await page.click(byTestId('syntheticsUrlField')); await page.fill(byTestId('syntheticsUrlField'), 'https://www.google.com'); @@ -66,7 +85,9 @@ journey('AddPrivateLocationMonitor', async ({ page, params: { kibanaUrl } }) => step('Click text=Edit Elastic Synthetics integration', async () => { await assertText({ page, text: 'This table contains 1 rows out of 1 rows; Page 1 of 1.' }); await page.click('[data-test-subj="integrationNameLink"]'); - await page.click('text=Edit in uptime'); + const btn = await page.locator(byTestId('syntheticsEditMonitorButton')); + expect(await btn.getAttribute('href')).toBe(`/app/synthetics/edit-monitor/${monitorId}`); + await btn.click(); await page.click('text=Private location monitor'); }); }); diff --git a/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx b/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx index b3875a052880f7..86e15182a740e7 100644 --- a/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx +++ b/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx @@ -43,8 +43,14 @@ export function syntheticsAppPageProvider({ page, kibanaUrl }: { page: Page; kib await this.waitForMonitorManagementLoadingToFinish(); }, - async navigateToOverview(doLogin = false) { - await page.goto(overview, { waitUntil: 'networkidle' }); + async navigateToOverview(doLogin = false, refreshInterval?: number) { + if (refreshInterval) { + await page.goto(`${overview}?refreshInterval=${refreshInterval}`, { + waitUntil: 'networkidle', + }); + } else { + await page.goto(overview, { waitUntil: 'networkidle' }); + } if (doLogin) { await this.loginToKibana(); } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/auto_refresh_button.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/auto_refresh_button.tsx new file mode 100644 index 00000000000000..6f40b000a68734 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/auto_refresh_button.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useRef } from 'react'; +import { EuiAutoRefreshButton, OnRefreshChangeProps } from '@elastic/eui'; +import { useDispatch, useSelector } from 'react-redux'; +import { CLIENT_DEFAULTS_SYNTHETICS } from '../../../../../../common/constants/synthetics/client_defaults'; +import { SyntheticsUrlParams } from '../../../utils/url_params'; +import { useUrlParams } from '../../../hooks'; +import { + selectRefreshInterval, + selectRefreshPaused, + setRefreshIntervalAction, + setRefreshPausedAction, +} from '../../../state'; +const { AUTOREFRESH_INTERVAL_SECONDS, AUTOREFRESH_IS_PAUSED } = CLIENT_DEFAULTS_SYNTHETICS; + +const replaceDefaults = ({ refreshPaused, refreshInterval }: Partial) => { + return { + refreshInterval: refreshInterval === AUTOREFRESH_INTERVAL_SECONDS ? undefined : refreshInterval, + refreshPaused: refreshPaused === AUTOREFRESH_IS_PAUSED ? undefined : refreshPaused, + }; +}; +export const AutoRefreshButton = () => { + const dispatch = useDispatch(); + + const refreshPaused = useSelector(selectRefreshPaused); + const refreshInterval = useSelector(selectRefreshInterval); + + const [getUrlsParams, updateUrlParams] = useUrlParams(); + + const { refreshInterval: urlRefreshInterval, refreshPaused: urlIsPaused } = getUrlsParams(); + + const isFirstRender = useRef(true); + + useEffect(() => { + if (isFirstRender.current) { + // sync url state with redux state on first render + dispatch(setRefreshIntervalAction(urlRefreshInterval)); + dispatch(setRefreshPausedAction(urlIsPaused)); + isFirstRender.current = false; + } else { + // sync redux state with url state on subsequent renders + if (urlRefreshInterval !== refreshInterval || urlIsPaused !== refreshPaused) { + updateUrlParams( + replaceDefaults({ + refreshInterval, + refreshPaused, + }), + true + ); + } + } + }, [updateUrlParams, refreshInterval, refreshPaused, urlRefreshInterval, urlIsPaused, dispatch]); + + const onRefreshChange = (newProps: OnRefreshChangeProps) => { + dispatch(setRefreshIntervalAction(newProps.refreshInterval / 1000)); + dispatch(setRefreshPausedAction(newProps.isPaused)); + + updateUrlParams( + replaceDefaults({ + refreshInterval: newProps.refreshInterval / 1000, + refreshPaused: newProps.isPaused, + }), + true + ); + }; + + return ( + + ); +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/last_refreshed.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/last_refreshed.tsx new file mode 100644 index 00000000000000..28a4ef1c5b1017 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/last_refreshed.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useState } from 'react'; +import moment from 'moment'; +import { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useSelector } from 'react-redux'; +import { SHORT_TIMESPAN_LOCALE, SHORT_TS_LOCALE } from '../../../../../../common/constants'; +import { useSyntheticsRefreshContext } from '../../../contexts'; +import { selectRefreshPaused } from '../../../state'; + +export function LastRefreshed() { + const { lastRefresh: lastRefreshed } = useSyntheticsRefreshContext(); + const [refresh, setRefresh] = useState(() => Date.now()); + + const refreshPaused = useSelector(selectRefreshPaused); + + useEffect(() => { + const interVal = setInterval(() => { + setRefresh(Date.now()); + }, 5000); + + return () => { + clearInterval(interVal); + }; + }, []); + + useEffect(() => { + setRefresh(Date.now()); + }, [lastRefreshed]); + + if (!lastRefreshed || refreshPaused) { + return null; + } + + const isWarning = moment().diff(moment(lastRefreshed), 'minutes') > 1; + const isDanger = moment().diff(moment(lastRefreshed), 'minutes') > 5; + + const prevLocal: string = moment.locale() ?? 'en'; + + const shortLocale = moment.locale(SHORT_TS_LOCALE) === SHORT_TS_LOCALE; + if (!shortLocale) { + moment.defineLocale(SHORT_TS_LOCALE, SHORT_TIMESPAN_LOCALE); + } + + const updatedDate = moment(lastRefreshed).from(refresh); + + // Need to reset locale so it doesn't effect other parts of the app + moment.locale(prevLocal); + + return ( + + + + ); +} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/refresh_button.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/refresh_button.tsx new file mode 100644 index 00000000000000..83a952204ebe7c --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/refresh_button.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButton } from '@elastic/eui'; +import { useSyntheticsRefreshContext } from '../../../contexts'; + +export function RefreshButton() { + const { refreshApp } = useSyntheticsRefreshContext(); + return ( + refreshApp()}> + {REFRESH_LABEL} + + ); +} + +export const REFRESH_LABEL = i18n.translate('xpack.synthetics.overview.refresh', { + defaultMessage: 'Refresh', +}); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx index 5a417b511c119a..6fae43af920e56 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.test.tsx @@ -27,7 +27,7 @@ describe('SyntheticsDatePicker component', () => { it('uses shared date range state when there is no url date range state', async () => { const customHistory = createMemoryHistory({ - initialEntries: ['/?dateRangeStart=now-15m&dateRangeEnd=now'], + initialEntries: ['/?dateRangeStart=now-24h&dateRangeEnd=now'], }); jest.spyOn(customHistory, 'push'); @@ -37,8 +37,6 @@ describe('SyntheticsDatePicker component', () => { core: startPlugins, }); - expect(await findByText('~ 15 minutes ago')).toBeInTheDocument(); - expect(await findByText('~ 30 minutes ago')).toBeInTheDocument(); expect(customHistory.push).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.tsx index 61398c562d1364..82f2874f9ffa2c 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/date_picker/synthetics_date_picker.tsx @@ -7,6 +7,7 @@ import React, { useContext, useEffect } from 'react'; import { EuiSuperDatePicker } from '@elastic/eui'; +import { CLIENT_DEFAULTS_SYNTHETICS } from '../../../../../../common/constants/synthetics/client_defaults'; import { useUrlParams } from '../../../hooks'; import { CLIENT_DEFAULTS } from '../../../../../../common/constants'; import { @@ -16,7 +17,7 @@ import { } from '../../../contexts'; const isSyntheticsDefaultDateRange = (dateRangeStart: string, dateRangeEnd: string) => { - const { DATE_RANGE_START, DATE_RANGE_END } = CLIENT_DEFAULTS; + const { DATE_RANGE_START, DATE_RANGE_END } = CLIENT_DEFAULTS_SYNTHETICS; return dateRangeStart === DATE_RANGE_START && dateRangeEnd === DATE_RANGE_END; }; @@ -31,12 +32,7 @@ export const SyntheticsDatePicker = ({ fullWidth }: { fullWidth?: boolean }) => // read time from state and update the url const sharedTimeState = data?.query.timefilter.timefilter.getTime(); - const { - autorefreshInterval, - autorefreshIsPaused, - dateRangeStart: start, - dateRangeEnd: end, - } = getUrlParams(); + const { dateRangeStart: start, dateRangeEnd: end } = getUrlParams(); useEffect(() => { const { from, to } = sharedTimeState ?? {}; @@ -70,8 +66,6 @@ export const SyntheticsDatePicker = ({ fullWidth }: { fullWidth?: boolean }) => start={start} end={end} commonlyUsedRanges={euiCommonlyUsedRanges} - isPaused={autorefreshIsPaused} - refreshInterval={autorefreshInterval} onTimeChange={({ start: startN, end: endN }) => { if (data?.query?.timefilter?.timefilter) { data?.query.timefilter.timefilter.setTime({ from: startN, to: endN }); @@ -81,13 +75,6 @@ export const SyntheticsDatePicker = ({ fullWidth }: { fullWidth?: boolean }) => refreshApp(); }} onRefresh={refreshApp} - onRefreshChange={({ isPaused, refreshInterval }) => { - updateUrl({ - autorefreshInterval: - refreshInterval === undefined ? autorefreshInterval : refreshInterval, - autorefreshIsPaused: isPaused, - }); - }} /> ); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.test.tsx index 343c5483855150..b672e732c791e1 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.test.tsx @@ -14,7 +14,7 @@ describe('ActionMenuContent', () => { const { getByRole, getByText } = render(); const settingsAnchor = getByRole('link', { name: 'Navigate to the Uptime settings page' }); - expect(settingsAnchor.getAttribute('href')).toBe('/settings?dateRangeStart=now-24h'); + expect(settingsAnchor.getAttribute('href')).toBe('/settings'); expect(getByText('Settings')); }); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx index a47d1cd9862496..a81b4a76eba995 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx @@ -11,6 +11,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useHistory, useRouteMatch } from 'react-router-dom'; import { createExploratoryViewUrl } from '@kbn/observability-plugin/public'; +import { LastRefreshed } from '../components/last_refreshed'; +import { AutoRefreshButton } from '../components/auto_refresh_button'; import { useSyntheticsSettingsContext } from '../../../contexts'; import { useGetUrlParams } from '../../../hooks'; import { MONITOR_ROUTE, SETTINGS_ROUTE } from '../../../../../../common/constants'; @@ -66,6 +68,8 @@ export function ActionMenuContent(): React.ReactElement { return ( + + ), diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/monitor_test_result/use_retrieve_step_image.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/monitor_test_result/use_retrieve_step_image.ts index 98d532b279a8ce..d2a6d193556176 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/monitor_test_result/use_retrieve_step_image.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/monitor_test_result/use_retrieve_step_image.ts @@ -42,7 +42,7 @@ export const useRetrieveStepImage = ({ /** * Whether to retry screenshot image fetch on revisit (when intersection change triggers). * Will only re-fetch if an image fetch wasn't successful in previous attempts. - * Set this to `true` fro "Run Once" / "Test Now" modes + * Set this to `true` from "Run Once" / "Test Now" modes * */ retryFetchOnRevisit: boolean; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/screenshot/journey_step_screenshot_container.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/screenshot/journey_step_screenshot_container.tsx index 0527b6ad8c67a9..57533e14ab7ad7 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/screenshot/journey_step_screenshot_container.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/screenshot/journey_step_screenshot_container.tsx @@ -46,11 +46,11 @@ export const JourneyStepScreenshotContainer = ({ const intersection = useIntersection(intersectionRef, { root: null, rootMargin: '0px', - threshold: 1, + threshold: 0.1, }); const imageResult = useRetrieveStepImage({ - hasIntersected: Boolean(intersection && intersection.intersectionRatio === 1), + hasIntersected: Boolean(intersection && intersection.intersectionRatio > 0), stepStatus, imgPath, retryFetchOnRevisit, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_save.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_save.ts index e09a4dd886133e..9fd18e5dfa04d4 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_save.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/hooks/use_monitor_save.ts @@ -8,13 +8,18 @@ import { FETCH_STATUS, useFetcher } from '@kbn/observability-plugin/public'; import { useParams, useRouteMatch } from 'react-router-dom'; import { useEffect } from 'react'; +import { useDispatch } from 'react-redux'; import { i18n } from '@kbn/i18n'; import { MONITOR_EDIT_ROUTE } from '../../../../../../common/constants'; import { SyntheticsMonitor } from '../../../../../../common/runtime_types'; import { createMonitorAPI, updateMonitorAPI } from '../../../state/monitor_management/api'; import { kibanaService } from '../../../../../utils/kibana_service'; +import { cleanMonitorListState } from '../../../state'; +import { useSyntheticsRefreshContext } from '../../../contexts'; export const useMonitorSave = ({ monitorData }: { monitorData?: SyntheticsMonitor }) => { + const dispatch = useDispatch(); + const { refreshApp } = useSyntheticsRefreshContext(); const { monitorId } = useParams<{ monitorId: string }>(); const editRouteMatch = useRouteMatch({ path: MONITOR_EDIT_ROUTE }); @@ -42,12 +47,14 @@ export const useMonitorSave = ({ monitorData }: { monitorData?: SyntheticsMonito toastLifeTimeMs: 3000, }); } else if (status === FETCH_STATUS.SUCCESS && !loading) { + refreshApp(); + dispatch(cleanMonitorListState()); kibanaService.toasts.addSuccess({ title: monitorId ? MONITOR_UPDATED_SUCCESS_LABEL : MONITOR_SUCCESS_LABEL, toastLifeTimeMs: 3000, }); } - }, [data, status, monitorId, loading]); + }, [data, status, monitorId, loading, refreshApp, dispatch]); return { status, loading, isEdit }; }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_earliest_start_date.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_range_from.ts similarity index 67% rename from x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_earliest_start_date.ts rename to x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_range_from.ts index 14429fe2477ffd..fe858f0a0056a6 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_earliest_start_date.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_monitor_range_from.ts @@ -7,18 +7,21 @@ import { useMemo } from 'react'; import moment from 'moment'; +import { useRefreshedRange } from '../../../hooks'; import { useSelectedMonitor } from './use_selected_monitor'; -export const useEarliestStartDate = () => { +export const useMonitorRangeFrom = () => { const { monitor, loading } = useSelectedMonitor(); + const { from, to } = useRefreshedRange(30, 'days'); + return useMemo(() => { if (monitor?.created_at) { const diff = moment(monitor?.created_at).diff(moment().subtract(30, 'day'), 'days'); if (diff > 0) { - return { from: monitor?.created_at, loading }; + return { to, from: monitor?.created_at, loading }; } } - return { from: 'now-30d/d', loading }; - }, [monitor?.created_at, loading]); + return { to, from, loading }; + }, [monitor?.created_at, to, from, loading]); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_monitor.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_monitor.tsx index cea0378020c579..fe2d6028151db7 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_monitor.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_monitor.tsx @@ -16,6 +16,7 @@ import { selectMonitorListState, selectorMonitorDetailsState, selectorError, + selectRefreshInterval, } from '../../../state'; export const useSelectedMonitor = (monId?: string) => { @@ -26,13 +27,14 @@ export const useSelectedMonitor = (monId?: string) => { } const monitorsList = useSelector(selectEncryptedSyntheticsSavedMonitors); const { loading: monitorListLoading } = useSelector(selectMonitorListState); + const refreshInterval = useSelector(selectRefreshInterval); const monitorFromList = useMemo( () => monitorsList.find((monitor) => monitor[ConfigKey.CONFIG_ID] === monitorId) ?? null, [monitorId, monitorsList] ); const error = useSelector(selectorError); - const { lastRefresh, refreshInterval } = useSyntheticsRefreshContext(); + const { lastRefresh } = useSyntheticsRefreshContext(); const { syntheticsMonitor, syntheticsMonitorLoading, syntheticsMonitorDispatchedAt } = useSelector(selectorMonitorDetailsState); const dispatch = useDispatch(); @@ -60,7 +62,7 @@ export const useSelectedMonitor = (monId?: string) => { !syntheticsMonitorLoading && !monitorListLoading && syntheticsMonitorDispatchedAt > 0 && - Date.now() - syntheticsMonitorDispatchedAt > refreshInterval + Date.now() - syntheticsMonitorDispatchedAt > refreshInterval * 1000 ) { dispatch(getMonitorAction.get({ monitorId })); } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx index cc7ea08168cccb..d16e3faf353dee 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx @@ -15,7 +15,7 @@ import { MonitorErrorsCount } from '../monitor_summary/monitor_errors_count'; import { FailedTestsCount } from './failed_tests_count'; import { MonitorFailedTests } from './failed_tests'; import { ErrorsList } from './errors_list'; -import { useAbsoluteDate, useGetUrlParams } from '../../../hooks'; +import { useRefreshedRangeFromUrl } from '../../../hooks'; import { useMonitorQueryId } from '../hooks/use_monitor_query_id'; export const ErrorsTabContent = ({ @@ -25,9 +25,7 @@ export const ErrorsTabContent = ({ errorStates: PingState[]; loading: boolean; }) => { - const { dateRangeStart, dateRangeEnd } = useGetUrlParams(); - - const time = useAbsoluteDate({ from: dateRangeStart, to: dateRangeEnd }); + const time = useRefreshedRangeFromUrl(); const monitorId = useMonitorQueryId(); @@ -39,11 +37,16 @@ export const ErrorsTabContent = ({ {monitorId && ( - + )} - + diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx index 8192142932dc87..99ef360b886b39 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_count.tsx @@ -12,7 +12,7 @@ import { FAILED_TESTS_LABEL } from './failed_tests'; import { ClientPluginsStart } from '../../../../../plugin'; import { useMonitorQueryId } from '../hooks/use_monitor_query_id'; -export const FailedTestsCount = (time: { to: string; from: string }) => { +export const FailedTestsCount = ({ from, to, id }: { to: string; from: string; id: string }) => { const { observability } = useKibana().services; const { ExploratoryViewEmbeddable } = observability; @@ -27,10 +27,11 @@ export const FailedTestsCount = (time: { to: string; from: string }) => { return ( { const emptyState = !loading && errorStates.length === 0; + const redirect = useMonitorDetailsPage(); + if (redirect) { + return redirect; + } + return ( <> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_history/monitor_history.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_history/monitor_history.tsx index b4f40aeef45c14..5dd0570cde7e33 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_history/monitor_history.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_history/monitor_history.tsx @@ -7,7 +7,8 @@ import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; -import { useAbsoluteDate, useUrlParams } from '../../../hooks'; +import { useMonitorDetailsPage } from '../use_monitor_details_page'; +import { useRefreshedRangeFromUrl, useUrlParams } from '../../../hooks'; import { useDimensions } from '../../../hooks'; import { SyntheticsDatePicker } from '../../common/date_picker/synthetics_date_picker'; import { AvailabilityPanel } from '../monitor_summary/availability_panel'; @@ -27,9 +28,8 @@ import { useMonitorQueryId } from '../hooks/use_monitor_query_id'; const STATS_WIDTH_SINGLE_COLUMN_THRESHOLD = 360; // ✨ determined by trial and error export const MonitorHistory = () => { - const [useGetUrlParams, updateUrlParams] = useUrlParams(); - const { dateRangeStart, dateRangeEnd } = useGetUrlParams(); - const { from, to } = useAbsoluteDate({ from: dateRangeStart, to: dateRangeEnd }); + const [, updateUrlParams] = useUrlParams(); + const { from, to } = useRefreshedRangeFromUrl(); const { elementRef: statsRef, width: statsWidth } = useDimensions(); const statsColumns = statsWidth && statsWidth < STATS_WIDTH_SINGLE_COLUMN_THRESHOLD ? 1 : 2; @@ -42,6 +42,10 @@ export const MonitorHistory = () => { ); const monitorId = useMonitorQueryId(); + const redirect = useMonitorDetailsPage(); + if (redirect) { + return redirect; + } return ( @@ -70,10 +74,14 @@ export const MonitorHistory = () => { - + - + @@ -81,12 +89,22 @@ export const MonitorHistory = () => { {monitorId && ( - + )} {monitorId && ( - + )} @@ -94,10 +112,10 @@ export const MonitorHistory = () => { - + - + diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_cell_tooltip.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_cell_tooltip.tsx index 04505a90628aa2..a6dc7956280cef 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_cell_tooltip.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_status/monitor_status_cell_tooltip.tsx @@ -9,7 +9,7 @@ import React from 'react'; import moment from 'moment'; import { EuiProgress } from '@elastic/eui'; -import { TooltipTable, TooltipHeader, TooltipValue } from '@elastic/charts'; +import { TooltipTable, TooltipHeader, TooltipValue, TooltipContainer } from '@elastic/charts'; import { usePingStatusesIsLoading } from '../hooks/use_ping_statuses'; import { MonitorStatusTimeBin, SUCCESS_VIZ_COLOR, DANGER_VIZ_COLOR } from './monitor_status_data'; @@ -71,7 +71,7 @@ export const MonitorStatusCellTooltip = ({ timeBin }: { timeBin?: MonitorStatusT ]; return ( - <> + {tooltipTitle} {isLoading && } - + ); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/availability_panel.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/availability_panel.tsx index cec258a0ea77f1..abb5fe617d80e5 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/availability_panel.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/availability_panel.tsx @@ -16,6 +16,7 @@ import { useSelectedLocation } from '../hooks/use_selected_location'; interface AvailabilityPanelprops { from: string; to: string; + id: string; } export const AvailabilityPanel = (props: AvailabilityPanelprops) => { @@ -34,6 +35,7 @@ export const AvailabilityPanel = (props: AvailabilityPanelprops) => { return ( { @@ -36,6 +37,7 @@ export const AvailabilitySparklines = (props: AvailabilitySparklinesProps) => { return ( { @@ -34,6 +35,7 @@ export const DurationPanel = (props: DurationPanelProps) => { return ( { @@ -36,6 +37,7 @@ export const DurationSparklines = (props: DurationSparklinesProps) => { return ( <> { return ( ({ diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_complete_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_complete_count.tsx index b9b2c191cdab5b..8e8d1a0f6600a6 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_complete_count.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_complete_count.tsx @@ -32,6 +32,7 @@ export const MonitorCompleteCount = (props: MonitorCompleteCountProps) => { return ( { return ( { +export const MonitorErrorSparklines = ({ from, to, monitorId, id }: Props) => { const { observability } = useKibana().services; const { ExploratoryViewEmbeddable } = observability; @@ -34,6 +35,7 @@ export const MonitorErrorSparklines = ({ from, to, monitorId }: Props) => { return ( { +export const MonitorErrorsCount = ({ monitorId, from, to, id }: MonitorErrorsCountProps) => { const { observability } = useKibana().services; const { ExploratoryViewEmbeddable } = observability; @@ -33,6 +34,7 @@ export const MonitorErrorsCount = ({ monitorId, from, to }: MonitorErrorsCountPr return ( { - const { from: fromRelative } = useEarliestStartDate(); - const toRelative = 'now'; - - const { from, to } = useAbsoluteDate({ from: fromRelative, to: toRelative }); + const { from, to } = useMonitorRangeFrom(); const monitorId = useMonitorQueryId(); const dateLabel = from === 'now-30d/d' ? LAST_30_DAYS_LABEL : TO_DATE_LABEL; + const redirect = useMonitorDetailsPage(); + if (redirect) { + return redirect; + } + return ( <> @@ -59,23 +61,35 @@ export const MonitorSummary = () => { - + - + - + - + - {monitorId && } + {monitorId && ( + + )} {monitorId && ( - + )} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_total_runs_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_total_runs_count.tsx index deb02dc98dc873..ef34498c92ab94 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_total_runs_count.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_summary/monitor_total_runs_count.tsx @@ -32,6 +32,7 @@ export const MonitorTotalRunsCount = (props: MonitorTotalRunsCountProps) => { return ( ( - - - - ), + component: MonitorSummary, dataTestSubj: 'syntheticsMonitorDetailsPage', pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'overview'), }, @@ -56,11 +52,7 @@ export const getMonitorDetailsRoute = ( values: { baseTitle }, }), path: MONITOR_HISTORY_ROUTE, - component: () => ( - - - - ), + component: MonitorHistory, dataTestSubj: 'syntheticsMonitorHistoryPage', pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'history'), }, @@ -70,11 +62,7 @@ export const getMonitorDetailsRoute = ( values: { baseTitle }, }), path: MONITOR_ERRORS_ROUTE, - component: () => ( - - - - ), + component: MonitorErrors, dataTestSubj: 'syntheticsMonitorHistoryPage', pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'errors'), }, @@ -84,7 +72,7 @@ export const getMonitorDetailsRoute = ( values: { baseTitle }, }), path: MONITOR_NOT_FOUND_ROUTE, - component: () => , + component: MonitorNotFoundPage, dataTestSubj: 'syntheticsMonitorNotFoundPage', pageHeader: { breadcrumbs: [getMonitorsBreadcrumb(syntheticsPath)], @@ -127,6 +115,7 @@ const getMonitorSummaryHeader = ( pageTitle: , breadcrumbs: [getMonitorsBreadcrumb(syntheticsPath)], rightSideItems: [ + , , , , diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_details_page.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/use_monitor_details_page.tsx similarity index 90% rename from x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_details_page.tsx rename to x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/use_monitor_details_page.tsx index beb7c6e9585d48..831bd9fb446c5d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_details_page.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/use_monitor_details_page.tsx @@ -13,7 +13,7 @@ import { ConfigKey } from '../../../../../common/runtime_types'; import { useMonitorListBreadcrumbs } from '../monitors_page/hooks/use_breadcrumbs'; import { useSelectedMonitor } from './hooks/use_selected_monitor'; -export const MonitorDetailsPage: React.FC<{ children: React.ReactElement }> = ({ children }) => { +export const useMonitorDetailsPage = () => { const { monitor, error } = useSelectedMonitor(); const { monitorId } = useParams<{ monitorId: string }>(); @@ -27,5 +27,5 @@ export const MonitorDetailsPage: React.FC<{ children: React.ReactElement }> = ({ ) { return ; } - return children; + return null; }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/no_monitors_found.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/no_monitors_found.test.tsx index 36d98281cc1a0d..a995b0617dd389 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/no_monitors_found.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/no_monitors_found.test.tsx @@ -18,7 +18,7 @@ describe('NoMonitorsFound', () => { useUrlParamsSpy = jest.spyOn(URL, 'useUrlParams'); updateUrlParamsMock = jest.fn(); - useUrlParamsSpy.mockImplementation(() => [jest.fn(), updateUrlParamsMock]); + useUrlParamsSpy.mockImplementation(() => [jest.fn().mockReturnValue({}), updateUrlParamsMock]); }); afterEach(() => { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/search_field.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/search_field.test.tsx index 3bd1e226cdd7db..0e0db9ffc9c849 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/search_field.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/common/search_field.test.tsx @@ -21,7 +21,7 @@ describe('SearchField', () => { useGetUrlParamsSpy = jest.spyOn(URL, 'useGetUrlParams'); updateUrlParamsMock = jest.fn(); - useUrlParamsSpy.mockImplementation(() => [jest.fn(), updateUrlParamsMock]); + useUrlParamsSpy.mockImplementation(() => [jest.fn().mockReturnValue({}), updateUrlParamsMock]); }); afterEach(() => { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs.tsx index 84865837bac6ea..9fbb1efceeb2de 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs.tsx @@ -11,7 +11,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useTheme } from '@kbn/observability-plugin/public'; import { ReportTypes } from '@kbn/observability-plugin/public'; -import { useAbsoluteDate } from '../../../../hooks'; +import { useRefreshedRange } from '../../../../hooks'; import { ClientPluginsStart } from '../../../../../../plugin'; import * as labels from '../labels'; @@ -21,7 +21,7 @@ export const MonitorTestRunsCount = ({ monitorIds }: { monitorIds: string[] }) = const { ExploratoryViewEmbeddable } = observability; - const { from: absFrom, to: absTo } = useAbsoluteDate({ from: 'now-30d', to: 'now' }); + const { from, to } = useRefreshedRange(30, 'days'); return ( 0 ? monitorIds : ['false-monitor-id'], // Show no data when monitorIds is empty }, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs_sparkline.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs_sparkline.tsx index 8b8d03cd6d8797..8791e8e1ce6a84 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs_sparkline.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_stats/monitor_test_runs_sparkline.tsx @@ -10,7 +10,7 @@ import React, { useMemo } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useTheme } from '@kbn/observability-plugin/public'; -import { useAbsoluteDate } from '../../../../hooks'; +import { useRefreshedRange } from '../../../../hooks'; import { ClientPluginsStart } from '../../../../../../plugin'; import * as labels from '../labels'; @@ -21,7 +21,7 @@ export const MonitorTestRunsSparkline = ({ monitorIds }: { monitorIds: string[] const theme = useTheme(); - const { from, to } = useAbsoluteDate({ from: 'now-30d', to: 'now' }); + const { from, to } = useRefreshedRange(30, 'days'); const attributes = useMemo(() => { return [ @@ -44,6 +44,7 @@ export const MonitorTestRunsSparkline = ({ monitorIds }: { monitorIds: string[] return ( { - const { from, to } = useAbsoluteDate({ from: 'now-12h', to: 'now' }); + const { from, to } = useRefreshedRange(12, 'hours'); const { observability } = useKibana().services; const { ExploratoryViewEmbeddable } = observability; @@ -47,6 +47,7 @@ export const OverviewAlerts = () => { { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_errors/overview_errors_count.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_errors/overview_errors_count.tsx index e2036ec82738ce..1d0ce0a90fc3bf 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_errors/overview_errors_count.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_errors/overview_errors_count.tsx @@ -32,6 +32,7 @@ export const OverviewErrorsCount = ({ return ( { return ( { useGetUrlParamsSpy = jest.spyOn(URL, 'useGetUrlParams'); updateUrlParamsMock = jest.fn(); - useUrlParamsSpy.mockImplementation(() => [jest.fn(), updateUrlParamsMock]); + useUrlParamsSpy.mockImplementation(() => [jest.fn().mockReturnValue({}), updateUrlParamsMock]); }); afterEach(() => { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx index 158061692d4753..2acb2b7a35ed74 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx @@ -56,6 +56,7 @@ export const OverviewPage: React.FC = () => { } = useEnablement(); const { + loaded: overviewLoaded, data: { monitors }, pageState, } = useSelector(selectOverviewState); @@ -94,7 +95,7 @@ export const OverviewPage: React.FC = () => { return ; } - const noMonitorFound = monitorsLoaded && monitors?.length === 0; + const noMonitorFound = monitorsLoaded && overviewLoaded && monitors?.length === 0; return ( <> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/route_config.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/route_config.tsx index 84b85cdb2579f7..57f40f56765937 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/route_config.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/route_config.tsx @@ -7,9 +7,10 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useLocation } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; +import { RefreshButton } from '../common/components/refresh_button'; import { OverviewPage } from './overview/overview_page'; import { MonitorsPageHeader } from './management/page_header/monitors_page_header'; import { CreateMonitorButton } from './create_monitor_button'; @@ -19,9 +20,14 @@ import { MONITORS_ROUTE, OVERVIEW_ROUTE } from '../../../../../common/constants' export const getMonitorsRoute = ( history: ReturnType, + location: ReturnType, syntheticsPath: string, baseTitle: string ): RouteProps[] => { + const sharedProps = { + pageTitle: , + rightSideItems: [, ], + }; return [ { title: i18n.translate('xpack.synthetics.overviewRoute.title', { @@ -32,9 +38,8 @@ export const getMonitorsRoute = ( component: OverviewPage, dataTestSubj: 'syntheticsOverviewPage', pageHeader: { - pageTitle: , - rightSideItems: [], - tabs: getMonitorsTabs(syntheticsPath, 'overview'), + ...sharedProps, + tabs: getMonitorsTabs(syntheticsPath, 'overview', location), }, }, { @@ -46,15 +51,18 @@ export const getMonitorsRoute = ( component: MonitorsPageWithServiceAllowed, dataTestSubj: 'syntheticsMonitorManagementPage', pageHeader: { - pageTitle: , - rightSideItems: [], - tabs: getMonitorsTabs(syntheticsPath, 'management'), + ...sharedProps, + tabs: getMonitorsTabs(syntheticsPath, 'management', location), }, }, ]; }; -const getMonitorsTabs = (syntheticsPath: string, selected: 'overview' | 'management') => { +const getMonitorsTabs = ( + syntheticsPath: string, + selected: 'overview' | 'management', + location: ReturnType +) => { return [ { label: ( @@ -63,7 +71,7 @@ const getMonitorsTabs = (syntheticsPath: string, selected: 'overview' | 'managem defaultMessage="Overview" /> ), - href: `${syntheticsPath}${OVERVIEW_ROUTE}`, + href: `${syntheticsPath}${OVERVIEW_ROUTE}${location.search}`, isSelected: selected === 'overview', 'data-test-subj': 'syntheticsMonitorOverviewTab', }, @@ -74,7 +82,7 @@ const getMonitorsTabs = (syntheticsPath: string, selected: 'overview' | 'managem defaultMessage="Management" /> ), - href: `${syntheticsPath}${MONITORS_ROUTE}`, + href: `${syntheticsPath}${MONITORS_ROUTE}${location.search}`, isSelected: selected === 'management', 'data-test-subj': 'syntheticsMonitorManagementTab', }, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings.ts index 6f53af4cb75bed..1f7d2ac810bbd7 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings.ts @@ -115,7 +115,7 @@ export const useNetworkTimings = (checkGroupIdArg?: string, stepIndexArg?: numbe }, }, }, - [checkGroupId, stepIndex], + [], { name: `stepNetworkTimingsMetrics/${checkGroupId}/${stepIndex}` } ); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings_prev.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings_prev.ts index ec6f96e15259cb..65fc47865b103a 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings_prev.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_network_timings_prev.ts @@ -158,9 +158,9 @@ export const useNetworkTimingsPrevious24Hours = ( }, }, }, - [configId, stepIndex, checkGroupId], + [], { - name: `stepNetworkPreviousTimings/${configId}/${stepIndex}`, + name: `stepNetworkPreviousTimings/${configId}/${checkGroupId}/${stepIndex}`, isRequestReady: Boolean(timestamp), } ); @@ -196,7 +196,7 @@ export const useNetworkTimingsPrevious24Hours = ( }; return { - loading, + loading: loading && !data, timings, timingsWithLabels: getTimingWithLabels(timings), }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_metrics.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_metrics.ts index 7c7d1ecb898283..fba2917c6ece20 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_metrics.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_metrics.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { useEsSearch } from '@kbn/observability-plugin/public'; import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import { useReduxEsSearch } from '../../../hooks/use_redux_es_search'; import { formatBytes } from './use_object_metrics'; import { formatMillisecond } from '../step_metrics/step_metrics'; import { @@ -36,7 +36,7 @@ export const useStepMetrics = (step?: JourneyStep) => { const checkGroupId = step?.monitor.check_group ?? urlParams.checkGroupId; const stepIndex = step?.synthetics.step?.index ?? urlParams.stepIndex; - const { data } = useEsSearch( + const { data } = useReduxEsSearch( { index: SYNTHETICS_INDEX_PATTERN, body: { @@ -91,11 +91,11 @@ export const useStepMetrics = (step?: JourneyStep) => { }, }, }, - [stepIndex, checkGroupId], - { name: 'stepMetrics' } + [], + { name: `stepMetrics/${checkGroupId}/${stepIndex}` } ); - const { data: transferData } = useEsSearch( + const { data: transferData } = useReduxEsSearch( { index: SYNTHETICS_INDEX_PATTERN, body: { @@ -104,9 +104,6 @@ export const useStepMetrics = (step?: JourneyStep) => { 'synthetics.payload.transfer_size': { type: 'double', }, - 'synthetics.payload.resource_size': { - type: 'double', - }, }, query: { bool: { @@ -135,17 +132,12 @@ export const useStepMetrics = (step?: JourneyStep) => { field: 'synthetics.payload.transfer_size', }, }, - resourceSize: { - sum: { - field: 'synthetics.payload.resource_size', - }, - }, }, }, }, - [stepIndex, checkGroupId], + [], { - name: 'stepMetricsFromNetworkInfos', + name: `stepMetricsFromNetworkInfos/${checkGroupId}/${stepIndex}`, } ); @@ -153,10 +145,6 @@ export const useStepMetrics = (step?: JourneyStep) => { const transferDataVal = transferData?.aggregations?.transferSize?.value ?? 0; return { - ...(data?.aggregations ?? {}), - transferData: transferData?.aggregations?.transferSize?.value ?? 0, - resourceSize: transferData?.aggregations?.resourceSize?.value ?? 0, - metrics: [ { label: STEP_DURATION_LABEL, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_prev_metrics.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_prev_metrics.ts index d29c142c030830..9940620f7cc170 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_prev_metrics.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/hooks/use_step_prev_metrics.ts @@ -6,7 +6,6 @@ */ import { useParams } from 'react-router-dom'; -import { useEsSearch } from '@kbn/observability-plugin/public'; import { formatBytes } from './use_object_metrics'; import { formatMillisecond } from '../step_metrics/step_metrics'; import { @@ -20,6 +19,7 @@ import { import { JourneyStep } from '../../../../../../common/runtime_types'; import { median } from './use_network_timings_prev'; import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants'; +import { useReduxEsSearch } from '../../../hooks/use_redux_es_search'; export const MONITOR_DURATION_US = 'monitor.duration.us'; export const SYNTHETICS_CLS = 'browser.experience.cls'; @@ -41,7 +41,7 @@ export const useStepPrevMetrics = (step?: JourneyStep) => { const checkGroupId = step?.monitor.check_group ?? urlParams.checkGroupId; const stepIndex = step?.synthetics.step?.index ?? urlParams.stepIndex; - const { data, loading } = useEsSearch( + const { data, loading } = useReduxEsSearch( { index: SYNTHETICS_INDEX_PATTERN, body: { @@ -112,10 +112,10 @@ export const useStepPrevMetrics = (step?: JourneyStep) => { }, }, }, - [monitorId, checkGroupId, stepIndex], - { name: 'previousStepMetrics' } + [], + { name: `previousStepMetrics/${monitorId}/${checkGroupId}/${stepIndex}` } ); - const { data: transferData } = useEsSearch( + const { data: transferData } = useReduxEsSearch( { index: SYNTHETICS_INDEX_PATTERN, body: { @@ -174,9 +174,9 @@ export const useStepPrevMetrics = (step?: JourneyStep) => { }, }, }, - [monitorId, checkGroupId, stepIndex], + [], { - name: 'previousStepMetricsFromNetworkInfos', + name: `previousStepMetricsFromNetworkInfos/${monitorId}/${checkGroupId}/${stepIndex}`, } ); @@ -210,7 +210,7 @@ export const useStepPrevMetrics = (step?: JourneyStep) => { const medianStepDuration = median(stepDuration); return { - loading, + loading: loading && !metrics, metrics: [ { label: STEP_DURATION_LABEL, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx index 1250bb02f8a2e6..804e0828e31430 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/step_details_page/step_waterfall_chart/waterfall/waterfall_bar_chart.tsx @@ -17,6 +17,7 @@ import { Settings, TickFormatter, TooltipInfo, + TooltipContainer, } from '@elastic/charts'; import { useEuiTheme } from '@elastic/eui'; import { useChartTheme } from '../../../../../../hooks/use_chart_theme'; @@ -45,14 +46,16 @@ const Tooltip = (tooltipInfo: TooltipInfo) => { ); }); return relevantItems.length ? ( - - {sidebarItem && ( - - )} - + + + {sidebarItem && ( + + )} + + ) : null; }, [data, sidebarItems, tooltipInfo.header?.value]); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_browser_run_once_monitors.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_browser_run_once_monitors.ts index cc45ef79db9056..4daea98b4e9232 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_browser_run_once_monitors.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_browser_run_once_monitors.ts @@ -66,15 +66,13 @@ export const useBrowserEsResults = ({ export const useBrowserRunOnceMonitors = ({ testRunId, skipDetails = false, - refresh = true, expectSummaryDocs, }: { testRunId: string; - refresh?: boolean; skipDetails?: boolean; expectSummaryDocs: number; }) => { - const { refreshTimer, lastRefresh } = useTickTick(5 * 1000, refresh); + const { refreshTimer, lastRefresh } = useTickTick(5 * 1000); const [checkGroupResults, setCheckGroupResults] = useState(() => { return new Array(expectSummaryDocs) diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_simple_run_once_monitors.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_simple_run_once_monitors.ts index e6cb731c605de3..46d619798b8f7d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_simple_run_once_monitors.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_simple_run_once_monitors.ts @@ -19,7 +19,7 @@ export const useSimpleRunOnceMonitors = ({ expectSummaryDocs: number; testRunId: string; }) => { - const { refreshTimer, lastRefresh } = useTickTick(2 * 1000, false); + const { refreshTimer, lastRefresh } = useTickTick(2 * 1000); const { data, loading } = useEsSearch( createEsParams({ diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_tick_tick.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_tick_tick.ts index c0e19e2450a710..de67aee828c918 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_tick_tick.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/hooks/use_tick_tick.ts @@ -5,19 +5,13 @@ * 2.0. */ -import { useEffect, useState, useContext } from 'react'; -import { SyntheticsRefreshContext } from '../../../contexts'; - -export function useTickTick(interval?: number, refresh = true) { - const { refreshApp } = useContext(SyntheticsRefreshContext); +import { useEffect, useState } from 'react'; +export function useTickTick(interval?: number) { const [nextTick, setNextTick] = useState(Date.now()); const [tickTick] = useState(() => setInterval(() => { - if (refresh) { - refreshApp(); - } setNextTick(Date.now()); }, interval ?? 5 * 1000) ); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/contexts/synthetics_refresh_context.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/contexts/synthetics_refresh_context.tsx index b6ee5e1616c5c8..b1ac1b391696fb 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/contexts/synthetics_refresh_context.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/contexts/synthetics_refresh_context.tsx @@ -6,18 +6,16 @@ */ import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { selectRefreshInterval, selectRefreshPaused } from '../state'; interface SyntheticsRefreshContext { lastRefresh: number; - refreshInterval: number; refreshApp: () => void; } -export const APP_DEFAULT_REFRESH_INTERVAL = 1000 * 30; - const defaultContext: SyntheticsRefreshContext = { lastRefresh: 0, - refreshInterval: APP_DEFAULT_REFRESH_INTERVAL, refreshApp: () => { throw new Error('App refresh was not initialized, set it when you invoke the context'); }, @@ -28,21 +26,32 @@ export const SyntheticsRefreshContext = createContext(defaultContext); export const SyntheticsRefreshContextProvider: React.FC = ({ children }) => { const [lastRefresh, setLastRefresh] = useState(Date.now()); + const refreshPaused = useSelector(selectRefreshPaused); + const refreshInterval = useSelector(selectRefreshInterval); + const refreshApp = useCallback(() => { const refreshTime = Date.now(); setLastRefresh(refreshTime); }, [setLastRefresh]); const value = useMemo(() => { - return { lastRefresh, refreshApp, refreshInterval: APP_DEFAULT_REFRESH_INTERVAL }; + return { + lastRefresh, + refreshApp, + }; }, [lastRefresh, refreshApp]); useEffect(() => { + if (refreshPaused) { + return; + } const interval = setInterval(() => { - refreshApp(); - }, value.refreshInterval); + if (document.visibilityState !== 'hidden') { + refreshApp(); + } + }, refreshInterval * 1000); return () => clearInterval(interval); - }, [refreshApp, value.refreshInterval]); + }, [refreshPaused, refreshApp, refreshInterval]); return ; }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_absolute_date.ts b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_absolute_date.ts index 5eb74058d6f67d..cba04921a9a069 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_absolute_date.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_absolute_date.ts @@ -7,7 +7,9 @@ import datemath from '@elastic/datemath'; import { useMemo } from 'react'; +import moment, { DurationInputArg1, DurationInputArg2 } from 'moment'; import { useSyntheticsRefreshContext } from '../contexts'; +import { useGetUrlParams } from './use_url_params'; export function useAbsoluteDate({ from, to }: { from: string; to: string }) { const { lastRefresh } = useSyntheticsRefreshContext(); @@ -21,3 +23,30 @@ export function useAbsoluteDate({ from, to }: { from: string; to: string }) { [from, to, lastRefresh] ); } + +export function useRefreshedRange(inp: DurationInputArg1, unit: DurationInputArg2) { + const { lastRefresh } = useSyntheticsRefreshContext(); + + return useMemo( + () => ({ + from: moment(lastRefresh).subtract(inp, unit).toISOString(), + to: new Date(lastRefresh).toISOString(), + }), + [lastRefresh, inp, unit] + ); +} + +const isDefaultRange = (from: string, to: string) => { + return from === 'now-24h' && to === 'now'; +}; + +export function useRefreshedRangeFromUrl() { + const { dateRangeStart, dateRangeEnd } = useGetUrlParams(); + const isDefault = isDefaultRange(dateRangeStart, dateRangeEnd); + + const absRange = useAbsoluteDate({ from: dateRangeStart, to: dateRangeEnd }); + + const defaultRange = useRefreshedRange(24, 'hours'); + + return isDefault ? defaultRange : absRange; +} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_url_params.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_url_params.test.tsx index 37a0c3ad7e56fe..c067f3b17108f5 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_url_params.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_url_params.test.tsx @@ -10,7 +10,9 @@ import userEvent from '@testing-library/user-event'; import { render } from '../utils/testing'; import React, { useState, Fragment } from 'react'; import { useUrlParams, SyntheticsUrlParamsHook } from './use_url_params'; -import { APP_DEFAULT_REFRESH_INTERVAL, SyntheticsRefreshContext } from '../contexts'; +import { SyntheticsRefreshContext } from '../contexts'; +import { CLIENT_DEFAULTS_SYNTHETICS } from '../../../../common/constants/synthetics/client_defaults'; +const { AUTOREFRESH_INTERVAL_SECONDS } = CLIENT_DEFAULTS_SYNTHETICS; interface MockUrlParamsComponentProps { hook: SyntheticsUrlParamsHook; @@ -30,7 +32,7 @@ const UseUrlParamsTestComponent = ({